{"slug": "warden-run-a-fleet-of-coding-agents-without-losing-your-mind", "title": "Warden – run a fleet of coding agents without losing your mind", "summary": "Warden is a free, self-hosted Go binary that orchestrates fleets of coding agents in isolated git worktrees, tracking costs and token savings without a database or telemetry. The tool supports multiple agent backends, a live TUI and web dashboard, and an MCP server for agent-driven coordination, with an autopilot mode that autonomously manages worker agents through CI and PRs.", "body_md": "📖\n\nDocs & guide:[https://srjn45.github.io/warden/]\n\n**Run a fleet of coding agents without losing your mind.** warden is a single Go\nbinary (`warden`\n\n, aliased `wd`\n\n) that spawns, monitors, and tears down coding-agent\nsessions — each in its own isolated git worktree — while tracking exactly what every agent\ncosts and how many tokens its lifecycle features keep out of context. It drives multiple\nagent backends (Claude Code by default — see [Agent backends](#agent-backends---backend)),\nbacked by a local daemon and a file-based JSON store: **no database, no SaaS, no telemetry.**\n\n**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 spend`\n\nprices 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 savings`\n\nis 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 savings --calibrate`\n\n) send data only where you explicitly configure them.**Driven by an agent itself**—`warden mcp`\n\nexposes the whole fleet as MCP tools, so an orchestrator agent (e.g. a Claude session) can spawn, query, and coordinate the fleet for you.\n\n```\ngo install github.com/srjn45/warden/cmd/warden@latest   # or grab a release binary (see Install)\nwarden setup --yes      # install missing deps (tmux, claude, …); `warden doctor` just checks\nwarden tutorial         # guided tour of the core loop: spawn → watch → commit → tear down\nwarden start \"review the auth module for security issues\"   # spawn your first agent\nwarden tui              # open the cockpit\n```\n\n`go install`\n\ngives you the CLI / daemon / TUI / MCP server. For the embeddedweb dashboard, use a[release binary]or build with`make release`\n\n— see[Install].\n\n**Architecture — one binary, multiple faces**\n\n`warden daemon`\n\nis the single writer to the on-disk session store, serving a loopback REST\nAPI and running a background poller. `warden ls|status|start|done|attach|send|tail`\n\nare thin\nHTTP clients to the daemon. `warden mcp`\n\nis a stdio MCP server that bridges MCP tool calls to\nthe same REST API, enabling an orchestrator agent session (e.g. Claude) to query agents and\ntalk to a specific running agent. A short alias `wd`\n\n(a symlink to `warden`\n\n) is installed alongside it.\n\n```\nalias agents=warden\n```\n\nNew 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-glancecoverage matrix(which of CLI / MCP / skill / web / TUI can drive each feature). The sections below cover build, install, and contributor setup.\n\nCapability highlights from recent releases (full notes on the [releases page](https://github.com/srjn45/warden/releases); the complete catalog lives in [docs/FEATURES.md](/srjn45/warden/blob/main/docs/FEATURES.md)):\n\n**Autopilot**— a goal-directed, long-running autonomous mode. Author a plan file (`autopilot.plan.yaml`\n\n), run`warden autopilot init`\n\nto scaffold the config, then`warden autopilot on`\n\nto start. A**manager** agent (role`autopilot`\n\n) drives a fleet of**worker** agents (role`worker`\n\n, one per task) in isolated worktrees, gates their PRs through CI, and lands them into`autopilot/integration`\n\n— all without human intervention, spawning a**resolver**(role`brain`\n\n) on demand to unblock a stuck worker. A guardian heal loop keeps the manager alive through stalls, a daemon-internal overwatch nudges it to tend idle/waiting workers, and a cost-tier backend ladder escalates from free (Antigravity) to subscription (Claude, Codex) when rate-limited. The kill switch is`warden autopilot off`\n\n. The switch is**per-repo**—`warden autopilot on`\n\nenables only the current repository (add`--repo <root>`\n\nto target another), the enabled set is persisted so repos come back up across a daemon restart, and the manager marks its plan`status: complete`\n\nin place when it finishes so a done run is never re-run. See[Autopilot guide](https://srjn45.github.io/warden/guides/autopilot/)and[Autopilot concepts](https://srjn45.github.io/warden/concepts/autopilot/).**Live config hot-reload**— edit`~/.warden/config.yaml`\n\nand warden**applies it with no daemon restart**: the autopilot template,`auto_approve`\n\npolicy, token/context guard (`tokens.*`\n\n),`rails.*`\n\n,`model_default`\n\n,`default_permission_mode`\n\n, hint gates, and`notify.*`\n\n/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`\n\n,`data_dir`\n\n, timers, loop cadences) are logged as changed-but-pending. See[Configuration](/srjn45/warden/blob/main/docs/FEATURES.md#12-configuration-yaml-config-file).**Agent roles (**— attach a named, persistent`--role`\n\n)**persona** to an agent at spawn (`warden start … --role reviewer`\n\n) or switch it on a running agent (`warden set-role <id> reviewer`\n\n, which relaunches to re-inject). Five built-in roles —`general`\n\n(default, no persona),`orchestrator`\n\n,`implementer`\n\n,`auto-merger`\n\n,`reviewer`\n\n— each carrying a persona plus default spawn flags (e.g.`reviewer`\n\ndefaults`--type pr-review`\n\n,`auto-merger`\n\nturns on auto-approve).`warden role list`\n\nshows the catalog; the TUI new-agent form has a`ctrl+r`\n\nrole picker and the web**+ New agent** modal a Role dropdown. See[Agent roles](#warden-role-list--warden-set-role).**Resilience & ergonomics round-up**—`warden recover`\n\nre-registers archived-but-alive agents (tombstone-reaper safety net); the web`/tui`\n\ncockpit**self-heals**(validated and auto-rebuilt if wedged;`warden tui --rebuild-web-cockpit`\n\nforces it);`warden tui`\n\ninside an existing tmux session lays out as a**native tmux window** instead of erroring (`--tmux-native`\n\n);`wd push --force-with-lease`\n\nfor safe force-pushes; rate-limit auto-resume now also answers Claude's**wait-menu and monthly spend cap**(`rate_limit.spend_retry_interval`\n\n); and all daemon stores (sessions, pipelines, schedules, snapshots, context, mailbox) run on an embedded ScrivaDB — still no database server.**Isolation guardrails (v5.0, breaking)**— write-type agents (`code`\n\n/`docs`\n\n/`website`\n\n/`debug-ci`\n\n/`tests`\n\n) now spawn into their own worktree by default (`--in-repo`\n\nopts out), backed by PreToolUse hooks that deny-redirect raw`git`\n\n/test commands to the first-class`warden commit`\n\n/`push`\n\n/`sync`\n\n/`check`\n\ntools. See[Lifecycle commands & boundary enforcement](#lifecycle-commands--boundary-enforcement).**Interactive mode (**— a terminal REPL with a real line editor (history, a live`warden repl`\n\n)`/`\n\n-command menu, Tab completion, guided argument forms, colour) that drives the fleet via deterministic`/`\n\ncommands (no model) or natural language (a local-LLM conductor that turns operator intent into confirmed warden tool calls without spending cloud-model tokens); optionally hosts the cockpit master pane.**Pipelines, end to end**— DAG pipelines are now drivable from the** MCP tools**(create/start/show/list/cancel), ship four built-in`--template`\n\nstarters, and support`run_if`\n\nconditional steps.**Agent sub-trees in the TUI**— agents spawned by another agent nest under their parent as a collapsible sub-tree (`▸ / ▾`\n\n, 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 search`\n\n+ tags, a`warden history`\n\narchive,`warden export`\n\n/`import`\n\n, an append-only`warden audit log`\n\n, spawn`preset`\n\ns and variabled`prompt-template`\n\ns (browse both via`warden library`\n\n), and web batch operations.**Observability**— per-agent metrics & performance history (`warden stats`\n\n), crash/anomaly detection, the context-size guard, and webhook/Slack notifications.**Token-savings ledger (**— a real, append-only ledger of the tokens warden's lifecycle features keep out of agents' context, with an`warden savings`\n\n)`--benchmark`\n\nA/B headline (without-vs-with warden, % reduction, $ saved) you can screenshot.**Cost governance (**— 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`warden spend`\n\n)**budget gate** that softly warns before a spawn pushes daily/weekly spend over a configured`$`\n\ncap (a`$`\n\ncolumn in`warden ls`\n\nand a live per-agent cost card on the web Metrics tab round it out).**Native scheduler (**— opt-in cron/at triggers that fire an agent or a pipeline on the daemon's own timer; no external crontab.`warden schedule`\n\n)**Snapshots & insights**—`warden snapshot`\n\ncheckpoints a worktree + transcript for rollback;`warden insights`\n\nmines agent history for patterns and parallelization wins.**Branch tracking (**— opt-in monitor of each agent's CI status and standing vs`warden branches`\n\n)`origin/main`\n\n, with non-blocking inbox/desktop alerts.**Extensibility**— a`warden plugin`\n\nsystem (custom task types + lifecycle hooks over JSON-stdio) and an interactive**OpenAPI/Swagger UI** at`/api/docs`\n\n.**Web**— real URL routing (`/cockpit`\n\n,`/tui`\n\n,`/pipelines`\n\n,`/metrics`\n\n,`/archive`\n\n,`/others`\n\n,`/agent/<id>`\n\n— deep-linkable, back/forward, shareable), a Cockpit home with a Fleet header, a highlighted top-bar**▢ TUI** launcher that opens the literal`warden tui`\n\n**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 token …`\n\n) and a Docker/compose deployment.**First-run tutorial (**— a guided walkthrough of the core loop, with a one-line nudge until you've taken (or skipped) the tour.`warden tutorial`\n\n)\n\n**Go 1.26+**— to build the binary (only needed for`go install`\n\nor building from source)**tmux**— every agent session runs in a detached tmux window** git**— worktree creation and guarded cleanup** Claude Code**(`claude`\n\non PATH) — the default agent runtime launched in each session**Aider**(`aider`\n\non PATH, optional) — only needed to spawn agents with`--backend aider`\n\n; bring-your-own-model (works with local Ollama models, $0)**OpenCode**(`opencode`\n\non PATH, optional) — only needed to spawn agents with`--backend opencode`\n\n; bring-your-own-model (works with local Ollama models, $0). Install:`npm install -g opencode-ai`\n\n([https://opencode.ai](https://opencode.ai))(GitHub CLI) — required for`gh`\n\n`pr-review`\n\nsessions to check out the PR branch, and for`warden done --create-pr`\n\n**Ollama**(optional) — only needed if you enable the local-LLM features (`local_llm`\n\n) or the`warden repl`\n\nREPL; warden falls back to Claude when it's off or unreachable\n\nTip:once you have the`warden`\n\nbinary, runto check these dependencies and`warden doctor`\n\nto install whatever is missing (Homebrew on macOS; apt/dnf/pacman on Linux; official installers for Claude Code and Ollama).`warden setup`\n\n`warden setup --yes`\n\ndoes it non-interactively.\n\nwarden is one self-contained binary. Pick whichever fits:\n\nGrab the archive for your OS/arch from the [latest release](https://github.com/srjn45/warden/releases/latest), extract `warden`\n\n, and put it on your `PATH`\n\n. Released binaries have the web dashboard embedded.\n\n```\n# example: macOS arm64 (adjust the version/arch)\ncurl -fsSL https://github.com/srjn45/warden/releases/latest/download/warden_8.16.3_darwin_arm64.tar.gz | tar -xz\nsudo mv warden /usr/local/bin/        # or any dir on your PATH\nwarden --version\n```\n\nmacOS Gatekeeper:downloaded binaries are unsigned, so the first run may be blocked. Clear the quarantine flag once:`xattr -d com.apple.quarantine $(which warden)`\n\n(or right-click → Open). Building from source — option 3 — avoids this.\n\nEvery release also ships native packages (all with the `wd`\n\nalias included and the web dashboard embedded):\n\n```\n# macOS — Homebrew tap (clears the Gatekeeper quarantine for you)\nbrew install --cask srjn45/tap/warden\n\n# Debian / Ubuntu\ncurl -fsSLO https://github.com/srjn45/warden/releases/latest/download/warden_8.16.3_linux_amd64.deb\nsudo apt install ./warden_8.16.3_linux_amd64.deb\n\n# Fedora / RHEL\nsudo dnf install https://github.com/srjn45/warden/releases/latest/download/warden_8.16.3_linux_amd64.rpm\n\n# Arch (AUR)\nyay -S warden-bin\n```\n\n(Adjust the version/arch in the URLs; the `.deb`\n\n/`.rpm`\n\npull in `tmux`\n\nand `git`\n\nas recommended packages.)\n\n```\ngo install github.com/srjn45/warden/cmd/warden@latest\n```\n\nThis installs the `warden`\n\nbinary (CLI + daemon + MCP server + TUI). **Note:** `go install`\n\ndoes *not* bundle the web dashboard (the UI is built from `web/`\n\nand 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 a release binary (option 1) or build from source (option 3).\n\n```\ngit clone https://github.com/srjn45/warden.git\ncd warden\nmake build           # CLI/daemon/TUI only → bin/warden\nmake release         # builds the web UI first, then embeds it → full GUI\n```\n\nwarden supports shell completion for Bash, Zsh, Fish, and PowerShell. Generate the completion script for your shell and install it to the appropriate location:\n\n**Bash:**\n\n```\n# System-wide installation:\nwarden completion bash | sudo tee /etc/bash_completion.d/warden\n\n# User-only installation:\nwarden completion bash > ~/.bash_completion\n```\n\n**Zsh:**\n\n```\n# System-wide installation:\nwarden completion zsh | sudo tee /usr/local/share/zsh/site-functions/_warden\n\n# User-only installation:\nmkdir -p ~/.zsh/completion\nwarden completion zsh > ~/.zsh/completion/_warden\n# Then add to your ~/.zshrc:\n# fpath=(~/.zsh/completion $fpath)\n# autoload -Uz compinit && compinit\n```\n\n**Fish:**\n\n```\nwarden completion fish > ~/.config/fish/completions/warden.fish\n```\n\n**PowerShell:**\n\n```\nwarden completion powershell > warden.ps1\n# Then add to your PowerShell profile\n```\n\nAfter installing the completion script, restart your shell or source the file for completions to take effect.\n\nThe 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.\n\nInstall with the script — it builds the release, installs the binary to\n`~/.local/bin/warden`\n\n, renders and loads the launchd plist, links the Claude\nskill, and registers the MCP server:\n\n```\n./scripts/install.sh        # or: make install\n```\n\nThe daemon then starts automatically at login and restarts on crash\n(`KeepAlive = true`\n\n), listening on `127.0.0.1:8765`\n\nby default.\n\n`~/.local/bin`\n\nmust be on your`PATH`\n\nto run`warden`\n\nfrom the shell — the installer warns if it isn't.\n\nThe launchd daemon is the macOS TCC *responsible process* for the agents it\nspawns and for its own directory picker, so reads of protected folders\n(Downloads, Documents, Desktop, the Music/media library) surface as *\"warden\nwould like to access…\"* prompts. Granting Full Disk Access once silences them —\nbut macOS ties the grant to the binary's code identity, and an unsigned Go\nbinary gets a new identity on every rebuild, which brings the prompts back.\n\nRun the one-time setup to give the binary a **stable** self-signed identity:\n\n```\n./scripts/codesign-setup.sh   # creates a self-signed code-signing cert (once)\n./scripts/install.sh          # reinstall so the binary is signed\n```\n\nThen grant access once: **System Settings → Privacy & Security → Full Disk\nAccess → \"+\"** and add `~/.local/bin/warden`\n\n. Because the signing identity is\nstable, the grant survives future rebuilds. (`install.sh`\n\n/`reinstall.sh`\n\nsign\nautomatically when the cert exists; without it they warn and leave the binary\nunsigned.)\n\n**Redeploy after a code change** (replaces `make release && ./bin/warden daemon`\n\n):\n\n```\n./scripts/reinstall.sh             # rebuild UI + binary, redeploy, restart\n./scripts/reinstall.sh --no-build  # redeploy the existing build only\n# or: make reinstall  /  make reinstall NO_BUILD=1\n```\n\n**Uninstall** (stops and removes the service, binary, skill link, and MCP\nregistration; **preserves** your session store at `~/.warden`\n\nand the logs):\n\n```\n./scripts/uninstall.sh                 # or: make uninstall\n./scripts/uninstall.sh --keep-binary   # leave ~/.local/bin/warden in place\n```\n\nLogs:\n\n- stdout:\n`/tmp/warden.daemon.log`\n\n- stderr:\n`/tmp/warden.daemon.err`\n\nNotifications:off by default. When enabled (set`notify.enabled: true`\n\nin the config file, or the deprecated`notify: true`\n\n), the daemon posts a macOS notification when an agent enters`waiting_for_input`\n\n,`idle`\n\n(stuck),`orphaned`\n\n, or`errored`\n\n. These appear only when the daemon runs in your GUI login session (a terminal, or a launchduser agent); a headless/system daemon logs them instead.\n\nThe same install script detects Linux and registers a systemd **user service**\ninstead of a launchd plist. It builds the release, installs the binary to\n`~/.local/bin/warden`\n\n, writes `~/.config/systemd/user/warden.service`\n\n, enables\nit, and links the Claude skill and MCP server:\n\n```\n./scripts/install.sh        # or: make install\n```\n\nThe daemon starts automatically at each login session and restarts on crash\n(`Restart=always`\n\n), listening on `127.0.0.1:8765`\n\nby default.\n\n`~/.local/bin`\n\nmust be on your`PATH`\n\n— the installer warns if it isn't.\n\nPersistent daemon:`install.sh`\n\ncalls`loginctl enable-linger`\n\nso the systemd user service keeps running after you close your terminal or SSH session (equivalent to launchd`RunAtLoad`\n\non macOS). This requires systemd 219+ and is a no-op on most modern distros.\n\n**Redeploy after a code change:**\n\n```\n./scripts/reinstall.sh             # rebuild UI + binary, redeploy, restart\n./scripts/reinstall.sh --no-build  # redeploy existing build only\n# or: make reinstall  /  make reinstall NO_BUILD=1\n```\n\n**Uninstall** (stops and removes the service, binary, skill link, and MCP\nregistration; **preserves** `~/.warden`\n\n):\n\n```\n./scripts/uninstall.sh\n./scripts/uninstall.sh --keep-binary   # leave ~/.local/bin/warden in place\n```\n\nLogs go to the systemd journal (the unit sets `StandardOutput=journal`\n\n/\n`StandardError=journal`\n\n), so they survive reboots even where `/tmp`\n\nis a tmpfs\n(Fedora, Arch, …):\n\n```\njournalctl --user -u warden -f        # follow live\njournalctl --user -u warden -n 100    # last 100 lines\n```\n\nNotifications:off by default. Set`notify.enabled: true`\n\nin the config file to enable (the deprecated`notify: true`\n\nalso works). The daemon calls`notify-send`\n\n(libnotify) when it's on`PATH`\n\n; install it with`apt install libnotify-bin`\n\n(Debian/Ubuntu) or`dnf install libnotify`\n\n(Fedora). Degrades to log-only if`notify-send`\n\nis not found.\n\nThe repo ships a multi-stage [ Dockerfile](/srjn45/warden/blob/main/Dockerfile) and a\n\n[. The image is a lean Alpine runtime (static](/srjn45/warden/blob/main/docker-compose.yml)\n\n`docker-compose.yml`\n\n`CGO_ENABLED=0`\n\nbinary plus `tmux`\n\n+ `git`\n\n) with the web dashboard baked\nin. State lives in a `~/.warden`\n\nvolume so it survives container restarts, and\nthe daemon binds `0.0.0.0:8765`\n\nfor remote access.\n\n```\n# Build the image (run from the repo root).\ndocker build -t warden:latest .\n\n# A non-loopback bind REQUIRES a bearer token — the daemon refuses to start\n# without one. Generate it locally (or use any secret) and run:\nexport WARDEN_TOKEN=$(warden token generate)\ndocker run -d --name warden \\\n  -p 8765:8765 \\\n  -e WARDEN_TOKEN \\\n  -v warden-data:/home/warden/.warden \\\n  warden:latest\n```\n\nOr with compose (reads `WARDEN_TOKEN`\n\nfrom your environment):\n\n```\nexport WARDEN_TOKEN=$(warden token generate)\ndocker compose up -d        # builds the image on first run\n```\n\nThe dashboard/API is then reachable at `http://<host>:8765`\n\n; the browser prompts\nfor the token on first load. Don't expose the port directly to the public\ninternet — front it with Tailscale or a Cloudflare Tunnel (see\n[Remote access](#remote-access)).\n\ntmux is required.warden runs every agent inside a tmux session, so the image installs`tmux`\n\n(and`git`\n\n, 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`\n\nCLI and its credentials inside the container — the base image deliberately omits these to stay lean; layer them on (and mount`~/.claude`\n\n) if you want the container to drive live agents rather than just manage/observe sessions.\n\nThe hook script posts lifecycle events (`SessionStart`\n\n, `Notification`\n\n, `Stop`\n\n, `SubagentStop`\n\n, `SessionEnd`\n\n) to the daemon so it can update agent status in real time without polling. `SessionEnd`\n\nmarks the session **done** (terminal) when claude exits.\n\nMerge `hooks/settings.snippet.json`\n\ninto `~/.claude/settings.json`\n\n. The snippet\nuses a `__WARDEN_HOOK__`\n\nplaceholder — substitute the absolute path to\n`hooks/warden-hook.sh`\n\nin your clone first:\n\n```\n# from the repo root, render the snippet with the real hook path:\nsed \"s|__WARDEN_HOOK__|$(pwd)/hooks/warden-hook.sh|g\" hooks/settings.snippet.json\n\n# If ~/.claude/settings.json doesn't exist yet, write it directly:\nsed \"s|__WARDEN_HOOK__|$(pwd)/hooks/warden-hook.sh|g\" hooks/settings.snippet.json > ~/.claude/settings.json\n\n# If it already exists, merge the rendered \"hooks\" key into the root of your\n# existing settings.json object.\n```\n\nThe hook fails soft — it never blocks or errors the agent, even if the daemon is down or the session is unknown.\n\nWarden supports per-agent model selection:\n\n**Short aliases:**`opus`\n\n,`sonnet`\n\n,`haiku`\n\n,`fable`\n\n**Full model IDs:**`claude-opus-4-8`\n\n,`claude-sonnet-4-6`\n\n, etc.**Default:**`claude-sonnet-4-6`\n\n(or the`model_default`\n\nconfig setting)\n\n```\n# Explicit model\nwarden start \"Complex task\" --model opus\n\n# Set the default model: edit ~/.warden/config.yaml (model_default: opus),\n# then restart the daemon. `warden config` shows what's live.\n\n# View model in agent list\nwarden ls  # Shows MODEL column\n```\n\nWarden drives **Claude Code** by default, but the agent layer is pluggable: pick\nthe backend per agent at spawn time with `--backend`\n\n(CLI) or the `backend`\n\nparam\n(`spawn_agent`\n\nMCP tool).\n\nSupported agents — status:warden is fully tested only withClaude Code.Codex CLIandAntigravity CLIareβ beta— live-verified state, approval, and transcript fidelity, still maturing. The remaining non-`claude`\n\nbackends (Aider, OpenCode, Crush, Goose, Cursor) areexperimental / work-in-progress— functionality may be reduced or unverified.\n\n| Agent | Status |\n|---|---|\n| Claude Code | ✅ Stable — fully tested, reference backend |\n| Aider | 🧪 Experimental (WIP) |\n| OpenCode | 🧪 Experimental (WIP) |\n| Codex CLI | β Beta |\n| Crush | 🧪 Experimental (WIP) |\n| Goose | 🧪 Experimental (WIP) |\n| Cursor CLI | 🧪 Experimental (WIP) |\n| Antigravity CLI | β Beta |\n\n| Backend | `--backend` |\nTier | Notes |\n|---|---|---|---|\nClaude Code (default) |\n`claude` |\nA | Full fidelity — digests, savings, priced spend, resume, all permission modes |\nAider |\n`aider` |\nA | 🧪 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), runs an autonomous `--message` task that exits when done |\nOpenCode |\n`opencode` |\nA | 🧪 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) |\nCodex CLI |\n`codex` |\nA | β Beta. 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\n`docs/agent-backends/codex.md` |\nCrush |\n`crush` |\nA | 🧪 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 into the TUI after launch via `PromptSeeder` ; context injection via `CRUSH.md` ; spend tokens-only. See\n`docs/agent-backends/crush.md` |\nGoose |\n`goose` |\nA | 🧪 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; context injection via `.goosehints` ; spend tokens-only. See\n`docs/agent-backends/goose.md` |\nCursor CLI |\n`cursor` |\nC | 🧪 Experimental. 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` . No structured transcript yet (interactive store is unreadable SQLite) ⇒ no digests; spend tokens-only. See\n`docs/agent-backends/cursor.md` |\nAntigravity CLI |\n`antigravity` |\nA | β Beta. 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\n`docs/agent-backends/antigravity.md` |\n\n```\n# Drive Aider against a local Ollama model (free, offline)\nexport OLLAMA_API_BASE=http://127.0.0.1:11434\nwarden start \"implement the add function\" --backend aider --model ollama_chat/qwen2.5-coder:3b --dir .\n\n# Drive OpenCode against a local Ollama model (free, offline)\nwarden start \"implement the add function\" --backend opencode --model ollama/qwen2.5-coder:3b --dir .\n\n# Drive Codex against a local Ollama model (configure provider in ~/.codex/config.toml first)\nwarden start \"implement the add function\" --backend codex --dir .\n\n# Drive Crush against a local Ollama model (configure provider in ~/.config/crush/crush.json first)\nwarden start \"implement the add function\" --backend crush --dir .\n\n# Drive Goose against a local Ollama model\nGOOSE_PROVIDER=ollama GOOSE_MODEL=qwen2.5-coder:3b \\\nwarden start \"implement the add function\" --backend goose --dir .\n```\n\nBackends differ in capabilities; warden **degrades gracefully** rather than\ncrashing when one lacks a capability (e.g. spend shows tokens-not-dollars for a\nbring-your-own-model backend; rotate/handoff re-spawn fresh when resume is\nunavailable). It also surfaces some backends' **native superpowers** as\nfirst-class verbs — `warden review`\n\n(Codex's diff reviewer), `warden models`\n\n(Antigravity/Cursor's live model menu), and `warden fork`\n\n(branch a Codex\nsession into a new managed agent — see [ warden fork](#warden-fork)); see\n\n[Agent-native superpowers](#agent-native-superpowers--warden-review--warden-models). See the design (\n\n`docs/superpowers/specs/2026-06-27-pluggable-agent-backends-design.md`\n\n, §5)\nand roadmap item #52.Warden reads all settings from a single YAML file (default `~/.warden/config.yaml`\n\n). Run `warden config init`\n\nto generate a fully-commented file, edit the values, then restart the daemon; `warden config`\n\nprints what's currently live. The `--config <path>`\n\nflag points any command at an alternate file, and `--addr <host:port>`\n\noverrides the daemon address for a single command.\n\n| Setting | Default | Description |\n|---|---|---|\n`addr` |\n`127.0.0.1:8765` |\nDaemon listen address. Non-loopback requires `WARDEN_TOKEN` (bearer-token auth — see\n|\n`data_dir` |\n`~/.warden` |\nDirectory 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 |\n`claude_projects_dir` |\n`~/.claude/projects` |\nRoot of Claude Code transcript directories; the poller reads agent transcripts here to generate subjects and the context gauge |\n`model_default` |\n`claude-sonnet-4-6` |\nDefault model for new agents (a model id or alias: `sonnet` /`opus` /`haiku` /`fable` ) |\n`default_permission_mode` |\n`auto` |\nDefault permission mode for new agents (`auto` /`default` /`acceptEdits` /`bypassPermissions` /`dontAsk` /`plan` ) |\n`notify.enabled` |\n`false` |\nDesktop notifications when an agent needs attention |\n`approvals` |\n`true` |\nThe 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 approvals` /`warden approve` , 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 approve` . Unrecognized prompts always fall back to attach |\n`tokens.guard` |\n`true` |\nThe 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) |\n`tokens.warn_alert` |\n`true` |\nFire a desktop notification (when `notify.enabled` is on) once per upward crossing into the warning or critical band |\n`tokens.auto_compact` |\n`true` |\nWhen an agent is `critical` and idle/waiting, auto-send `/compact` to reclaim its context (cooldown-guarded) |\n`tokens.force_compact` |\n`false` |\nWhen 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 force-compact <id> on|off|inherit` |\n`tokens.compact_resume_prompt` |\n(built-in) |\nMessage sent to a force-compacted agent once compaction lands so it resumes its work |\n`tokens.warn` |\n`200000` |\nWarning threshold in context tokens (inclusive lower bound). If `tokens.critical` is not greater than this, both reset to the defaults |\n`tokens.critical` |\n`400000` |\nCritical threshold in context tokens (inclusive lower bound) — the auto-`/compact` trigger band |\n`auto_approve` |\n`false` |\nAuto-answer recognized permission prompts. Bare on/off, or an allow/deny rule policy (by tool / glob / regex / paths, with per-agent overrides) — see `warden auto-approve` |\n`notify.webhook_enabled` / `notify.webhook_url` |\n`false` / (empty) |\nPOST 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` |\n`collab.enabled` / `collab.interval` / `collab.hint` |\n`true` / … / `true` |\nFile-conflict detection across worktrees, scan interval, and the spawn-time coordination hint |\n`rails.isolation_guard` / `rails.git_redirect` / `rails.check_redirect` / `rails.git_conventions` |\n`true` |\nBoundary-enforcement hooks (see\n|\n\n`log.level`\n\n/ `log.format`\n\n`info`\n\n/ `text`\n\n`debug`\n\n/`info`\n\n/`warn`\n\n/`error`\n\n) and format (`text`\n\n/`json`\n\n); `warden daemon --log-level`\n\n/`--log-format`\n\noverride`local_llm.enabled`\n\n(+ `.url`\n\n/`.model`\n\n/`.timeout`\n\n)`false`\n\n`warden repl`\n\n(its `/`\n\ncommands work without it)`local_llm.repl`\n\n`false`\n\n`warden repl`\n\nmode instead of a plain shell`warden config`\n\nlists every setting, including `worktree.spawn_gate`\n\n/ `worktree.spawn_gate_max_agents`\n\n, `tokens.budget_gate`\n\n/ `tokens.budget_daily_usd`\n\n/ `tokens.budget_weekly_usd`\n\n, `metrics`\n\n, `allow_nonloopback`\n\n, `pipeline.keep_done`\n\n/ `pipeline.hint`\n\n, `worktree.keep_done`\n\n/ `worktree.auto_prune`\n\n, the `auto_restart.*`\n\nand `rate_limit.*`\n\nknobs, and the REPL tier knobs (`local_llm.tier`\n\n/ `local_llm.escalate`\n\n/ `local_llm.classifier`\n\n).\n\nRelated settings are grouped into namespaced blocks (\n\n`pipeline.*`\n\n,`auto_restart.*`\n\n,`collab.*`\n\n,`memory.*`\n\n,`branch_track.*`\n\n,`rate_limit.*`\n\n,`http.*`\n\n,`log.*`\n\n,`plugins.*`\n\n, alongside the existing`rails.*`\n\n/`tokens.*`\n\n/`notify.*`\n\n/`worktree.*`\n\n/`local_llm.*`\n\n). The old flat keys (`collab_enabled`\n\n,`log_level`\n\n,`memory_inject`\n\n, …) still load asdeprecated aliases— they work but emit a one-time deprecation warning;`warden config`\n\nrewrites them into the nested form.\n\nConfig namespacing:Settings are grouped into five YAML blocks —`rails`\n\n,`tokens`\n\n,`notify`\n\n,`worktree`\n\n,`local_llm`\n\n. Old flat keys (e.g.`token_guard`\n\n,`local_llm_url`\n\n,`notify`\n\n) are still accepted as deprecated aliases and migrate to the namespaced form automatically when`warden config init`\n\nis re-run.\n\nLegacy env vars:the old`WARDEN_*`\n\nenvironment variables (e.g.`WARDEN_ADDR`\n\n,`WARDEN_NOTIFY`\n\n,`WARDEN_TOKEN_*`\n\n) 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`\n\n,`WARDEN_PIPELINE_ID`\n\n,`WARDEN_JOB_ID`\n\n) are not configuration and are unaffected.\n\nThe simplest way to create an agent is to give it a plain prompt and let the system figure out the rest:\n\n```\nwarden start \"review the auth module for security issues\"\n# spawned agent-a1b2 (classifying…) — attach with `warden attach agent-a1b2`\n```\n\nIn the web GUI, **+ New agent** opens a single prompt textarea — no type or repo fields.\n\n**How it works:**\n\n**Runs in the caller's directory.** Prompt-spawned agents run`claude --dangerously-skip-permissions '<prompt>'`\n\n(or`--permission-mode acceptEdits`\n\nwith`--supervised`\n\n) in the directory you invoked`start`\n\nfrom (or the`--dir`\n\nyou pass) — no per-agent directory is created. Point it elsewhere with`--dir`\n\n, 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`\n\nand updates the type label. It appears as \"classifying…\" until then. Requires`claude`\n\non the daemon's`PATH`\n\n; falls back to`other`\n\nif 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`\n\nconfig setting) or, if no transcript is found, captures the tmux pane, then asks`claude -p`\n\nfor 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 …`\n\nis unchanged — see the section below.\n\nTo launch an agent in a directory other than your current one, pass `--dir`\n\n:\n\n```\nwarden start \"summarize recent changes\" --dir /path/to/repo\n```\n\nWhen you need a managed git worktree (e.g. a development branch tied to a Jira ticket), pass `--type`\n\n. The type controls whether a git worktree is created and determines how the session is set up.\n\n| Type | Worktree | Notes |\n|---|---|---|\n`development` |\nyes (new branch) | Creates `.worktrees/<ticket>` on a new branch named after the ticket |\n`pr-review` |\nyes (PR branch) | Detached worktree; runs `gh pr checkout <PR>` inside it. Requires `--pr` or `--branch` . Exempt from the write-type isolation default |\n`analysis` |\nopt-in (`--worktree` ) |\nRuns in the repo by default; pass `--worktree` to get a scratch branch |\n`spike` |\nopt-in (`--worktree` ) |\nSame as analysis |\n`code` |\nyes (new branch) | Isolated in `.worktrees/<id>` ; pass `--in-repo` to share the repo |\n`docs` |\nyes (new branch) | Isolated in `.worktrees/<id>` ; pass `--in-repo` to share the repo |\n`website` |\nyes (new branch) | Isolated in `.worktrees/<id>` ; pass `--in-repo` to share the repo |\n`debug-ci` |\nyes (new branch) | Isolated in `.worktrees/<id>` ; pass `--in-repo` to share the repo |\n`tests` |\nyes (new branch) | Isolated in `.worktrees/<id>` ; pass `--in-repo` to share the repo |\n`other` |\nno | Catch-all; also used for unrecognized type strings |\n\nEvery **write-type** agent (`code`\n\n/`docs`\n\n/`website`\n\n/`debug-ci`\n\n/`tests`\n\n) gets its own isolated worktree by default so parallel agents don't collide on the shared tree; pass `--in-repo`\n\nto opt back into the repo root. `pr-review`\n\nis exempt (it already checks out the PR branch). This isolation is what makes the boundary-enforcement hooks (see [Lifecycle commands & boundary enforcement](#lifecycle-commands--boundary-enforcement)) meaningful.\n\nBy default every agent runs `claude --dangerously-skip-permissions`\n\n— permission prompts are suppressed and the agent runs fully autonomously; the `Notification`\n\nhook still records them as events in the session doc.\n\nPass `--supervised`\n\nto opt into a lighter permission mode (`--permission-mode acceptEdits`\n\n): 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`\n\nrow → `i`\n\n/`1`\n\n-`9`\n\n), or the CLI (`warden approve`\n\n) when `approvals`\n\nis on. A restored agent keeps its supervised setting.\n\nIf a worktree for the ticket already exists on disk, the spawn adopts it (reattaches claude to the existing branch) instead of erroring.\n\n```\nwarden tui   # open the cockpit\nwarden       # bare invocation — same thing\n```\n\n`warden tui`\n\n(or bare `warden`\n\n) opens a **tmux-composited cockpit** — a dedicated tmux session with three panes: an agents list (top-left), a terminal shell for running CLI commands (bottom-left), and a full-height live detail pane (right) that opens the selected agent's interactive `claude`\n\nsession. Browse the list freely with `↑`\n\n/`↓`\n\nwithout disturbing the detail pane; press `Enter`\n\nto open an agent in it.\n\nAgents spawned by another agent (via the `spawn_agent`\n\nMCP tool) **nest under their parent** as a collapsible sub-tree (`▸ / ▾`\n\n, 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`\n\n) — no terminal/attach pane — so its children never vanish; the daemon reaps the tombstone once the whole sub-tree finishes.\n\nThe 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`\n\nand 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`\n\ncloses just the cockpit window). Force the native window with `warden tui --tmux-native`\n\n, or the classic own-session cockpit with `env -u TMUX warden tui`\n\n— see [docs/USAGE.md §7](/srjn45/warden/blob/main/docs/USAGE.md).\n\nThe list pane polls the daemon about once a second. The daemon must be running (`warden daemon`\n\n) before opening the TUI.\n\n**Keys (cockpit)**\n\n| Key | Action |\n|---|---|\n`↑` / `↓` or `j` / `k` |\nMove selection (detail pane is unaffected) |\n`←` / `→` or `h` / `l` |\nCollapse / expand the pipeline or agent sub-tree under the cursor |\n`Enter` |\nOpen the selected agent (or running pipeline job) in the right detail pane — a finished agent or tombstone shows its stored detail instead of attaching |\n`n` |\nNew agent — opens a prompt textarea; `ctrl+s` to submit, `esc` to cancel |\n`o` |\nOpen a directory as a group (becomes the spawn target for `n` ) |\n`s` |\nSend a message to the selected agent — `enter` to send, `esc` to cancel |\n`a` |\nAttach — full-screen the agent's (or running job's) tmux session; press to return to the dashboard`Ctrl-b Enter` |\n`d` |\nCompletion digest for the selected agent — scrollable overlay; `d` /`esc` to close |\n`i` |\nAnswer pending approvals (also `enter` on the ⏳ Approvals row) — `1` -`9` to answer, `tab` for next |\n`c` |\nShared-context + message-traffic inspector |\n`r` |\nRetry a failed / needs-attention pipeline job |\n`x` |\nContext-sensitive: terminate the selected agent / cancel a pipeline / close an opened dir (confirm with `y` ) |\n`D` |\nDelete a stopped pipeline's record (confirm with `y` ) |\n`?` |\nToggle help overlay |\n`Alt+t` |\nToggle the bottom-left master pane between Claude and a shell (both stay alive) |\n`q` |\nQuit and tear down the cockpit |\n\nMove focus between panes with **Alt+←/→/↑/↓** (no tmux prefix); toggle the bottom-left master pane between Claude and a shell with **Alt+t**. See [docs/USAGE.md §7](/srjn45/warden/blob/main/docs/USAGE.md) for the full cockpit guide and caveats around nested tmux.\n\nOpen the live terminal cockpit. Also launched by bare `warden`\n\nwith no subcommand.\n\n```\nwarden tui\nwarden       # equivalent\n```\n\nSee the [Terminal UI](#terminal-ui) section above for the full key reference.\n\nSpawn a new agent session. Two modes:\n\n**Prompt mode** (no `--type`\n\n) — pass a quoted prompt; the type is assigned automatically:\n\n```\nwarden start \"review the auth module for security issues\"\nwarden start \"investigate why the nightly build is flaky\"\n```\n\n**Managed worktree mode** (`--type`\n\nrequired) — creates a git worktree for the ticket:\n\n```\n# Development agent for a Jira ticket:\nwarden start PROJ-350 --type development\n\n# PR review — checks out the PR branch in a fresh worktree:\nwarden start --type pr-review --pr 1234\n\n# Debug CI — no worktree, runs in current directory:\nwarden start --type debug-ci\n\n# Spike with an optional scratch worktree:\nwarden start --type spike --worktree\n\n# Point at a specific repo and branch:\nwarden start PROJ-350 --type development --repo /path/to/repo --branch my-branch\n\n# Permission mode examples:\n# Use acceptEdits mode for careful prompting on risky operations:\nwarden start \"refactor the auth module\" --permission-mode acceptEdits\n\n# Set a global default for all new agents: put default_permission_mode: acceptEdits\n# in ~/.warden/config.yaml, then restart the daemon.\nwarden start \"debug the API rate limit\"  # uses acceptEdits mode\n\n# Override the global default for a specific agent:\nwarden start \"quick spike\" --permission-mode auto  # bypass global setting\n\n# Change permission mode for a running agent:\nwarden set-permission-mode agent-abc123 dontAsk\n```\n\nFlags:\n\n`--type`\n\n— task type; omit to use prompt mode (auto-typed)`--repo`\n\n— repo path (default: current directory; managed worktree mode only)`--branch`\n\n— new branch name (development) or checkout target (pr-review)`--pr`\n\n— PR number or URL (pr-review only)`--dir <path>`\n\n— directory to run a prompt-spawned agent in (default: current directory)`--worktree`\n\n— opt-in worktree for analysis/spike`--in-repo`\n\n— write-type opt-out: run in the shared repo instead of an isolated worktree (ignored for pr-review)`--model <model>`\n\n— per-agent model (id or alias`opus`\n\n/`sonnet`\n\n/`haiku`\n\n/`fable`\n\n); defaults to the`model_default`\n\nconfig setting`--role <role>`\n\n— built-in agent role:`general`\n\n(default, no persona) ·`orchestrator`\n\n·`implementer`\n\n·`auto-merger`\n\n·`reviewer`\n\n. Injects the role's persona as a system-prompt addendum and fills its default spawn flags (`--type`\n\n/`--model`\n\n/`--permission-mode`\n\n/auto-approve/tags) for any you leave unset (explicit flags still win). See`warden role list`\n\n`--tags <a,b>`\n\n— attach tags (lowercased, deduped); searchable and filterable with`warden ls --tag`\n\n`--preset <name>`\n\n— seed spawn defaults from a saved preset (`warden preset save`\n\n); explicit flags still override`--prompt-template <name> --set VAR=value`\n\n— fill a saved prompt template (`warden prompt-template save`\n\n) into the spawn prompt; repeat`--set`\n\nper variable. A positional prompt still wins; free-form only (no`--type`\n\n)`--auto-restart`\n\n— opt this agent into daemon auto-restart on error (tuned by`auto_restart_*`\n\nconfig)`--permission-mode <mode>`\n\n— control Claude's permission level (valid modes:`acceptEdits`\n\n,`auto`\n\n,`bypassPermissions`\n\n,`default`\n\n,`dontAsk`\n\n,`plan`\n\n); defaults to the`default_permission_mode`\n\nconfig setting (default:`auto`\n\n)`--supervised`\n\n— legacy alias for`--permission-mode acceptEdits`\n\n; risky tools prompt and the approvals inbox surfaces them (see the`approvals`\n\nsetting)\n\nList all active agent sessions with their type, status, working directory, and subject.\n\n```\nwarden ls\n# ID                TYPE         STATUS    AGE   DIR                SUBJECT\n# PROJ-350    development  working   2m    PROJ-350     refactoring auth middleware\n# prreview-a1b2     pr-review    idle      5m    prreview-a1b2      reviewing PR 1234\n# agent-c3d4        …            working   1m    agent-c3d4         investigate flaky nightly build\n```\n\n`DIR`\n\nshows the base name of the agent's working directory. `SUBJECT`\n\nis the auto-generated one-line summary of what the agent is currently doing (empty until the first poller refresh).\n\nUse `--json`\n\nfor machine-readable output (a JSON array of full session objects; an empty fleet prints `[]`\n\n). Useful for scripts and for Claude driving the CLI:\n\n```\nwarden ls --json\n```\n\nOther flags:\n\n`--watch`\n\n/`-w`\n\n— live-update the table on every agent state change over the daemon's SSE stream (Ctrl+C to exit); combine with`--json`\n\nto stream one JSON snapshot per change.`--tag <tag>`\n\n— filter to agents carrying*every*given tag (AND semantics; repeatable or comma-separated). Tags are set at spawn with`warden start --tags backend,urgent`\n\nand are part of the search haystack.\n\nShow full detail for one session: working directory, subject, worktree, branch, PR, all events.\n\n```\nwarden status PROJ-350\n```\n\nAdd `--json`\n\nto emit the full session as a single JSON object (including the `events`\n\narray):\n\n```\nwarden status PROJ-350 --json\n```\n\nRegister an existing Claude session into warden.\n\n**Plain shell**— finds the newest Claude conversation for the directory and resumes it under a new tmux session (`claude --resume`\n\n).**Inside tmux**— registers the current tmux session live without relaunching claude.\n\n```\nwarden adopt                          # newest session for cwd, resume under tmux\nwarden adopt --session-id <uuid>      # pick a specific Claude conversation\nwarden adopt --dir /path/to/project   # target a different directory\n```\n\nAttach your terminal to the agent's tmux session interactively.\n\n```\nwarden attach PROJ-350\n```\n\nThe **single umbrella teardown verb.** By default `warden stop <TICKET>`\n\ndoes a **full teardown**: terminate the tmux + claude session, clear (archive) the record, **and** remove the git worktree + branch (asking for confirmation first, unless `--yes`\n\n). Subtractive flags keep parts around; `--pr`\n\nopens a GitHub PR first while the agent is still intact. Safe order is always PR → terminate → clear record → remove worktree, so a failed push leaves the agent running.\n\n```\nwarden stop PROJ-350                 # full teardown (asks before removing the worktree)\nwarden stop PROJ-350 --yes           # ...without the confirmation prompt\nwarden stop PROJ-350 --keep-worktree # terminate + clear record, keep the worktree (== `done`)\nwarden stop PROJ-350 --keep-record   # terminate + remove worktree, keep the record\nwarden stop PROJ-350 --hard          # purge the record instead of archiving\nwarden stop PROJ-350 --pr --base main # open a GitHub PR first, then tear down\n```\n\nThe four older verbs are kept as thin **aliases** — each is just `stop`\n\nwith a fixed flag combo:\n\n| old verb | equivalent |\n|---|---|\n`wd terminate <T>` |\n`wd stop <T> --keep-record --keep-worktree` |\n`wd delete <T> [--hard]` |\n`wd stop <T> --keep-worktree` (record only) |\n`wd remove-worktree <T>` |\n`wd stop <T> --keep-record` (worktree only) |\n`wd done <T> [--hard|--create-pr]` |\n`wd stop <T> --keep-worktree [--hard|--pr]` |\n`wd stop <T>` |\nterminate + clear record + remove worktree |\n\nTerminate the agent (kill its tmux + claude session) **and** clear its stored record in one step. It does **not** remove the git worktree — that is a separate, explicitly-confirmed step (`remove-worktree`\n\n). Equivalent to `terminate`\n\nfollowed by `delete`\n\n, i.e. `stop --keep-worktree`\n\n.\n\n```\nwarden done PROJ-350          # terminate + clear record (worktree kept)\nwarden done PROJ-350 --hard   # purge the record instead of archiving it\nwarden done PROJ-350 --create-pr --base main   # push the branch + open a GitHub PR first\n```\n\n`--create-pr`\n\npushes the agent's branch and opens a GitHub PR (via `gh`\n\n) — titled from the agent, bodied from its digest, targeting `--base`\n\n(default `main`\n\n) — *before* terminating, so a failure leaves the agent running to retry; an existing PR for the branch is reported, not re-created.\n\nStop 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 restore`\n\n. Alias for `stop --keep-record --keep-worktree`\n\n.\n\n```\nwarden terminate PROJ-350\n```\n\nRecreate and resume a lost/orphaned agent's tmux + claude session (`claude --resume`\n\n). Use only when the agent's tmux session is gone (status `orphaned`\n\n).\n\n```\nwarden restore PROJ-350\n```\n\nThe safety net for the tombstone reaper (which auto-archives a parent record once its whole sub-tree goes terminal): a stale `orphaned`\n\nstatus racing a daemon restart could previously let a genuinely-live session's record get archived out from under it. Bare `warden recover`\n\nscans **archived** records and only reports the ones whose tmux session is confirmed still alive; `--apply`\n\nre-inserts each candidate into the active store under its original id — any children (linked via `parent_id`\n\n, untouched by archiving) reconnect automatically.\n\n```\nwarden recover                # report candidates only (dry run)\nwarden recover --apply        # actually revive them\nwarden recover --json         # scripting\n```\n\nClear an agent's stored record (archives by default; `--hard`\n\npurges). Does not touch tmux or the worktree. Alias for `stop --keep-worktree`\n\n(record only).\n\n```\nwarden delete PROJ-350\nwarden delete PROJ-350 --hard\n```\n\nRemove an agent's git worktree and branch. **Destructive.** It refuses if the agent is still running (terminate it first) or if the worktree has uncommitted changes or unpushed commits — use `--force`\n\nto override the guard. Alias for `stop --keep-record`\n\n(worktree only); always asks unless `--yes`\n\n.\n\n```\nwarden remove-worktree PROJ-350\nwarden remove-worktree PROJ-350 --force\n```\n\nType a message into the agent's claude session and press Enter.\n\n```\nwarden send PROJ-350 \"run the unit tests and fix any failures\"\n```\n\nPrint the recent terminal output of the agent's claude session.\n\n```\nwarden tail PROJ-350\nwarden tail PROJ-350 --lines 80\n```\n\nSummarize what an agent accomplished — files touched, branch, number of turns, and a short narrative (best-effort, via `claude -p`\n\n). Also available as a web **Digest** panel and, in the cockpit, the `d`\n\nkey (opens a scrollable digest for the selected agent).\n\n```\nwarden digest PROJ-350\nwarden digest PROJ-350 --json\n```\n\nThe **approvals inbox** (on by default; the `approvals`\n\nsetting). When a `--supervised`\n\nagent hits a tool-permission prompt, the daemon recognizes it and surfaces the numbered options so you can answer without attaching.\n\n```\nwarden approvals                 # list pending permission prompts (with their options)\nwarden approve PROJ-350 1  # answer prompt for that agent with option 1 (e.g. \"Yes\")\n```\n\nUnrecognized prompts always fall back to attach. Also surfaced in the web AttentionQueue (one-click buttons) and the TUI **⏳ Approvals** row.\n\nPreflight checks — required binaries (`tmux`\n\n, `git`\n\n, `claude`\n\n), optional ones (`gh`\n\n, `ollama`\n\n, warn-only), daemon reachability, and the data directory. It also prints a one-line hardware-aware `local_llm_model`\n\nrecommendation for the REPL.\n\n```\nwarden doctor\n```\n\nVerifies 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;\n\n`--yes`\n\ninstalls everything without prompting (for automation). Required deps (`tmux`\n\n, `git`\n\n, `claude`\n\n) come first, then optional ones (`gh`\n\n, `ollama`\n\n). Package managers are auto-detected — Homebrew on macOS (never auto-bootstrapped) and `apt`\n\n/`dnf`\n\n/`pacman`\n\non Linux — and Claude Code and Ollama use their official installers. After installing, it re-runs the checks and prints a doctor-style report. `setup`\n\nis **CLI-only**(it installs host packages) and is not exposed over MCP.\n\n```\nwarden setup            # confirm-each install of anything missing\nwarden setup --yes      # non-interactive: install all missing deps\n```\n\nRecommends local models for the REPL (`warden repl`\n\n), sized to this machine. It auto-detects **two** figures from the *same* memory pool — **total** memory (the bound) and **average free** memory (sampled to smooth spikes) — using NVIDIA VRAM (`nvidia-smi`\n\n), Apple unified memory, or Linux `MemAvailable`\n\n. It scores a curated, **tool-calling-forward** catalog (Qwen3, gpt-oss, Mistral Small, Qwen2.5) by **conductor suitability** — not raw size or coding skill, since the REPL routes tool calls and never writes code. Scores are calibrated against the [Berkeley Function-Calling Leaderboard](https://gorilla.cs.berkeley.edu/leaderboard.html) (BFCL v4), weighted toward the multi-turn subcategory that matches the REPL's tool-call loop. Each model is marked `fits now`\n\n/ `free memory first`\n\n/ `too large`\n\n. The ★ pick is the best-scoring model that runs *comfortably now* with headroom for your real workload (Docker, DBs, IDE, Claude sessions, the daemon). It only ever recommends — you set `local_llm_model`\n\nyourself.\n\n```\nwarden llm suggest                    # auto-detect and rank\nwarden llm suggest --samples 8        # average more free-memory samples\nwarden llm suggest --total-gb 48 --free-gb 30   # what-if for another machine\nwarden llm suggest --json\n```\n\nA 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).\n\n```\nwarden tutorial                       # run the walkthrough, then mark it complete\nwarden tutorial --skip                # mark complete without running it\nwarden tutorial --reset               # clear the marker so the tour (and hint) run again\n```\n\nDisable the hint entirely with `tutorial: false`\n\nin the config.\n\nRun **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`\n\nskill (the agent writes a handoff file + resume prompt and shows you); on your go-ahead it spawns the successor and reaps itself.\n\n```\nwarden handoff --retire --confirm \\\n  --resume-file \"${TMPDIR:-/tmp}/warden-rotate-handoff-$WARDEN_SESSION_ID.md\" \\\n  --resume-prompt \"Continue the migration from where the notes leave off\"\n# `warden rotate --confirm …` is an exact alias.\n```\n\nThe 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`\n\nself-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`\n\nis mutually exclusive with `--to`\n\n.\n\nDefine a **DAG of agent jobs** in YAML and let the daemon run them: jobs with no dependencies start first, and each job's `emit`\n\npublishes its output and unblocks its dependents. The daemon owns the cheap \"await + fire\" so the lead Claude stays off the critical path.\n\n```\nwarden pipeline validate -f review.yaml # check the spec (DAG/refs/cycles); exit 0/1, no daemon\nwarden pipeline create -f review.yaml   # validate + register (does not start)\nwarden pipeline list-templates          # list the built-in starter templates + their placeholders\nwarden pipeline create --template analyze-implement-review --set REPO=. # render from a template\nwarden pipeline start <id>              # spawn jobs with no dependencies\nwarden pipeline show <id>               # jobs, status, branches, and emitted output\nwarden pipeline list\nwarden pipeline edit-job <id> <job> ... # edit a not-yet-started job's fields\nwarden pipeline retry <id> <job>        # re-run a failed/needs-attention job\nwarden pipeline pause <id>              # stop spawning new jobs (in-flight keep running)\nwarden pipeline resume <id>             # resume a paused pipeline\nwarden pipeline cancel <id>             # terminate running jobs\nwarden pipeline delete <id>             # remove the record (cancel first if live)\n```\n\nFour `go:embed`\n\n-bundled templates ship in the binary — `analyze-implement-review`\n\n, `parallel-tasks`\n\n, `test-fix-verify`\n\n, `research-synthesis`\n\n. Render one with `warden pipeline create --template <name>`\n\n, substituting placeholders via `{{NAME}}`\n\n/`{{REPO}}`\n\n(auto-filled) and `--set KEY=VALUE`\n\n.\n\nA minimal `analyze → implement → review`\n\nspec (job prompts must **not** mention `emit`\n\n— the daemon auto-appends it and auto-injects upstream outputs):\n\n```\nname: auth-refactor\njobs:\n  - id: analyze\n    prompt: \"Analyze the auth module and list the concrete refactors needed.\"\n  - id: implement\n    depends_on: [analyze]\n    worktree: fresh\n    prompt: \"Implement the refactors identified upstream.\"\n  - id: review\n    depends_on: [implement]\n    prompt: \"Review the implementation branch for correctness and regressions.\"\n```\n\nJobs can be made conditional with `run_if: success`\n\n(default) `| failure | always`\n\n— e.g. a `run_if: failure`\n\nrollback/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](/srjn45/warden/blob/main/docs/USAGE.md) for the full authoring guide.\n\nFire an agent spawn **or** a pipeline on the daemon's own timer — no external crontab. **Opt-in:** set `scheduler_enabled: true`\n\nin the config and keep the daemon running (schedules only fire while it is up).\n\n```\n# Recurring agent spawn (5-field cron; @daily etc. supported):\nwarden schedule create daily-review --cron \"0 9 * * *\" \\\n  --type pr-review --repo . --prompt \"Review yesterday's merged PRs\"\n\n# Single-shot spawn (RFC3339 or 2006-01-02T15:04, local time):\nwarden schedule create launch --at 2026-06-27T09:00 --prompt \"Kick off the release checklist\"\n\n# Fire a pipeline on a schedule (each run gets a timestamped name):\nwarden schedule create nightly --cron \"0 2 * * *\" --pipeline ci.yaml\n\nwarden schedule list                  # kind, mode, spec, enabled, next run, last error\nwarden schedule delete daily-review\n```\n\nMissed 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`\n\n, never crashes the loop). `list_schedules`\n\nexposes the same read-only view over MCP.\n\nThe substrate pipelines are built on, usable directly so agents can collaborate:\n\n```\n# Shared context: a namespaced key/value blackboard all agents can read/write\nwarden ctx set build.status \"green\" --as agent-4f2a\nwarden ctx get build.status\nwarden ctx list --prefix build.\n\n# Directed messages: per-agent inbox; sending wakes a parked (idle/waiting) agent\nwarden msg send agent-9c1d \"the API contract changed — re-check your client\"\nwarden msg inbox --as agent-9c1d\nwarden msg wait --as agent-9c1d --timeout 120   # block in the daemon until a message arrives\n```\n\nThe daemon watches each active agent's worktree (fsnotify, with a `git diff`\n\npoll 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.\n\n```\nwarden collab conflicts                 # current cross-agent file conflicts\nwarden collab who-is-editing <file>     # which agents (if any) are touching a file\n```\n\nTunable via the `collab.enabled`\n\n/ `collab.interval`\n\n/ `collab.hint`\n\nconfig settings; also exposed as the `get_collaboration_status`\n\n/ `who_is_editing_file`\n\nMCP tools and a **File conflicts** card on the dashboard.\n\nFirst-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](#lifecycle-commands--boundary-enforcement).\n\n```\nwarden commit            # stage + commit the agent's worktree (message auto-filled if omitted)\nwarden commit -m \"fix: …\"\nwarden push              # push the worktree's branch\nwarden push --force-with-lease  # safe force after a rebase/amend\nwarden sync              # rebase-sync against the upstream (refuses on a dirty tree)\nwarden check [name]      # run the project's .warden/check.yml checks; reports only failures\n```\n\nRails: no commit/push on `main`\n\n/`master`\n\n, no dirty-tree sync, pre-commit-hook failures surfaced as a result. Force pushes are always `--force-with-lease`\n\n(never a bare `--force`\n\n), so a rebased branch can't clobber a teammate's push. All four are also MCP tools.\n\nSome 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`\n\n, these **exec in the agent's worktree with no daemon round-trip**, so they are **CLI-only by design** (no MCP twin).\n\n```\nwarden review                  # the backend reviews its OWN uncommitted diff and streams findings\nwarden review --base main      # review the branch's changes against a base instead\nwarden review --prompt \"focus on error handling\"\nwarden review --json           # neutral machine-readable findings: {summary, verdict, findings[]}\nwarden models                  # the backend's LIVE model menu (one id per line; --json for an array)\n```\n\n— the agent-native counterpart to`warden review`\n\n`warden check`\n\n(configured test/lint) and a`pr-review`\n\nagent (a whole reviewer session): it runs the backend's own one-shot reviewer against the worktree.**Codex** implements it (`codex review`\n\n); backends without a native reviewer (e.g. Claude) exit non-zero pointing you at`warden check`\n\n/`pr-review`\n\n.`--json`\n\nruns the structured form (`codex exec review`\n\n) and normalizes the backend's native output into one neutral findings shape; review quality rides the backend's configured model.— the live runtime model menu (vs warden's static`warden models`\n\n`opus`\n\n/`sonnet`\n\n/`haiku`\n\n/`fable`\n\naliases).**Antigravity**(`agy models`\n\n) and**Cursor**(`cursor-agent --list-models`\n\n) implement it; the ids feed`--model`\n\nverbatim. Listing is a metadata read, so it spends no quota. Backends with a static model set (Claude) degrade non-zero (\"pass`--model`\n\nwith a known id\").\n\nBoth take `--backend <id>`\n\nto target a specific backend (default: the current agent's). See [Agent backends](#agent-backends---backend).\n\nwarden owns one committed, backend-neutral **project memory** — `.warden/memory.md`\n\n(beside `.warden/check.yml`\n\n), keyed implicitly by the repo root and holding durable cross-agent facts (\"where X lives\", \"run Y via `warden check`\n\n\", project invariants). The point: **the next agent — any backend — doesn't re-pay the rediscovery tax** the last one already paid.\n\n```\nwarden memory                  # show the resolved path + the rendered view injected into agents\nwarden memory --raw            # print the file verbatim\nwarden memory --edit           # open it in $EDITOR (auto-creates it first)\nwarden memory --path           # just the resolved path (scriptable; no auto-create)\n```\n\nAt **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`\n\n(file-backed, so it never bloats the launch line), **codex / cursor / opencode / antigravity** via their `AGENTS.md`\n\nwarden block, **crush** via `CRUSH.md`\n\n, **goose** via `.goosehints`\n\n; **aider** degrade-skips. **7 of 8 backends project with zero new adapter code.** It is config-gated by `memory.inject`\n\n(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`\n\nis warden's own. `warden memory`\n\nis CLI-local like `warden check`\n\n/`warden review`\n\n(no daemon round-trip, no MCP twin).\n\n**Auto-curation ( memory.curate, default OFF).** warden can also\n\n*propose*memory for you: on the existing completion-digest hook, a debounced extraction pass reads finished agents' digests + the current memory and writes\n\n**durable, reusable facts** back as\n\n`- [unverified · <date> · <provenance>] <fact>`\n\n. It is deliberately never authoritative — proposals land in the **working tree only**(warden\n\n**never commits and never pushes** them, so the committed diff is the human review gate), promote to\n\n`trusted`\n\nonly when corroborated by a second agent or a human, **supersede** older contradicting facts (struck with a tombstone),\n\n**age out** past a TTL, and get\n\n**flagged stale** when a named path vanishes. It prefers the\n\n`$0`\n\nlocal model 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.\n\n**Local grounding ( memory.ground, default ON).** In\n\n`warden repl`\n\nyou can also *ask*this memory a question —\n\n`/memory <q>`\n\n(`/mem`\n\n/`/ask`\n\n), or the model-callable `project_memory`\n\ntool — and warden answers \"where does X live?\" / \"how do I run Y?\" **locally** from\n\n`.warden/memory.md`\n\n. This is the token-*removing*lever of the feature: unlike projection (which\n\n*adds*input tokens per turn), grounding\n\n*removes*a cloud round-trip by serving the answer from the local model. It is read-only (never creates or writes memory), cites each entry's trust (\n\n`unverified`\n\n/`trusted`\n\n/`human`\n\n) + provenance so a stale hint reads as a hint, stays on the **local tier only**(structurally\n\n`$0`\n\n— it can never escalate to a paid model), and with no local model configured degrades to returning the matching entries verbatim. An absent/empty file answers \"not in project memory\".\n\n```\nwarden search auth backend          # AND every term across active sessions; --closed folds in the archive\nwarden history --since 7d --type development --limit 20   # browse the archived (closed) store\n```\n\n`search`\n\nmatches case-insensitively over id/name/ticket/type/subject/prompt/branch/tags/last-pane; `--json`\n\non either prints raw records. The web dashboard carries a live search box and a 🗄 Archive tab mirrors `history`\n\n.\n\nSerialize session **metadata** (not worktrees/branches/tmux) to JSON for backup or moving between machines.\n\n```\nwarden export > fleet.json           # active records; --all also dumps the archive\nwarden import < fleet.json           # idempotent by id; --merge overwrites colliding records\n```\n\nAn append-only trail of the daemon's meaningful actions (`spawn`\n\n, `terminate`\n\n, `delete`\n\n, `approve`\n\n, `pipeline_start`\n\n/`pipeline_cancel`\n\n) written to `~/.warden/audit.jsonl`\n\n(`0600`\n\n). Read directly from the file, so it works even while the daemon is down.\n\n```\nwarden audit log                                  # newest last (default tail 50)\nwarden audit log --action spawn --since 24h --json\nwarden audit log --target PROJ-350 --tail 0       # 0 = all\n```\n\nSave reusable spawn defaults under a name and replay them with `warden start --preset <name>`\n\n.\n\n```\nwarden preset save fast --model haiku --permission-mode acceptEdits --auto-restart\nwarden preset list\nwarden start \"quick fix\" --preset fast            # explicit flags still override the preset\n```\n\n`--type`\n\n/`--model`\n\n/`--permission-mode`\n\n/`--auto-restart`\n\n/`--worktree`\n\n/`--in-repo`\n\nare persisted to `~/.warden/presets.yaml`\n\n; per-invocation inputs (ticket, branch, PR, dir) are not.\n\nWhere a preset stores reusable *flags*, a prompt template stores a reusable *prompt body* with `{{VAR}}`\n\nplaceholders. Save one, then fill it in at spawn time (alias `pt`\n\n).\n\n```\nwarden prompt-template save bugfix --prompt \"Fix the bug in {{FILE}} described by {{TICKET}}\"\nwarden prompt-template list                        # each template + its variables\nwarden start --prompt-template bugfix --set FILE=server.go --set TICKET=WARD-42\n```\n\nVariables are auto-derived from the body and persisted to `~/.warden/prompt-templates.yaml`\n\n. Every declared variable must be supplied (a typo'd `--set`\n\nis rejected), and an explicit positional prompt still wins. `--prompt-template`\n\nis free-form only (no `--type`\n\n).\n\nOne umbrella over all three kinds of reusable launch config — saved spawn **presets**, saved **prompt templates**, and the built-in pipeline **templates**.\n\n```\nwarden library list                               # presets + prompt templates + pipeline templates, labeled sections (alias: wd lib list)\nwarden library save-preset fast --model haiku     # delegates to `warden preset save`\nwarden library save-prompt bugfix --prompt \"Fix {{FILE}}\"   # delegates to `warden prompt-template save`\n```\n\nPurely additive: it reuses the existing preset store, the prompt-template store, and the embedded template catalog, so `warden preset`\n\n, `warden prompt-template`\n\n, and `warden pipeline list-templates`\n\nkeep working unchanged. Pipeline templates are embedded/read-only (no `save-template`\n\n; author one with `warden pipeline create -f <spec.yaml>`\n\n). Also exposed over MCP as `library_list`\n\n(returns `{presets, prompt_templates, templates}`\n\n).\n\nCLI view of the resource metrics (per-agent process-tree RSS/CPU, system memory/pressure, daemon self-stats).\n\n```\nwarden stats                          # live snapshot\nwarden stats --history                # per-agent performance history + anomaly warnings\nwarden stats --history --agent PROJ-350\n```\n\nOne 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`\n\nwith no subcommand prints a combined at-a-glance summary of both.\n\n```\nwarden cost                           # combined: SPEND section + SAVINGS section\nwarden cost spend                     # same as `warden spend` (all flags wired through)\nwarden cost savings --benchmark       # same as `warden savings --benchmark`\n```\n\nPurely additive: it reuses the existing spend rollup and savings ledger and their render logic, so the top-level `warden spend`\n\nand `warden savings`\n\nkeep working unchanged (they remain available as aliases). Resource footprint — memory/CPU/pressure — is a different axis; see `warden stats`\n\n.\n\nRead 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`\n\nconfig setting (default on). Also reachable as `warden cost savings`\n\n.\n\n```\nwarden savings                        # per-feature table (saved/raw tokens, events)\nwarden savings --benchmark            # headline A/B: without-vs-with warden, % cut, $ saved, trend sparkline\nwarden savings --since 7d             # scope to a window (24h/7d/2w) or a date\nwarden savings --json                 # structured summary\nwarden savings --audit                # raw-vs-kept provenance samples (needs savings_samples)\nwarden savings --calibrate            # measure this workload's bytes/token vs Claude count_tokens (needs ANTHROPIC_API_KEY)\n```\n\nTwo 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 entirely onto the local LLM, in $). Each figure states its basis — `CALIBRATED`\n\nor the 4-bytes/token `HEURISTIC`\n\n. See [docs/FEATURES.md §29](/srjn45/warden/blob/main/docs/FEATURES.md).\n\nThe 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`\n\nconfig setting. Also reachable as `warden cost spend`\n\n.\n\n```\nwarden spend                          # total / today / this week, then per-agent/repo/day $ tables\nwarden spend --by agent               # just one rollup: agent, repo, or day\nwarden spend --json                   # structured rollup\n```\n\nA **budget gate** (off by default) turns this into a guardrail: set `budget_daily_usd`\n\n/ `budget_weekly_usd`\n\nand flip `budget_gate: true`\n\n, and a spawn that would push measured spend over the cap warns first (re-run with `--force`\n\nto proceed) — mirroring the memory-pressure spawn gate. `warden ls`\n\nalso gains a **COST** column, and the web Metrics tab a live per-agent cost card. See [docs/FEATURES.md §30](/srjn45/warden/blob/main/docs/FEATURES.md).\n\nOpt-in, read-only view of each active agent's branch health: its **GitHub CI status** (latest `gh run list`\n\nin the worktree) and its **standing vs origin/main** (commits behind/ahead, merged?).\n\n```\nwarden branches                       # table of per-agent CI + base-branch standing\nwarden branches --json\n```\n\nThe daemon monitor behind it (enable with `branch_track.enabled`\n\n) 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`\n\n/git call fails open. Also exposed via `GET /api/v1/collab/branches`\n\nand the `get_branch_status`\n\nMCP tool.\n\nMine archived agent history for **patterns** — recurring task shapes, slow/failure-prone work, and parallelization opportunities — as a deterministic report (optionally narrated by the local LLM). Gated by `insights`\n\n(default on).\n\n```\nwarden insights\nwarden insights --json\n```\n\nCheckpoint an agent's **worktree changes + session transcript** and roll back later. Gated by `snapshots`\n\n(default on).\n\n```\nwarden snapshot create [name] -m \"before risky refactor\"   # capture a checkpoint\nwarden snapshot list [name] [--all]                        # list checkpoints\nwarden snapshot restore <id> [--force]                     # re-apply onto its worktree\n```\n\nRestore 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`\n\n/`snapshot_list`\n\n/`snapshot_restore`\n\nMCP tools.\n\nTwo layers control auto-approval:\n\n**Per-agent toggle** — opt one agent into evaluation even when the global policy is off:\n\n```\nwarden auto-approve agent-abc123 on\nwarden auto-approve agent-abc123 off\n```\n\n**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`\n\n), a **Go regexp** (`--regex`\n\n) over the prompt, and/or path globs (`--paths`\n\n). A **per-agent override** (`--agent`\n\n, keyed by name or id) gets its own rule set that replaces the default. Changes take effect immediately and persist to config.\n\n```\nwarden auto-approve rules                         # show the live policy\nwarden auto-approve enable                         # turn the policy on\nwarden auto-approve allow --tool Read              # auto-approve all Read prompts\nwarden auto-approve allow --regex '^Bash\\(git (status|diff|log)\\)'\nwarden auto-approve deny  --tool Bash --pattern rm\nwarden auto-approve allow --agent reviewer --tool Grep\nwarden auto-approve clear --agent reviewer         # drop reviewer's overrides\n```\n\nWith **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`\n\n(toggle) and `set_auto_approve_policy`\n\n(rules) MCP tools.\n\nChange a running agent's permission mode (`acceptEdits`\n\n/`auto`\n\n/`bypassPermissions`\n\n/`default`\n\n/`dontAsk`\n\n/`plan`\n\n); preserved on restore.\n\n```\nwarden set-permission-mode agent-abc123 dontAsk\n```\n\nA **role** is a named, persistent system-prompt **persona** attached to an\nagent, plus a set of default spawn flags. Every agent has exactly one role; the\ndefault is `general`\n\n, which injects no persona and behaves exactly as agents do\ntoday. The role set is a **fixed built-in catalog** (no user-defined roles):\n\n| Role | Persona | Default flags |\n|---|---|---|\n`general` |\n(none — plain agent) |\n— |\n`orchestrator` |\ncoordinates a fleet of warden agents; plans and delegates, doesn't write feature code itself unless trivial | `--permission-mode auto` |\n`implementer` |\nimplements a task end-to-end on its own branch (code, tests, checks, commit, PR) | `--type development` |\n`auto-merger` |\nowns getting an open PR merged: watches CI, fixes failures/conflicts, merges when green | `--permission-mode auto` , auto-approve on |\n`reviewer` |\nreviews a branch/PR for correctness, coverage, and style; produces findings + a verdict, no fixes unless asked | `--type pr-review` |\n\nThe persona is injected through the same system-prompt seam warden already uses\nfor its collab/git/pipeline hints (Claude via `--append-system-prompt`\n\n, the\ninjecting backends via their rules file); only the role **name** is persisted,\nso the persona re-resolves from the registry at every (re)launch — nothing\npersona-shaped is stored on disk. Role default flags fill only the fields you\nleft unset (explicit `start`\n\nflags win); default tags are unioned in.\n\n```\n# List the built-in roles and their descriptions\nwarden role list\n\n# Spawn an agent with a role (its default flags apply unless you override them)\nwarden start \"review PR 1234 for correctness\" --role reviewer\n\n# Switch a running agent's role — relaunches to re-inject the new persona\nwarden set-role agent-abc123 reviewer\n\n# Clear the persona (back to a plain agent)\nwarden set-role agent-abc123 general\n```\n\nRoles are also drivable from the UIs (TUI new-agent `ctrl+r`\n\npicker, web\n**+ New agent** Role dropdown) and over MCP (`spawn_agent`\n\n's `role`\n\nparam,\n`set_role`\n\n, `list_roles`\n\n) — see [Orchestrator (MCP)](#orchestrator-mcp).\n`set-role`\n\n**relaunches** the agent (its in-flight turn is discarded) because a\npersona only takes effect at (re)launch, mirroring how `set-permission-mode`\n\npersists a value but a persona additionally needs a fresh launch.\n\nThe umbrella for warden's worktree operations — **list** and **prune**:\n\n```\nwarden worktree                       # list warden-owned worktrees (same as `worktree list`)\nwarden worktree list                  # list worktrees under .worktrees, joined to records (alias: ls)\nwarden worktree prune                 # reclaim orphaned worktrees (prompts; --force overrides guards)\nwarden worktree prune --include-archived  # widen scope to archived records\n```\n\n`warden prune`\n\nremains as a top-level alias for `warden worktree prune`\n\n(same flags, prompts, and output). Retention is policy-driven via the `worktree.keep_done`\n\n/ `worktree.auto_prune`\n\nconfig settings; dirty/unpushed worktrees are always kept. Reclaiming whole orphaned worktrees is distinct from `warden remove-worktree`\n\n, which tears down one agent's worktree.\n\nThe single verb for passing work to another agent, with three modes. Default mode spawns a fresh delegate in its own isolated worktree; `--to <id>`\n\ndelivers 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`\n\n(requires `--confirm`\n\n) is the **self-succession** mode: it spawns a successor in the calling agent's **same** worktree and reaps the caller — exactly what the `warden rotate`\n\nalias runs (see above). `--retire`\n\nand `--to`\n\nare mutually exclusive. Phase 1 (writing the handoff) is `/warden`\n\n-skill-driven.\n\nShorthand for `warden start --fork-from <agent>`\n\n— 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`\n\n'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`\n\n(rewinds one timeline) or `rotate`\n\n/`handoff`\n\n(carry the task, drop the conversation).\n\n```\nwarden fork agent-7                  # fork agent-7, continue its conversation\nwarden fork agent-7 \"now try X\"      # fork and seed a divergent first prompt\n```\n\nOnly backends with a native session fork are forkable — **Codex** today (`codex fork`\n\n); 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`\n\ndefaults to `development`\n\n. Unlike `warden review`\n\n/ `warden models`\n\n, fork is a managed spawn that crosses the daemon, so it has **MCP + CLI parity** — the `fork_agent`\n\nMCP tool is the orchestrator twin (a thin wrapper over `spawn_agent`\n\nwith `fork_from`\n\nset, no new endpoint).\n\nManage the bearer token that gates non-loopback (remote) access — see [Remote access](#remote-access).\n\n```\nwarden token generate                 # mint a 256-bit token (persisted to ~/.warden/token.env, 0600)\nwarden token show                     # print the current token (paste into a remote client)\nwarden token rotate                   # regenerate in place + restart the daemon\nwarden token show --readonly          # print the read-only token (WARDEN_READONLY_TOKEN)\n```\n\nThe `WARDEN_TOKEN`\n\nenv var overrides the file so the secret can stay off disk.\n\n**Read-only token.** Set an optional second token, `WARDEN_READONLY_TOKEN`\n\n, to hand\nout view-only access (e.g. a shared dashboard or a teammate). A read-only token may\nread everything — all GETs plus the live event stream — but is denied every\nstate-changing action and the interactive attach. Mint one with `warden token generate`\n\nand export it as `WARDEN_READONLY_TOKEN`\n\n(it only works alongside a\nprimary `WARDEN_TOKEN`\n\n; the daemon refuses to start with a read-only token but no\nprimary one).\n\nwarden'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,\n\n**Tab completion**, colourised prompt) that closes cleanly with Ctrl-D. It drives the fleet two ways:\n\n**Deterministic**—`/`\n\ncommands (no model)`/agents`\n\n,`/spawn <prompt>`\n\n,`/tell <id> <text>`\n\n,`/memory <question>`\n\n,`/pipelines`\n\n, … Typing`/`\n\npops a live, filtering menu of matching verbs (each with its summary);`/help`\n\nlists them all. These keep working even when the local model is slow or wrong. 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`+`\n\n-suffixed verb (`/spawn+`\n\n); a local model, if present, pre-fills each field with a suggestion you can accept, override, or clear.**Natural language (local LLM)**— any other line is planned into** confirmed**warden tool calls without spending cloud-model tokens. It conducts; it never implements — all code work is delegated by spawning an agent.**Local project grounding (**— ask a project question (\"where does the spawn gate live?\", \"how do I run the tests?\") via`$0`\n\n)`/memory <q>`\n\n(`/mem`\n\n/`/ask`\n\n) or the`project_memory`\n\ntool and warden answers it**locally** from`.warden/memory.md`\n\n, 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 local model, default on via`memory.ground`\n\n.\n\nIt **starts without a local model** (the `/`\n\ncommands and `!`\n\n-shell always work); only the natural-language half needs `local_llm: true`\n\n. Every mutating action passes a mandatory confirm gate. Run standalone, or as the cockpit master pane via the `repl`\n\nconfig / `--repl`\n\nflag (Alt+t toggles it with a raw shell). See [docs/FEATURES.md §17](/srjn45/warden/blob/main/docs/FEATURES.md).\n\n```\nwarden repl                           # aliases: warden interactive, warden i\n```\n\nInspect 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`\n\nto enable, since plugins run external code).\n\n```\nwarden plugin list                    # registered plugins: paths, custom task types, subscribed hook events, config errors\n```\n\nHooks (`pre/post-spawn`\n\n, `pre/post-commit`\n\n, `pre/post-check`\n\n) are **advisory and fail-open** — a missing, slow, or crashing plugin is logged and skipped, never blocking an agent. Configure via `plugins.enabled`\n\n+ a `plugins.registry`\n\nlist in `~/.warden/config.yaml`\n\n; a worked example lives under [ examples/plugins/](/srjn45/warden/blob/main/examples/plugins). See\n\n[docs/FEATURES.md §26](/srjn45/warden/blob/main/docs/FEATURES.md).\n\nRun the daemon (HTTP API + background poller). Normally managed by launchd (macOS) or systemd (Linux); run manually for debugging.\n\n```\nwarden daemon\nwarden daemon --addr 127.0.0.1:9000\n```\n\nRun the MCP stdio server so an orchestrator agent session (e.g. Claude) can manage agents via tool calls.\n\n```\nwarden mcp\nwarden mcp --addr 127.0.0.1:8765\n```\n\nTools exposed: `list_agents`\n\n, `get_agent`\n\n, `spawn_agent`\n\n, `adopt_agent`\n\n, `send_to_agent`\n\n, `get_agent_output`\n\n, `stop_agent`\n\n, `terminate_agent`\n\n, `restore_agent`\n\n, `delete_agent`\n\n, `remove_worktree`\n\n, `ctx_set`\n\n, `ctx_get`\n\n, `ctx_list`\n\n, `ctx_cas`\n\n, `ctx_append`\n\n, `send_message`\n\n, `read_inbox`\n\n, `wait_for_message`\n\n, `list_approvals`\n\n, `approve`\n\n, `commit`\n\n, `push`\n\n, `sync`\n\n, `check`\n\n, `get_collaboration_status`\n\n, `who_is_editing_file`\n\n, `get_branch_status`\n\n, `create_pipeline`\n\n, `start_pipeline`\n\n, `show_pipeline`\n\n, `list_pipelines`\n\n, `cancel_pipeline`\n\n, `list_schedules`\n\n, `snapshot_create`\n\n, `snapshot_list`\n\n, `snapshot_restore`\n\n, `insights`\n\n, `savings`\n\n, `spend`\n\n.\n\nGenerate shell completion scripts for Bash, Zsh, Fish, or PowerShell.\n\n```\nwarden completion bash   # generate bash completion script\nwarden completion zsh    # generate zsh completion script\nwarden completion fish   # generate fish completion script\nwarden completion powershell   # generate PowerShell completion script\n```\n\nThe completion script should be redirected to the appropriate location for your shell. See the [Shell Completion](#shell-completion) section for installation instructions.\n\nRegister `warden mcp`\n\nas an MCP server in your orchestrator agent's MCP config. For a Claude Code orchestrator that's `~/.claude/claude_desktop_config.json`\n\nor the project-level `.claude/mcp.json`\n\n; other MCP-capable agents use their own config path:\n\n```\n{\n  \"mcpServers\": {\n    \"warden\": {\n      \"command\": \"warden\",\n      \"args\": [\"mcp\"]\n    }\n  }\n}\n```\n\n`warden mcp`\n\nconnects to the daemon at the `addr`\n\nconfig setting (default `127.0.0.1:8765`\n\n); to point it elsewhere use `\"args\": [\"mcp\", \"--addr\", \"host:port\"]`\n\n.\n\nOnce registered, the orchestrator session can call these tools directly:\n\n| Tool | Description |\n|---|---|\n`list_agents` |\nList all active agents with their status, working directory, and subject |\n`get_agent` |\nGet full detail (status, workdir, subject, events, worktree) for one agent |\n`spawn_agent` |\nSpawn 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 |\n`set_role` / `list_roles` |\nSwitch 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 |\n`adopt_agent` |\nRegister an existing Claude session: resume newest-for-dir under tmux, or live-register a running tmux session |\n`send_to_agent` |\nType a message into a specific agent's claude session |\n`get_agent_output` |\nReturn the recent terminal output of a specific agent |\n`stop_agent` |\nUmbrella 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 |\n`terminate_agent` |\nStop an agent (kill tmux + the agent process); keeps the record and worktree. Reversible via `restore_agent` — the default \"stop this agent\" action |\n`restore_agent` |\nRecreate and resume a lost/orphaned agent's session (`claude --resume` ) |\n`recover_agents` |\nSafety net for the tombstone reaper: revive archived 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 |\n`delete_agent` |\nClear an agent's stored record (archives by default; `hard` purges). Does not touch tmux or the worktree |\n`remove_worktree` |\nRemove an agent's git worktree + branch — destructive; refuses while the agent runs or has uncommitted/unpushed work unless `force` |\n`ctx_set` / `ctx_get` / `ctx_list` / `ctx_cas` / `ctx_append` |\nRead/write the shared-context key/value blackboard agents collaborate through (with compare-and-swap and append) |\n`send_message` / `read_inbox` / `wait_for_message` |\nSend a directed message to an agent (wakes it if parked) / read this agent's inbox / block until a message arrives |\n`list_approvals` / `approve` |\nList recognized pending tool-permission prompts / answer one by option number |\n`commit` / `push` / `sync` |\nGit 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 |\n`check` |\nRun the project's `.warden/check.yml` checks, returning pass/fail with output for only the failing ones |\n`get_collaboration_status` / `who_is_editing_file` |\nFile-conflict view across the fleet / who (if anyone) is editing a given file |\n`create_pipeline` / `start_pipeline` / `show_pipeline` / `list_pipelines` / `cancel_pipeline` |\nDrive a DAG pipeline — create from a YAML spec, start entry jobs, inspect, list, cancel |\n\nPipeline 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 (\n\n`pause_pipeline`\n\n,`resume_pipeline`\n\n,`delete_pipeline`\n\n,`edit_pipeline_job`\n\n,`retry_pipeline_job`\n\n) are available over MCP too, mirroring the`warden pipeline …`\n\nCLI.\n\nExample orchestrator prompts:\n\n- \"What is PROJ-350 doing?\" — calls\n`get_agent`\n\nto fetch current status and events - \"Tell PROJ-343 to run the tests\" — calls\n`send_to_agent`\n\nwith`\"run the tests\"`\n\n- \"List all my agents\" — calls\n`list_agents`\n\n- \"Spin up an agent to research SSE reconnection\" — calls\n`spawn_agent`\n\nwith a`prompt`\n\n(auto-typed) - \"Spawn a debug-ci agent in /path/to/repo\" — calls\n`spawn_agent`\n\nwith`type`\n\n+`repo`\n\n- \"Stop PROJ-350\" — calls\n`terminate_agent`\n\n(reversible); \"clear its record too\" — then`delete_agent`\n\nBeyond raw tool access, install the packaged **Claude Code skill** so a Claude\norchestrator session knows *how and when* to manage your fleet (triage, create-from-prompt,\nrelay \"tell X to do Y\", terminate-with-confirmation, daemon-down handling). Other\nMCP-capable orchestrators drive the same tools directly without the skill:\n\n```\nmake install-skill   # symlinks skills/warden into ~/.claude/skills/warden\n```\n\nWith the MCP server registered (above) and the skill installed, just talk to a\nClaude session: *\"list my agents\"*, *\"spin up an agent to research X\"*,\n*\"what is agent-4f2a doing?\"*, *\"tell agent-4f2a to run the tests\"*, *\"kill the\nidle ones\"* — it drives the MCP tools (falling back to the `warden`\n\nCLI if the\nMCP server isn't registered). The daemon must be running.\n\nwarden moves deterministic responsibilities off agents — git and checks — onto the first-class `warden commit`\n\n/`push`\n\n/`sync`\n\n/`check`\n\ncommands (CLI + MCP), and **enforces** the worktree boundary with PreToolUse hooks delivered through a per-agent `claude --settings`\n\nfile (Claude Code backend). Each hook fails open (a hook error never blocks the agent) and is individually config-gated (default on):\n\n| Layer | Setting | What it does |\n|---|---|---|\nPrompt steer |\n`git_conventions` |\nA system-prompt hint steering agents toward `wd commit` /`push` /`sync` /`check` over raw git/test Bash — the gentle first layer |\nIsolation guard |\n`isolation_guard` |\nDenies an isolated agent's Edit/Write that escapes its worktree into the shared repo |\nGit-guard |\n`git_redirect` |\nDeny-redirects raw `git commit` /`push` /`pull` /`rebase` to the warden tools (reads stay allowed) |\nCheck-guard |\n`check_redirect` |\nDeny-redirects a raw test/lint/build command registered in `.warden/check.yml` to `wd check` (focused `-run` invocations pass through) |\n\nThe default write-type isolation (each `code`\n\n/`docs`\n\n/`website`\n\n/`debug-ci`\n\n/`tests`\n\nagent gets its own worktree unless `--in-repo`\n\n) is what makes the isolation guard meaningful and fixes parallel-agent collisions. See [docs/FEATURES.md §22](/srjn45/warden/blob/main/docs/FEATURES.md) for the full model.\n\n```\n# 1. Start the daemon (once — then managed by launchd)\n./scripts/install.sh   # install + start as a background launchd service (recommended)\nmake run-daemon        # foreground, for debugging only (blocks the terminal; ctrl-C to stop)\n\n# 2. Spawn an agent for a ticket\nwarden start PROJ-350 --type development\n\n# 3. Watch what it's doing\nwarden ls\nwarden status PROJ-350\n\n# 4. Drop into its terminal if needed\nwarden attach PROJ-350\n\n# 5. Clean up when done\nwarden done PROJ-350\nmake build            # go build -o bin/warden ./cmd/warden\nmake test             # go test ./...  (includes fuzz seed corpora)\nmake lint             # go vet ./...\nmake run-daemon       # build + start daemon in the foreground (debugging only)\nmake test-integration # build-tagged end-to-end suite (real daemon subprocess + CLI)\nmake bench            # run the Benchmark* suite (store I/O, pipeline, approvals)\nmake fuzz             # deeper fuzz sweep of the YAML/pane/session parsers\nmake cover            # whole-repo statement coverage (prints the total%)\n```\n\nThe README coverage badge is a static snapshot of `make cover`\n\n's total — refresh\nit when coverage moves materially.\n\nAll unit tests run without Docker or any external services:\n\n```\ngo test ./...\n```\n\nThe integration suite (`make test-integration`\n\n, build tag `integration`\n\n) boots a\nreal `warden daemon`\n\nagainst an isolated `HOME`\n\n; its spawn-lifecycle test\nself-skips unless `tmux`\n\nand `claude`\n\nare installed, so it stays CI-safe.\n\nThe repo ships version-controlled hooks in `.githooks/`\n\n. Wire them once with:\n\n```\nmake install-hooks          # git config core.hooksPath .githooks\n# or: ./scripts/install-hooks.sh\n```\n\n`scripts/install.sh`\n\n(the service installer) also does this automatically. Once\nwired:\n\n**pre-commit** runs`make fmt-check lint`\n\n(gofmt +`go vet`\n\n) — fast, so a formatting/vet slip is caught before the commit lands.**pre-push** runs`make verify-fast`\n\n(gofmt/vet/web/release build) — the CI subset that doesn't need an isolated machine.\n\nBypass either in a pinch with `git commit --no-verify`\n\n/ `git push --no-verify`\n\n.\nBecause `core.hooksPath`\n\nis a relative path, the hooks work across git worktrees\ntoo.\n\nThe daemon embeds a React dashboard (Astro + React) and serves it at `http://localhost:8765`\n\nalongside the REST API — no separate server required.\n\n```\nmake release     # 1. builds the Astro UI (web/), 2. embeds it via go:embed, 3. builds bin/warden\nwarden daemon  # start the daemon as usual\n```\n\nThen open `http://localhost:8765`\n\nin a browser.\n\nNote:the UI is baked into the binary at build time. After changing anything under`web/`\n\n, re-run`make release`\n\n(or`make ui`\n\nto rebuild only the frontend) and restart the daemon for the changes to take effect.\n\nThe 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:\n\n| Route | Tab | What's there |\n|---|---|---|\n`/cockpit` |\n⊞ Cockpit |\nThe home view (`/` redirects here). A slim Fleet header (totals · busy · waiting · errored, pressure, dirs) above the full agent grid. |\n`/others` |\n▦ Others |\nThe former Overview, now a catch-all: Needs you (attention queue), File conflicts, and Recent activity. |\n`/pipelines` |\n⛓ Pipelines |\nPipeline list + live DAG / job drawer. |\n`/metrics` |\n📊 Metrics |\nPer-agent and fleet-wide charts — see below. |\n`/archive` |\n🗄 Archive |\nEnded sessions with since/type filters. |\n`/agent/<id>` |\n`<id>` |\nA pinned agent's live terminal (one closeable tab per pinned agent). |\n\n**Cockpit is the home**—`/`\n\nredirects to`/cockpit`\n\n. 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 (**— a scrollable column of uPlot chart cards:`/metrics`\n\n)**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`\n\nrow),**Context per agent**(a client-accumulated time series of each agent's live context fill, legend dot colored by`ok`\n\n/`warning`\n\n/`critical`\n\n; 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`\n\n\" 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`\n\n) — a real`tmux attach`\n\nbridged 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`\n\ninstead of full bypass. For a managed worktree, use the CLI:`warden start TICKET --type development --repo …`\n\n.**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:`?`\n\nhelp overlay,`n`\n\nnew agent,`/`\n\nfocus filter,`r`\n\nrefresh,`1`\n\n–`9`\n\njump to a tab,`j`\n\n/`k`\n\nnext/previous tab,`Esc`\n\nclose/blur (also closes the Context overlay).**Browser notifications**— opt in to get a desktop notification when an agent enters`waiting_for_input`\n\n(gated so they only fire while the tab is hidden).\n\nThe dashboard is mobile-responsive and can be reached from your phone or another machine. Generate a token (`export WARDEN_TOKEN=$(warden token generate)`\n\n), bind a non-loopback address (`warden daemon --addr 0.0.0.0:8765`\n\n), 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](/srjn45/warden/blob/main/docs/USAGE.md#remote-access-phone-tablet-another-machine) for the full walkthrough.\n\nRun two terminals in parallel — no rebuild loop needed while iterating on the UI:\n\n```\n# Terminal 1 — daemon (REST API + SSE on :8765)\nwarden daemon\n\n# Terminal 2 — Astro dev server (:4321, proxies /api/* (REST + /api/v1/.../attach WS + /api/v1/events SSE) and /healthz to :8765)\nmake ui-dev\n```\n\nOpen `http://localhost:4321`\n\n. Edits under `web/src/`\n\ntrigger HMR instantly; the browser stays on the same origin as the real daemon API so SSE and all REST calls work without CORS configuration.\n\n```\nmake web-test    # Vitest — frontend unit tests (status mapping, API client)\ngo test ./...    # Go suite — covers daemon hub, SSE endpoint, static embed, and all existing routes\n```\n\nThe frontend Vitest suite lives in `web/src/lib/`\n\nalongside the source files (`status.test.ts`\n\n, `api.test.ts`\n\n). The Go daemon tests cover the broadcaster (`hub_test.go`\n\n), the SSE handler (`sse_test.go`\n\n), and the static file serving with SPA fallback (`static_test.go`\n\n).\n\nIssues and pull requests are welcome. See [CONTRIBUTING.md](/srjn45/warden/blob/main/CONTRIBUTING.md) for\nlicensing, the **DCO sign-off** (`git commit -s`\n\n), and dependency/notices rules.\nBefore opening a PR:\n\n```\ngofmt -l $(git ls-files '*.go')   # must be empty (CI enforces gofmt)\nmake lint                          # go vet ./...\nmake test                          # go test ./...\nmake web-test                      # frontend unit tests\n```\n\nCI (build, test, lint) runs on every push and PR to `main`\n\n— see [ .github/workflows/ci.yml](/srjn45/warden/blob/main/.github/workflows/ci.yml).\n\nLicensed under the **Apache License, Version 2.0**. See [LICENSE](/srjn45/warden/blob/main/LICENSE) and [NOTICE](/srjn45/warden/blob/main/NOTICE).\nThird-party dependency licenses are listed in [THIRD-PARTY-NOTICES.md](/srjn45/warden/blob/main/THIRD-PARTY-NOTICES.md).\n\nwarden is an independent open-source project. It is **not** affiliated with,\nendorsed by, or sponsored by Anthropic, OpenAI, Google, Cursor, Block, or any\nother agent-backend vendor. \"Claude\" and \"Claude Code\" are trademarks of\nAnthropic, PBC; \"Codex\" of OpenAI; and all other product and company names are\ntrademarks of their respective owners, used here for identification only.\n\nwarden is a local orchestrator: it drives agent-backend CLIs and services using\n**credentials you supply**. You are responsible for complying with the terms,\nusage policies, and rate limits of every backend and account you connect. warden\ngrants no rights to any third-party service and makes no representation that a\ngiven automation or concurrency pattern is permitted under your plan.\n\n```\nCopyright 2026 Srajan Pathak\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n```\n\n", "url": "https://wpnews.pro/news/warden-run-a-fleet-of-coding-agents-without-losing-your-mind", "canonical_source": "https://github.com/srjn45/warden", "published_at": "2026-07-27 08:48:36+00:00", "updated_at": "2026-07-27 09:22:33.005878+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools", "ai-infrastructure"], "entities": ["Warden", "Claude Code", "Go", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/warden-run-a-fleet-of-coding-agents-without-losing-your-mind", "markdown": "https://wpnews.pro/news/warden-run-a-fleet-of-coding-agents-without-losing-your-mind.md", "text": "https://wpnews.pro/news/warden-run-a-fleet-of-coding-agents-without-losing-your-mind.txt", "jsonld": "https://wpnews.pro/news/warden-run-a-fleet-of-coding-agents-without-losing-your-mind.jsonld"}}