squadrant
v0.12.0
Published
Multi-project orchestration for your coding agents (Claude, Codex, opencode, Gemini)
Maintainers
Readme
Squadrant
Multi-project orchestration layer for coding agents. One command session controls everything.
Direction: Squadrant is moving to support all major coding agents — Claude Code, Codex, Cursor, Gemini CLI — not just Claude Code. Claude Code is the reference implementation today; other agents land through the plugin system's driver abstractions and the upcoming cross-agent projection layer (#31). See
docs/specs/2026-04-24-multi-agent-direction.md.
How It Works
squadrant launch <project> → Captain (per project, in cmux)
squadrant launch --all → Every Captain
squadrant command --task briefing → One-shot Command session in a split pane
(also: --task learnings-review | wiki-aggregate)
Captain → squadrant crew spawn … → Crew (new tab in the captain workspace, fresh agent CLI)squadrant init— first-time setupsquadrant launch <project>— start the project's captain in cmuxsquadrant launch --all— start every captain at oncesquadrant command --task briefing— on-demand Command session for cross-project work (optional; spawns in a split pane and exits when done)squadrant status— quick status check without spawning anything
Install
npm i -g squadrant # global `squadrant` CLI (alias: `squad`)
squadrant init
squadrant doctorOr from source:
git clone https://github.com/tu11aa/squadrant.git
cd squadrant
pnpm install
pnpm build # produces dist/index.js (the squadrant bin)
npm link # symlinks the global `squadrant`/`squad` to dist/index.js
squadrant init
squadrant doctorSquadrant was formerly published/developed as
claude-cockpit; it was rebranded in 0.9.0 as it grew into a multi-agent orchestration layer.
Prerequisites
- Claude Code >= 2.1.32
- cmux (macOS terminal for coding agents)
- Obsidian (status tracking)
- Node.js >= 18
Required Integrations
# Claude Memory — cross-session continuity
/plugin marketplace add thedotmack/claude-mem
/plugin install claude-mem
# Task Master — PRD decomposition (works via Max subscription)
npm install -g task-master-ai
# GSD — wave-based execution for crew (fresh context per step)
npx get-shit-done-cc@latest --claude --globalSee core/plugins.md for full plugin setup.
Obsidian Plugins
See obsidian/plugins.md for Dataview, Templater setup.
Commands
| Command | Description |
|---------|-------------|
| squadrant init | First-time setup — config, hub vault, scripts |
| squadrant launch <project> | Start a specific project captain |
| squadrant launch --all | Launch all captain workspaces |
| squadrant command [--task <briefing\|learnings-review\|wiki-aggregate>] [--agent <a>] | Spawn a one-shot Command session in a split pane (no persistent Command). |
| squadrant status | Show all project status (no Claude needed) |
| squadrant standup | Daily standup summary (zero LLM tokens) |
| squadrant doctor | Health check — verify dependencies |
| squadrant projects list | List registered projects |
| squadrant projects add <name> <path> | Register a project |
| squadrant projects remove <name> | Unregister a project |
| squadrant dashboard [--once] | Print a one-shot status grid for all projects to the terminal. |
| squadrant dashboard --pane [--direction <dir>] [--interval <s>] | Open a refreshing sidebar pane in the current cmux workspace. |
| squadrant dashboard sync-hub [--json] | Mirror spoke status.md files into {hubVault}/projects/ for Obsidian Dataview. |
| squadrant runtime status <project> | Check if a project's captain workspace is running |
| squadrant runtime send <project> <msg> | Send a message to a captain workspace (auto-Enter) |
| squadrant runtime list | List all workspaces from the active runtime |
| squadrant workspace read <project> <path> | Read a scope-relative file from the project's spoke vault |
| squadrant workspace list <project> <dir> | List entries in a spoke vault directory |
| squadrant workspace read --hub <path> | Read from the hub vault |
| squadrant notify <message> | Send a message to the user via the configured notifier |
| squadrant projection emit [--scope user\|project] [--project <name>] [--target <name>] [--all] | Emit squadrant rules + skills to Cursor/Codex/Gemini config files |
| squadrant projection diff [same flags] | Preview projection changes without writing |
| squadrant projection list | Show registered projection targets and their destinations |
| squadrant crew spawn <project> <task> [--name <n>] [--direction tab\|right\|left\|up\|down] [--agent <a>] | Spawn an interactive crew sub-session (tab in the captain workspace by default; --direction for a pane) |
| squadrant crew send <project> <name> <message> | Send a follow-up turn to an existing crew |
| squadrant crew read <project> <name> | Read a crew session's current screen |
| squadrant crew close <project> <name> | Shutdown a crew session (closes its tab) |
| squadrant crew list <project> | List live crews for a project |
| squadrant shutdown [project] | Graceful shutdown |
| squadrant effort [max\|balance\|low] | Get or set the global crew tokenomics dial (no arg prints current) |
| squadrant retro | Generate a retro (weekly/sprint summary) from daily logs and git (zero tokens) |
| squadrant config check | Detect config drift vs the current default schema |
| squadrant heal [--dry-run\|daemon] | Targeted, idempotent remediation for squadrant components (daemon, health) |
| squadrant group dispatch … | Cross-project intra-group operations (dispatch a task to a sibling project) |
| squadrant cmux … | cmux integration helpers |
| squadrant feedback | Open opt-in feedback issue |
Monorepo structure
Six internal packages in a one-way dependency DAG. All are private (not published to npm).
| Package | Owns | Notes |
|---|---|---|
| @squadrant/shared | Config schema, TypeScript types, constants | Leaf lib — zero internal deps |
| @squadrant/core | Daemon logic, state-machine, protocol, AgentDriver interface, task/crew bus | No concrete drivers — pure interfaces + orchestration |
| @squadrant/agents | AI driver seam — claude, codex, opencode, gemini drivers + registry | Implements AgentDriver. Add a new AI agent here. |
| @squadrant/workspaces | Runtime (cmux), workspace (obsidian), notifier (cmux) drivers + registries | Implements surface/workspace/notifier seams |
| @squadrant/web | Observability dashboard — bundled HTML/JS served by CLI | Read-only UI; inlined by CLI's tsup build |
| @squadrant/cli | Commands, bin entry, daemon host, templates, plugin dir | Root — depends on all other packages |
Dependency DAG: shared ◄ core ◄ {agents, workspaces, web} ◄ cli
Build outputs (pnpm build via tsup, all internal packages inlined):
dist/index.js— CLI bin (squadrantcommand), entry:packages/cli/src/index.tsdist/squadrantd.js— daemon process, entry:packages/cli/src/daemon-host.ts
See the architecture diagram for a visual overview.
Architecture
Roles
- Command (Opus) — on-demand cross-project session. Spawned by
squadrant command --task <briefing|learnings-review|wiki-aggregate>in a split pane; exits when the task completes. No persistent Command process. - Captain (Opus) — project leader, uses Agent Teams + git worktrees
- Crew (Sonnet by default) — interactive sub-session running as a new tab in the captain's workspace (or a split pane via
--direction). Each crew is named (crew-1,crew-2, …) and stays idle between turns waiting for the captain's next message — same model as a Claude Agent Team subagent. Spawn withsquadrant crew spawn, send follow-ups withsquadrant crew send, close when done. Works with any agent CLI (claude and opencode are fully interactive; codex/gemini currently print-mode). Uses GSD for complex tasks.
Model Routing
Each role runs on the optimal model for cost/quality tradeoff. Configured in config.json:
- Command/Captain/Review: Opus (coordination + quality)
- Crew: Sonnet (execution)
- Exploration: Haiku (cheap lookups)
Runtime Abstraction
Workspaces run on a pluggable runtime driver (currently only cmux). Each project may override the global default via its runtime field. Bash scripts call squadrant runtime <op> to talk to the configured runtime instead of any specific binary. New runtimes (tmux, Docker, SSH) are added as driver files in @squadrant/workspaces (packages/workspaces/runtimes/) — see docs/specs/archive/2026-04-20-plugin-system-runtime-design.md.
Workspace Abstraction
Vault storage (hub + per-project spokes) runs behind a pluggable workspace driver (currently only obsidian). Filesystem operations — read, write, list, exists, mkdir — go through the driver instead of fs directly. Each project may override the global default via its workspace field. Bash scripts call squadrant workspace <op> to read/write vault data without hardcoding paths. New backends (Notion, plain-md, S3) are added as driver files in @squadrant/workspaces (packages/workspaces/workspaces/) — see docs/specs/archive/2026-04-21-plugin-system-workspace-design.md.
Notifier Abstraction
User-facing notifications run behind a pluggable notifier driver (currently only cmux). Escalations and other "tell the user" events go through squadrant notify <message>. The default CmuxNotifier delegates to squadrant runtime send --command — the abstraction exists as a swap-point for future Slack/Discord/email/pager drivers. Notifier is global (no per-project override). See docs/specs/archive/2026-04-21-plugin-system-notifier-design.md.
Crew Spawn (Interactive Sub-Sessions)
Crew is the captain's equivalent of an Agent Team subagent — but runtime-agnostic. The captain spawns a crew via squadrant crew spawn <project> "<task>" [--name <n>], which opens a new tab in the captain's cmux workspace, boots an interactive Claude session (no -p), and sends the task as the first turn. The crew works on it and stays idle waiting for follow-ups. The captain drives the session with squadrant crew send/read/close/list, addressing each crew by its tab title (🔧 <project>:<name>).
Pass --direction right|left|up|down to use a split pane instead of a tab. State lives in the surface buffer + git; tabs die with the captain workspace on squadrant shutdown. Non-Claude agents (codex/gemini) currently still launch in print-mode; full interactive support is a follow-up. See docs/specs/archive/2026-05-05-squadrant-thin-redirect-design.md.
Effort Dial (Tokenomics)
squadrant effort max|balance|low is a single global dial that biases how aggressively crews consume tokens — a captain-discretion signal, not mechanical routing. max favors quality/tokens, low biases toward economy (e.g. preferring opencode for cheap work); balance sits between. Run squadrant effort with no argument to print the current setting. The value lives in config and is honored by captains via the captain-ops playbook (#317 / #381).
Crew Lifecycle & Delivery
- Daemon-direct delivery — crew turns and handoffs are delivered straight to the cmux surface by the daemon. The old
notify-relaysupervisor was deleted; there is no relay process to keep alive (#332). - Semantic heartbeat — crews emit a lifecycle signal the captain reads as CREW IDLE / QUIET / STALLED, distinguishing "waiting for you" from "wedged" without scraping the pane (#354).
stoppedproject status + orphan reap — when a captain goes away, the daemon reaps its orphaned crews and marks the projectstopped(intentional shutdown) rather than leaving stale tabs or faulting (#324 / #323 / #388).
Telegram (Two-Way, opt-in)
Drive squadrant from your phone (#65). When a telegram block is present in config, a daemon-internal bridge:
- Outbound — pushes each project's crew lifecycle events (CREW DONE / FAILED / BLOCKED / APPROVAL / INPUT / TIMEOUT / IDLE) and other captain notifications to that project's Telegram forum topic, filtered by a per-project crew tier (see Notification tuning below). Best-effort: a Telegram failure never delays or breaks delivery to the captain pane.
- Inbound (project topic) — a message you send in a project's topic is delivered into that project's captain pane as a labeled
📩 [from Telegram]message; the captain decides what to do with it. With remote control enabled (see below), if no captain is alive the daemon auto-launches one, then delivers (#403). - General command channel — slash commands in the supergroup's General topic run a curated set of squadrant operations from your phone (#402). Available:
/help,/status,/projects,/crews <project>,/launch <project>,/effort [max|balance|low],/config get <key>,/config set <key> <value>,/spawn <project> <task…>. Each maps to a validated CLI argv run via asyncexecFile— never a shell passthrough. Unknown commands and freeform text get a/helphint.
Absent the config block, the bridge is never constructed — zero behavior change. No runtime SDK is added (plain fetch; @grammyjs/types is a dev-only type dependency).
Setup (recommended):
- Create a bot with @BotFather and copy its token.
- Run
squadrant telegram setup— it prompts for the bot token (input hidden), validates it via the Bot API, auto-detects your supergroup id, captures your Telegram user-id, and offers to enable remote control. - Bind a project to a topic:
squadrant telegram link <project>(creates the forum topic and records the binding). - Check wiring with
squadrant telegram status.
Setup (manual):
Put the token + ids in config (or export TELEGRAM_BOT_TOKEN) — see the telegram block under Config. Then run squadrant telegram link <project>.
Security model (#321) — fail-closed remote control
The control surfaces (auto-launch + General command channel) are off by default and gated by two independent checks. A control action runs only when both hold:
remoteControl: true— an explicit opt-in master switch (defaultfalse).message.from.id ∈ users[]— the sender's Telegram user-id is on the allowlist. An empty/absentuserslist ⇒ control is disabled (fail-closed). Chat membership alone is never enough for control.
When remote control is off (the default after upgrade), behavior is exactly v1: project-topic messages queue to the captain pane (no auto-launch), and General-topic slash commands are rejected with ⛔ not authorized. Inbound text is always treated as data; only the curated registry maps to actions, and /config set is restricted to a default-deny writable-key allowlist (currently just defaults.effort) — secrets (botToken, users, chats, supergroupId) can never be written over Telegram.
Notification tuning (per-project)
Notifications resolve through a layered config: built-in defaults → global config.json (telegram.notify) → per-project ~/.config/squadrant/projects/<name>.json, merged per key (overriding one key never resets its siblings). Two axes are independent:
- Live mute (
active) — system-tracked session state intelegram-state.json. Flipped by engagement (any message into a topic auto-unmutes),/mute//unmute(Telegram), orsquadrant telegram notify <project> on|off. The live value wins over the config default when present. - Deliberate preferences (
crew,cap) — persistent settings in the per-project config file. Written bysquadrant telegram notify <project> crew <tier>/cap <on|off>(CLI) or/notify crew <tier>//notify cap <on|off>(Telegram, fail-closed behind remote control).
Crew tiers (cumulative) select which lifecycle events reach a topic when active:
| Tier | Events delivered |
|---|---|
| none | nothing |
| done_only | task.done, task.failed |
| alert_only (default) | done_only + task.blocked, task.approval.requested, task.input.requested, task.timeout |
| all | every lifecycle event (incl. progress/heartbeat noise) |
cap (default on) gates explicit captain pushes via squadrant telegram send — set cap off for a project to stop the captain DM-ing you there (independent of idle-mute; an explicit push is not dropped just because the topic is idle-muted).
Config (deliberate prefs) and state (live toggles) are kept separate by design: /unmute flips your session, it does not rewrite your config file. An absent projects/<name>.json behaves exactly as the global defaults — the layer is fully additive, no migration. See docs/superpowers/specs/2026-06-23-per-project-layered-config-design.md.
Remote wake (#403) — operator-side
Auto-launch boots a captain when the daemon is already running. Waking a sleeping Mac from your phone (Wake-on-LAN / a relay that nudges the machine) is operator-side infrastructure, out of scope for this repo — see #403 for the end-to-end flow.
Interim note (link ↔ daemon 409): the Telegram Bot API allows only one
getUpdatesconsumer at a time. Thesetupwizard pollsgetUpdatesto detect your group/user-id, so run it with the daemon stopped.linkuses onlycreateForumTopic, so it's unaffected.
Projection (Cross-Agent Config Sync)
Squadrant rules (Karpathy principles, captain-ops) and per-project AGENTS.md emit to each supported agent's canonical path via squadrant projection emit. User-level projection pushes squadrant's skills to ~/.cursor/rules/squadrant-global.mdc, ~/.codex/AGENTS.md, ~/.gemini/GEMINI.md. Project-level projection pushes a managed project's own AGENTS.md into {project}/CLAUDE.md, {project}/.cursor/rules/squadrant.mdc, {project}/GEMINI.md — zero squadrant-global content leaks into the project repo. Shared files use <!-- squadrant:start --> ... <!-- squadrant:end --> markers; dedicated files overwrite. See docs/specs/archive/2026-04-24-plugin-system-projection-design.md.
The user-level projection now also inlines templates/captain.generic.md and templates/crew.generic.md as ## Captain Role / ## Crew Role sections inside the squadrant marker block, so non-Claude agents (Codex, Gemini, Cursor) load the same role descriptions Claude Code loads via --append-system-prompt-file. See docs/specs/archive/2026-05-05-multi-agent-template-parity-plan.md (#45).
Obsidian Vaults (Hub-and-Spoke)
- Hub vault (
~/squadrant-hub) — cross-project dashboard + hub wiki - Spoke vaults — per-project status, learnings, and wiki
Knowledge System (opt-in writes)
- Status (opt-in) — captains record
{spokeVault}/status.mdviawrite-status.sh(also written by the captain session-end hook) when there's something worth noting (a blocker, "starting work on X"). Not on a schedule. - Dashboard —
squadrant dashboard --paneopens a refreshing sidebar pane in cmux that lists every project's live state, queried from the squadrant daemon's task records.squadrant dashboard sync-hubmirrors each spokestatus.mdinto{hubVault}/projects/so the hub vault'sdashboard.mdDataview query renders the same data inside Obsidian. - Handoff files — captain writes when in-flight work needs to survive into tomorrow; skipped on uneventful sessions.
- Daily logs — captain writes when the day produced something worth a log; not on a schedule.
- Learnings — recorded when a captain encounters a genuinely surprising or reusable pattern.
- Wiki — compiled, indexed knowledge pages in spoke vaults (
wiki/pages/); promoted from learnings when worth maintaining. - Hub Wiki — cross-project knowledge aggregated by an on-demand
squadrant command --task wiki-aggregaterun. - Scripts:
wiki-ingest.sh,wiki-query.sh,wiki-log.sh.
Session Continuity
- Handoff files — captain writes context on shutdown, reads on startup
- Session freshness — auto-detects new day or template changes, forces fresh context
- claude-mem — cross-session memory via MCP plugin
Config
~/.config/squadrant/config.json
{
"commandName": "command",
"hubVault": "~/squadrant-hub",
"runtime": "cmux",
"workspace": "obsidian",
"notifier": "cmux",
"telegram": {
"botToken": "123456:ABC...",
"supergroupId": -1001234567890,
"chats": [-1001234567890],
"users": [987654321],
"remoteControl": true,
"pollMs": 1000
},
"projects": {
"brove": {
"path": "~/projects/brove",
"captainName": "brove-captain",
"spokeVault": "~/squadrant-hub/spokes/brove",
"host": "local",
"runtime": "cmux",
"workspace": "obsidian",
}
},
"defaults": {
"maxCrew": 5,
"worktreeDir": ".worktrees",
"teammateMode": "in-process",
"permissions": {
"command": "default",
"captain": "acceptEdits"
},
"models": {
"command": "opus",
"captain": "opus",
"crew": "sonnet",
"exploration": "haiku",
"review": "opus"
}
}
}The telegram block is optional — omit it and the Telegram bridge is never constructed. botToken may be left out of the file and supplied via the TELEGRAM_BOT_TOKEN env var instead. chats is the inbound chat_id allowlist; users is the per-user-id allowlist for control actions and remoteControl (default false) is the master opt-in for auto-launch + the General command channel — both must be set for any remote control to act (fail-closed, #321). pollMs (default 1000) is the inbound long-poll cadence. See Telegram (Two-Way, opt-in).
Supported Agents
| Agent | Status | Notes |
|---|---|---|
| Claude Code | ✅ Shipping | Reference implementation; reads CLAUDE.md, Skill tool, MCP via settings.json |
| Codex CLI | ✅ projection (skills + roles) | Captain/crew roles inlined into ~/.codex/AGENTS.md (#45). First-class role identity is #35. |
| Cursor | ✅ projection (skills + roles) | Captain/crew roles inlined into ~/.cursor/rules/squadrant-global.mdc (#45). |
| Gemini CLI | ✅ projection (skills + roles) | Captain/crew roles inlined into ~/.gemini/GEMINI.md (#45). |
| opencode | ✅ driver + projection (interactive crew) | opencode run "<prompt>" with --format json / -m <model>; AGENTS.md projects to ~/.config/opencode/AGENTS.md. |
Cross-agent config sync (one canonical source → agent-specific formats) is tracked in #31.
Inspirations
- Andrej Karpathy — coding principles baked into every captain/crew role (
plugin/skills/karpathy-principles/SKILL.md) - forrestchang/andrej-karpathy-skills — reference packaging for the four principles (MIT)
- Multica — validated the multi-agent runtime + skill-compounding direction
- AGENTS.md — convergence point for cross-agent instructions
- OpenSpace — self-improving learnings loop (record → capture → fix → mark-useful)
- ComposioHQ — tool/skill portability across agents
License
MIT
