# C4 Container diagram — Fleet Dispatch # Rendered with D2 (v0.7.1, tooling present at build time): d2 c4-container.d2 c4-container.svg # Referenced from docs/technical/ARCHITECTURE.md and docs/README.md. # Scope: one Fleet Dispatch node (any house PC) plus the shared infrastructure it depends on # and the external systems/actors it talks to. Every other house PC runs an identical node. direction: right operator: Andrew (Operator) { shape: person } mission_control: Fleet Mission Control { shape: person tooltip: "External system. Reads WorkerHeartbeat /health, reads the signed repo inventory,\nwrites the manual availability-override file. Not part of this repo." } house_pc: Fleet Dispatch node (one house PC) { shape: rectangle style.stroke-dash: 0 cli: fleet-dispatch CLI { shape: rectangle tooltip: "src/FleetDispatch.Cli/Program.cs — init-key, enqueue, send, listen, serve,\nrepo-scan, status, results, cancel, steer, worktree, kinds" } server: DispatchServer { shape: rectangle tooltip: "HttpListener bound to LAN/Tailscale addr + 127.0.0.1.\nGET /health, POST /dispatch." } queue: QueueService { shape: rectangle tooltip: "Gated queue-drain loop against this PC's own OneDrive inbox." } gate: AvailabilityGate { shape: rectangle tooltip: "FLT-128. Pure, stateless, fresh-signals-every-time hard gate.\nChecked before every non-control job, on both paths." } detector: AvailabilityDetector { shape: rectangle tooltip: "FLT-129. Always-on ~4s poll loop, hysteresis'd (90s/120s grace),\npublishes /health's availability object. Advisory only." } governor: GovernorGate { shape: rectangle tooltip: "Reads usage-governor state.json. RED/BLACKOUT defers non-critical jobs." } executor: RealJobExecutor { shape: rectangle tooltip: "IJobExecutor. Spawns the harness CLI or makes the odysseus HTTP call." } scanner: RepoRegistryScanner { shape: rectangle tooltip: "FLT-126. Boot + daily-timer scan of approved roots, signed, written\nto the shared repo-inventory dir." } cli -> queue: enqueue writes signed job to inbox cli -> server: send POSTs signed job to a peer's /dispatch server -> gate: evaluate before executing queue -> gate: evaluate before executing gate -> governor: (if allowed) check tier governor -> executor: (if not deferred) execute detector -> server: publishes availability for /health cli -> scanner: repo-scan (on demand) server -> scanner: boot + daily timer (in-process, ungated) } onedrive: OneDrive shared dispatch folder { shape: cylinder tooltip: "%OneDrive%\\PC-Bootstrap\\_shared\\dispatch\\\\{inbox,processing,outbox,archive}\nand \\_shared\\repo-inventory\\{PC}.json" } peer_registry: Peer registry files { shape: cylinder tooltip: "~/.claude/fleet-peers.json + _shared/peers/*.json — {PCNAME: host:port}" } fleet_key: Fleet key { shape: cylinder tooltip: "~/.claude/fleet-dispatch.key — 32-byte shared HMAC secret, copied via SSH,\nNEVER through OneDrive." } governor_state: Usage governor state.json { shape: cylinder tooltip: "~/.claude/usage-governor/state.json — {tier: GREEN|YELLOW|RED|BLACKOUT}" } steam_obs: Steam / OBS / registry { shape: rectangle tooltip: "HKCU Steam RunningAppID, obs64/obs32 process presence,\nlocal game allowlist JSON, manual override file" } harness_clis: Harness CLIs { shape: rectangle tooltip: "claude, codex (ChatGPT CLI), agy (Antigravity/Gemini), grok, ollama, pwsh/powershell" } odysseus: Odysseus (127.0.0.1:7000) { shape: rectangle tooltip: "Listener-side-only HTTP target for kind=odysseus jobs." } operator -> house_pc.cli: runs commands mission_control -> house_pc.server: GET /health (heartbeat) mission_control -> onedrive: "reads signed repo-inventory\\{PC}.json" mission_control -> onedrive: "writes availability\\{PC}.override.json" house_pc.queue -> onedrive: reads inbox, writes outbox/archive (atomic) house_pc.scanner -> onedrive: "writes signed repo-inventory\\{PC}.json" house_pc.cli -> fleet_key: init-key creates / loads house_pc.server -> fleet_key: verify bearer + job HMAC house_pc.queue -> fleet_key: verify job HMAC house_pc.server -> peer_registry: self-register on start house_pc.cli -> peer_registry: send resolves target host:port house_pc.governor -> governor_state: read tier house_pc.gate -> steam_obs: read fresh signals every job house_pc.detector -> steam_obs: poll every ~4s house_pc.executor -> harness_clis: spawn process (kind-dependent) house_pc.executor -> odysseus: HTTP call (kind=odysseus only) other_pcs: Other house PCs (identical nodes) { shape: rectangle style.stroke-dash: 4 } house_pc.server <-> other_pcs: POST /dispatch (direct peer path) other_pcs -> onedrive: shared queue + registry (async path)