Command Book for AI Agents (Claude Code, Codex, Cursor)

AI coding agents are great at writing code, but they're notoriously bad at managing the long-running processes that code needs: dev servers, databases, workers, and build watchers. Command Book's CLI gives any agent a reliable, machine-readable way to launch a process, poll whether it's actually up, and stop it cleanly when the work is done.

This page is the human-facing setup guide. For the terse, copy-into-your-agent reference, see the raw AI Agent CLI Reference — it's written specifically for LLMs to load into their instructions.

Why agents + Command Book

When an agent starts a server with a bare background shell (python app.py &), it has no dependable way to answer two simple questions later: Is it still running? and How do I stop it? The result is the failure mode every developer has seen an agent fall into:

  • Orphaned servers that keep running after the task is "done," holding onto ports and memory.
  • Port conflicts when the agent starts a second copy because it lost track of the first.
  • Guessed sleep timers (sleep 5 && curl ...) that are either too short (server isn't up yet) or wastefully long.

Command Book fixes this by being the front door for long-running processes. Every process started through Command Book — whether from the GUI or from commandbook run — is tracked in a runtime registry. So when the agent asks commandbook status, there is always a truthful answer, and when it asks commandbook stop, there is always a real handle to act on. No PID bookkeeping, no leaked processes.

Only processes Command Book launched are visible to status and stop. If your agent needs to manage a process, it must start it through commandbook run.

The loop: launch → poll → act → stop

This is the entire pattern Command Book is built around. An agent should follow these four steps for any long-running process:

  1. Launch the saved command with commandbook run <slug>. Because run is a long-running foreground process, the agent backgrounds it (or runs it with a timeout) so it can keep working.
  2. Wait for it with commandbook wait <slug> — one call that blocks until the process is up and returns the instant it is. Add --http <url> or --port <n> to wait until the server actually accepts connections, not just until the process exists. No guessed sleep timers, and a built-in timeout so a failed boot can't hang the agent.
  3. Act against the now-running process: hit its port, run a test suite, scrape a page, whatever the task requires.
  4. Stop it with commandbook stop <slug> when finished. This also suppresses auto-restart, so the process stays down.
# 1. Launch (background the long-running foreground process)
commandbook run api-server &

# 2. Block until the port answers — returns the moment it's ready, or fails fast on a bad boot.
commandbook wait api-server --http http://127.0.0.1:5000

# 3. Do the work against the running server here...

# 4. Stop cleanly when done (also suppresses auto-restart)
commandbook stop api-server

The CLI in 60 seconds

These are the commands an agent needs. The full reference, with every flag and example, lives on the CLI page.

commandbook list                          # Discover exact slugs — never guess them
commandbook details <slug> --json         # Full config + status for one command
commandbook run <slug>                    # Run a saved command (long-running, foreground)
commandbook run --command "<cmd>" --name <handle>   # Run an arbitrary command ad-hoc (not saved)
commandbook status <slug> --json          # Is it running? Machine-readable snapshot.
commandbook wait <slug> --http <url>      # Block until up & the port answers (timeout ceiling)
commandbook stop <slug> --json            # Stop gracefully (machine-readable result)
commandbook stop <slug> --force           # Stop immediately (SIGKILL)

commandbook new --name "<name>" --command "<cmd>"   # Save a command (no prompts with flags)
commandbook edit <slug> --command "<cmd>"           # Change only the fields you pass
commandbook delete <slug>                           # Remove a saved command

Every one of these is non-interactive and safe to run with stdin closed.

status --json

Prefer the --json form when you want to parse state instead of branching on exit codes:

{
  "slug": "talk-python-dev",
  "state": "running",
  "instances": [
    { "pid": 81234, "startedAt": "2026-06-17T10:02:00Z", "source": "app", "uptimeSeconds": 720 }
  ]
}
  • state is "running", "stopped" (known but nothing live), or "not_found".
  • source is "cli" (started via commandbook run) or "app" (started in the GUI). status sees both.
  • The no-arg commandbook status --json returns a JSON array, one entry per running command.

Exit codes (scriptable, HTTP-flavored)

status, stop, details, new, edit, and delete share the same exit-code vocabulary, which makes them easy to script:

Code Meaning
0 Running / stopped at least one instance / command exists (details) / wrote a command
1 stop matched live processes but none could be killed
204 Known but not running
44 Slug not found (shown as 404 in the message/JSON)
45 new — a command already owns that slug (use --if-not-exists to make it a no-op)
46 delete — the command is running and --force wasn't passed
47 run — the command is already running (use --restart or --allow-multiple)
244 Runtime registry error (shown as 500)
64 Invalid arguments — a bad --dir, --icon, or --env, or a missing required flag

Because exit code 0 means "running," commandbook status is pollable in a loop — but prefer commandbook wait (below), which does the polling for you with a timeout and an optional readiness probe.

Two states share exit 0: running and restarting. A restarting command is between auto-restart attempts — momentarily down, but still managed, still listed, and still stoppable. Don't treat it as stopped. If you need the process actually answering, use wait --http/--port rather than status.

Check status before run. run refuses to start a second copy of a live command and exits 47 — that's "already up", not a failure. It's an easy state to reach when a run was backgrounded in an earlier step or another shell, and --restart is the fix when you mean to replace it.

Waiting for a command: commandbook wait

commandbook wait <slug> blocks until a condition is met and returns the instant it is — the timeout is only a ceiling, never a fixed delay. It replaces hand-rolled until commandbook status …; do sleep 1; done loops, which have no timeout and can't tell "still booting" from "already crashed."

commandbook wait <slug>                                # until the process is registered and alive
commandbook wait <slug> --http http://127.0.0.1:5000   # until that URL returns 2xx/3xx
commandbook wait <slug> --port 5000                    # until that TCP port accepts a connection
commandbook wait <slug> --for stopped                  # until it is no longer running
commandbook wait <slug> --timeout 60 --json            # raise the ceiling; emit JSON
  • Readiness, not just liveness. With --http/--port, wait returns only once the server actually answers — so you can drop the separate curl-retry loop. A server is "running" for a moment before its port binds; this closes that gap.
  • Fail-fast. If the process exits before becoming ready, wait returns immediately (exit 205) instead of burning the whole timeout.
  • Short commands. A plain wait <slug> (no probe) also succeeds if the command has already exited cleanly (exit 0); a non-zero exit is propagated as wait's own exit code. Use --for stopped to block until a one-shot command finishes and get its exit code back.
Code Meaning
0 Condition met (running / ready / clean exit / stopped)
124 Timed out before the condition was met
205 --http/--port target exited before becoming ready
44 Slug not found (shown as 404)
244 Runtime registry error (shown as 500)

The --json output carries state (running · ready · exited · stopped · timeout), waitedSeconds, an exitCode once the command has ended, and the live instances:

{ "slug": "talk-python-dev", "state": "ready", "waitedSeconds": 0.34,
  "instances": [ { "pid": 81234, "source": "cli", "uptimeSeconds": 0 } ] }

Set up your agent

There are two ways to give your agent the Command Book workflow: install the ready-made skill (the fastest path — see below), or paste a per-tool instruction block into your tool's config (Claude Code, Codex, and Cursor blocks are further down). Either way, the source of truth is the AI Agent CLI Reference — it spells out the commands, the loop, and the gotchas.

Install the Command Book bundle (skill + agent)

The same setup is packaged as a ready-made Command Book bundle so you don't have to hand-write instructions. It's two pieces: the ask-commandbook skill (the launch → wait → stop loop your main agent follows inline) and a commandbook operator agent (for multi-process orchestration). There are three ways to get it in place, from easiest to most manual.

Install from the app (easiest)

In Command Book, open Settings → AI Agents → "Install Claude Code Skill & Agent". One click installs the skill to ~/.claude/skills/ask-commandbook/ and the agent to ~/.claude/agents/commandbook.md, where Claude Code picks them up automatically across all your projects. This is the recommended path — no download, no unzip — and it keeps itself up to date: when a newer Command Book ships an updated bundle, the app refreshes your installed copy on launch.

Download the bundle

Prefer to do it by hand, or installing for a tool other than Claude Code? Download the bundle and drop it where your tool looks for instructions:

  • commandbook-skill.zip — contains skills/ask-commandbook/ (with SKILL.md + reference/cli-reference.md) and agents/commandbook.md.

Then put it in place per tool:

  • Claude Code — unzip into ~/.claude/ for a personal install (all projects), or into <project>/.claude/ for a single project. Either way you'll end up with …/.claude/skills/ask-commandbook/SKILL.md and …/.claude/agents/commandbook.md. The exact command for a personal install:

    unzip commandbook-skill.zip -d ~/.claude/
    

    Verify it loaded by asking Claude to "start X with Command Book," or by running /skills if your version supports it.

  • Codex — Codex can't load a SKILL.md directly, so add the instruction block to your project's AGENTS.md instead — see the Codex block under "Per-tool setup" below.

  • Cursor — add the instruction block to .cursorrules (or a project rule) — see the Cursor block under "Per-tool setup" below.

Manual copy (no download)

If you'd rather not download anything, the raw skill is viewable at /static/downloads/SKILL.md and the full CLI reference at /docs/ai-guide.md. Paste the relevant block straight into your tool's instruction file.

Per-tool setup

Copy-paste instruction blocks for each tool. If you installed the skill above, Claude Code is already set up — these are the manual equivalents.

Claude Code

The skill above packages this automatically. To set it up by hand instead, add the reference URL to your project's CLAUDE.md:

## Long-running processes

Use the Command Book CLI to start, check, and stop long-running processes
(dev servers, databases, workers). Full reference:
https://commandbookapp.com/docs/ai-guide.md

The loop: `commandbook run <slug> &`, poll `commandbook status <slug>` until
it exits 0 (running), do the work, then `commandbook stop <slug>`.
Use `commandbook list` to discover exact slugs.

Codex

Add the same instruction block to your project's AGENTS.md:

## Long-running processes (Command Book)

Start dev servers and other long-running processes with the Command Book CLI
instead of bare background shells, so they can be monitored and stopped cleanly.
Reference: https://commandbookapp.com/docs/ai-guide.md

Loop: `commandbook run <slug> &` → poll `commandbook status <slug>` until it
exits 0 → do the work → `commandbook stop <slug>`.

Cursor

Add to your project's .cursorrules (or a project rule):

When you need a long-running process (dev server, database, worker), use the
Command Book CLI so it can be monitored and stopped reliably:
- Discover slugs with `commandbook list`
- Start with `commandbook run <slug> &`
- Poll `commandbook status <slug>` until it exits 0 (running)
- Stop with `commandbook stop <slug>` when done
Full reference: https://commandbookapp.com/docs/ai-guide.md

Generic / any agent

Any agent that can load a URL or a markdown file can use Command Book. Point it at:

Both are plain text written for machine consumption.

Worked example: run a dev server, test it, stop it

Suppose you have a Flask app saved in Command Book as talk-python-dev. Here's how an agent would start it, wait for it to come up, run work against it, and tear it down — all with real commandbook commands.

# Confirm the slug exists (don't guess it).
commandbook list

# Launch the dev server. It's a long-running foreground process, so background it.
commandbook run talk-python-dev &

# Wait until the server actually accepts connections. Returns the instant it's ready,
# fails fast (exit 205) if the process dies during boot, and gives up after --timeout.
commandbook wait talk-python-dev --http http://127.0.0.1:5000/health --timeout 30

# The server is up — now do the work against it.
curl -fsS http://127.0.0.1:5000/health
python -m pytest tests/integration/

# Stop the server cleanly. This also suppresses auto-restart.
commandbook stop talk-python-dev

If you'd rather inspect the result yourself, add --json and branch on state:

commandbook wait talk-python-dev --http http://127.0.0.1:5000 --json
# {"slug":"talk-python-dev","state":"ready","waitedSeconds":0.3, ... }

Writing to the command book, not just reading it

An agent can create and maintain saved commands, not only run them. new, edit, and delete prompt only when you run them with no flags; pass flags and they never read stdin, so they're safe to run with stdin closed.

This is what turns "set up my dev servers" into a one-shot agent task. The agent saves the commands, and they land in your ⌘K palette where they belong — instead of the agent running everything ad-hoc and leaving you nothing to reuse tomorrow.

# Create the command, idempotently, and capture its slug.
slug=$(commandbook new --name "API Server" \
                       --command "uv run flask --app app.main run --port 5000" \
                       --dir ~/src/api --icon flask --if-not-exists --json | jq -r .slug)

# Use it immediately — no second lookup needed.
commandbook run "$slug" &
commandbook wait "$slug" --http http://127.0.0.1:5000

What an agent needs to know:

  • --dir defaults to the current directory, not ~, which is almost always what's meant.
  • --if-not-exists makes provisioning idempotent. Without it, a slug that already exists exits 45 and writes nothing, so a setup script run twice fails the second time.
  • There's no --slug flag. Slugs are derived from --name; that's how you control them.
  • --json returns the same object as details --json, so create-then-inspect never needs a second call.
  • edit changes only the fields you pass. --env merges into the existing variables rather than replacing them; --clear-env wipes them first.
  • delete refuses while the command is running (exit 46) so you can't orphan a live process. Pass --force to stop it first.
  • Environment variable values are never printed back — only their names — on every one of these commands.
  • The user sees it immediately. A running Command Book picks up commands the CLI creates, edits, or deletes as they happen; no restart needed.

Gotchas

A few behaviors are worth teaching your agent up front:

  • stop blocks during graceful shutdown. It escalates SIGINT → SIGTERM → SIGKILL to the process group, which can take up to ~12s per instance (5s SIGINT + 5s SIGTERM + 2s SIGKILL). When a graceful shutdown isn't needed, use commandbook stop <slug> --force to skip straight to SIGKILL (~2s).
  • Auto-restart retry caveat. If a command has auto-restart enabled and you stop it during its brief restart-delay countdown, the stop can be a silent no-op while the pending restart still fires. If stop unexpectedly returns 204 for an auto-restart command, poll status and retry stop once it shows running.
  • Only Command Book–launched processes are visible. status and stop can only see processes started through commandbook run or the GUI. The CLI cannot find or kill arbitrary processes started elsewhere — so start everything you want to manage through Command Book.
  • Ad-hoc for throwaway, saved for keepers. To launch something that isn't a saved slug, use commandbook run --command "<cmd>" --name <handle> — fully managed by status/stop, but not added to the user's command list. Use that for one-off agent processes so you don't clutter their list. When the process is one the user will want again — their dev server, database, or worker — save it with commandbook new instead (see below).
  • Inspect before you run. commandbook details <slug> --json returns a command's full configuration (command, working directory, env var names, auto-restart) plus its current status — so you can verify exactly what a slug will do before launching it. Environment variable values are never printed.
  • Always pass the slug explicitly. commandbook run with no slug launches an interactive picker, which an agent can't drive.

Learn more