Skip to content

Latest commit

 

History

History
178 lines (149 loc) · 17.1 KB

File metadata and controls

178 lines (149 loc) · 17.1 KB

claudectl

Orchestrate a swarm of Claude Code agents with a local-LLM brain that learns from you.

Build & Test

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 formatting

Architecture

Workspace layout

This 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.

Core modules — claudectl-core (crates/claudectl-core/src/)

  • runtime.rs — view traits + DTOs + Runtime + MockRuntime. See above.
  • session.rs — Session data structures and formatting
  • discovery.rs — Scans ~/.claude/sessions/*.json and resolves JSONL paths
  • monitor.rs — Parses JSONL conversation logs for tokens, cost, status events
  • process.rs — Process introspection via native ps (not sysinfo crate)
  • history.rs — Session history persistence and cost analytics
  • health.rs — Session health monitoring (cache ratio, cost spikes, loop detection, stalls, context saturation). Owns HealthThresholds.
  • rules.rs — Auto-rule engine: match sessions by status/tool/command/project/cost, then approve/deny/send/terminate/route/spawn/delegate
  • models.rs — Model pricing profiles (built-in + user overrides) for cost tracking
  • transcript.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 logging
  • helpers.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 CLI
  • skills.rs — Skill registry + claude-plugin metadata
  • config.rsBrainConfig / IdleConfig data structs (the binary still owns TOML parsing in src/config.rs; only the value types live here)
  • terminals/ — Terminal backends; see below.

TUI modules — claudectl-tui (crates/claudectl-tui/src/)

  • app.rsApp state struct, refresh loop, keyboard event handling. Holds a claudectl_core::runtime::Runtime for 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, feature relay), 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. Includes DemoHighlightState and demo_peers (feature relay).

Feature flags: coord, relay, hive mirror the binary's same-named features and gate App fields and ui panels.

Binary modules — claudectl (src/)

  • 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 on brain::metrics and brain::risk; main.rs calls brain_screen::render_brain_screen for the brain panel. Every other ui render goes through claudectl_tui::ui::*.
  • doctor.rsclaudectl doctor (#326). Unified install + runtime health checklist (PATH, hooks, plugin files, brain endpoint, bus feature, bus DB, session discovery, terminal integration). Returns Check rows with Pass/Advisory/Fail/Skipped + fix hints; --json form for scripting. Replaces the scattered --doctor flag and init --check paths.
  • config.rs — Layered TOML config: CLI flags > .claudectl.toml > ~/.config/claudectl/config.toml > defaults. Re-exports BrainConfig, IdleConfig, HealthThresholds from claudectl-core.
  • orchestrator.rs — Multi-session task runner with dependency ordering.
  • commands.rs — CLI command dispatch shared between modes.
  • init/claudectl init opinionated onboarding wizard (5 phases: budget, brain, plugin, bus, skills); see docs/AGENT_BUS.md §8 and issue #257. init/plugin_assets.rs (#325) embeds every claude-plugin/ file via include_str! so the Plugin phase writes a working install to ~/.claude/plugins/claudectl/ without a repo clone.
  • runtime/Live* adapters that implement the claudectl-core::runtime traits against the real subsystems (sessions, brain, coord SQLite, bus SQLite, orchestrator, hive). See runtime/{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 calls
  • hooks/scripts/budget-check.sh — PreToolUse hook: enforces spend limits
  • commands/ — Slash commands: /sessions, /spend, /brain-stats, /brain, /auto-insights
  • agents/supervisor.md — Session health triage agent
  • skills/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 decisions
  • client.rs — HTTP client for local LLM endpoints (ollama, llama.cpp, vLLM, LM Studio)
  • context.rs — Builds session context summaries for LLM prompts
  • decisions.rs — Decision logging and few-shot retrieval (learns from past corrections)
  • agents.rs — Agent delegation support
  • mailbox.rs — Message passing between brain and TUI
  • prompts.rs — Prompt templates (built-in + user overrides via ~/.claudectl/brain/prompts/)
  • evals.rs — Eval harness for testing brain decision quality against scenarios
  • insights.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 storage
  • crypto.rs — Inline SHA-256 + HMAC-SHA256, PSK generation/formatting
  • protocol.rs — NDJSON framing over TCP, HMAC challenge-response auth
  • peer.rs — PeerConnection: connect, send, reader thread, heartbeat, reconnect
  • listener.rs — TcpListener accept loop with auth rate limiting, max peers
  • mesh.rs — PeerRegistry: broadcast, send_to, message dedup, heartbeat tick
  • delegation.rs — DelegationContext, message builders for DelegateTask/TaskStatus/TaskHandoff/TaskInterrupt
  • worker.rs — RemoteWorker: accepts delegated tasks, spawns claude sessions, reports status
  • invite.rs — Invite codes (base32), word phrases (256-word list), invite links (cctl://), QR rendering
  • lan.rs — UDP broadcast LAN discovery: announcer and scanner threads
  • cli.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 surface
  • store.rs — SQLite (WAL) at ~/.claudectl/bus/bus.db: roles + messages tables (with hop_count column), drain + peek semantics
  • roles.rs — Role addressing, cwd-inference, ambiguity/unbound resolution. Caller may override with CLAUDECTL_BUS_ROLE or --role
  • policy.rs — Guardrails: subject grammar, type allowlist, body cap, leading-/ neutralization (§9), hop cap (default 8), reserved-role guard (supervisor/operator cannot be bound)
  • rate_limit.rs — In-process token bucket per sender_role; default 60 messages/min, refills continuously without a background timer
  • mcp.rs — rmcp stdio server exposing whoami, list_agents, publish (with parent_hop), read_inbox (with peek), plus supervisor tools submit_task / list_tasks / task_status
  • cli.rsclaudectl bus subcommand (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.rstasks / task_attempts / task_verifications / task_transitions CRUD + state machine. Every transition writes state + log in one transaction so the ledger invariant "every state has a cause" holds.
  • supervisor.rspure reconciler. Reads desired state from coord, observed state from Sensors, returns Vec<Action>. No I/O. Health-check → HealthAction mapping table. Unknown observed status is the no-actuation backstop (RFC §6).
  • actuator.rs — Carries out Actions. 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.rsVerifier enum (Run/Brain/Agent) + run_verifier dispatch. Fail-closed on missing PASS/FAIL marker. build_retry_prompt composes 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 to Inherit keeps the manual-upgrade gap non-breaking.
  • hook_events.rshook_events table (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 /metrics server (no web framework dep). Worker thread per scrape so the tick loop never blocks. Exposes claudectl_tasks_by_state, claudectl_fleet_cost_usd_total, claudectl_retries_total, claudectl_verifier_pass_rate.
  • supervisor_cli.rsclaudectl supervisor subcommand (run / submit / status / logs / cancel / drain / undrain). Hand-rolled TOML reader for the tasks.toml subset.
  • src/ingest.rsclaudectl ingest --hook <name> subcommand. Bash hooks call claudectl 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 channel
  • store.rs — JSONL-backed knowledge store with semantic index, atomic save
  • distiller.rs — Converts DistilledPreferences/Insights into KnowledgeUnits with thresholds
  • merger.rs — Conflict resolution: local always wins, peer-vs-peer by confidence*evidence
  • gossip.rs — GossipEngine: incremental sync, snapshot pagination, epidemic propagation
  • trust.rs — PeerTrust with auto-drift, TrustTier classification, TrustStore persistence
  • injection.rs — Brain prompt integration with trust labels, concordance checking for drift
  • cli.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.

Key Design Decisions

  • Minimal dependencies — 7 runtime crates in the sync core. Startup under 50ms. Exception: the bus feature pulls rmcp + Tokio + schemars (every available MCP SDK is async) and is in the default feature set since the supervisor RFC (#342) — cargo install and brew install produce the same ~6 MB binary. The minimal sync-only build path (--no-default-features --features hive) remains CI-tested as the lower bound.
  • Native ps over sysinfo crate 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 bus MCP server (src/bus/mcp.rs) runs inside a current-thread Tokio runtime when invoked as claudectl 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-mode controls on/off/auto. File absent = on (default). The plugin hook and --brain-query both check this before querying the LLM.
  • Insights mode~/.claudectl/brain/insights-mode controls auto-generation of insights. File absent = off (opt-in). When on, insights are generated alongside preference distillation every 10 decisions.

Conventions

  • Run cargo fmt and cargo clippy -- -D warnings before committing.
  • Tests live in tests/integration_tests.rs and tests/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.rs have 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 in config.rs, merge logic in config.rs).
  • Dependency direction: claudectl (binary) depends on claudectl-tui and claudectl-core. claudectl-tui depends on claudectl-core only. claudectl-core depends on nothing claudectl-specific — no crate::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 to pub instead. 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-prompts to list sources.
  • Plugin hook scripts must check for claudectl availability and exit 0 on failure — never block Claude Code.
  • Plugin commands call claudectl CLI modes and format output — they don't implement logic directly.