Orchestrate a swarm of Claude Code agents with a local-LLM brain that learns from you.
cargo build # Debug build
cargo build --release # Release build, default features (bus+coord+relay+hive) — ~6.3 MB; matches the Homebrew bottle
cargo build --release --no-default-features --features hive # Minimal sync-only build — ~3.5 MB
cargo test # Run all tests
cargo clippy -- -D warnings # Lint (warnings are errors in CI)
cargo fmt --check # Check formattingThis is a Cargo workspace with three crates. Dependencies flow strictly downward — claudectl → claudectl-tui → claudectl-core — and CI enforces it (Layering grep on core, plus standalone build jobs for each crate). Adding upward arrows is what the workspace exists to prevent.
crates/
├── claudectl-core/ # foundational types, IO, the UI↔runtime trait contract
│ # session, discovery, monitor, process, transcript,
│ # models, theme, logger, helpers, history, terminals/,
│ # health, rules, config, hooks, launch, skills, runtime
└── claudectl-tui/ # terminal UI + recording + demo fixtures
# app.rs, ui/*, recorder.rs, session_recorder.rs, demo.rs
# Depends on claudectl-core. Never on the binary.
src/ # the binary crate `claudectl`
# main.rs + brain/ + bus/ + coord/ + hive/ + relay/ +
# orchestrator + init + commands + config.rs +
# brain_screen.rs.
# Implements the runtime traits over the real
# subsystems via `src/runtime/`.
UI ↔ runtime contract lives at crates/claudectl-core/src/runtime.rs. Eight traits — SessionSource, BrainView, CoordView, BusView, Actions, BrainReviewView, Orchestrator, HiveActions, plus the stateful BrainDriver — wrapped in a Runtime aggregate. Core-owned DTOs (SessionSnapshot, DecisionSummary, LeaseSummary, HiveViewSnapshot, etc.) so the contract doesn't drag brain / coord / bus types upward. The binary's src/runtime/ provides Live* adapters that implement each trait over the real subsystem.
Re-export bridge: src/lib.rs and src/main.rs both do pub use claudectl_core::{session, discovery, …}; and pub use claudectl_tui::{app, demo, recorder, session_recorder, ui}; so existing crate::session::* / crate::app::* paths in the binary keep resolving without rewriting every import.
Feature propagation: the binary's coord, relay, hive features propagate to claudectl-tui via claudectl-tui/coord etc. in [features], so a single #[cfg(feature = "...")] gate resolves consistently across both crates.
runtime.rs— view traits + DTOs +Runtime+MockRuntime. See above.session.rs— Session data structures and formattingdiscovery.rs— Scans~/.claude/sessions/*.jsonand resolves JSONL pathsmonitor.rs— Parses JSONL conversation logs for tokens, cost, status eventsprocess.rs— Process introspection via nativeps(not sysinfo crate)history.rs— Session history persistence and cost analyticshealth.rs— Session health monitoring (cache ratio, cost spikes, loop detection, stalls, context saturation). OwnsHealthThresholds.rules.rs— Auto-rule engine: match sessions by status/tool/command/project/cost, then approve/deny/send/terminate/route/spawn/delegatemodels.rs— Model pricing profiles (built-in + user overrides) for cost trackingtranscript.rs— JSONL transcript parser (messages, tool use, tool results, usage data)theme.rs— Color theming (dark/light/monochrome, respects NO_COLOR)logger.rs— Structured diagnostic logginghelpers.rs— Shared utilities (webhook, notification, kill_process, aggregate session)hooks.rs— Event hook system (shell commands fired on session events)launch.rs— Launch and resume Claude Code sessions from the TUI or CLIskills.rs— Skill registry + claude-plugin metadataconfig.rs—BrainConfig/IdleConfigdata structs (the binary still owns TOML parsing insrc/config.rs; only the value types live here)terminals/— Terminal backends; see below.
app.rs—Appstate struct, refresh loop, keyboard event handling. Holds aclaudectl_core::runtime::Runtimefor all brain/coord/bus reads and writes; never touches binary-only modules directly.ui/— Render functions:table.rs(session list),detail.rs(expanded panel),help.rs(overlay),status_bar.rs(footer),peers.rs(relay peers panel, featurerelay),skills.rs(skills overlay).recorder.rs— Dashboard recording (asciicast/GIF capture of full TUI).session_recorder.rs— Per-session highlight reel recording (extracts edits, commands, errors; strips idle time).demo.rs— Deterministic fake sessions for screenshots, recordings, demos. IncludesDemoHighlightStateanddemo_peers(featurerelay).
Feature flags: coord, relay, hive mirror the binary's same-named features and gate App fields and ui panels.
main.rs— CLI entry point, mode dispatch (TUI, watch, JSON, list, history, stats, orchestrator, clean, brain-eval, brain-query, mode, insights, init, doctor).brain_screen.rs— Full-screen Brain Review surface (scorecard + interactive review). Stays in the binary because it depends onbrain::metricsandbrain::risk;main.rscallsbrain_screen::render_brain_screenfor the brain panel. Every other ui render goes throughclaudectl_tui::ui::*.doctor.rs—claudectl doctor(#326). Unified install + runtime health checklist (PATH, hooks, plugin files, brain endpoint, bus feature, bus DB, session discovery, terminal integration). ReturnsCheckrows with Pass/Advisory/Fail/Skipped + fix hints;--jsonform for scripting. Replaces the scattered--doctorflag andinit --checkpaths.config.rs— Layered TOML config: CLI flags >.claudectl.toml>~/.config/claudectl/config.toml> defaults. Re-exportsBrainConfig,IdleConfig,HealthThresholdsfromclaudectl-core.orchestrator.rs— Multi-session task runner with dependency ordering.commands.rs— CLI command dispatch shared between modes.init/—claudectl initopinionated onboarding wizard (5 phases: budget, brain, plugin, bus, skills); seedocs/AGENT_BUS.md§8 and issue #257.init/plugin_assets.rs(#325) embeds everyclaude-plugin/file viainclude_str!so the Plugin phase writes a working install to~/.claude/plugins/claudectl/without a repo clone.runtime/—Live*adapters that implement theclaudectl-core::runtimetraits against the real subsystems (sessions, brain, coord SQLite, bus SQLite, orchestrator, hive). Seeruntime/{sessions,brain,brain_driver,brain_review,coord,bus,actions,orchestrator,hive}.rs.
Claude Code Plugin (claude-plugin/): Integrates the brain directly into Claude Code sessions.
hooks/scripts/brain-gate.sh— PreToolUse hook: queries brain for approve/deny on Bash/Write/Edit callshooks/scripts/budget-check.sh— PreToolUse hook: enforces spend limitscommands/— Slash commands:/sessions,/spend,/brain-stats,/brain,/auto-insightsagents/supervisor.md— Session health triage agentskills/session-monitoring/— Auto-activated session awareness skill
Brain (src/brain/): Local LLM auto-pilot subsystem.
engine.rs— Main brain loop: observes sessions, evaluates rules, queries LLM, executes decisionsclient.rs— HTTP client for local LLM endpoints (ollama, llama.cpp, vLLM, LM Studio)context.rs— Builds session context summaries for LLM promptsdecisions.rs— Decision logging and few-shot retrieval (learns from past corrections)agents.rs— Agent delegation supportmailbox.rs— Message passing between brain and TUIprompts.rs— Prompt templates (built-in + user overrides via~/.claudectl/brain/prompts/)evals.rs— Eval harness for testing brain decision quality against scenariosinsights.rs— Auto-insights: friction pattern detection, rule suggestions, differential tracking
Relay (src/relay/): Cross-machine TCP transport (feature-gated behind relay).
mod.rs— PeerId, RelayMessage, MessageType, identity persistence, peer PSK storagecrypto.rs— Inline SHA-256 + HMAC-SHA256, PSK generation/formattingprotocol.rs— NDJSON framing over TCP, HMAC challenge-response authpeer.rs— PeerConnection: connect, send, reader thread, heartbeat, reconnectlistener.rs— TcpListener accept loop with auth rate limiting, max peersmesh.rs— PeerRegistry: broadcast, send_to, message dedup, heartbeat tickdelegation.rs— DelegationContext, message builders for DelegateTask/TaskStatus/TaskHandoff/TaskInterruptworker.rs— RemoteWorker: accepts delegated tasks, spawns claude sessions, reports statusinvite.rs— Invite codes (base32), word phrases (256-word list), invite links (cctl://), QR renderinglan.rs— UDP broadcast LAN discovery: announcer and scanner threadscli.rs— CLI dispatch for all relay subcommands (serve, invite, join, discover, delegate, etc.)
Bus (src/bus/): Agent-bus MCP server, durable role directory, and mailbox (feature-gated behind bus; see docs/AGENT_BUS.md).
mod.rs— module surfacestore.rs— SQLite (WAL) at~/.claudectl/bus/bus.db: roles + messages tables (withhop_countcolumn), drain + peek semanticsroles.rs— Role addressing, cwd-inference, ambiguity/unbound resolution. Caller may override withCLAUDECTL_BUS_ROLEor--rolepolicy.rs— Guardrails: subject grammar, type allowlist, body cap, leading-/neutralization (§9), hop cap (default 8), reserved-role guard (supervisor/operatorcannot be bound)rate_limit.rs— In-process token bucket persender_role; default 60 messages/min, refills continuously without a background timermcp.rs— rmcp stdio server exposingwhoami,list_agents,publish(withparent_hop),read_inbox(withpeek), plus supervisor toolssubmit_task/list_tasks/task_statuscli.rs—claudectl bussubcommand (stdio, role bind/list, send, inbox +--peek, whoami, stop-hook driver, prune)
Supervisor (src/coord/{supervisor,actuator,verify,resume,tasks,session_policy,hook_events,events,exporter,supervisor_cli}.rs, src/ingest.rs): Durable, verified task lifecycles on top of the bus (see docs/AGENT_BUS.md#10-supervisor and README §Supervisor).
tasks.rs—tasks/task_attempts/task_verifications/task_transitionsCRUD + state machine. Every transition writes state + log in one transaction so the ledger invariant "every state has a cause" holds.supervisor.rs— pure reconciler. Reads desired state from coord, observed state fromSensors, returnsVec<Action>. No I/O. Health-check →HealthActionmapping table.Unknownobserved status is the no-actuation backstop (RFC §6).actuator.rs— Carries outActions. Three-step: insert attempt → perform side effect → log transition. Side-effect failure stops before the transition is recorded, so the next tick re-emits.verify.rs—Verifierenum (Run/Brain/Agent) +run_verifierdispatch. Fail-closed on missing PASS/FAIL marker.build_retry_promptcomposes original + failure output + "fix these issues" feedback.resume.rs— Tree-state hash (git when available, mtime fallback) + recovery-prompt builder. Resume the task, not the session.session_policy.rs— Atomic per-session policy file at~/.claudectl/coord/session-policy/<session>.json. Brain-gate hook reads it on every tool call; fail-open toInheritkeeps the manual-upgrade gap non-breaking.hook_events.rs—hook_eventstable (latency-only signal path; JSONL tail stays authoritative).events.rs— v1 NDJSON event schema (frozen). Three families:task.transition,task.verification,task.escalated.exporter.rs— Hand-rolled HTTP/metricsserver (no web framework dep). Worker thread per scrape so the tick loop never blocks. Exposesclaudectl_tasks_by_state,claudectl_fleet_cost_usd_total,claudectl_retries_total,claudectl_verifier_pass_rate.supervisor_cli.rs—claudectl supervisorsubcommand (run / submit / status / logs / cancel / drain / undrain). Hand-rolled TOML reader for thetasks.tomlsubset.src/ingest.rs—claudectl ingest --hook <name>subcommand. Bash hooks callclaudectl ingest --hook PostToolUse 2>/dev/null || true. Best-effort by construction.
Coord schema is gated on PRAGMA user_version (EXPECTED_COORD_SCHEMA_VERSION = 3 today). A binary that meets a newer schema refuses to start with the exact init --upgrade remediation in the error.
Hive (src/hive/): Gossip-based knowledge sharing across connected brains (feature-gated behind relay).
mod.rs— KnowledgeUnit, KnowledgeScope, KnowledgeContent types, semantic key, broadcast channelstore.rs— JSONL-backed knowledge store with semantic index, atomic savedistiller.rs— Converts DistilledPreferences/Insights into KnowledgeUnits with thresholdsmerger.rs— Conflict resolution: local always wins, peer-vs-peer by confidence*evidencegossip.rs— GossipEngine: incremental sync, snapshot pagination, epidemic propagationtrust.rs— PeerTrust with auto-drift, TrustTier classification, TrustStore persistenceinjection.rs— Brain prompt integration with trust labels, concordance checking for driftcli.rs— CLI dispatch for hive subcommands (status, knowledge, export, import, trust)
Terminal backends (crates/claudectl-core/src/terminals/): Ghostty, Kitty, tmux, WezTerm, Warp, iTerm2, Terminal.app, Gnome Terminal, Windows Terminal — auto-detected, used for tab switching and input sending.
- Minimal dependencies — 7 runtime crates in the sync core. Startup under 50ms. Exception: the
busfeature pulls rmcp + Tokio + schemars (every available MCP SDK is async) and is in the default feature set since the supervisor RFC (#342) —cargo installandbrew installproduce the same ~6 MB binary. The minimal sync-only build path (--no-default-features --features hive) remains CI-tested as the lower bound. - Native
psoversysinfocrate to keep binary small. - Multi-signal status inference — combines CPU usage, JSONL events, and timestamps (not just one signal).
- Incremental JSONL parsing — tracks file offsets, never rereads full files.
- No async runtime — synchronous with polling. Keeps complexity low. Exception: the
busMCP server (src/bus/mcp.rs) runs inside a current-thread Tokio runtime when invoked asclaudectl bus stdio. The TUI and every other code path remain sync. - Deny-first rule evaluation — deny rules always override approve/brain suggestions, regardless of config order.
- Brain decisions are local-only — all decision logs and few-shot examples stay on the user's machine.
- Brain gate mode —
~/.claudectl/brain/gate-modecontrols on/off/auto. File absent = on (default). The plugin hook and--brain-queryboth check this before querying the LLM. - Insights mode —
~/.claudectl/brain/insights-modecontrols auto-generation of insights. File absent = off (opt-in). When on, insights are generated alongside preference distillation every 10 decisions.
- Run
cargo fmtandcargo clippy -- -D warningsbefore committing. - Tests live in
tests/integration_tests.rsandtests/unit_tests.rs. - Status inference logic has extensive test coverage — do not change status detection without updating tests.
- Health checks in
crates/claudectl-core/src/health.rshave full unit test coverage — add tests for new checks. - Terminal backends implement the pattern in
crates/claudectl-core/src/terminals/mod.rs— add new terminals there. - Config fields must be added to all three layers (CLI args in
main.rs, TOML struct inconfig.rs, merge logic inconfig.rs). - Dependency direction:
claudectl(binary) depends onclaudectl-tuiandclaudectl-core.claudectl-tuidepends onclaudectl-coreonly.claudectl-coredepends on nothing claudectl-specific — nocrate::brain,crate::bus,crate::coord,crate::hive, etc. references from inside core. CI rejects upward references via a grep guard plus standalone build jobs (Core (standalone),TUI (standalone)). - Foundational modules in core (and now TUI) never have
pub(crate)on items downstream needs to call — promote topubinstead. The binary is a downstream consumer of both other crates. - Brain prompt templates can be overridden by placing files in
~/.claudectl/brain/prompts/— run--brain-promptsto list sources. - Plugin hook scripts must check for
claudectlavailability and exit 0 on failure — never block Claude Code. - Plugin commands call
claudectlCLI modes and format output — they don't implement logic directly.