From 1cf7be95dbd6644b8a1bfd50ae42ece89a9af826 Mon Sep 17 00:00:00 2001 From: Barada Sahu Date: Tue, 9 Jun 2026 14:27:52 -0700 Subject: [PATCH] feat: align cargo default features with brew + reconcile hook docs (#343) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR1 of the supervisor RFC (#342). Two related quickstart fixes that unblock everything else in the epic. ## Default features `cargo install claudectl` shipped `["hive"]` only; the Homebrew bottle ships `["bus","coord","relay","hive"]`. So cargo users hit silent no-ops on `claudectl bus`, `claudectl coord`, and (under #345 onward) the supervisor. Flip defaults to match brew — same ~6 MB binary from either install path. The minimal sync-only build path (~3.5 MB) survives as `--no-default-features --features hive` and is now CI-tested as the lower bound (previously the default). Knock-on: `cargo clippy --all-targets` under new defaults caught a pre-existing `collapsible_match` lint in `relay/mesh.rs` that the old defaults never exercised. Fixed inline — pure cleanup, no behavior change. ## Hook docs The quickstart's hook table listed only the legacy `claudectl --json` hooks written to `~/.claude/settings.json`. Reality: `init` also installs the embedded plugin under `~/.claude/plugins/claudectl/`, whose `hooks/hooks.json` adds brain-gate, outcome-record, session-briefing, and inbox-drain on top. The inbox-drain hook returns `decision:"block"` for the Trigger A continue-in-turn path documented in `docs/AGENT_BUS.md`. Both sets coexist; Claude Code merges them. The table now enumerates both, with the actual installed commands and what each does. This is the consent surface for the supervisor's future hook consumer (#345 ingest path) — a skeptical reader needs to see the full picture before that lands. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 9 ++++++--- .github/workflows/release.yml | 7 ++++--- CLAUDE.md | 6 +++--- Cargo.toml | 12 +++++++++--- README.md | 14 ++++++-------- docs/quickstart.md | 27 ++++++++++++++++++++------- src/relay/mesh.rs | 8 +++----- 7 files changed, 51 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ac2cc24..77d7567f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,8 +17,11 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + # Default features now include bus+coord+relay+hive (mirrors the + # Homebrew bottle). The no-default-features matrix preserves coverage + # of the minimal sync-only build path. - run: cargo check --all-targets - - run: cargo check --all-targets --features coord + - run: cargo check --all-targets --no-default-features --features hive fmt: name: Format @@ -40,7 +43,7 @@ jobs: components: clippy - uses: Swatinem/rust-cache@v2 - run: cargo clippy --all-targets -- -D warnings - - run: cargo clippy --all-targets --features coord -- -D warnings + - run: cargo clippy --all-targets --no-default-features --features hive -- -D warnings test: name: Test (${{ matrix.os }}) @@ -53,7 +56,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo test --all-targets - - run: cargo test --all-targets --features coord + - run: cargo test --all-targets --no-default-features --features hive # Workspace refactor (#279) — verify claudectl-core builds and tests # standalone, without the binary crate. Guards the diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7e3166b6..dd19f92a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,9 +76,10 @@ jobs: - name: Build (native) # #321 — release tarballs (and therefore Homebrew bottles) # include every optional feature so `claudectl bus`, `coord`, - # `relay`, and `hive` all work out of the box. Cargo-install - # users still get the default (`hive`) build; they can opt in - # with `cargo install claudectl --features bus,coord,relay,hive`. + # `relay`, and `hive` all work out of the box. Since the + # supervisor RFC (#342, PR1) the cargo defaults match this set, + # so `--features` here is redundant but kept explicit — release + # builds should never silently drift if defaults change later. if: matrix.target != 'aarch64-unknown-linux-musl' run: | cargo build --release \ diff --git a/CLAUDE.md b/CLAUDE.md index 458330ad..0289bc4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,8 +6,8 @@ Orchestrate a swarm of Claude Code agents with a local-LLM brain that learns fro ```bash cargo build # Debug build -cargo build --release # Release build, default features (hive only) — ~3.5 MB -cargo build --release --features "bus,coord,relay,hive" # Full feature set — ~6.3 MB; what the Homebrew bottle ships +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 @@ -137,7 +137,7 @@ Feature flags: `coord`, `relay`, `hive` mirror the binary's same-named features ## Key Design Decisions -- **Minimal dependencies** — 7 runtime crates. Binary must stay under 1MB, startup under 50ms. **Exception:** the `bus` feature deliberately relaxes this (pulls rmcp + Tokio + schemars) because every available MCP SDK is async; the default build still honors the invariant. +- **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. diff --git a/Cargo.toml b/Cargo.toml index 225cdf28..e4f6b556 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,15 +20,21 @@ categories = ["command-line-utilities", "development-tools"] exclude = ["*.gif", "*.cast", "claude-demo.*", "CLAUDE.md", ".github/"] [features] -default = ["hive"] +# Default features mirror the Homebrew bottle (see .github/workflows/release.yml) +# so `cargo install claudectl` and `brew install claudectl` produce identical +# binaries. The supervisor (issue #342) requires `coord` at minimum and +# `bus` for its MCP tool surface — keeping defaults aligned prevents the +# "cargo users hit silent no-ops" gap that motivated this change. +default = ["bus", "coord", "relay", "hive"] # Propagated to claudectl-tui so its `App` struct can cfg-gate the matching # UI panels (coord widgets, relay peers panel, hive overlay tabs). coord = ["rusqlite", "claudectl-tui/coord"] relay = ["claudectl-tui/relay"] hive = ["claudectl-tui/hive"] # The agent bus (docs/AGENT_BUS.md). Lives on top of coord's SQLite layer and -# pulls in an async MCP server stack (rmcp + tokio). Opt-in: the default build -# stays small and sync. +# pulls in an async MCP server stack (rmcp + tokio). Now in defaults; opt +# out with `cargo build --no-default-features --features hive` for the +# ~3.5 MB sync-only build. bus = ["coord", "dep:rmcp", "dep:tokio", "dep:schemars", "dep:async-trait"] [[bin]] diff --git a/README.md b/README.md index d57d11c5..3623c4eb 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,11 @@ Run `claudectl --brain-stats impact` to see your numbers: ## Install ```bash -brew install mercurialsolo/tap/claudectl # Homebrew (macOS / Linux) — ships with bus/coord/relay/hive -cargo install claudectl # Cargo (any platform) — default features (hive only) -cargo install claudectl --features bus,coord,relay,hive # Cargo with all features +brew install mercurialsolo/tap/claudectl # Homebrew (macOS / Linux) +cargo install claudectl # Cargo (any platform) ``` -Homebrew ships the full-feature binary so `claudectl bus`, `coord`, `relay`, and `hive` work out of the box (~6 MB). `cargo install` defaults to the minimal build (`hive` only, ~3.5 MB) — opt in to the rest with `--features` as shown. +Both produce the same ~6 MB binary with bus/coord/relay/hive enabled — `claudectl bus`, `coord`, `relay`, and `hive` work out of the box. For the minimal ~3.5 MB sync-only build, opt out with `cargo install claudectl --no-default-features --features hive`.
Other methods @@ -173,7 +172,7 @@ claudectl Multi-agent coordination for parallel coding sessions. Prevents duplicate work, manages ownership, and routes context between agents. -Build with `cargo build --features coord` to enable. +Enabled by default. For the minimal sync-only build, use `cargo build --no-default-features --features hive`. ```bash # Ownership leases — prevent two agents from editing the same file @@ -206,7 +205,7 @@ The coordination layer stores state in a local SQLite database (`~/.claudectl/co A durable directory + mailbox that exposes the running swarm as an MCP server. Agents discover each other (`list_agents`), look up their own role (`whoami`), publish directed messages, and drain their inbox at turn boundaries. Phases 1–4 of the [design spec](docs/AGENT_BUS.md) are shipped. -Build with `cargo build --features bus` to enable. Pulls in `rmcp` + a current-thread Tokio runtime, so the bus-enabled binary is larger (~6.4 MB vs. ~3.5 MB default) and the no-async-runtime invariant is deliberately relaxed for this feature path only. +Enabled by default. Pulls in `rmcp` + a current-thread Tokio runtime, which is why the default binary is ~6 MB; the no-async-runtime invariant is deliberately relaxed for the `bus` feature path. For the minimal sync-only build (~3.5 MB), use `cargo build --no-default-features --features hive`. ```bash # Bind durable role addresses to working directories @@ -243,8 +242,7 @@ claudectl hive status claudectl hive knowledge claudectl hive distill # Condense archive into curriculum -# Add relay for cross-machine networking -cargo install claudectl --features relay +# Relay for cross-machine networking is enabled by default claudectl relay invite # Generate an invite code claudectl relay join YEK-AGA-YHK-QAA-BM # Join from another machine claudectl relay discover # Scan LAN for nearby instances diff --git a/docs/quickstart.md b/docs/quickstart.md index 91820475..951e63d7 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -35,15 +35,28 @@ If you only want the hook install (the previous `--init` flag), that's the **Plu Your existing Claude Code settings are preserved; the hook install only adds claudectl entries. -**What gets added:** +**What gets added:** the Plugin phase writes hooks in two places — into `~/.claude/settings.json` (the dashboard-observability hooks) and into the embedded plugin at `~/.claude/plugins/claudectl/hooks/hooks.json` (the bus + brain plugin hooks). Both sets coexist; Claude Code merges them. -| Hook | Matcher | What it does | -|------|---------|--------------| -| `PreToolUse` | `Bash` | Lets claudectl see commands before they run | -| `PostToolUse` | `*` | Notifies claudectl after every tool completion | -| `Stop` | (all) | Notifies claudectl when a session ends | +**`~/.claude/settings.json` (dashboard observability):** -The hooks call `claudectl --json 2>/dev/null || true` — if claudectl isn't running, Claude Code continues normally. +| Hook | Matcher | Command | What it does | +|------|---------|---------|--------------| +| `PreToolUse` | `Bash` | `claudectl --json 2>/dev/null \|\| true` | Lets claudectl see Bash commands before they run | +| `PostToolUse` | `*` | `claudectl --json 2>/dev/null \|\| true` | Notifies claudectl after every tool completion | +| `Stop` | (all) | `claudectl --json 2>/dev/null \|\| true` | Notifies claudectl when a turn ends | + +These are fire-and-forget snapshot reads. `|| true` keeps Claude Code unblockable if claudectl isn't installed or fails. + +**`~/.claude/plugins/claudectl/hooks/hooks.json` (bus + brain plugin):** + +| Hook | Matcher | Script | What it does | +|------|---------|--------|--------------| +| `PreToolUse` | `Bash\|Write\|Edit\|NotebookEdit` | `brain-gate.sh` | Queries the local LLM for approve/deny on potentially destructive tool calls | +| `PostToolUse` | `Bash\|Write\|Edit\|NotebookEdit` | `outcome-record.sh` | Records the outcome so the brain learns from your corrections | +| `SessionStart` | (all) | `session-briefing.sh` | Surfaces queued mail and recent context at session start | +| `Stop` | (all) | `inbox-drain.sh` | Drains the agent's bus mailbox; can return `decision:"block"` with `additionalContext` to deliver mail in the same turn (Trigger A in [docs/AGENT_BUS.md](AGENT_BUS.md#6-notification--delivery-handshake)) | + +Both sets are removed cleanly by `claudectl init --remove`. ## 3. Verify the install diff --git a/src/relay/mesh.rs b/src/relay/mesh.rs index ca63965c..79c65d35 100644 --- a/src/relay/mesh.rs +++ b/src/relay/mesh.rs @@ -182,11 +182,9 @@ impl PeerRegistry { } } } - PeerState::Disconnected if peer.is_initiator => { - if peer.should_reconnect() { - events.push(MeshEvent::ReconnectNeeded(peer.peer_id.clone(), peer.addr)); - peer.schedule_reconnect(); - } + PeerState::Disconnected if peer.is_initiator && peer.should_reconnect() => { + events.push(MeshEvent::ReconnectNeeded(peer.peer_id.clone(), peer.addr)); + peer.schedule_reconnect(); } _ => {} }