Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }})
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 9 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

<details>
<summary>Other methods</summary>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
27 changes: 20 additions & 7 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 3 additions & 5 deletions src/relay/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
_ => {}
}
Expand Down
Loading