diff --git a/README.md b/README.md
index 5c52da8..7e4330c 100644
--- a/README.md
+++ b/README.md
@@ -1,84 +1,166 @@
-# bullpen
+
bullpen
-A durable agent harness in Rust. A bullpen is a roster of warmed-up relievers
-you call in, pull back, and send out again — agents as managed, durable
-workers, not fire-and-forget processes.
+
+ A durable agent harness in Rust.
+ Agents as managed, resumable workers — not fire-and-forget processes.
+
-**Status: v0.** Headless vertical slice — a working agent loop (Anthropic,
-six workspace tools, SQLite-backed resumable sessions). TUI, durable
-subagents, OS sandboxing, and the workflow engine are on the
-[roadmap](ARCHITECTURE.md#roadmap).
+
+
+
+
+
+
-## Use
+
+
+
+
+A bullpen is a roster of warmed-up relievers you call in, pull back, and send
+out again. That is the whole thesis: agent runs should survive the process
+that started them.
+
+## Why it's different
+
+**Every step is durable the moment it happens.** Sessions live in one SQLite
+database (WAL), not in the memory of whatever process launched them. Kill
+bullpen mid-run — crash, `kill -9`, power loss — and the next invocation
+recovers: interrupted tool calls are marked, the transcript is closed
+cleanly, and the session resumes where it stopped.
+
+**No daemon, no supervisor.** A background session is just a detached
+`bullpen run` coordinating through the store. The dashboard is a read-and-
+dispatch view over that store — close it and the work keeps going, because
+nothing was ever supervising it.
+
+**The sandbox is a feature, not a footnote.** `--sandbox` confines writes to
+the workspace on every platform and, on macOS, runs shell commands *and their
+children* under Seatbelt. `--sandbox-strict` also cuts network.
+
+## Install
```bash
cargo install --path crates/cli
+```
+
+Rust 1.97+ (pinned in `rust-toolchain.toml`, so `rustup` fetches the right
+one automatically).
+
+## Quickstart
+
+Point it at a provider — any one of these is enough:
-# Pick your provider(s):
-export ANTHROPIC_API_KEY=sk-ant-... # anthropic (default), streams live
-bullpen login openrouter # OpenRouter, official OAuth PKCE
+```bash
+export ANTHROPIC_API_KEY=sk-ant-... # streams tokens live
+bullpen login openrouter # official OAuth PKCE
bullpen login codex # ChatGPT subscription, device-code flow
-export GLM_API_KEY=... # GLM (Z.ai), Anthropic-compatible
-export KIMI_API_KEY=... # Kimi (Moonshot), Anthropic-compatible
-# ...or skip codex login entirely: bullpen borrows a logged-in Codex CLI's
-# session (~/.codex/auth.json) read-only.
+```
+
+Already have the Codex CLI logged in? bullpen borrows its session from
+`~/.codex/auth.json` read-only — nothing to configure, and it never
+refreshes that token so it can't invalidate the other tool's login.
+Then work:
+
+```bash
cd your-project
-bullpen run "find the failing test, explain why it fails"
-bullpen run -p codex "..." # ChatGPT subscription
-bullpen run -p glm "..." # or -p kimi, -p openrouter
-bullpen run --sandbox "refactor X" # confine writes to the workspace (Seatbelt on macOS)
-bullpen run -v "..." # show tool activity on stderr
-bullpen sessions # list stored sessions
-bullpen sessions --json # machine-readable session list
-bullpen run -r "follow-up question" # resumes with the session's provider
-
-# Dispatch and watch many background sessions from one screen:
-bullpen run --bg "audit the auth module" # detached; returns immediately
-bullpen agents # dashboard: grouped, live, dispatch + peek
-bullpen logs # tail a background session's output
+bullpen run "find the failing test and explain why it fails"
+bullpen run --sandbox "refactor the retry logic" # confine writes
+bullpen run -v "..." # tool activity on stderr
+```
+
+Sessions are resumable by id prefix, with the provider they were created
+with:
+
+```bash
+bullpen sessions # what have I got
+bullpen sessions --json # same, machine-readable
+bullpen run -r 6ee4acc9 "now write the fix"
+```
+
+## Run many at once
+
+```bash
+bullpen run --bg "audit the auth module" # detached, returns immediately
+bullpen agents # the dashboard in the GIF above
+bullpen logs 6ee4acc9 # tail a background session
```
-**Agent view** (`bullpen agents`) manages background sessions from one
-screen — dispatch, watch them work, peek their output. It's daemonless:
-each background session is a detached `bullpen run` that coordinates through
-the SQLite store, so they keep running after you close the dashboard, survive
-crashes (a dead process shows as Failed and resumes on `run -r`), and appear
-in `bullpen sessions` like anything else.
-
-Providers: **anthropic** (true token streaming + prompt caching), **codex**
-(ChatGPT subscription), **openrouter**, **glm**, **kimi**. `--sandbox`
-confines file writes to the workspace on every platform and, on macOS, runs
-shell commands under Seatbelt so arbitrary code can't escape either;
-`--sandbox-strict` also cuts network.
-
-Sessions persist in `~/.bullpen/bullpen.db` (SQLite, WAL) as an append-only
-entry tree plus an execution log — every step of a run is durable the moment
-it happens. Kill bullpen mid-run (crash, `kill -9`, power loss) and the next
-invocation recovers: interrupted tool calls get marked, the transcript is
-closed cleanly, and the session resumes where it left off.
-
-The same machinery powers **the pen**: the model can delegate bounded tasks
-to child agents via the `agent` tool (`inspect` = read-only, `work` = full
-tools). Children are ordinary sessions — durable, budgeted, listed by
+`bullpen agents` groups sessions by state — **Working** (running, live pid),
+**Failed** (running, dead pid — it crashed), **Completed**, **Idle** — and
+lets you dispatch from the input line, `Space` to peek at output, `Esc` to
+quit. Quitting stops nothing.
+
+## The pen
+
+The model can delegate bounded work to child agents through the `agent`
+tool: `inspect` for read-only reconnaissance, `work` for the full toolset.
+Children are ordinary sessions — durable, budgeted, listed by
`bullpen sessions`, resumable — with deterministic identities, so a replayed
delegation reattaches to its child instead of running it twice.
+## Providers
+
+| Provider | Wire format | Auth | Verified |
+|---|---|---|---|
+| `anthropic` | Anthropic messages | `ANTHROPIC_API_KEY` | wire-level tests |
+| `codex` | OpenAI Responses (SSE) | `bullpen login codex`, or borrow the Codex CLI | live, incl. tools + resume |
+| `openrouter` | OpenAI chat-completions | `bullpen login openrouter` or `OPENROUTER_API_KEY` | live, incl. tools |
+| `glm` | Anthropic-compatible | `GLM_API_KEY` | config-only |
+| `kimi` | Anthropic-compatible | `KIMI_API_KEY` | config-only |
+
+Adapters are organized by wire format rather than vendor, which is why
+compatible hosts are configuration instead of code.
+
+Built-in tools: `bash`, `read_file`, `write_file`, `edit_file`, `grep`,
+`glob` — plus `agent` when the pen is enabled.
+
+## Where state lives
+
+`~/.bullpen/bullpen.db` — SQLite in WAL mode, holding an append-only entry
+tree (the conversation) plus a separate execution log (the orchestration).
+Delete every execution record and you still have a complete, valid
+conversation.
+
+Reading it while sessions run needs the immutable flag, since WAL databases
+can't be opened read-only without their shared-memory file:
+
+```bash
+sqlite3 "file:$HOME/.bullpen/bullpen.db?immutable=1" "select id, status from sessions"
+```
+
+## Status
+
+**v0.** Honest about what that means:
+
+| | |
+|---|---|
+| ✅ Shipped | Durable execution + crash recovery · the pen (durable subagents) · write-confinement sandbox with Seatbelt on macOS · agent view (dispatch, peek, live state) · 5 providers |
+| 🚧 Next | Interactive attach to a live session · needs-input state · notifications · compaction |
+| 📋 Planned | Landlock confinement on Linux · a durable workflow engine (steps in SQLite, resumable from any step) |
+
+Outside `--sandbox`, tools run with the process's full authority. Run it
+somewhere you would trust the model to act.
+
## Design
-Start with [ARCHITECTURE.md](ARCHITECTURE.md). The one-sentence version:
-a policy-free core loop (`bullpen-agent`) that knows nothing about vendors,
-config, or UI, with everything else composed around it at the edge — plus a
-single durable store instead of per-process state.
+[ARCHITECTURE.md](ARCHITECTURE.md) is the source of truth. The one-sentence
+version: a policy-free core loop (`bullpen-agent`) that knows nothing about
+vendors, config, or UI, with everything else composed around it at the edge
+— plus a single durable store instead of per-process state.
## Develop
```bash
-cargo test # all crates
-cargo clippy --all-targets
-cargo run -p bullpen -- run "hello"
+cargo test --workspace
+cargo clippy --workspace --all-targets -- -D warnings
+cargo fmt --all --check
```
+All three gate CI on Linux and macOS. The demo above is reproducible —
+`docs/media/bullpen-agents.tape` drives the real binary through
+[VHS](https://github.com/charmbracelet/vhs).
+
## License
MIT
diff --git a/docs/media/bullpen-agents.gif b/docs/media/bullpen-agents.gif
new file mode 100644
index 0000000..3e372f5
Binary files /dev/null and b/docs/media/bullpen-agents.gif differ
diff --git a/docs/media/bullpen-agents.tape b/docs/media/bullpen-agents.tape
new file mode 100644
index 0000000..99fae5c
--- /dev/null
+++ b/docs/media/bullpen-agents.tape
@@ -0,0 +1,52 @@
+Output bullpen-agents.gif
+Output bullpen-agents.mp4
+Set Shell zsh
+Set FontSize 20
+Set Width 1300
+Set Height 470
+Set Padding 18
+Set TypingSpeed 40ms
+
+Hide
+Type "export PS1='$ ' PATH=/Users/vics/.cargo/bin:$PATH HOME=/tmp/bpdemo/home; cd /tmp/bpdemo/work; clear"
+Enter
+Sleep 1s
+Show
+
+Sleep 700ms
+Type "bullpen agents"
+Sleep 300ms
+Enter
+Sleep 1800ms
+
+Type "find the bug in src/retry.rs"
+Sleep 300ms
+Enter
+Sleep 1500ms
+
+Type "count unchecked items in notes.md"
+Sleep 300ms
+Enter
+Sleep 1500ms
+
+Type "what is MAX_ATTEMPTS set to?"
+Sleep 300ms
+Enter
+Sleep 3s
+
+Sleep 27s
+
+Down
+Sleep 600ms
+Space
+Sleep 5s
+
+Escape
+Sleep 500ms
+Escape
+Sleep 800ms
+
+Type "bullpen sessions"
+Sleep 300ms
+Enter
+Sleep 2500ms