dragoon
Disconnected Rapid Guidance Once-deployed Operational Network — a public-relay command executor for long-running experiments, named after the Gundam SEED 浮游炮 system since the architecture is isomorphic: a controller pilots remote autonomous nodes that execute tasks under cryptographically authenticated commands.
The model is ctl → server → worker(s) over HTTPS: every component connects out, so no NAT/firewall holes are needed on the worker boxes.
Three binaries, one Cargo workspace:
| Binary | Role |
|---|---|
dragoon-server |
Public-relay HTTP server (axum + rusqlite). The only host that needs an inbound port. |
dragoon-worker |
Execution agent. Polls the server, runs shell payloads, streams logs/artifacts back. |
dragoon-ctl |
Controller CLI. Submits commands, tails logs, drains the message inbox. |
The original Python implementation lives in git history (last commit:
8cce0de deletes it). Wire format, SQLite schema, canonical strings and
fingerprints are byte-for-byte unchanged — fixture parity tests in
crates/dragoon-proto/tests/ lock that down.
See docs/plans/2026-04-27-remote-executor-design.md
for the full design (auth model, protocol, state machine).
Build
# produces target/release/{dragoon-server, dragoon-worker, dragoon-ctl}
Tests: cargo test --workspace (~120 unit + integration tests, including
4 byte-for-byte parity fixtures and the auth_routes axum integration tests).
Lint: cargo clippy --workspace --all-targets -- -D warnings is clean.
Quick start (loopback, no TLS)
DATA=/tmp/re-demo
&&
# admin pipeline
|
TOTP_SECRET=... # printed by the previous step
CODE=
# server up
&
# worker register + run (on the same or a different box)
&
# ctl: log in, submit, watch
TOTP=
|
TID=
Cross-compile a worker for another arch
The xtask cargo subcommand detects the target's arch over SSH and
builds a static musl binary against the right Rust target triple, then
scps it over and installs.
# detects Linux aarch64 -> aarch64-unknown-linux-musl
# cargo build --release -p dragoon-worker --target aarch64-unknown-linux-musl
# scp -> /tmp/dragoon-worker.new.<pid> -> install -m 0755 to /usr/local/bin/dragoon-worker
Build all supported triples for an offline distribution:
# dragoon-worker-aarch64-unknown-linux-musl
# dragoon-worker-armv7-unknown-linux-musleabihf
If a target's musl linker isn't on PATH, cargo xtask doctor --triple T
tells you what to install (apt install musl-tools,
aarch64-linux-musl-cross, etc.) — or fall back to cargo install cross
and use cross build directly.
macOS targets (x86_64-apple-darwin, aarch64-apple-darwin) only build
on a mac host — Linux→Mac cross-compilation is intentionally out of scope.
Workspace layout
crates/
dragoon-proto/ shared protocol primitives (constants, wire format,
canonical strings, signers, models). Pure-Rust, no
tokio/reqwest/sqlite. The byte-parity fixture tests
live here.
dragoon-server/ axum app + rusqlite (bundled) + argon2id + totp-rs +
ed25519/RSA key handling. Routes:
/v1/auth/{challenge,login,logout}
/v1/workers, /v1/workers/{name}/fetch
/v1/tasks, /v1/tasks/{id}/{cancel,log,artifact}
/v1/messages, /v1/messages/ack
/v1/worker/{init,poll,log,finish,blob}
dragoon-worker/ reqwest + nix (setsid + killpg) + globset + walkdir.
Spawns bash -c in its own process group; threaded
stdout/stderr readers; SIGTERM→grace→SIGKILL on cancel.
dragoon-ctl/ reqwest signed-request client (KeyFileSigner or
AgentSigner over SSH_AUTH_SOCK) + clap CLI.
dragoon-testkit/ dev-only fixture loaders + harness.
xtask/ cross-compile orchestrator (see above).
fixtures/ JSON fixtures committed to repo; the source of truth
for canonical_request, canonical_task, fingerprints
and ed25519 signatures.
.claude/skills/ Project-level Claude Code skills (deploy-server,
deploy-worker, send-command).
Authentication summary
ctl → server
Every business request must carry all of:
Authorization: Bearer <session_token>X-RE-Timestamp(±60 s window)X-RE-Nonce(5-min one-shot)X-RE-Key-Fingerprint(must match the session-bound fp)X-RE-Signature(SSH-wire ed25519 / rsa-sha2-512 signature over theRE-V1canonical request bytes)
KeyFileSigner (loaded private key) and AgentSigner (talks the SSH
agent protocol over SSH_AUTH_SOCK) both produce the wire format the
server's verify_ssh_wire_signature accepts.
server → worker
Every assigned task is signed by the per-server ed25519 task-signing
key. Worker pins the public key on init and rejects any
out-of-signature, mismatched-name, or out-of-order-seq task with
error="bad_task_signature: <reason>" before spawning a subprocess.
License
Dual-licensed under either of:
at your option.