Skip to content
srjn45Public

About

Run a fleet of Claude Code agents from one Go binary — spawn, monitor, and tear them down in isolated git worktrees, track per-agent cost, and see how many tokens you're saving. No database, no SaaS.

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

1,523 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

warden warden

CI Coverage License Go Reference Release

📖 Docs & guide: https://srjn45.github.io/warden/

Run a fleet of coding agents without losing your mind. warden is a single Go binary (warden, aliased wd) that spawns, monitors, and tears down coding-agent sessions — each in its own isolated git worktree — while tracking exactly what every agent costs and how many tokens its lifecycle features keep out of context. It drives multiple AI CLIs (Claude Code by default — see AI CLIs), backed by a local daemon and a file-based JSON store: no database, no SaaS, no telemetry.

warden in action: spawning and monitoring a fleet of coding agents from one cockpit

Why warden

  • Orchestrate, don't babysit — spawn many agents in parallel, watch them in a live TUI cockpit or web dashboard, and talk to any one of them. Write-type agents get their own worktree by default, so parallel agents never collide on the same tree.
  • See what it costs — warden usage spend prices each agent's real model usage into dollars with a budget gate (priced for the Claude backend; bring-your-own-model backends report tokens), and warden usage savings is an append-only ledger of the tokens warden keeps out of agents' context, with a without-vs-with A/B benchmark you can screenshot.
  • Self-hosted and free — one binary, a loopback REST API, and a JSON store on disk. Run it on your laptop or a box. By default nothing leaves your machine — no telemetry, no SaaS. Opt-in features (webhook/Slack alerts, remote access, and warden usage savings --calibrate) send data only where you explicitly configure them.
  • Driven by an agent itself — warden daemon mcp exposes the whole fleet as MCP tools, so an orchestrator agent (e.g. a Claude session) can spawn, query, and coordinate the fleet for you.

Quickstart

go install github.com/srjn45/warden/cmd/warden@latest   # or grab a release binary (see Install)
warden setup --yes      # install missing deps (tmux, claude, …); `warden doctor` just checks
warden tutorial         # guided tour of the core loop: spawn → watch → commit → tear down
warden start "review the auth module for security issues"   # spawn your first agent
warden tui              # open the cockpit

go install gives you the CLI / daemon / TUI / MCP server. For the embedded web dashboard, use a release binary or build with make release — see Install.

Screenshots

The warden TUI cockpit in motion: a live agents list grouped by directory, an Approvals row, a terminal, and the selected agent's session in the full-height agent pane.

TUI cockpit — agents list, shell, and the selected agent's live session, side by side in tmux.

The warden web dashboard in motion: the Cockpit home with a Fleet summary and grouped agents, then the Metrics tab with per-agent and fleet-total CPU/memory charts.

Web dashboard — mission control: Fleet header and grouped agents, then a live walk to the Metrics tab.

The warden Metrics tab: CPU and memory per agent beside fleet totals, plus a per-agent cost card.

Metrics & cost — per-agent and fleet CPU/memory, context, tokens saved, and real model spend in dollars.

A warden pipeline rendered as a DAG in the web UI, with each job card showing its live status.

Pipelines — chain dependent agents into a DAG and watch each job's live status.

Architecture — one binary, multiple faces

warden daemon is the single writer to the on-disk session store, serving a loopback REST API and running a background poller. warden ls|status|start|done|attach|send|tail are thin HTTP clients to the daemon. warden daemon mcp is a stdio MCP server that bridges MCP tool calls to the same REST API, enabling an orchestrator agent session (e.g. Claude) to query agents and talk to a specific running agent. A short alias wd (a symlink to warden) is installed alongside it.

alias agents=warden

New here? See docs/USAGE.md for a task-oriented guide to running agents day to day, docs/FEATURES.md for a complete catalog of what warden can do, and FEATURES.md for the at-a-glance coverage matrix (which of CLI / MCP / skill / web / TUI can drive each feature). The sections below cover build, install, and contributor setup.


What's new

Capability highlights from recent releases (full notes on the releases page; the complete catalog lives in docs/FEATURES.md):

  • Mandatory agent naming — every agent gets a non-empty name. Omit --name and warden resolves one at spawn: role/pipeline conventions (AP:<plan>, wkr:<task>, brain:<target>, <pipe>:<stage>), else a 2–4 word kebab-case slug from the Fast-Brain engine (Decide(KindResolveAgentName), fast tier, 1.5s timeout) with memorable adjective-noun codename fallback (swift-falcon), else a codename for prompt-less spawns. Auto-names disambiguate with -2/-3 (never 409); explicit name collisions still 409. See docs/USAGE.md § Mandatory agent names and Spawn & watch.
  • ScrivaDB-canonical Plans — Plans are first-class ScrivaDB records (goal, tasks, lifecycle, revision, execution evidence). Repository plans/**/*.{yaml,yml,json} is an optional inert export via wd plan sync-to-repo (YAML default; --format json opt-in), never required for create/run/complete, and not scanned at daemon startup. JSON replicas are never execution SoT. Use wd plan create / run / complete / archive for DB-native work; while pending, mutate definitions with wd plan update / edit / task (non-pending → 409 Conflict; see docs/specs/2026-10-04-plan-modification-api.md); wd plan import-legacy for one-time YAML cutover; wd plan backup export|restore for recovery without Git; wd plan task status for per-task progress; wd plan delete to remove a pending, completed, or archived plan (in-progress plans are refused). Finish flow: an autopilot plan stays in_progress (awaiting_merge) until its final PR is merged — not merely green — then completes and its integration branch is deleted; wd plan complete refuses unmerged integration work unless --abandon-unmerged; wd plan archive refuses a live executor and keeps unmerged branches; wd plan unarchive restores a plan (spec). A running plan's definition cannot be edited. The old plan scan / import / status / sync_to_repo commands remain only as hidden aliases. Playbooks: Plans migration, Using plans, Plan backup, Plans concepts, docs/MIGRATION-plans-scrivadb.md. Phase 12 acceptance gate is green (report); JSON export #585 is opt-in; Hub plan sync #586 ships as opt-in explicit Push/Pull/Discover plus read-only remote discovery. Defaults remain offline: no startup calls or background replication, and Hub never replaces merged Git history as code-shipping authority.
  • Autopilot — a goal-directed, long-running autonomous mode. Journey: wd plan create → wd plan run <id> --mode autopilot → wd plan show <id> --watch (one plan) or wd autopilot status (all runs) → merge the final PR. There is no enable step and no autopilot init. wd plan run prints preflight warnings (including the CI-coverage hint). Each run renders as a plan-scoped tree with stable slot ids (<scope>-autopilot for the manager, <scope>-guardian for the guardian daemon session) — guardian heal-ladder rotation is an in-place hot-swap into the same slot, not a new agent-<hex> id. A manager agent (role autopilot) drives worker agents (role worker, one per task) in isolated worktrees, gates their PRs through CI, and lands them into a per-plan integration branch (default autopilot/<plan-name>; existing runs on autopilot/integration are grandfathered) — all without human intervention, spawning a resolver (role brain) on demand to unblock a stuck worker. Multiple named runs can be active in one repo concurrently, each with its own branch. Configure CI with autopilot/** in workflow pull_request triggers so gate: auto covers every per-plan branch. Pause a run with wd plan pause <id>. A stopped, parked or stuck run is brought back with wd plan restart <id> — destructive (terminates the agents and removes their worktrees, keeps landed work and branches with commits; needs --yes, --force for a healthy executor), and the new agents get a ## Restart context. A progress watchdog (autopilot.guardian.progress_watchdog_enabled, progress_watchdog_window, default 2h) escalates a manager that heartbeats but makes no progress, then parks it as no_progress. The manager marks its plan status: complete in place when it finishes so a done run is never re-run. See Autopilot guide and Autopilot concepts.
  • Fast-Brain observability & controls — redacted, bounded-label metrics and a decision trace for every internal Fast-/Thinking-Brain call (warden inspect fastbrain status|decisions, Web Metrics tab, MCP fastbrain_status), plus audited per-kind pause/resume (fails open; fast_brain.disabled_kinds for a persistent switch). See docs/USAGE.md § Fast-Brain.
  • Live activity badge — each agent row in the TUI shows a 3–5 word status badge (Fixing failing auth tests) that Fast-Brain refreshes from the agent's pane only while it is changing, at most once per activity.interval (default 15s); a failed decision keeps the previous badge. See docs/FEATURES.md.
  • Fast-Brain PR titles & bodies — warden agent stop <AGENT> --pr drafts the PR title and a short what/why body from the task, git diff --stat and commit subjects (fast tier first, thinking tier as retry), with per-field fallback to the deterministic title/digest body; an explicit title/body always wins.
  • Backend registry — warden detects the coding-agent CLIs installed on this machine (claude, codex, aider, …) and persists each with a billing tier (free/subscription/pay_per_use/unclassified), an enabled flag, and at most one default. The store is the single source of truth — autopilot's cost-tier ladder reads from it. warden's own internal micro-cognition (task classification, summaries, agent naming, commit messages, digest narration, memory curation, REPL planning) runs on Fast-Brain — a latency-bounded, fail-open gateway over a headless backend CLI — and is independent of the registry's tiers. Manage it with warden backend list|rescan|tier|default|enable|disable, the web 🧩 backends panel, the TUI Backends page (b), or MCP (list_backends, rescan_backends, set_backend_tier, set_default_backend). It supersedes the deprecated autopilot.brain.backends / allow_pay_per_use config (imported once, then ignored). See Backend registry guide.
  • Live config hot-reload — edit ~/.warden/config.yaml and warden applies it with no daemon restart: the autopilot template, auto_approve policy, token/context guard (tokens.*), rails.*, model_default, default_permission_mode, hint gates, and notify.*/webhook all re-apply on the next tick or spawn. A bad edit keeps the last-good config and alerts you rather than falling back to defaults; keys that genuinely need a restart (addr, data_dir, timers, loop cadences) are logged as changed-but-pending. See Configuration.
  • Agent roles (--role) — attach a named, persistent persona to an agent at spawn (warden start … --role worker) or switch it on a running agent (warden agent set <id> role worker, which relaunches to re-inject). Six built-in roles — general (default, no persona), orchestrator, planner, worker, autopilot, brain — each carrying a persona, default spawn flags, and a default model tier (the legacy names implementer/auto-merger/reviewer still work, mapped to worker). warden agent role list shows the catalog; the TUI new-agent form has a ctrl+r role picker and the web + New agent modal a Role dropdown. See Agent roles.
  • Tiered model routing (--task / --tier) — warden picks each spawn's backend+model by quota headroom within a model tier, so a fleet spreads across providers instead of hammering one. The tier is resolved with the precedence explicit --tier > task tier > role default tier > tier-2: a task (--task architecture, the what, from the task registry) or role (--role planner, the who) derives the tier, or pin it with --tier tier-1. Headroom is per quota scope (e.g. Cursor api/auto/included), so exhausting one scope no longer blocks sibling models on the same backend. The TUI new-agent form is tier-first (ctrl+t: auto / tier-1/2/3 plus a live candidate table); spawn passes the tier to the resolver rather than pinning a backend CLI. A pinned --aicli/--model bypasses the resolver, and a first spawn degrades to defaults if routing is unavailable — it never hard-fails. --tier is also a pipeline-job field (tier:). See Tiered model routing, docs/specs/agent-roles.md, and per-scope quota routing.
  • Reactive backend hard-limit recovery — when an agent hits a confirmed provider hard limit (session, weekly, or monthly cap), the daemon automatically tries the next eligible backend/model from the backend registry without operator intervention. Daemon-owned QuotaBinding maps agents to capacity domains; fresh provider usage snapshots can bulk-reconcile exhausted buckets to every bound peer (Claude wait-menu still fires immediately even with no parseable resets banner). Opt-in polling: rate_limit.recovery.usage_reconciliation (default off); operator one-shot: wd usage recover [--dry-run]. Legacy backend/model-only agents stay unbound_legacy (never mass-swapped on a guess; bind on next HotSwap). Usage windows are refreshed from internal/backendusage, candidates are ranked by known headroom, and each attempt must stabilize (10 s of live non-limited status) before recovery clears. When all candidates are exhausted, the agent persists waiting_for_capacity and retries on the earliest reset. Manual switch/stop/delete always supersedes automatic recovery. See Backend hard-limit recovery guide and Phase 10 acceptance.
  • Resilience & ergonomics round-up — warden agent recover re-registers archived orphaned agents with live panes (tombstone-reaper safety net); the web /tui cockpit self-heals (validated and auto-rebuilt if wedged; warden tui --rebuild-web-cockpit forces it); warden tui inside an existing tmux session lays out as a native tmux window instead of erroring (--tmux-native); wd push --force-with-lease for safe force-pushes; rate-limit auto-resume now also answers Claude's wait-menu and monthly spend cap (rate_limit.spend_retry_interval); and all daemon stores (sessions, pipelines, schedules, snapshots, context, mailbox) run on an embedded ScrivaDB — still no database server.
  • Factory reset (warden factory-reset) — drain all live agents/pipelines/autopilot/schedules, then wipe on-disk stores with --scope runtime|data|full. --backup archives the data dir first; --keep-config and --keep-backends preserve configuration and the backend registry across the wipe. Requires --yes. CLI-only by design (destructive; the daemon must be stopped for the data phase). See reference/cli#warden-factory-reset.

Hub plan-sync local smoke test

Run a local Hub with an explicit bearer token, then point a Hub-enabled client at it. The Hub envelope store is persisted under the daemon data directory, separately from canonical local plans and repository exports.

export WARDEN_TOKEN="$(warden token generate)"
warden daemon --addr 127.0.0.1:8787

# In another shell, configure the client that will push/pull plan envelopes.
# plan_sync.provider: hub
# plan_sync.hub_url: http://127.0.0.1:8787
# plan_sync.token: $WARDEN_PLAN_SYNC_TOKEN
export WARDEN_PLAN_SYNC_TOKEN="$WARDEN_TOKEN"

For a direct endpoint check, POST a valid v1 plan-sync envelope to http://127.0.0.1:8787/api/v1/plan-sync/push with Authorization: Bearer $WARDEN_TOKEN; use the matching pull or discover endpoint to read it back. Stop the daemon with Ctrl-C when finished. A default installation remains local/offline and makes no Hub network calls.

  • Isolation guardrails (v5.0, breaking) — write-type agents (code/docs/website/debug-ci/tests) now spawn into their own worktree by default (--in-repo opts out), backed by PreToolUse hooks that deny-redirect raw git/test commands to the first-class warden commit/push/sync/check tools. See Lifecycle commands & boundary enforcement.
  • Interactive mode (warden repl) — a terminal REPL with a real line editor (history, a live /-command menu, Tab completion, guided argument forms, colour) that drives the fleet via deterministic / commands (no model) or natural language (a Fast-Brain conductor that turns operator intent into confirmed warden tool calls — works out of the box, no local model needed).
  • Pipelines, end to end — DAG pipelines are now drivable from the MCP tools (create/start/show/list/cancel), ship four built-in --template starters, and support run_if conditional steps.
  • Stored entity hierarchy — projects own complete agents[], pipelines[], and terminals[] membership lists. Agents store parent_id, child_agents[], and child_pipelines[]; pipelines store parent_agent_id. Pipeline job agents belong to pipeline jobs, never the owner’s child_agents[]. The UX uses pending, busy, idle, need-input, done, orphaned, and rate_limited; raw status aliases remain compatible. See the entity model and lifecycle.
  • Project groups & per-project orchestrators — organize repos into named project groups visible in the TUI tree (each member shows its group label), managed via first-class warden projects and warden project-groups CLI commands. Opening a project restores whatever members were hibernated when it was last closed and otherwise opens empty — you (or a parent agent) spawn an orchestrator into a project when you want one. Orchestrators running in a grouped project learn their group name and sibling orchestrator names via context injection at every launch so they can coordinate without manual wiring. See Project groups guide.
  • Agent sub-trees in the TUI — agents spawned by another agent nest under their parent as a collapsible sub-tree (▸ / ▾, indented per depth); deleting a parent with live children leaves a muted terminated tombstone header so the children never orphan, reaped once the sub-tree finishes.
  • Fleet at scale — full-text warden inspect search + tags, a warden inspect history archive, warden inspect export/import, an append-only warden inspect audit, spawn presets and variabled prompt-templates (browse both via warden project library), and web batch operations.
  • Observability — per-agent metrics & performance history (warden inspect resources), crash/anomaly detection, the context-size guard, and webhook/Slack notifications.
  • Token-savings ledger (warden usage savings) — a real, append-only ledger of the tokens warden's lifecycle features keep out of agents' context, with an --benchmark A/B headline (without-vs-with warden, % reduction, $ saved) you can screenshot.
  • Cost governance (warden usage spend) — the REAL model spend warden measures from agents' transcripts, priced per model into dollars and rolled up per-agent/repo/day (priced for the Claude backend; bring-your-own-model backends report tokens), plus a budget gate that softly warns before a spawn pushes daily/weekly spend over a configured $ cap (a $ column in warden ls and a live per-agent cost card on the web Metrics tab round it out).
  • Native scheduler (warden schedule) — opt-in cron/at triggers that fire an agent or a pipeline on the daemon's own timer; no external crontab.
  • Snapshots & insights — warden workspace snapshot checkpoints a worktree + transcript for rollback; warden usage insights mines agent history for patterns and parallelization wins.
  • Branch tracking (warden workspace branches) — opt-in monitor of each agent's CI status and standing vs origin/main, with non-blocking inbox/desktop alerts.
  • Extensibility — a warden project plugin system (custom task types + lifecycle hooks over JSON-stdio) and an interactive OpenAPI/Swagger UI at /api/docs.
  • Web — real URL routing (/cockpit, /tui, /pipelines, /metrics, /archive, /others, /agent/<id> — deep-linkable, back/forward, shareable), a Cockpit home with a Fleet header, a highlighted top-bar ▢ TUI launcher that opens the literal warden tui full-screen (the whole three-pane cockpit — same panes, shortcuts, real shells and live agent sessions — edge-to-edge over the viewport, Ctrl+Q to exit) so you can drive the fleet from a laptop exactly as you do locally, a dedicated Metrics tab (per-agent and fleet-total CPU / memory, per-agent context, fleet size, tokens saved — two columns on desktop, single column on mobile), dark-mode theming, global keyboard shortcuts, Cockpit agent grouping, and an Archive tab plus an Others catch-all (last).
  • Remote access — bearer-token auth (warden daemon token …) and a Docker/compose deployment.
  • First-run tutorial (warden tutorial) — a guided walkthrough of the core loop, with a one-line nudge until you've taken (or skipped) the tour.

Prerequisites

  • Go 1.26+ — to build the binary (only needed for go install or building from source)
  • tmux — every agent session runs in a detached tmux window
  • git — worktree creation and guarded cleanup
  • Claude Code (claude on PATH) — the default agent runtime launched in each session
  • Aider (aider on PATH, optional) — only needed to spawn agents with --aicli aider; bring-your-own-model (works with local Ollama models, $0)
  • OpenCode (opencode on PATH, optional) — only needed to spawn agents with --aicli opencode; bring-your-own-model (works with local Ollama models, $0). Install: npm install -g opencode-ai (https://opencode.ai)
  • gh (GitHub CLI) — required for pr-review sessions to check out the PR branch, and for warden agent stop <AGENT> --pr

Tip: once you have the warden binary, run warden doctor to check these dependencies and warden setup to install whatever is missing (Homebrew on macOS; apt/dnf/pacman on Linux; official installers for Claude Code). warden setup --yes does it non-interactively.


Install

warden is one self-contained binary. The official install needs only curl — no git, Go, npm, or OS package manager.

1. Official one-liner (recommended)

curl -fsSL https://raw.githubusercontent.com/srjn45/warden/main/scripts/install.sh | bash

That downloads a verified GitHub release archive for your OS/arch, installs ~/.local/bin/warden (plus the wd alias), wires the user-level daemon service (launchd on macOS, systemd --user on Linux), links the Claude skill, registers the MCP server, and probes /healthz. Pin a release with WARDEN_VERSION=9.9.0 (with or without a leading v).

Same script from a git checkout: ./scripts/install.sh / make install builds from source instead of downloading a release. See Install the daemon as a service below for codesigning, redeploy, and uninstall.

Upgrade after install:

warden update          # or: wd update
warden update --plan   # preview upgrade path, migrations, breaking changes & downtime
warden update --check  # report only (query releases)
warden update --yes    # non-interactive update without confirmation prompt
warden update --version v9.9.0

warden update verifies checksums, atomically swaps the binary, re-signs on macOS when the warden-codesign identity is present, runs config migrations, restarts the daemon service, and rolls back unless /healthz reports ok on the new version and its data schema (schema_version). In the TUI cockpit, press u when the footer shows an update chip ([u] Update to vX.Y.Z available), or r to hot-reload the cockpit in place after an external upgrade (syscall.Exec — active tmux agent sessions keep running).

To preview the planned upgrade without mutating state or stopping the daemon:

warden update --plan

To roll back an update, run warden rollback (or wd rollback). It performs a plain binary swap when no data format changed, or restores the pre-update data snapshot (<data>/backups/pre-<ver>-<ts>/) with confirmation when the schema advanced.

For offline data migrations and store repairs:

warden migrate --check       # inspect data store schema status
warden migrate --apply       # apply pending data migrations
warden repair all --resolve-history=live-wins  # repair conflicting keys across all stores
warden init                  # initialize fresh data dir or verify baseline migrations

Deprecated: Homebrew, apt/deb, rpm, and AUR packages are no longer published. Use the curl installer and warden update instead. Existing package installs still run; migrate with the one-liner above.

2. go install (Go toolchain)

go install github.com/srjn45/warden/cmd/warden@latest

This installs the warden binary (CLI + daemon + MCP server + TUI). Note: go install does not bundle the web dashboard (the UI is built from web/ and embedded at release time, and isn't committed to the repo). The CLI, daemon API, TUI, and MCP server all work; for the embedded web GUI use the official installer (option 1) or build from source (option 3). go install also does not register the background service — run ./scripts/install.sh --no-build from a checkout, or start warden daemon manually.

3. Build from source

git clone https://github.com/srjn45/warden.git
cd warden
make build           # CLI/daemon/TUI only → bin/warden
make release         # builds the web UI first, then embeds it → full GUI
./scripts/install.sh --no-build   # deploy + start the user service

Shell Completion

warden supports shell completion for Bash, Zsh, Fish, and PowerShell. Generate the completion script for your shell and install it to the appropriate location:

Bash:

# System-wide installation:
warden completion bash | sudo tee /etc/bash_completion.d/warden

# User-only installation:
warden completion bash > ~/.bash_completion

Zsh:

# System-wide installation:
warden completion zsh | sudo tee /usr/local/share/zsh/site-functions/_warden

# User-only installation:
mkdir -p ~/.zsh/completion
warden completion zsh > ~/.zsh/completion/_warden
# Then add to your ~/.zshrc:
# fpath=(~/.zsh/completion $fpath)
# autoload -Uz compinit && compinit

Fish:

warden completion fish > ~/.config/fish/completions/warden.fish

PowerShell:

warden completion powershell > warden.ps1
# Then add to your PowerShell profile

After installing the completion script, restart your shell or source the file for completions to take effect.


Run it as a background service (macOS)

The recommended setup on macOS installs warden as an auto-starting launchd daemon (and links the Claude skill + registers the MCP server). See the next section.


Install the daemon as a launchd service (auto-start)

The official one-liner already installs and starts the daemon. From a git checkout the same script builds from source, installs the binary to ~/.local/bin/warden, renders and loads the launchd plist, links the Claude skill, and registers the MCP server:

./scripts/install.sh        # or: make install
# or, without a checkout:
# curl -fsSL https://raw.githubusercontent.com/srjn45/warden/main/scripts/install.sh | bash

The daemon then starts automatically at login and restarts on crash (KeepAlive = true), listening on 127.0.0.1:8765 by default.

~/.local/bin must be on your PATH to run warden from the shell — the installer warns if it isn't.

Stop macOS "warden would like to access…" prompts (optional, macOS)

The launchd daemon is the macOS TCC responsible process for the agents it spawns and for its own directory picker, so reads of protected folders (Downloads, Documents, Desktop, the Music/media library) surface as "warden would like to access…" prompts. Granting Full Disk Access once silences them — but macOS ties the grant to the binary's code identity, and an unsigned Go binary gets a new identity on every rebuild, which brings the prompts back.

Run the one-time setup to give the binary a stable self-signed identity:

./scripts/codesign-setup.sh   # creates a self-signed code-signing cert (once)
./scripts/install.sh          # reinstall so the binary is signed

Then grant access once: System Settings → Privacy & Security → Full Disk Access → "+" and add ~/.local/bin/warden. Because the signing identity is stable, the grant survives future rebuilds. (install.sh/reinstall.sh sign automatically when the cert exists; without it they warn and leave the binary unsigned.)

Redeploy after a code change (replaces make release && ./bin/warden daemon):

./scripts/reinstall.sh             # rebuild UI + binary, redeploy, restart
./scripts/reinstall.sh --no-build  # redeploy the existing build only
# or: make reinstall  /  make reinstall NO_BUILD=1

Uninstall (stops and removes the service, binary, skill link, and MCP registration; preserves your session store at ~/.warden and the logs):

./scripts/uninstall.sh                 # or: make uninstall
./scripts/uninstall.sh --keep-binary   # leave ~/.local/bin/warden in place

Logs:

  • stdout: /tmp/warden.daemon.log
  • stderr: /tmp/warden.daemon.err

Notifications: off by default. When enabled (set notify.enabled: true in the config file, or the deprecated notify: true), the daemon posts a macOS notification when an agent enters waiting_for_input, idle (stuck), orphaned, or errored. These appear only when the daemon runs in your GUI login session (a terminal, or a launchd user agent); a headless/system daemon logs them instead.


Run it as a background service (Linux — systemd)

The same install script detects Linux and registers a systemd user service instead of a launchd plist. It builds the release, installs the binary to ~/.local/bin/warden, writes ~/.config/systemd/user/warden.service, enables it, and links the Claude skill and MCP server:

./scripts/install.sh        # or: make install

The daemon starts automatically at each login session and restarts on crash (Restart=always), listening on 127.0.0.1:8765 by default.

~/.local/bin must be on your PATH — the installer warns if it isn't.

Persistent daemon: install.sh calls loginctl enable-linger so the systemd user service keeps running after you close your terminal or SSH session (equivalent to launchd RunAtLoad on macOS). This requires systemd 219+ and is a no-op on most modern distros.

Redeploy after a code change:

./scripts/reinstall.sh             # rebuild UI + binary, redeploy, restart
./scripts/reinstall.sh --no-build  # redeploy existing build only
# or: make reinstall  /  make reinstall NO_BUILD=1

Uninstall (stops and removes the service, binary, skill link, and MCP registration; preserves ~/.warden):

./scripts/uninstall.sh
./scripts/uninstall.sh --keep-binary   # leave ~/.local/bin/warden in place

Logs go to the systemd journal (the unit sets StandardOutput=journal / StandardError=journal), so they survive reboots even where /tmp is a tmpfs (Fedora, Arch, …):

journalctl --user -u warden -f        # follow live
journalctl --user -u warden -n 100    # last 100 lines

Notifications: off by default. Set notify.enabled: true in the config file to enable (the deprecated notify: true also works). The daemon calls notify-send (libnotify) when it's on PATH; install it with apt install libnotify-bin (Debian/Ubuntu) or dnf install libnotify (Fedora). Degrades to log-only if notify-send is not found.

Run the daemon in Docker

The repo ships a multi-stage Dockerfile and a docker-compose.yml. The image is a lean Alpine runtime (static CGO_ENABLED=0 binary plus tmux + git) with the web dashboard baked in. State lives in a ~/.warden volume so it survives container restarts, and the daemon binds 0.0.0.0:8765 for remote access.

# Build the image (run from the repo root).
docker build -t warden:latest .

# A non-loopback bind REQUIRES a bearer token — the daemon refuses to start
# without one. Generate it locally (or use any secret) and run:
export WARDEN_TOKEN=$(warden daemon token generate)
docker run -d --name warden \
  -p 8765:8765 \
  -e WARDEN_TOKEN \
  -v warden-data:/home/warden/.warden \
  warden:latest

Or with compose (reads WARDEN_TOKEN from your environment):

export WARDEN_TOKEN=$(warden daemon token generate)
docker compose up -d        # builds the image on first run

The dashboard/API is then reachable at http://<host>:8765; the browser prompts for the token on first load. Don't expose the port directly to the public internet — front it with Tailscale or a Cloudflare Tunnel (see Remote access).

tmux is required. warden runs every agent inside a tmux session, so the image installs tmux (and git, for worktree-isolated agents) even though the container's primary job is to host the daemon, REST API, and dashboard. Spawning agents that actually call Claude additionally needs the claude CLI and its credentials inside the container — the base image deliberately omits these to stay lean; layer them on (and mount ~/.claude) if you want the container to drive live agents rather than just manage/observe sessions.


Wire in the Claude Code hooks

The hook script posts lifecycle events (SessionStart, Notification, Stop, SubagentStop, SessionEnd) to the daemon so it can update agent status in real time without polling. SessionEnd marks the session done (terminal) when claude exits.

Merge hooks/settings.snippet.json into ~/.claude/settings.json. The snippet uses a __WARDEN_HOOK__ placeholder — substitute the absolute path to hooks/warden-hook.sh in your clone first:

# from the repo root, render the snippet with the real hook path:
sed "s|__WARDEN_HOOK__|$(pwd)/hooks/warden-hook.sh|g" hooks/settings.snippet.json

# If ~/.claude/settings.json doesn't exist yet, write it directly:
sed "s|__WARDEN_HOOK__|$(pwd)/hooks/warden-hook.sh|g" hooks/settings.snippet.json > ~/.claude/settings.json

# If it already exists, merge the rendered "hooks" key into the root of your
# existing settings.json object.

The hook fails soft — it never blocks or errors the agent, even if the daemon is down or the session is unknown.


Model Selection

Warden supports per-agent model selection:

  • Any model id, passed through verbatim to the AI CLI (e.g. opus, sonnet, claude-sonnet-4-6)
  • Default: claude-sonnet-4-6 (or the model_default config setting)
# Explicit model
warden start "Complex task" --model opus

# Set the default model: edit ~/.warden/config.yaml (model_default: opus),
# then restart the daemon. `warden config` shows what's live.

# View model in agent list
warden ls  # Shows MODEL column

AI CLIs (--aicli)

Warden drives Claude Code by default, but the agent layer is pluggable: pick the AI CLI per agent at spawn time with --aicli (CLI; --backend still works as a hidden alias) or the ai_cli param (spawn_agent MCP tool).

Supported agents — status: warden is fully tested only with Claude Code. Codex CLI and Antigravity CLI are β beta — live-verified state, approval, and transcript fidelity, still maturing. The remaining non-claude backends (Aider, OpenCode, Crush, Goose, Cursor) are experimental / work-in-progress — functionality may be reduced or unverified.

Agent Status
Claude Code ✅ Stable — fully tested, reference backend
Aider 🧪 Experimental (WIP)
OpenCode 🧪 Experimental (WIP)
Codex CLI ✅ Stable
Crush 🧪 Experimental (WIP)
Goose 🧪 Experimental (WIP)
Cursor CLI ✅ Stable
Antigravity CLI ✅ Stable
AI CLI --aicli Tier Notes
Claude Code (default) claude A Full fidelity — digests, savings, priced spend, resume, all permission modes
Aider aider A 🧪 Experimental. Bring-your-own-model (pass --model, e.g. ollama_chat/qwen2.5-coder:3b); structured markdown transcript ⇒ real digests; no resume, no priced spend (tokens only); interactive task seeded via PromptSeeder (same seed_status recovery as Crush); headless classify/summarize uses --message
OpenCode opencode A 🧪 Experimental. Bring-your-own-model (pass --model, e.g. ollama/qwen2.5-coder:3b); structured JSON transcript (via opencode export) ⇒ real digests; resumes the worktree's last session (opencode -c); spend tokens-only (BYO model)
Codex CLI codex A ✅ Stable. BYO provider (via Codex config / -m); structured JSONL transcript (rollout files) ⇒ real digests; resumes dir-scoped (codex resume --last), upgraded to exact-id via discover-then-pin; live state + approval detection; context injection via AGENTS.md; spend tokens-only. See docs/agent-backends/codex.md
Crush crush A 🧪 Experimental. BYO model (config-driven TUI; headless crush run accepts -m); structured JSON transcript (via crush session show --json) ⇒ real digests; resumes dir-scoped (--continue); initial prompt auto-typed after launch via PromptSeeder (failures set seed_status on the session and leave the prompt at <data_dir>/prompts/<id> — see warden status); context injection via CRUSH.md; spend tokens-only. See docs/agent-backends/crush.md
Goose goose A 🧪 Experimental. BYO provider (GOOSE_PROVIDER/GOOSE_MODEL env); structured JSON transcript (via goose session export) ⇒ real digests; resumes name-deterministic (goose session -r --name <id>); no model flag on session launch; initial prompt seeded via PromptSeeder (same seed_status recovery as Crush); context injection via .goosehints; spend tokens-only. See docs/agent-backends/goose.md
Cursor CLI cursor C ✅ Stable. Hosted plan (cursor-agent, billed to your Cursor subscription); rich native permission modes (plan/ask/auto-review/force); resumes dir-scoped (--continue); live state + approval/trust detection; context injection via AGENTS.md; initial prompt seeded via PromptSeeder (same seed_status recovery as Crush). No structured transcript yet (interactive store is unreadable SQLite) ⇒ no digests; spend tokens-only. See docs/agent-backends/cursor.md
Antigravity CLI antigravity A ✅ Stable. Google-hosted free tier (agy, multi-vendor model menu); structured trajectory JSONL (incl. tool calls / files changed) ⇒ real digests; resumes dir-scoped (agy -c); live state + approval/trust detection; context injection via AGENTS.md; spend tokens-only. See docs/agent-backends/antigravity.md
# Optional BYO: drive Aider against a local Ollama model (free, offline) — a backend
# provider choice, not a warden dependency (warden itself no longer needs Ollama)
export OLLAMA_API_BASE=http://127.0.0.1:11434
warden start "implement the add function" --aicli aider --model ollama_chat/qwen2.5-coder:3b --dir .

# Drive OpenCode against a local Ollama model (free, offline)
warden start "implement the add function" --aicli opencode --model ollama/qwen2.5-coder:3b --dir .

# Drive Codex against a local Ollama model (configure provider in ~/.codex/config.toml first)
warden start "implement the add function" --aicli codex --dir .

# Drive Crush against a local Ollama model (configure provider in ~/.config/crush/crush.json first)
warden start "implement the add function" --aicli crush --dir .

# Drive Goose against a local Ollama model
GOOSE_PROVIDER=ollama GOOSE_MODEL=qwen2.5-coder:3b \
warden start "implement the add function" --aicli goose --dir .

Terminals are not a backend. A plain interactive shell beside the fleet is a first-class terminal session (kind=terminal), not an agent backend — so terminal is no longer a --backend choice. Create one from the cockpit (t on a project row — a terminal always belongs to a project) or over the API with kind=terminal (backend=terminal is still accepted as a back-compat alias). Terminals get warden's normal worktree/git/tmux lifecycle (attach, commit/push/sync, snapshot, teardown, cockpit listing) but no AI features. See the cockpit section below.

Backends differ in capabilities; warden degrades gracefully rather than crashing when one lacks a capability (e.g. spend shows tokens-not-dollars for a bring-your-own-model backend; rotate/handoff re-spawn fresh when resume is unavailable). It also surfaces some backends' native superpowers as first-class verbs — warden git review (Codex's diff reviewer), warden backend model (Antigravity/Cursor's live model menu), and warden agent fork (branch a Codex session into a new managed agent — see warden agent fork); see Agent-native superpowers. See the design (docs/superpowers/specs/2026-06-27-pluggable-agent-backends-design.md, §5) and roadmap item #52.


Backend registry (warden backend)

Which backends exist, how they're billed, and which one is the default is a durable, inspectable fact — not something re-derived on every spawn. warden detects the coding-agent CLIs installed on this machine (claude, codex, aider, …) and persists each in an embedded store (~/.warden/backends) with a billing tier, an enabled flag, and at most one default. The store is warden's single source of truth: autopilot's cost-tier ladder reads from it.

  • Detection is a fact; tiering is a preference. warden backend rescan reconciles detection (adds newly installed CLIs, marks vanished ones uninstalled) and never touches your tier / default / enabled choices.
  • Tiers: free · subscription · pay_per_use · unclassified (and the retired local row is no longer listed). A newly detected CLI starts unclassified (treated as not free).
  • Internal thinking runs on Fast-Brain, not the registry. warden's own micro-cognition (task classification, summaries, agent naming, commit messages, curation, digest/insights narration, REPL planning) goes through Fast-Brain (internal/fastbrain): latency-bounded and fail-open — on timeout or no backend warden falls back to deterministic output. The old thinking-mode setting, the reserved local row and the local-model router are retired (PUT /api/v1/backends/thinking-mode is a 200 no-op for old clients).
warden backend list                 # full table of detected backends
warden backend rescan               # re-detect installed CLIs, preserve preferences
warden backend tier codex free      # tier codex as a $0 backend
warden backend default claude       # make claude the default backend
warden backend disable aider        # stop using a backend

Drive it from the web 🧩 backends panel, the TUI Backends page (b), or over MCP (list_backends, rescan_backends, set_backend_tier, set_default_backend — enabling/disabling is CLI/web/TUI + REST PATCH /api/v1/backends/{id}). The registry supersedes the deprecated autopilot.brain.backends ladder and autopilot.brain.allow_pay_per_use gate: those config keys are imported into the store once on the first boot after upgrade, then ignored. Full walkthrough: Backend registry guide.


Configuration

Warden reads all settings from a single YAML file (default ~/.warden/config.yaml). Run warden config init to generate a fully-commented file, edit the values, then restart the daemon; warden config prints what's currently live. The --config <path> flag points any command at an alternate file, and --addr <host:port> overrides the daemon address for a single command.

Setting Default Description
addr 127.0.0.1:8765 Daemon listen address. Non-loopback requires WARDEN_TOKEN (bearer-token auth — see Remote access); the daemon refuses a non-loopback bind without a token
data_dir ~/.warden Directory for warden state: the embedded ScrivaDB session store (sessions-db/, with a one-time-imported read-only JSON backup in sessions/+closed/), per-agent prompt files (prompts/), inbox, pipelines, and metrics
claude_projects_dir ~/.claude/projects Root of Claude Code transcript directories; the poller reads agent transcripts here to generate subjects and the context gauge
ai_cli_default (empty) Default AI CLI when a spawn does not pin one (falls through to the backend-registry default, then claude). Deprecated alias: backend_default.
model_default claude-sonnet-4-6 Default model for new agents (passed through verbatim to the AI CLI)
default_permission_mode auto Default permission mode for new agents (auto/default/acceptEdits/bypassPermissions/dontAsk/plan)
git.protected_branches / git.protect_default_branch main, master / true Lifecycle branches protected from direct commit, push, or PR-head use. A custom list replaces main/master; the repository default branch remains protected unless explicitly disabled. Hot-reloaded.
notify.enabled false Desktop notifications when an agent needs attention
approvals true The approvals inbox: the daemon parses recognized Claude Code tool-permission prompts and surfaces them for answering. The web AttentionQueue shows one-click option buttons, the CLI exposes warden approval list/warden approval answer, and the TUI shows a pinned ⏳ Approvals row — answer it in place (i, or enter on the row, then 1-9; tab cycles between waiting agents) or from the web / warden approval answer. Unrecognized prompts always fall back to attach
tokens.guard true The context-size guard: the poller reads each live agent's context-window fill from its transcript, classifies it ok/warning/critical, and shows a state-colored token figure in warden ls, the TUI row, and the web tile. Master switch for the whole guard (gauge, alert, auto-compact)
tokens.warn_alert true Fire a desktop notification (when notify.enabled is on) once per upward crossing into the warning or critical band
tokens.auto_compact true When an agent is critical and idle/waiting, auto-send /compact to reclaim its context (cooldown-guarded). Autopilot workers and pipeline jobs are short-lived and are never compacted by this default (the long-lived autopilot manager still is).
tokens.force_compact false When an agent goes critical while still working, interrupt it (Escape), /compact once it idles, then send the resume prompt. Destructive — discards the in-flight turn — so off by default. Per-agent override via warden agent set <id> compact on|off|inherit. Autopilot workers and pipeline jobs are short-lived and are never compacted by this default (the long-lived autopilot manager still is).
tokens.compact_resume_prompt (built-in) Message sent to a force-compacted agent once compaction lands so it resumes its work
tokens.warn 200000 Warning threshold in context tokens (inclusive lower bound). If tokens.critical is not greater than this, both reset to the defaults
tokens.critical 400000 Critical threshold in context tokens (inclusive lower bound) — the auto-/compact trigger band
auto_approve false Auto-answer recognized permission prompts. Bare on/off, or an allow/deny rule policy (by tool / glob / regex / paths, with per-agent overrides) — see warden approval auto set
router.use_fast_brain false Opt-in prompt-complexity tier routing: for a spawn that pins no tier, task, role, model or ai_cli, Fast-Brain rates the prompt (tier-1 trivial tweaks / tier-2 standard / tier-3 deep refactors) and the router uses it only at confidence ≥ 0.8. Lowest-precedence input; recorded as a tier-route event on the agent. Hot-reloaded
notify.webhook_enabled / notify.webhook_url false / (empty) POST a JSON payload to webhook_url on attention + context-size alerts (a Slack incoming-webhook URL works out of the box); runs alongside notify.enabled
collab.enabled / collab.interval / collab.git_reconcile_interval / collab.hint true / 10s / 2m / true File-conflict detection: fsnotify-first dirty tracking, watch-reconcile interval, git-diff backstop, and the spawn-time coordination hint
rails.isolation_guard / rails.git_redirect / rails.check_redirect / rails.git_conventions true Boundary-enforcement hooks (see Lifecycle commands & boundary enforcement)
log.level / log.format info / text Daemon log verbosity (debug/info/warn/error) and format (text/json); warden daemon --log-level/--log-format override
local_llm.* — Retired. Legacy local_llm keys still parse but are ignored; Fast-Brain replaced the local Ollama provider (no config needed)

warden config lists every setting, including worktree.spawn_gate / worktree.spawn_gate_max_agents, tokens.budget_gate / tokens.budget_daily_usd / tokens.budget_weekly_usd, metrics, allow_nonloopback, pipeline.keep_done / pipeline.hint, worktree.keep_done / worktree.auto_prune, the auto_restart.* and rate_limit.* knobs.

Related settings are grouped into namespaced blocks (pipeline.*, auto_restart.*, collab.*, memory.*, branch_track.*, rate_limit.*, http.*, log.*, plugins.*, alongside the existing rails.* / tokens.* / notify.* / worktree.* / local_llm.*). The old flat keys (collab_enabled, log_level, memory_inject, …) still load as deprecated aliases — they work but emit a one-time deprecation warning; warden config rewrites them into the nested form.

Config namespacing: Settings are grouped into five YAML blocks — rails, tokens, notify, worktree (plus the retired, ignored local_llm). Old flat keys (e.g. token_guard, local_llm_url, notify) are still accepted as deprecated aliases and migrate to the namespaced form automatically when warden config init is re-run.

Legacy env vars: the old WARDEN_* environment variables (e.g. WARDEN_ADDR, WARDEN_NOTIFY, WARDEN_TOKEN_*) are no longer read — the daemon warns once at startup if any are still set. The per-agent IPC vars warden injects into each agent (WARDEN_SESSION_ID, WARDEN_PIPELINE_ID, WARDEN_JOB_ID) are not configuration and are unaffected.


Prompt-spawn (no repo, auto-typed)

The simplest way to create an agent is to give it a plain prompt and let the system figure out the rest:

warden start "review the auth module for security issues"
# spawned agent-a1b2 (classifying…) — attach with `warden agent attach agent-a1b2`

In the web GUI, + New agent opens a single prompt textarea — no type or repo fields.

How it works:

  • Runs in the caller's directory. Prompt-spawned agents run claude --dangerously-skip-permissions '<prompt>' (or --permission-mode acceptEdits with --supervised) in the directory you invoked start from (or the --dir you pass) — no per-agent directory is created. Point it elsewhere with --dir, and include any extra repo context in the prompt itself.
  • Type is auto-assigned. Shortly after creation the daemon classifies the prompt with claude -p and updates the type label. It appears as "classifying…" until then. Requires claude on the daemon's PATH; falls back to other if unavailable.
  • Subject is auto-generated. Each agent has a one-line subject summarizing what it is currently working on. It is seeded from the first words of the prompt at spawn, then refreshed periodically by the poller: the poller reads the agent's Claude Code transcript (looked up under the claude_projects_dir config setting) or, if no transcript is found, captures the tmux pane, then asks claude -p for an ≤8-word phrase. Refreshes are throttled and only run when the pane content has changed.
  • Managed worktrees still available. warden start TICKET --type development --repo … is unchanged — see the section below.

To launch an agent in a directory other than your current one, pass --dir:

warden start "summarize recent changes" --dir /path/to/repo

Task types and the --type flag

When you need a managed git worktree (e.g. a development branch tied to a Jira ticket), pass --type. The type controls whether a git worktree is created and determines how the session is set up.

Type Worktree Notes
development yes (new branch) Creates .worktrees/<ticket> on a new branch named after the ticket
pr-review yes (PR branch) Detached worktree; runs gh pr checkout <PR> inside it. Requires --pr or --branch. Exempt from the write-type isolation default
analysis opt-in (--worktree) Runs in the repo by default; pass --worktree to get a scratch branch
spike opt-in (--worktree) Same as analysis
code yes (new branch) Isolated in .worktrees/<id>; pass --in-repo to share the repo
docs yes (new branch) Isolated in .worktrees/<id>; pass --in-repo to share the repo
website yes (new branch) Isolated in .worktrees/<id>; pass --in-repo to share the repo
debug-ci yes (new branch) Isolated in .worktrees/<id>; pass --in-repo to share the repo
tests yes (new branch) Isolated in .worktrees/<id>; pass --in-repo to share the repo
other no Catch-all; also used for unrecognized type strings

Every write-type agent (code/docs/website/debug-ci/tests) gets its own isolated worktree by default so parallel agents don't collide on the shared tree; pass --in-repo to opt back into the repo root. pr-review is exempt (it already checks out the PR branch). This isolation is what makes the boundary-enforcement hooks (see Lifecycle commands & boundary enforcement) meaningful.

By default every agent runs claude --dangerously-skip-permissions — permission prompts are suppressed and the agent runs fully autonomously; the Notification hook still records them as events in the session doc.

Pass --supervised to opt into a lighter permission mode (--permission-mode acceptEdits): file edits and common filesystem commands auto-approve, but other tools (bash writes, network calls, etc.) surface the numbered permission prompt — which the approvals inbox captures and lets you answer from the web AttentionQueue (one-click buttons), the TUI (⏳ Approvals row → i/1-9), or the CLI (warden approval answer) when approvals is on. A restored agent keeps its supervised setting.

If a worktree for the ticket already exists on disk, the spawn adopts it (reattaches claude to the existing branch) instead of erroring.


Terminal UI

warden tui   # open the cockpit
warden       # bare invocation — same thing

warden tui (or bare warden) opens a tmux-composited cockpit — a dedicated tmux session with three panes: the control pane (top-left), a terminal pane (bottom-left), and a full-height agent pane (right). The control pane is a navigator tree grouped by project — each project's agents, pipelines, plans and terminals nest under it — that you browse freely with ↑/↓ without disturbing the viewports; press Enter to open the selected entity. Opening an agent attaches its interactive claude session in the agent pane (right); opening a terminal attaches it in the terminal pane (bottom-left). Terminals are created on demand with t (inside the project under the cursor, like n); nothing is auto-spawned.

Agents spawned by another agent (via the spawn_agent MCP tool) nest under their parent as a collapsible sub-tree (▸ / ▾, indented per depth — the same affordance pipelines use), so you can see which agents an orchestrator fanned out. Deleting a parent that still has live children keeps it as a muted terminated tombstone header (terminated · N running) — no terminal/attach pane — so its children never vanish; the daemon reaps the tombstone once the whole sub-tree finishes.

The cockpit requires tmux ≥ 3.1 (it composites real tmux panes); if tmux isn't installed it exits with an error. Launched from inside an existing tmux session, warden detects $TMUX and lays the cockpit out as a native tmux window in your current session instead of nesting (your own keybindings, copy-mode, and resizing apply; q closes just the cockpit window). Force the native window with warden tui --tmux-native, or the classic own-session cockpit with env -u TMUX warden tui — see docs/USAGE.md §7.

The control pane polls the daemon about once a second. The daemon must be running (warden daemon) before opening the TUI.

Keys (cockpit)

Key Action
↑ / ↓ or j / k Move selection (the viewports are unaffected)
← / → or h Collapse / expand the section or the pipeline/agent sub-tree under the cursor
Enter Open the selected entity — an agent (or running pipeline job) attaches in the right agent pane; a terminal attaches in the bottom-left terminal pane; a finished agent or tombstone shows its stored detail instead of attaching
t Create a terminal inside the project under the cursor (same targeting as n); refused when the cursor is outside any project
n New agent — opens a prompt textarea; ctrl+s to submit, esc to cancel
o Open a directory as a group (becomes the spawn target for n)
s Send a message to the selected agent — enter to send, esc to cancel
a Attach — full-screen the agent's (or running job's) tmux session; press Ctrl-b Enter to return to the dashboard
l Log viewer — scrollable tail of the TUI log (~/.warden/tui.log or $WARDEN_TUI_LOG); g/G top/bottom, l/esc to close; levels coloured (ERROR red, WARN yellow, INFO cyan)
d Completion digest for the selected agent — scrollable overlay; d/esc to close
i Answer pending approvals (also enter on the ⏳ Approvals row) — 1-9 to answer, tab for next
c Shared-context + message-traffic inspector
r Retry a failed / needs-attention pipeline job
x Context-sensitive: terminate the selected agent / cancel a pipeline / close a terminal / close an opened dir (confirm with y)
D Delete a stopped pipeline's record (confirm with y)
? Toggle help overlay
Alt+t / Alt+a / Alt+p Rotate a viewport — Alt+t cycles the terminal pane over terminals, Alt+a cycles the agent pane over all agents, Alt+p cycles the agent pane over pipeline agents. Each grabs focus on the target pane. Global (works from any pane, even while typing)
Alt+Shift+t / Alt+Shift+a / Alt+Shift+p Same rotations in reverse
Ctrl-b then t/a/p Config-free rotation fallback (add Shift for reverse) — identical to Alt+t/a/p but via the tmux prefix, for terminals that don't send Alt/Option as Meta (macOS Terminal.app / iTerm2 default)
◆ Marks the agent/terminal currently shown in a pane (not a key) — its name carries a bold magenta badge in the control tree, tracking both Enter-open and the Alt+t/Alt+a/Alt+p rotation
q Quit and tear down the cockpit

Move focus between panes with Alt+←/→/↑/↓ (no tmux prefix); rotate the terminal/agent viewports with Alt+t / Alt+a / Alt+p (add Shift to rotate in reverse). Rotation grabs focus on the pane it drives, so cycling agents drops you straight into the session. On macOS, Terminal.app and iTerm2 don't send Option as Meta by default, so Option+t/a/p won't fire — use the config-free Ctrl-b prefix fallback (Ctrl-b then t/a/p, Shift for reverse), or enable "Use Option as Meta key". The row currently docked in a pane is marked with a ◆ and a bold name badge in the control tree, following both Enter-open and the Alt rotation. See docs/USAGE.md §7 for the full cockpit guide and caveats around nested tmux.


Command reference

warden tui

Open the live terminal cockpit. Also launched by bare warden with no subcommand.

warden tui
warden       # equivalent

See the Terminal UI section above for the full key reference.

warden start [TICKET|"<prompt>"] [--type <TYPE>]

Spawn a new agent session. Two modes:

Prompt mode (no --type) — pass a quoted prompt; the type is assigned automatically:

warden start "review the auth module for security issues"
warden start "investigate why the nightly build is flaky"

Managed worktree mode (--type required) — creates a git worktree for the ticket:

# Development agent for a Jira ticket:
warden start PROJ-350 --type development

# PR review — checks out the PR branch in a fresh worktree:
warden start --type pr-review --pr 1234

# Debug CI — no worktree, runs in current directory:
warden start --type debug-ci

# Spike with an optional scratch worktree:
warden start --type spike --worktree

# Point at a specific repo and branch:
warden start PROJ-350 --type development --repo /path/to/repo --branch my-branch

# Permission mode examples:
# Use acceptEdits mode for careful prompting on risky operations:
warden start "refactor the auth module" --permission-mode acceptEdits

# Set a global default for all new agents: put default_permission_mode: acceptEdits
# in ~/.warden/config.yaml, then restart the daemon.
warden start "debug the API rate limit"  # uses acceptEdits mode

# Override the global default for a specific agent:
warden start "quick spike" --permission-mode auto  # bypass global setting

# Change permission mode for a running agent:
warden agent set agent-abc123 permission-mode dontAsk

Flags:

  • --type — task type; omit to use prompt mode (auto-typed)
  • --repo — repo path (default: current directory; managed worktree mode only)
  • --branch — new branch name (development) or checkout target (pr-review)
  • --pr — PR number or URL (pr-review only)
  • --dir <path> — directory to run a prompt-spawned agent in (default: current directory)
  • --worktree — opt-in worktree for analysis/spike
  • --in-repo — write-type opt-out: run in the shared repo instead of an isolated worktree (ignored for pr-review)
  • --model <model> — per-agent model id (passed through verbatim); defaults to the model_default config setting
  • --role <role> — built-in agent role (who the agent is): general (default, no persona) · orchestrator · planner · worker · autopilot · brain (the legacy names implementer/auto-merger/reviewer still work, mapped to worker). Injects the role's persona as a system-prompt addendum and fills its default spawn flags (--type/--model/--permission-mode/auto-approve/tags) for any you leave unset (explicit flags still win). See warden agent role list
  • --task <name> — the unit of work (what the agent is doing) from the task registry, used to derive the model tier for quota-balanced routing when --tier is empty (e.g. architecture→tier-1, development→tier-2, merge-pr→tier-3). Distinct from --type (which controls worktree policy)
  • --tier <tier> — pin the model tier for the resolver directly (tier-1/tier-2/tier-3). Empty derives it from --task, then --role, else tier-2. A pinned --aicli/--model still wins over the resolver. See Tiered model routing
  • --tags <a,b> — attach tags (lowercased, deduped); searchable and filterable with warden ls --tag
  • --preset <name> — seed spawn defaults from a saved preset (warden project preset save); explicit flags still override
  • --prompt-template <name> --set VAR=value — fill a saved prompt template (warden project prompt-template save) into the spawn prompt; repeat --set per variable. A positional prompt still wins; free-form only (no --type)
  • --auto-restart — opt this agent into daemon auto-restart on error (tuned by auto_restart_* config)
  • --permission-mode <mode> — control Claude's permission level (valid modes: acceptEdits, auto, bypassPermissions, default, dontAsk, plan); defaults to the default_permission_mode config setting (default: auto)
  • --supervised — hidden legacy alias for --permission-mode acceptEdits; risky tools prompt and the approvals inbox surfaces them (see the approvals setting)

warden ls

List all active agent sessions with their type, status, working directory, and subject.

warden ls
# ID                TYPE         STATUS    AGE   DIR                SUBJECT
# PROJ-350    development  working   2m    PROJ-350     refactoring auth middleware
# prreview-a1b2     pr-review    idle      5m    prreview-a1b2      reviewing PR 1234
# agent-c3d4        …            working   1m    agent-c3d4         investigate flaky nightly build

DIR shows the base name of the agent's working directory. SUBJECT is the auto-generated one-line summary of what the agent is currently doing (empty until the first poller refresh).

Use --json for machine-readable output (a JSON array of full session objects; an empty fleet prints []). Useful for scripts and for Claude driving the CLI:

warden ls --json

Other flags:

  • --watch / -w — live-update the table on every agent state change over the daemon's SSE stream (Ctrl+C to exit); combine with --json to stream one JSON snapshot per change.
  • --tag <tag> — filter to agents carrying every given tag (AND semantics; repeatable or comma-separated). Tags are set at spawn with warden start --tags backend,urgent and are part of the search haystack.

warden status <AGENT>

Show full detail for one session: working directory, subject, worktree, branch, PR, all events.

warden status PROJ-350

Add --json to emit the full session as a single JSON object (including the events array):

warden status PROJ-350 --json

warden agent adopt [--session-id <uuid>] [--dir <path>]

Register an existing Claude session into warden.

  • Plain shell — finds the newest Claude conversation for the directory and resumes it under a new tmux session (claude --resume).
  • Inside tmux — registers the current tmux session live without relaunching claude.
warden agent adopt                          # newest session for cwd, resume under tmux
warden agent adopt --session-id <uuid>      # pick a specific Claude conversation
warden agent adopt --dir /path/to/project   # target a different directory

warden agent attach <AGENT>

Attach your terminal to the agent's tmux session interactively.

warden agent attach PROJ-350

warden agent stop <AGENT>

The single umbrella teardown verb. By default warden agent stop <AGENT> does a full teardown: terminate the tmux + claude session, clear (archive) the record, and remove the git worktree + branch (asking for confirmation first, unless --yes). Subtractive flags keep parts around; --pr opens a GitHub PR first while the agent is still intact. Safe order is always PR → terminate → remove worktree → clear record, so a failed push leaves the agent running.

warden agent stop PROJ-350                 # full teardown (asks before removing the worktree)
warden agent stop PROJ-350 --yes           # ...without the confirmation prompt
warden agent stop PROJ-350 --keep-worktree # terminate + clear record, keep the worktree (the old `done`)
warden agent stop PROJ-350 --keep-record   # terminate + remove worktree, keep the record
warden agent stop PROJ-350 --hard          # purge the record instead of archiving
warden agent stop PROJ-350 --pr --base main # open a GitHub PR first, then tear down

A failed step stops the teardown and names itself plus what already ran, e.g. remove worktree failed: … (completed: terminated; record left intact — fix the cause and retry). Because the record is cleared last, a worktree guard (agent alive / uncommitted / unpushed work) leaves it intact and stop is safely retryable once the cause is fixed; a branch that is already gone counts as success. No workaround is needed — do not call delete/delete_agent first (that archives the record and orphans the worktree). Worktrees orphaned by the older order (record cleared, worktree left behind) are reclaimed with warden worktree prune.

Older verbs still work as hidden aliases (they no longer appear in --help): agent done = stop --keep-worktree (with --hard/--pr), agent delete (record only) and agent remove-worktree (worktree only) have no exact stop equivalent because they do not terminate the session. Prefer stop with --keep-* flags. Pass --json to stop/terminate for the teardown result (id + steps that ran); --json never prompts, so removing a worktree then needs --yes.

warden agent terminate <AGENT>

Stop an agent: kill its tmux + claude session, but keep the record and worktree. This is the safe "stop this agent" default — it is reversible with warden agent restore. Alias for stop --keep-record --keep-worktree.

warden agent terminate PROJ-350

warden agent restore <AGENT>

Recreate and resume a lost/orphaned agent's tmux + claude session (claude --resume). Use only when the agent's tmux session is gone (status orphaned).

warden agent restore PROJ-350

warden agent recover

The safety net for the tombstone reaper (which auto-archives a parent record once its whole sub-tree goes terminal): a stale orphaned status racing a daemon restart could previously let a genuinely-live session's record get archived out from under it. Bare warden agent recover scans archived orphaned records and only reports the ones whose tmux session is confirmed still alive; --apply re-inserts each candidate into the active store under its original id — any children (linked via parent_id, untouched by archiving) reconnect automatically.

warden agent recover                # report candidates only (dry run)
warden agent recover --apply        # actually revive them
warden agent recover --json         # scripting

warden send <AGENT> <message...>

Type a message into the agent's claude session and press Enter.

warden send PROJ-350 "run the unit tests and fix any failures"

warden agent tail <AGENT>

Print the recent terminal output of the agent's claude session.

warden agent tail PROJ-350
warden agent tail PROJ-350 --lines 80

warden agent digest <AGENT>

Summarize what an agent accomplished — files touched, branch, number of turns, and a short narrative (best-effort, via claude -p). Also available as a web Digest panel and, in the cockpit, the d key (opens a scrollable digest for the selected agent).

warden agent digest PROJ-350
warden agent digest PROJ-350 --json

warden approval list / warden approval answer <AGENT> <option>

The approvals inbox (on by default; the approvals setting). When a --supervised agent hits a tool-permission prompt, the daemon recognizes it and surfaces the numbered options so you can answer without attaching.

warden approval list                 # list pending permission prompts (with their options)
warden approval answer PROJ-350 1  # answer prompt for that agent with option 1 (e.g. "Yes")

Unrecognized prompts always fall back to attach. Also surfaced in the web AttentionQueue (one-click buttons) and the TUI ⏳ Approvals row.

warden doctor

Preflight checks — required binaries (tmux, git, claude), optional ones (gh, warn-only), daemon reachability, and the data directory. It no longer checks for Ollama.

warden doctor

warden setup

Verifies the install with the same checks as doctor, then installs whatever is missing — idempotent, so it only touches deps that aren't already on PATH. It prints the exact install command for each missing dependency and prompts before running it; --yes installs everything without prompting (for automation). Required deps (tmux, git, claude) come first, then optional ones (gh). Package managers are auto-detected — Homebrew on macOS (never auto-bootstrapped) and apt/dnf/pacman on Linux — and Claude Code uses its official installer. After installing, it re-runs the checks and prints a doctor-style report. setup is CLI-only (it installs host packages) and is not exposed over MCP.

warden setup            # confirm-each install of anything missing
warden setup --yes      # non-interactive: install all missing deps

warden backend suggest (retired)

Retired compatibility stub: warden no longer runs a local model (the REPL and internal thinking use Fast-Brain), so there is nothing to size or pull. It prints a notice and exits 0.

warden tutorial (first-run walkthrough)

A guided tour of the core loop (spawn → watch → commit → tear down). Until you've taken or skipped it, warden prints a single non-blocking stderr hint nudging you toward it (suppressed for piped/non-interactive use).

warden tutorial                       # run the walkthrough, then mark it complete
warden tutorial --skip                # mark complete without running it
warden tutorial --reset               # clear the marker so the tour (and hint) run again

Disable the hint entirely with tutorial: false in the config.

warden agent handoff --retire (self-rotation; alias warden agent rotate)

Run inside an agent session to retire a long-lived, context-heavy agent and hand off to a fresh successor in the same workdir/worktree. Phase 1 is driven by the /warden skill (the agent writes a handoff file + resume prompt and shows you); on your go-ahead it spawns the successor and reaps itself.

warden agent handoff --retire --yes \
  --resume-file "${TMPDIR:-/tmp}/warden-rotate-handoff-$WARDEN_SESSION_ID.md" \
  --resume-prompt "Continue the migration from where the notes leave off"
# `warden agent rotate --yes …` is an exact alias.

The handoff file lives at a unique, per-agent temp path so concurrent rotations never clobber each other; the successor deletes it once read (and /tmp self-clears). Spawn-before-reap is fail-safe: if the successor fails to spawn, the current agent keeps running. Rotation reuses the worktree by cwd and never removes it. --retire is mutually exclusive with --to.

Pipelines — warden pipeline

Define a DAG of agent jobs in YAML and let the daemon run them: jobs with no dependencies start first, and each job's emit publishes its output and unblocks its dependents. The daemon owns the cheap "await + fire" so the lead Claude stays off the critical path.

warden pipeline validate review.yaml    # check the spec (DAG/refs/cycles); exit 0/1, no daemon
warden pipeline create review.yaml      # validate + register (does not start)
warden pipeline create review.yaml --start  # create and start in one step
warden pipeline create -f review.yaml --json  # -f still works; --json for scripting
warden pipeline template list          # list the built-in starter templates + their placeholders
warden pipeline create --template analyze-implement-review --set REPO=. # render from a template
warden pipeline start <id>              # spawn jobs with no dependencies
warden pipeline show <id>               # jobs table (status, agent, backend, after, branch)
warden pipeline show <id> --watch       # refresh until done/stalled/canceled
warden pipeline show <id> --prompts     # also print each job's prompt and handoff
warden pipeline show <id> --all-jobs    # include warden-injected span-out/span-in jobs
warden pipeline show <id> --json        # full machine-readable view
warden pipeline list                    # current project (use --all / --project / --status / --json)
warden pipeline job show <id> <job>     # full detail for one job
warden pipeline job edit <id> <job> ... # edit a not-yet-started job's fields
warden pipeline job retry <id> <job>    # re-run a failed/needs-attention job
warden pipeline pause <id>              # stop spawning new jobs (in-flight keep running)
warden pipeline resume <id>             # resume a paused pipeline
warden pipeline cancel <id> [--yes]     # terminate running jobs (confirms if any are live; cannot restart)
warden pipeline delete <id> [--yes]     # remove the record (always confirms; cancel first if live)

pipeline list defaults to the project of the current directory (--all for every project, --project to pick one, --status / --json to filter or script). Span-out/span-in jobs are created by warden for fan-out/join — hidden by default in show, marked [warden] with --all-jobs, and cannot be edited or retried. A pipeline run by a plan is controlled with wd plan pause|resume|stop — the pipeline pause/resume/cancel/delete verbs refuse it. A canceled pipeline cannot be restarted; create a new one from the same spec or template.

Removed in this release: pipeline edit-job → pipeline job edit; pipeline retry → pipeline job retry; pipeline list-templates → pipeline template list.

Four go:embed-bundled templates ship in the binary — analyze-implement-review, parallel-tasks, test-fix-verify, research-synthesis. Render one with warden pipeline create --template <name>, substituting placeholders via {{NAME}}/{{REPO}} (auto-filled) and --set KEY=VALUE.

A minimal analyze → implement → review spec (job prompts must not mention emit — the daemon auto-appends it and auto-injects upstream outputs):

name: auth-refactor
jobs:
  - id: analyze
    prompt: "Analyze the auth module and list the concrete refactors needed."
  - id: implement
    depends_on: [analyze]
    worktree: fresh
    prompt: "Implement the refactors identified upstream."
  - id: review
    depends_on: [implement]
    prompt: "Review the implementation branch for correctness and regressions."

Jobs can be made conditional with run_if: success (default) | failure | always — e.g. a run_if: failure rollback/notify step that only runs when an upstream job fails. Pipelines have full TUI and web visibility (a ▸ Pipelines section / a Pipelines tab). See docs/USAGE.md for the full authoring guide.

warden schedule (native cron/at)

Fire an agent spawn or a pipeline on the daemon's own timer — no external crontab. Opt-in: set scheduler_enabled: true in the config and keep the daemon running (schedules only fire while it is up).

# Recurring agent in the current directory (a weekday-morning review):
warden schedule create morning-review --cron "0 9 * * 1-5" --role reviewer \
  --prompt "Review yesterday's merged PRs and list follow-ups"

# Single-shot agent in an isolated worktree off a repo, on a chosen AI CLI + model:
warden schedule create release-prep --at 2026-12-01T08:00 --repo ~/dev/app \
  --aicli claude --model sonnet --prompt "Prepare the release notes"

# Fire a pipeline instead (each run gets a timestamped name):
warden schedule create nightly --cron "0 2 * * *" --pipeline ci.yaml

warden schedule list                    # NAME, STATE, WHEN, FIRES, NEXT, LAST
warden schedule show morning-review     # full fire payload + last run
warden schedule run  morning-review     # fire once now, to test it
warden schedule edit morning-review --cron "0 8 * * 1-5"
warden schedule disable morning-review  # stop firing (kept; re-enable later)
warden schedule enable  morning-review  # re-arm (recompute next run)
warden schedule delete  morning-review --yes  # --yes skips the confirmation prompt

A scheduled agent starts exactly as warden start would with the same flags: --cwd (default: the directory you ran create in), or --repo for an isolated worktree (--branch picks the branch), plus --role (default worker with --repo, otherwise general), --aicli/--model, --tier, --tags. A schedule that could never fire (unknown role, missing directory, no prompt) is rejected at create time. A past --at is rejected; --now fires once immediately. A --at time without a zone, and every cron spec, use the daemon host's local time (prefix a cron spec with TZ=<zone> to override). schedule list shows each schedule's state — enabled, disabled, done (single-shot that fired) or failed (single-shot whose fire failed); show prints the full payload and last run. schedule run fires a schedule once to test it and does not move its next run. schedule edit changes only the flags you pass (an empty value clears an optional field). delete asks for confirmation (--yes to skip; required without a terminal). --pipeline cannot be combined with agent flags.

Each fired run's session carries a schedule_id back-reference (on agent spawns and a scheduled pipeline's job sessions), so scheduled runs are separable from ad-hoc agents everywhere sessions surface — list, GET /sessions, and the SSE stream. Daemons advertise the scheduled-agents capability when this is supported end-to-end.

Fixed and removed in this release: agent schedules created without --type never fired — fixed; every accepted schedule now fires. warden schedule get is removed (use schedule show) and so is --type (use --role/--repo).

Missed runs are not backfilled — on daemon startup each next-fire is recomputed from the wall clock. The reconcile loop fails soft (a bad fire is recorded in last_error, never crashes the loop). list_schedules exposes the same read-only view over MCP.

Shared context & messaging — warden context / warden message

The substrate pipelines are built on, usable directly so agents can collaborate:

# Shared context: a namespaced key/value blackboard all agents can read/write
warden context set build.status "green" --as agent-4f2a
warden context get build.status
warden context list --prefix build.

# Directed messages: per-agent inbox; sending wakes a parked (idle/waiting) agent
warden message send agent-9c1d "the API contract changed — re-check your client"
warden message inbox --as agent-9c1d
warden message wait --as agent-9c1d --timeout 120   # block in the daemon until a message arrives

File-conflict detection — warden workspace

The daemon watches each active agent's worktree (fsnotify, with a git diff poll as a safety net) and warns — via the inbox, deduplicated — when two agents edit the same file. Spawned agents also get a system-prompt hint to check before editing shared files, so they coordinate rather than overwrite.

warden workspace conflicts                 # current cross-agent file conflicts
warden workspace who-is-editing <file>     # which agents (if any) are touching a file

Tunable via the collab.enabled / collab.interval / collab.git_reconcile_interval / collab.hint config settings; also exposed as the get_collaboration_status / who_is_editing_file MCP tools and a File conflicts card on the dashboard.

Git & check lifecycle — warden commit / push / sync / check

First-class, deterministic commands that move git and test/lint/build work off the agent and return compact results instead of raw tool-spam. PreToolUse hooks (config-gated, fail-open) steer agents toward these and deny-redirect the raw escapes — see Lifecycle commands & boundary enforcement.

warden commit            # stage + commit the agent's worktree (message auto-filled if omitted)
warden commit -m "fix: …"
warden commit -m "fix: …" src/a.go   # stage + commit only these paths
warden commit --amend    # rewrite the last commit (--force if already pushed)
warden push              # push the worktree's branch
warden push --force-with-lease  # safe force after a rebase/amend
warden sync              # rebase onto the session/integration/default base (refuses on a dirty tree; non-zero on conflicts)
warden sync --continue   # finish a conflicted rebase (or --abort to drop it)
warden git pr            # open/return the PR without ending the agent (MCP create_pr)
warden check [name]      # run the project's .warden/check.yml checks; reports only failures
warden check list        # list configured checks without running them

Rails: no commit/push on main/master, no dirty-tree sync, pre-commit-hook failures surfaced as a result. Force pushes are always --force-with-lease (never a bare --force), so a rebased branch can't clobber a teammate's push. commit, push, sync, check and git pr (create_pr) are also MCP tools; check finds .warden/check.yml from the repository root even when run from a subdirectory. Which branches count as protected is configurable (git.protected_branches, git.protect_default_branch).

Agent-native superpowers — warden git review / warden backend model

Some backends ship native capabilities Claude Code doesn't, and warden surfaces them as first-class verbs (added on top — never a restriction). Like warden check, these exec in the agent's worktree with no daemon round-trip, so they are CLI-only by design (no MCP twin).

warden git review                  # the backend reviews its OWN uncommitted diff and streams findings
warden git review --base main      # review the branch's changes against a base instead
warden git review --prompt "focus on error handling"
warden git review --json           # neutral machine-readable findings: {summary, verdict, findings[]}
warden backend model                  # the backend's LIVE model menu (one id per line; --json for an array)
  • warden git review — the agent-native counterpart to warden check (configured test/lint) and a reviewer-role agent (a whole reviewer session): it runs the backend's own one-shot reviewer against the worktree. Codex implements it (codex review); backends without a native reviewer (e.g. Claude) exit non-zero pointing you at warden check or a reviewer-role agent. --json runs the structured form (codex exec review) and normalizes the backend's native output into one neutral findings shape; review quality rides the backend's configured model.
  • warden bug-report [id] — review a sanitized crash draft staged under ~/.warden/crashes/ and file it as a GitHub issue only if you answer y (default N): authenticated gh creates the issue, otherwise a pre-filled link is printed. The cockpit shows [⚠️ Bug Detected: Press B to Review] with a Submit / Dismiss modal. Agents never auto-submit.
  • warden git release (alias wd release) — the release tag advisor: recommends the next SemVer bump + tag from the commits since the latest tag, prints a categorized changelog, and (on confirmation, default N) creates an annotated tag and pushes it. --dry-run, --yes, --push, --json.
  • warden backend model — the live runtime model menu for backends that expose one. Antigravity (agy models) and Cursor (cursor-agent --list-models) implement it; the ids feed --model verbatim. Listing is a metadata read, so it spends no quota. Claude has no live menu (pass --model with any id the Claude CLI accepts; warden does not rewrite it) and degrades non-zero.

Both take --backend <id> to target a specific backend (default: the current agent's). See AI CLIs.

warden project memory — project memory projected into every spawn

warden owns one committed, backend-neutral project memory — .warden/memory.md (beside .warden/check.yml), keyed implicitly by the repo root and holding durable cross-agent facts ("where X lives", "run Y via warden check", project invariants). The point: the next agent — any backend — doesn't re-pay the rediscovery tax the last one already paid.

warden project memory                  # show the resolved path + the rendered view injected into agents
warden project memory --raw            # print the file verbatim
warden project memory --edit           # open it in $EDITOR (auto-creates it first)
warden project memory --path           # just the resolved path (scriptable; no auto-create)

At every spawn warden projects the budgeted, navigational render into the agent's system prompt through the same seam the collab/pipeline/git hints ride: Claude via --append-system-prompt (file-backed, so it never bloats the launch line), codex / cursor / opencode / antigravity via their AGENTS.md warden block, crush via CRUSH.md, goose via .goosehints; aider degrade-skips. 7 of 8 backends project with zero new adapter code. It is config-gated by memory.inject (default on) — off, or an empty/absent file, makes the launch byte-identical to no injection. warden reads but never rewrites your CLAUDE.md/AGENTS.md/CONVENTIONS.md; .warden/memory.md is warden's own. warden project memory is CLI-local like warden check/warden git review (no daemon round-trip, no MCP twin).

Auto-curation (memory.curate, default OFF). warden can also propose memory for you: on the existing completion-digest hook, a debounced extraction pass reads finished agents' digests + the current memory and writes durable, reusable facts back as - [unverified · <date> · <provenance>] <fact>. It is deliberately never authoritative — proposals land in the working tree only (warden never commits and never pushes them, so the committed diff is the human review gate), promote to trusted only when corroborated by a second agent or a human, supersede older contradicting facts (struck with a tombstone), age out past a TTL, and get flagged stale when a named path vanishes. It runs on Fast-Brain (latency-bounded, fail-open) and never sits on a paid critical path. This is the core defence against memory poisoning: one agent's wrong belief can never silently mislead the fleet.

Local grounding (memory.ground, default ON). In warden repl you can also ask this memory a question — /memory <q> (/mem//ask), or the model-callable project_memory tool — and warden answers "where does X live?" / "how do I run Y?" from .warden/memory.md. This is the token-removing lever of the feature: unlike projection (which adds input tokens per turn), grounding answers from the curated memory file rather than a full agent turn. It is read-only (never creates or writes memory), cites each entry's trust (unverified/trusted/human) + provenance so a stale hint reads as a hint, runs on Fast-Brain (latency-bounded, never a paid agent turn), and with no backend available degrades to returning the matching entries verbatim. An absent/empty file answers "not in project memory".

warden inspect search <query…> / warden inspect history

warden inspect search auth backend          # AND every term across active sessions; --closed folds in the archive
warden inspect history --since 7d --type development --limit 20   # browse the archived (closed) store

search matches case-insensitively over id/name/ticket/type/subject/prompt/branch/tags/last-pane; --json on either prints raw records. The web dashboard carries a live search box and a 🗄 Archive tab mirrors history.

warden inspect export / warden inspect import

Serialize session metadata (not worktrees/branches/tmux) to JSON for backup or moving between machines.

warden inspect export > fleet.json           # active records; --all also dumps the archive
warden inspect import < fleet.json           # idempotent by id; --merge overwrites colliding records

warden inspect audit

An append-only trail of the daemon's meaningful actions (spawn, terminate, delete, approve, pipeline_start/pipeline_cancel) written to ~/.warden/audit.jsonl (0600). Read directly from the file, so it works even while the daemon is down.

warden inspect audit                                  # newest last (default tail 50)
warden inspect audit --action spawn --since 24h --json
warden inspect audit --target PROJ-350 --tail 0       # 0 = all

warden project preset save|list

Save reusable spawn defaults under a name and replay them with warden start --preset <name>.

warden project preset save fast --model haiku --permission-mode acceptEdits --auto-restart
warden project preset list
warden start "quick fix" --preset fast            # explicit flags still override the preset

--type/--model/--permission-mode/--auto-restart/--worktree/--in-repo are persisted to ~/.warden/presets.yaml; per-invocation inputs (ticket, branch, PR, dir) are not.

warden project prompt-template save|list

Where a preset stores reusable flags, a prompt template stores a reusable prompt body with {{VAR}} placeholders. Save one, then fill it in at spawn time (alias pt).

warden project prompt-template save bugfix --prompt "Fix the bug in {{FILE}} described by {{TICKET}}"
warden project prompt-template list                        # each template + its variables
warden start --prompt-template bugfix --set FILE=server.go --set TICKET=WARD-42

Variables are auto-derived from the body and persisted to ~/.warden/prompt-templates.yaml. Every declared variable must be supplied (a typo'd --set is rejected), and an explicit positional prompt still wins. --prompt-template is free-form only (no --type).

warden project library list|save-preset|save-prompt

One umbrella over all three kinds of reusable launch config — saved spawn presets, saved prompt templates, and the built-in pipeline templates.

warden project library list                               # presets + prompt templates + pipeline templates, labeled sections (alias: wd project library list)
warden project preset save fast --model haiku     # delegates to `warden project preset save`
warden project prompt-template save bugfix --prompt "Fix {{FILE}}"   # delegates to `warden project prompt-template save`

Purely additive: it reuses the existing preset store, the prompt-template store, and the embedded template catalog, so warden project preset, warden project prompt-template, and warden pipeline template list keep working unchanged. Pipeline templates are embedded/read-only (no save-template; author one with warden pipeline create -f <spec.yaml>). Also exposed over MCP as library_list (returns {presets, prompt_templates, templates}).

warden projects — manage registered projects

Manage first-class daemon projects (checkout roots or remote repos). Projects register themselves: launching an agent, pipeline or terminal, or creating/running a plan, in a directory auto-registers its project as open (or reopens it if closed; .worktrees/ checkouts map to the parent repo), so open / open-local / open-remote are an optional convenience, not a prerequisite — and close still works (a closed project reopens on the next launch in it).

warden projects list                         # list all registered projects (alias: ls)
warden projects open <id> [--name <name>]     # register or reopen by ID
warden projects open-local <path>            # register an existing local directory
warden projects open-remote <url>            # clone a remote repo and register it
warden projects new <name>                   # scaffold a fresh project
warden projects close <id>                   # hibernate project and gracefully stop agents

warden project-groups — organize projects into groups

Manage named collections of projects and group membership:

warden project-groups list                   # list all groups and member projects (alias: ls)
warden project-groups show <id>              # show group details
warden project-groups create <name>          # create a new group (--project <id> repeatable)
warden project-groups update <id>            # bulk update name and/or projects
warden project-groups delete <id>            # delete a group (projects remain intact)
warden project-groups members add <id> <project-id>    # incrementally add member
warden project-groups members remove <id> <project-id> # incrementally remove member

warden inspect resources

CLI view of the resource metrics (per-agent process-tree RSS/CPU, system memory/pressure, daemon self-stats).

warden inspect resources                          # live snapshot
warden inspect resources --history                # per-agent performance history + anomaly warnings
warden inspect resources --history --agent PROJ-350

warden cost

One umbrella over warden's two financial views: spend (the real dollars agents billed to the model provider) and savings (the tokens — and the dollars they represent — warden kept out of context). warden cost with no subcommand prints a combined at-a-glance summary of both.

warden cost                           # combined: SPEND section + SAVINGS section
warden usage spend                     # same as `warden usage spend` (all flags wired through)
warden usage savings --benchmark       # same as `warden usage savings --benchmark`

Purely additive: it reuses the existing spend rollup and savings ledger and their render logic, so the top-level warden usage spend and warden usage savings keep working unchanged (they remain available as aliases). Resource footprint — memory/CPU/pressure — is a different axis; see warden inspect resources.

warden usage savings

Read back the token-savings ledger — the tokens warden's lifecycle features kept out of agents' context windows. A real, append-only record, not an estimate. Gated by the savings config setting (default on). Also reachable as warden usage savings.

warden usage savings                        # per-feature table (saved/raw tokens, events)
warden usage savings --benchmark            # headline A/B: without-vs-with warden, % cut, $ saved, trend sparkline
warden usage savings --since 7d             # scope to a window (24h/7d/2w) or a date
warden usage savings --json                 # structured summary
warden usage savings --audit                # raw-vs-kept provenance samples (needs savings_samples)
warden usage savings --calibrate            # measure this workload's bytes/token vs Claude count_tokens (needs ANTHROPIC_API_KEY)

Two axes are reported separately and never blended: the context axis (how much leaner context stayed, in % and $) and the offload axis (cloud-model work moved off to Fast-Brain, in $). Each figure states its basis — CALIBRATED or the 4-bytes/token HEURISTIC. See docs/FEATURES.md §29.

warden usage spend

The cost side of the ledger: the REAL billed model spend warden measured from agents' transcripts, priced per model into dollars and rolled up per agent / repo / day. Dollar pricing currently covers the Claude backend; bring-your-own-model backends report tokens only. Gated by the same savings config setting. Also reachable as warden usage spend.

warden usage spend                          # total / today / this week, then per-agent/repo/day $ tables
warden usage spend --by agent               # just one rollup: agent, repo, or day
warden usage spend --json                   # structured rollup

A budget gate (off by default) turns this into a guardrail: set budget_daily_usd / budget_weekly_usd and flip budget_gate: true, and a spawn that would push measured spend over the cap warns first (re-run with --force to proceed) — mirroring the memory-pressure spawn gate. warden ls also gains a COST column, and the web Metrics tab a live per-agent cost card. See docs/FEATURES.md §30.

warden workspace branches

Opt-in, read-only view of each active agent's branch health: its GitHub CI status (latest gh run list in the worktree) and its standing vs origin/main (commits behind/ahead, merged?).

warden workspace branches                       # table of per-agent CI + base-branch standing
warden workspace branches --json

The daemon monitor behind it (enable with branch_track.enabled) delivers non-blocking alerts — an inbox note to the agent (and a desktop ping to you) on a new CI failure, an inbox nudge on a merged or far-behind branch. Every gh/git call fails open. Also exposed via GET /api/v1/collab/branches and the get_branch_status MCP tool.

warden usage insights

Mine archived agent history for patterns — recurring task shapes, slow/failure-prone work, and parallelization opportunities — as a deterministic report (optionally narrated by Fast-Brain). Gated by insights (default on).

warden usage insights
warden usage insights --json

warden workspace snapshot

Checkpoint an agent's worktree changes + session transcript and roll back later. Gated by snapshots (default on).

warden workspace snapshot create [name] -m "before risky refactor"   # capture a checkpoint
warden workspace snapshot list [name] [--all]                        # list checkpoints
warden workspace snapshot restore <id> [--force]                     # re-apply onto its worktree

Restore reapplies the captured stash onto the recorded worktree; it refuses a dirty/conflicting tree rather than clobbering, and a failed apply leaves the snapshot intact. Also available as the snapshot_create/snapshot_list/snapshot_restore MCP tools.

warden approval auto set

Two layers control auto-approval:

Per-agent toggle — opt one agent into evaluation even when the global policy is off:

warden approval auto set agent-abc123 on
warden approval auto set agent-abc123 off

Rule policy — a real allow/deny engine. A recognized prompt is auto-answered only when it matches an allow rule, matches no deny rule, and isn't on warden's built-in destructive deny-list (which always wins). Rules match by tool name, a case-insensitive glob/substring (--pattern), a Go regexp (--regex) over the prompt, and/or path globs (--paths). A per-agent override (--agent, keyed by name or id) gets its own rule set that replaces the default. Changes take effect immediately and persist to config.

warden approval auto rules                         # show the live policy
warden approval auto enable                         # turn the policy on
warden approval auto allow --tool Read              # auto-approve all Read prompts
warden approval auto allow --regex '^Bash\(git (status|diff|log)\)'
warden approval auto deny  --tool Bash --pattern rm
warden approval auto allow --agent reviewer --tool Grep
warden approval auto clear --agent reviewer         # drop reviewer's overrides

With no rules configured, an enabled policy keeps the simple legacy behavior: it auto-answers every recognized, non-destructive prompt (selecting the least-privilege affirmative). Multi-select / text-entry / unrecognized prompts always fall back to manual. Also available as the set_auto_approve (toggle) and set_auto_approve_policy (rules) MCP tools.

warden agent set <AGENT> <key> <value> / warden agent get <AGENT> [key]

One pair of verbs for every per-agent setting. Keys: permission-mode (acceptEdits/auto/bypassPermissions/default/dontAsk/plan; preserved on restore), compact (on/off/inherit — per-agent force-compact override), role (a role name; relaunches the agent) and auto-approve (on/off). get prints all four, or one with a key; --json emits machine-readable output.

warden agent set agent-abc123 permission-mode dontAsk
warden agent set agent-abc123 compact inherit
warden agent get agent-abc123 --json

The older agent permission-mode set, agent compact set and agent role set still work as hidden aliases.

warden agent role list / warden agent set <AGENT> role <role>

A role is a named, persistent system-prompt persona attached to an agent, plus a set of default spawn flags. Every agent has exactly one role; the default is general, which injects no persona and behaves exactly as agents do today. The role set is a fixed built-in catalog (no user-defined roles). Each role also carries a default model tier that feeds the tiered router when nothing more specific pins the tier:

Role Persona Default flags Default tier
general (none — plain agent) — tier-2
orchestrator coordinates a fleet of warden agents; plans and delegates, doesn't write feature code itself unless trivial --permission-mode bypassPermissions, auto-approve on (hardcoded) tier-1
planner research/analysis/planning only — produces specs, RFCs, design docs; must not edit code --permission-mode plan tier-1
worker owns one task end-to-end (implement, self-review, PR, drive green, merge) and reports status back to its coordinator --type development, --permission-mode auto, auto-approve on tier-2
autopilot long-lived headless manager of a whole autopilot run — decomposes, spawns workers/brains, gates + lands into the integration branch --permission-mode bypassPermissions, auto-approve on tier-1
brain on-demand decision resolver — unblocks a stuck agent or makes an ad-hoc design/arch call, no human interaction --permission-mode bypassPermissions, auto-approve on (hardcoded) tier-2

autopilot, worker, and brain power autopilot's manager → worker → brain topology. Legacy aliases: reviewer, implementer, and auto-merger are no longer first-class roles — that work is now a task (pr-review/development/merge-pr, see Tiered model routing) — but the three names still resolve to the worker role for back-compat.

The persona is injected through the same system-prompt seam warden already uses for its collab/git/pipeline hints (Claude via --append-system-prompt, the injecting backends via their rules file); only the role name is persisted, so the persona re-resolves from the registry at every (re)launch — nothing persona-shaped is stored on disk. Role default flags fill only the fields you left unset (explicit start flags win); default tags are unioned in.

# List the built-in roles and their descriptions
warden agent role list            # add --json for scripting

# Spawn an agent with a role (its default flags apply unless you override them)
warden start "ship the auth refactor end-to-end" --role worker

# Switch a running agent's role — relaunches to re-inject the new persona
warden agent set agent-abc123 role worker

# Clear the persona (back to a plain agent)
warden agent set agent-abc123 role general

# Change a role's default model tier
warden agent role tier set worker tier-2

Roles are also drivable from the UIs (TUI new-agent ctrl+r role picker and ctrl+t tier picker with live candidates, web + New agent Role dropdown) and over MCP (spawn_agent's role param, set_role, list_roles) — see Orchestrator (MCP). set-role relaunches the agent (its in-flight turn is discarded) because a persona only takes effect at (re)launch, mirroring how set-permission-mode persists a value but a persona additionally needs a fresh launch.

Tiered model routing (--task / --tier)

warden resolves each spawn's backend + model by quota headroom within a model tier, so a fleet spreads across providers instead of exhausting one. Two optional, orthogonal inputs feed it (a spawn's third axis, alongside --aicli and --role):

  • --task <name> — what the agent is doing, from the built-in task registry. Each task carries a tier: tier-1 (analysis, architecture, design, research, spike), tier-2 (code-review, development, docs, pr-review), tier-3 (debug-ci, merge-pr, monitor-ci, release). This is the canonical task→tier source.
  • --tier <tier> — pin the tier directly (tier-1/tier-2/tier-3).

The target tier is resolved with the precedence explicit --tier > task tier > role default tier > tier-2; within the tier the router scores every model by headroom (1 − used/limit), skips rate-limited or ineligible backends, and picks the highest-headroom candidate (round-robin among ties). A pinned --aicli or --model bypasses the router, and a first spawn degrades to the request defaults if no resolver is wired — routing never hard-fails a spawn.

warden start "design the sync protocol" --role planner        # role → tier-1
warden start PROJ-9 --type development --task development      # task → tier-2
warden start "cut the v9 release" --task release              # task → tier-3
warden start "urgent hotfix" --tier tier-1                    # pin the tier
warden start "run it on codex" --aicli codex --model o1     # pins bypass routing

--task ≠ --type. --type decides worktree/branch policy (see worktrees & task types); --task decides the model tier. The two name-sets overlap but are independent. Surfaces: --tier and --task are on warden start and the REST spawn body; --tier is also a pipeline-job field (tier:, alongside role:). Over MCP, spawn_agent routes by role only (its default tier feeds the resolver) — no tier/task params. See docs/specs/tiered-model-routing.plan.md and docs/specs/agent-roles.md for the full model.

warden workspace

The umbrella for warden's worktree operations — list and prune:

warden workspace                       # list warden-owned worktrees (same as `worktree list`)
warden workspace list                  # list worktrees under .worktrees, joined to records (alias: ls)
warden workspace prune                 # reclaim orphaned worktrees (prompts; --force overrides guards)
warden workspace prune --include-archived  # widen scope to archived records
warden workspace clean                 # preview, then delete merged branches + prune stale worktrees
warden workspace clean --dry-run       # preview only (also --json, --local-only, --force, --yes)

warden workspace clean (alias warden clean) is different from prune: prune reclaims orphaned warden worktrees (their agent record is gone), while clean deletes merged branches — local and on origin, including squash-merged ones — and the stale worktrees checked out on them. It previews three tables (merged local branches, merged remote branches, stale worktrees), asks [y/N] (skip with --yes), removes worktrees first, then local, then remote branches. main/master/develop/release/*, the base branch and the current branch are never deleted; dirty worktrees are kept unless --force.

warden workspace prune remains as a top-level alias for warden workspace prune (same flags, prompts, and output). Retention is policy-driven via the worktree.keep_done / worktree.auto_prune config settings; dirty/unpushed worktrees are always kept. Reclaiming whole orphaned worktrees is distinct from warden agent remove-worktree, which tears down one agent's worktree.

warden agent handoff

The single verb for passing work to another agent, with three modes. Default mode spawns a fresh delegate in its own isolated worktree; --to <id> delivers the handoff into an existing agent's inbox (waking it) — both keep the source running and inline the handoff content into the recipient's prompt/message. --retire (requires --yes) is the self-succession mode: it spawns a successor in the calling agent's same worktree and reaps the caller — exactly what the warden agent rotate alias runs (see above). --retire and --to are mutually exclusive. Phase 1 (writing the handoff) is /warden-skill-driven.

warden agent fork

Shorthand for warden start --fork-from <agent> — fork an existing agent's recorded session into a new managed agent. A fork branches the source's conversation/reasoning (Codex's session rollout) into a divergent session and continues it as its own agent: a fresh sibling worktree off the source's branch HEAD, seeded with the source's uncommitted tracked changes (dirty-tree carry; untracked/.gitignore'd build artifacts are not carried), with its own tmux session warden manages and tears down. The source agent keeps running, untouched — fork branches sideways, unlike snapshot (rewinds one timeline) or rotate/handoff (carry the task, drop the conversation).

warden agent fork agent-7                  # fork agent-7, continue its conversation
warden agent fork agent-7 "now try X"      # fork and seed a divergent first prompt

Only backends with a native session fork are forkable — Codex today (codex fork); forking one without (e.g. Claude) reports a clean "cannot fork". The source's backend session id must already be pinned (let it run a turn first). The fork inherits the source's repo + backend; --type defaults to development. Unlike warden git review / warden backend model, fork is a managed spawn that crosses the daemon, so it has MCP + CLI parity — the fork_agent MCP tool is the orchestrator twin (a thin wrapper over spawn_agent with fork_from set, no new endpoint).

warden daemon token generate|show|rotate

Manage the bearer token that gates non-loopback (remote) access — see Remote access.

warden daemon token generate                 # mint a 256-bit token (persisted to ~/.warden/token.env, 0600)
warden daemon token show                     # print the current token (paste into a remote client)
warden daemon token rotate                   # regenerate in place + restart the daemon
warden daemon token show --readonly          # print the read-only token (WARDEN_READONLY_TOKEN)

The WARDEN_TOKEN env var overrides the file so the secret can stay off disk.

Read-only token. Set an optional second token, WARDEN_READONLY_TOKEN, to hand out view-only access (e.g. a shared dashboard or a teammate). A read-only token may read everything — all GETs plus the live event stream — but is denied every state-changing action and the interactive attach. Mint one with warden daemon token generate and export it as WARDEN_READONLY_TOKEN (it only works alongside a primary WARDEN_TOKEN; the daemon refuses to start with a read-only token but no primary one).

warden repl — interactive mode

warden's interactive mode: a proper terminal REPL to drive the fleet, with a real line editor (arrow keys, persisted history, reverse-search, a live /-command menu that filters as you type, Tab completion, colourised prompt) that closes cleanly with Ctrl-D. It drives the fleet two ways:

  • Deterministic / commands (no model) — /agents, /spawn <prompt>, /tell <id> <text>, /memory <question>, /pipelines, … Typing / pops a live, filtering menu of matching verbs (each with its summary); /help lists them all. These keep working even when Fast-Brain is slow or unavailable. When a command needs more input, a guided argument form collects it — numbered pick-lists for known fields (model, permission, type), free text for the rest — opening automatically for a missing required arg or on a +-suffixed verb (/spawn+); Fast-Brain, if available, pre-fills each field with a suggestion you can accept, override, or clear.
  • Natural language (Fast-Brain) — any other line is planned into confirmed warden tool calls by Fast-Brain; it works out of the box, with no local model or local_llm config. It conducts; it never implements — all code work is delegated by spawning an agent.
  • Local project grounding ($0) — ask a project question ("where does the spawn gate live?", "how do I run the tests?") via /memory <q> (/mem//ask) or the project_memory tool and warden answers it from .warden/memory.md, citing each entry's trust + provenance. It removes a cloud round-trip (rather than adding tokens like injection); read-only, degrades to the matching entries verbatim with no backend available, default on via memory.ground.

The / commands and !-shell always work, even if Fast-Brain is unavailable. Every mutating action passes a mandatory confirm gate. Run it standalone with warden repl. See docs/FEATURES.md §17.

warden repl                                   # aliases: warden i, warden interactive; also warden backend repl

warden project plugin

Inspect the plugin registry — external executables that extend warden with custom agent task types and lifecycle hooks (over a versioned JSON-over-stdio protocol). Default off (plugins: true to enable, since plugins run external code).

warden project plugin list                    # registered plugins: paths, custom task types, subscribed hook events, config errors

Hooks (pre/post-spawn, pre/post-commit, pre/post-check) are advisory and fail-open — a missing, slow, or crashing plugin is logged and skipped, never blocking an agent. Configure via plugins.enabled + a plugins.registry list in ~/.warden/config.yaml; a worked example lives under examples/plugins/. See docs/FEATURES.md §26.

warden daemon

Run the daemon (HTTP API + background poller). Normally managed by launchd (macOS) or systemd (Linux); run manually for debugging.

warden daemon
warden daemon --addr 127.0.0.1:9000

warden daemon mcp

Run the MCP stdio server so an orchestrator agent session (e.g. Claude) can manage agents via tool calls.

warden daemon mcp
warden daemon mcp --addr 127.0.0.1:8765

Tools exposed: list_agents, get_agent, spawn_agent, adopt_agent, send_to_agent, get_agent_output, stop_agent, terminate_agent, restore_agent, delete_agent, remove_worktree, ctx_set, ctx_get, ctx_list, ctx_cas, ctx_append, send_message, read_inbox, wait_for_message, list_approvals, approve, commit, push, sync, check, get_collaboration_status, who_is_editing_file, get_branch_status, create_pipeline, start_pipeline, show_pipeline, list_pipelines, cancel_pipeline, list_schedules, snapshot_create, snapshot_list, snapshot_restore, insights, savings, spend.

warden completion <shell>

Generate shell completion scripts for Bash, Zsh, Fish, or PowerShell.

warden completion bash   # generate bash completion script
warden completion zsh    # generate zsh completion script
warden completion fish   # generate fish completion script
warden completion powershell   # generate PowerShell completion script

The completion script should be redirected to the appropriate location for your shell. See the Shell Completion section for installation instructions.


Orchestrator (MCP)

Register warden daemon mcp as an MCP server in your orchestrator agent's MCP config. For a Claude Code orchestrator that's ~/.claude/claude_desktop_config.json or the project-level .claude/mcp.json; other MCP-capable agents use their own config path:

{
  "mcpServers": {
    "warden": {
      "command": "warden",
      "args": ["mcp"]
    }
  }
}

warden daemon mcp connects to the daemon at the addr config setting (default 127.0.0.1:8765); to point it elsewhere use "args": ["mcp", "--addr", "host:port"].

Once registered, the orchestrator session can call these tools directly:

Tool Description
list_agents List all active agents with their status, working directory, and subject
get_agent Get full detail (status, workdir, subject, events, worktree) for one agent
spawn_agent Spawn a new agent — pass a prompt for a quick auto-typed agent, or type+repo for a managed worktree; set supervised: true for --permission-mode acceptEdits instead of full bypass; pass role to attach a built-in role persona + its default flags
set_role / list_roles Switch a running agent's built-in role (relaunches to re-inject the persona; general/empty clears it) / list the fixed built-in role catalog (name + description) for a picker
adopt_agent Register an existing Claude session: resume newest-for-dir under tmux, or live-register a running tmux session
send_to_agent Type a message into a specific agent's claude session
get_agent_output Return the recent terminal output of a specific agent
stop_agent Umbrella teardown. Default = full teardown (terminate + clear record + remove worktree). keep_record / keep_worktree subtract steps (keep_worktree alone == the old done); hard purges the record; pr/base open a GitHub PR first while the agent is intact; force/delete_adopted_branch for the worktree guards. Destructive when it removes the worktree — only after explicit user confirmation
terminate_agent Stop an agent (kill tmux + the agent process); keeps the record and worktree. Reversible via restore_agent — the default "stop this agent" action
restore_agent Recreate and resume a lost/orphaned agent's session (claude --resume)
recover_agents Safety net for the tombstone reaper: revive archived orphaned records whose tmux session is confirmed still alive. apply:false (default) only reports candidates; apply:true re-inserts each one under its original id, reconnecting any children automatically
delete_agent Clear an agent's stored record (archives by default; hard purges). Does not touch tmux or the worktree
remove_worktree Remove an agent's git worktree + branch — destructive; refuses while the agent runs or has uncommitted/unpushed work unless force
ctx_set / ctx_get / ctx_list / ctx_cas / ctx_append Read/write the shared-context key/value blackboard agents collaborate through (with compare-and-swap and append)
send_message / read_inbox / wait_for_message Send a directed message to an agent (wakes it if parked) / read this agent's inbox / block until a message arrives
list_approvals / approve List recognized pending tool-permission prompts / answer one by option number
commit / push / sync Git lifecycle on the agent's pinned worktree (staged commit with auto-message, push — force uses --force-with-lease, rebase-sync) returning compact structs instead of raw git output
check Run the project's .warden/check.yml checks, returning pass/fail with output for only the failing ones
get_collaboration_status / who_is_editing_file File-conflict view across the fleet / who (if anyone) is editing a given file
create_pipeline / start_pipeline / show_pipeline / list_pipelines / cancel_pipeline Drive a DAG pipeline — create from a YAML spec, start entry jobs, inspect, list, cancel

Pipeline MCP tools are thin wrappers over the same daemon routes the CLI uses, so an orchestrator session can run a multi-stage workflow (analyze→implement→review) without shelling out. Lifecycle controls (pause_pipeline, resume_pipeline, delete_pipeline, edit_pipeline_job, retry_pipeline_job) are available over MCP too, mirroring the warden pipeline … CLI.

Example orchestrator prompts:

  • "What is PROJ-350 doing?" — calls get_agent to fetch current status and events
  • "Tell PROJ-343 to run the tests" — calls send_to_agent with "run the tests"
  • "List all my agents" — calls list_agents
  • "Spin up an agent to research SSE reconnection" — calls spawn_agent with a prompt (auto-typed)
  • "Spawn a debug-ci agent in /path/to/repo" — calls spawn_agent with type+repo
  • "Stop PROJ-350" — calls terminate_agent (reversible); "clear its record too" — then delete_agent

Drive it from an orchestrator agent (the warden skill)

Beyond raw tool access, install the packaged Claude Code skill so a Claude orchestrator session knows how and when to manage your fleet (triage, create-from-prompt, relay "tell X to do Y", terminate-with-confirmation, daemon-down handling). Other MCP-capable orchestrators drive the same tools directly without the skill:

make install-skill   # symlinks skills/warden into ~/.claude/skills/warden

With the MCP server registered (above) and the skill installed, just talk to a Claude session: "list my agents", "spin up an agent to research X", "what is agent-4f2a doing?", "tell agent-4f2a to run the tests", "kill the idle ones" — it drives the MCP tools (falling back to the warden CLI if the MCP server isn't registered). The daemon must be running.


Lifecycle commands & boundary enforcement

warden moves deterministic responsibilities off agents — git and checks — onto the first-class warden commit/push/sync/check commands (CLI + MCP), and enforces the worktree boundary with PreToolUse hooks delivered through a per-agent claude --settings file (Claude Code backend). Each hook fails open (a hook error never blocks the agent) and is individually config-gated (default on):

Layer Setting What it does
Prompt steer git_conventions A system-prompt hint steering agents toward wd commit/push/sync/check over raw git/test Bash — the gentle first layer
Isolation guard isolation_guard Denies an isolated agent's Edit/Write that escapes its worktree into the shared repo
Git-guard git_redirect Deny-redirects raw git commit/push/pull/rebase to the warden tools (reads stay allowed)
Check-guard check_redirect Deny-redirects a raw test/lint/build command registered in .warden/check.yml to wd check (focused -run invocations pass through)

The default write-type isolation (each code/docs/website/debug-ci/tests agent gets its own worktree unless --in-repo) is what makes the isolation guard meaningful and fixes parallel-agent collisions. See docs/FEATURES.md §22 for the full model.


Typical workflow

# 1. Start the daemon (once — then managed by launchd)
./scripts/install.sh   # install + start as a background launchd service (recommended)
make run-daemon        # foreground, for debugging only (blocks the terminal; ctrl-C to stop)

# 2. Spawn an agent for a ticket
warden start PROJ-350 --type development

# 3. Watch what it's doing
warden ls
warden status PROJ-350

# 4. Drop into its terminal if needed
warden agent attach PROJ-350

# 5. Clean up when done
warden agent stop PROJ-350 --keep-worktree

Development

make build            # go build -o bin/warden ./cmd/warden
make test             # go test ./...  (includes fuzz seed corpora)
make lint             # go vet ./...
make run-daemon       # build + start daemon in the foreground (debugging only)
make test-integration # build-tagged end-to-end suite (real daemon subprocess + CLI)
make bench            # run the Benchmark* suite (store I/O, pipeline, approvals)
make fuzz             # deeper fuzz sweep of the YAML/pane/session parsers
make cover            # whole-repo statement coverage (prints the total%)

The README coverage badge is a static snapshot of make cover's total — refresh it when coverage moves materially.

All unit tests run without Docker or any external services:

go test ./...

The integration suite (make test-integration, build tag integration) boots a real warden daemon against an isolated HOME; its spawn-lifecycle test self-skips unless tmux and claude are installed, so it stays CI-safe.

Git hooks

The repo ships version-controlled hooks in .githooks/. Wire them once with:

make install-hooks          # git config core.hooksPath .githooks
# or: ./scripts/install-hooks.sh

scripts/install.sh (the service installer) also does this automatically. Once wired:

  • pre-commit runs make fmt-check lint (gofmt + go vet) — fast, so a formatting/vet slip is caught before the commit lands.
  • pre-push runs make verify-fast (gofmt/vet/web/release build) — the CI subset that doesn't need an isolated machine.

Bypass either in a pinch with git commit --no-verify / git push --no-verify. Because core.hooksPath is a relative path, the hooks work across git worktrees too.


Web GUI

The daemon embeds a React dashboard (Astro + React) and serves it at http://localhost:8765 alongside the REST API — no separate server required.

Build & run

make release     # 1. builds the Astro UI (web/), 2. embeds it via go:embed, 3. builds bin/warden
warden daemon  # start the daemon as usual

Then open http://localhost:8765 in a browser.

Note: the UI is baked into the binary at build time. After changing anything under web/, re-run make release (or make ui to rebuild only the frontend) and restart the daemon for the changes to take effect.

What it does

The dashboard is a routed mission-control shell. Tabs are real URLs (History-API routing — back/forward, refresh, and shareable deep links all work), so each surface has its own address:

Route Tab What's there
/cockpit ⊞ Cockpit The home view (/ redirects here). A slim Fleet header (totals · busy · waiting · errored, pressure, dirs) above the full agent grid.
/others ▦ Others The former Overview, now a catch-all: Needs you (attention queue), File conflicts, and Recent activity.
/pipelines ⛓ Pipelines Pipeline list + live DAG / job drawer.
/metrics 📊 Metrics Per-agent and fleet-wide charts — see below.
/archive 🗄 Archive Ended sessions with since/type filters.
/agent/<id> <id> A pinned agent's live terminal (one closeable tab per pinned agent).
  • Cockpit is the home — / redirects to /cockpit. It carries the Fleet summary header (moved out of the old Overview) above the canonical agent grid; the redundant Quick spawn widget and the duplicate All agents mini-grid were removed.
  • Metrics tab (/metrics) — a scrollable column of uPlot chart cards: CPU per agent, Memory per agent (GiB), Cost per agent (live measured model spend in $, with a total/today/this-week headline and a sorted per-agent cost bar chart — top-N costliest, rest folded into an others row), Context per agent (a client-accumulated time series of each agent's live context fill, legend dot colored by ok/warning/critical; in-session only — resets on full reload), Number of agents (fleet size over time), and Tokens saved (daily bars from the savings ledger + a headline saved-tokens/$ figure). When the savings ledger is disabled the savings/cost cards show a "set savings: true" hint instead of an empty chart. A Live footprint card carries the former Resources panel.
  • Context & Messages — no longer a tab; opened from a small 🗒 button in the header as a dismissible overlay (Esc to close).
  • Agent tabs — pin any agent to its own tab to get a live, interactive terminal (AttachTerminal) — a real tmux attach bridged to the browser over a WebSocket, so you can type into the agent and watch it respond in real time.
  • Create agent — + New agent opens a prompt box (with a directory picker and a Supervised checkbox). Type the task and press Create (or Cmd/Ctrl+Enter); the type label is assigned automatically. Tick Supervised to launch with --permission-mode acceptEdits instead of full bypass. For a managed worktree, use the CLI: warden start TICKET --type development --repo ….
  • Terminate — surfaces the git guard (409 → Force + optional hard-delete) when there's uncommitted/unpushed work.
  • Agent grouping — the Cockpit grid buckets agents into collapsible panes by Directory / Type / Status / Tag (choice saved to LocalStorage).
  • Batch operations — per-tile checkboxes (Shift-click range select) raise a bulk action bar offering Message…, Terminate, and Delete across the selection.
  • Search & Archive — a live search box filters the fleet client-side; the 🗄 Archive tab browses ended sessions with since/type filters.
  • Theme toggle — header control cycles System → Light → Dark (defaults to System; persisted, applied before first paint).
  • Keyboard shortcuts — a global layer: ? help overlay, n new agent, / focus filter, r refresh, 1–9 jump to a tab, j/k next/previous tab, Esc close/blur (also closes the Context overlay).
  • Browser notifications — opt in to get a desktop notification when an agent enters waiting_for_input (gated so they only fire while the tab is hidden).

Remote access

The dashboard is mobile-responsive and can be reached from your phone or another machine. Generate a token (export WARDEN_TOKEN=$(warden daemon token generate)), bind a non-loopback address (warden daemon --addr 0.0.0.0:8765), and expose it over Tailscale (recommended) or a Cloudflare Tunnel. The daemon refuses to bind non-loopback without a token; the browser prompts for it on first load. See docs/USAGE.md → Remote access for the full walkthrough.

Dev workflow

Run two terminals in parallel — no rebuild loop needed while iterating on the UI:

# Terminal 1 — daemon (REST API + SSE on :8765)
warden daemon

# Terminal 2 — Astro dev server (:4321, proxies /api/* (REST + /api/v1/.../attach WS + /api/v1/events SSE) and /healthz to :8765)
make ui-dev

Open http://localhost:4321. Edits under web/src/ trigger HMR instantly; the browser stays on the same origin as the real daemon API so SSE and all REST calls work without CORS configuration.

Tests

make web-test    # Vitest — frontend unit tests (status mapping, API client)
go test ./...    # Go suite — covers daemon hub, SSE endpoint, static embed, and all existing routes

The frontend Vitest suite lives in web/src/lib/ alongside the source files (status.test.ts, api.test.ts). The Go daemon tests cover the broadcaster (hub_test.go), the SSE handler (sse_test.go), and the static file serving with SPA fallback (static_test.go).


Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md for licensing, the DCO sign-off (git commit -s), and dependency/notices rules. Before opening a PR:

gofmt -l $(git ls-files '*.go')   # must be empty (CI enforces gofmt)
make lint                          # go vet ./...
make test                          # go test ./...
make web-test                      # frontend unit tests

CI (build, test, lint) runs on every push and PR to main — see .github/workflows/ci.yml.


License

Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE. Third-party dependency licenses are listed in THIRD-PARTY-NOTICES.md.

Trademarks & affiliation

warden is an independent open-source project. It is not affiliated with, endorsed by, or sponsored by Anthropic, OpenAI, Google, Cursor, Block, or any other agent-backend vendor. "Claude" and "Claude Code" are trademarks of Anthropic, PBC; "Codex" of OpenAI; and all other product and company names are trademarks of their respective owners, used here for identification only.

Your credentials, your responsibility

warden is a local orchestrator: it drives agent-backend CLIs and services using credentials you supply. You are responsible for complying with the terms, usage policies, and rate limits of every backend and account you connect. warden grants no rights to any third-party service and makes no representation that a given automation or concurrency pattern is permitted under your plan.

Copyright 2026 Srajan Pathak

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

About

Run a fleet of Claude Code agents from one Go binary — spawn, monitor, and tear them down in isolated git worktrees, track per-agent cost, and see how many tokens you're saving. No database, no SaaS.

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages