Skip to main content

botctl command reference

This page is the current CLI reference for shipped commands and aliases.

botctl supports Claude Code as an actively guarded automation target, Codex CLI as a screen-classified target with narrow YOLO permission approval, OpenCode as a passively discovered dashboard target, Pi as a passively discovered dashboard/last-message target, and Antigravity (agy) as a passively discovered dashboard/last-message target with pane-scrape extraction. Codex panes are visible when captured terminal text identifies a Codex screen; Codex YOLO can send y for Yes, proceed on command permission dialogs. OpenCode panes are visible when their tmux title and cwd can be matched safely to OpenCode's SQLite session database. Pi panes are visible when a pi tmux command can be matched to a Pi JSONL session under ~/.pi/agent/sessions. Antigravity panes are visible when the pane command is agy and a secondary signal passes (state directory exists or frame fingerprint matches). Broader keybinding automation remains Claude-only.

Global conventions:

  • botctl --version prints the installed version.
  • botctl help, botctl help <command>, and <command> --help show terminal help.
  • --no-color, NO_COLOR, TERM=dumb, and non-TTY output disable rich help color.
  • Exit code 0 means success, including help and --version.
  • Exit code 1 means runtime failure, such as tmux, filesystem, state database, or keybinding errors.
  • Exit code 2 means usage error or guarded refusal where botctl intentionally refuses unsafe or non-actionable automation.
  • Exit code 130 means interrupted when the process is terminated by the default Ctrl-C/SIGINT path; long-running cleanup handlers may stop gracefully with 0.
  • Usage errors point at focused help instead of dumping global help.
  • --json is available on one-shot inspection commands where documented; JSON is printed to stdout.
  • --plain preserves current line-oriented output for attach, list, status, and doctor; it cannot be combined with --json.
  • last-message writes the latest persisted assistant message as raw Markdown, or writes the Markdown body to stdout with --out -.
  • prompt success output is assistant text only on stdout; launch/wait/temp-file progress goes to stderr only with --verbose.

Canonical command names:

  • Use yolo, approve, reject, and dismiss-survey in new docs and scripts.
  • approve-permission remains a compatibility alias for approve.
  • reject-permission remains a compatibility alias for reject.
  • Commands marked advanced are supported, but intended for diagnostics, fixtures, prompt plumbing, or low-level automation.

For the most useful commands, start here:

Main commands

runtime

Purpose: start the central local runtime that owns live observation, guarded actions, and yolo supervision.

Syntax:

botctl runtime [--reconcile-ms N] [--history-lines N] [--state-dir PATH]
botctl runtime stop [--state-dir PATH]
botctl runtime --foreground [--reconcile-ms N] [--history-lines N] [--state-dir PATH]

Examples:

botctl runtime
botctl runtime --state-dir /tmp/botctl-state

Notes:

  • listens on <state-dir>/runtime.sock
  • starts a hidden tmux-backed runtime session by default
  • stop shuts down the current runtime
  • --foreground runs the runtime in the current process instead of the hidden tmux session
  • dashboard, yolo, and serve connect to this process instead of running independent long-lived control loops; in managed mode they auto-start it when needed
  • one runtime should own one local state root and tmux socket at a time

prompt

Purpose: run a one-shot Claude request through an observable interactive Claude TUI in a new detached tmux window. It does not call claude -p or claude --prompt.

Syntax:

botctl prompt [--session NAME] [--window NAME] [--cwd PATH] [--command CMD] \
[--source PATH ...] [--text TEXT] [--stdin] [--append-system-prompt PATH ...] \
[--poll-ms N] [--submit-delay-ms N] [--ready-timeout-ms N] [--idle-timeout-ms N] \
[--state-dir PATH] [--workspace PATH|UUID] [--large-prompt-threshold BYTES] \
[--keep-temp] [--no-yolo] [--verbose] [-- CLAUDE_ARG ...]

Examples:

botctl prompt --text "Summarize this repo"
botctl prompt --source task.md --append-system-prompt rules.md
cat prompt.md | botctl prompt --stdin --cwd /path/to/project
botctl prompt --source big-plan.md --large-prompt-threshold 10 --keep-temp
botctl prompt --text "Fix the failing tests" --no-yolo
botctl prompt --text hi -- --model sonnet --name "Just testing"

Flags and defaults:

  • --session NAME defaults to the shared botctl tmux session, which is created automatically when needed.
  • --window NAME defaults to claude; each prompt run creates a new window in the owning session.
  • --cwd PATH defaults to the current directory.
  • --command CMD defaults to claude; leave it as claude unless debugging a compatible wrapper.
  • --source PATH is repeatable and is concatenated in flag order.
  • --text TEXT may be supplied once.
  • --stdin reads stdin explicitly; when no input flags are present, piped stdin is read implicitly.
  • --append-system-prompt PATH is repeatable and is prepended as labeled text because the TUI accepts one chat prompt.
  • --poll-ms default 1000; --submit-delay-ms default 250.
  • --ready-timeout-ms default 30000; --idle-timeout-ms default 600000.
  • --large-prompt-threshold default 8192 bytes; larger prompts are written under the state dir and a short file-pointer prompt is submitted.
  • --keep-temp preserves that large-prompt instruction file and prints its path to stderr.
  • --no-yolo refuses permission, folder-trust, and survey blockers instead of using the safe recovery paths.
  • --verbose prints launch/wait/temp-file progress to stderr.
  • -- CLAUDE_ARG ... passes additional arguments to the interactive Claude command. Prompt/headless mode (-p/--prompt) is still refused.

Output and safety:

  • stdout contains only the latest assistant message text on success.
  • with --verbose, progress, temp paths, and wait status go to stderr; cleanup warnings always go to stderr.
  • successful runs load a fresh assistant message first, then kill only the captured prompt window.
  • failed prompt windows are left alive for inspection.
  • submission waits for ChatReady, pastes the resolved prompt into the interactive TUI through tmux, waits for final ChatReady, and refuses to print stale transcript output.
  • exit code 2 is used for usage errors and guarded refusals such as empty input, TTY stdin without data, unsafe blockers, unknown state, or a non-Claude launched pane.

mcp

Purpose: run the small MCP-compatible JSON-RPC server for persistent agent sessions backed by managed tmux windows. Claude, Codex, and Agy are supported through provider-specific spawn tools.

Syntax:

botctl mcp stdio [--state-dir PATH]
botctl mcp http --bind 127.0.0.1:8787 [--state-dir PATH]

Tools (clients typically expose them under the server name, e.g. mcp__botctl__spawn_claude; provider-specific spawn tools are listed only when their provider binary is available on PATH):

  • spawn_claude (Claude spawn: required cwd; optional model_preset, advanced raw model, effort, agent, permission_mode, settings, timeout_ms, policy)
  • spawn_codex (Codex spawn: required cwd; optional model_preset, advanced raw model, effort, timeout_ms, policy)
  • spawn_agy (Agy spawn: required cwd; optional timeout_ms, policy)
  • prompt
  • wait
  • kill
  • snapshot (returns raw pane_text; recent_lines and structured outcome.snapshot omit trailing blank terminal padding and agent.state is refreshed from the live classification)
  • send_keys
  • one_shot (preferred prompt, aliases text/message/input; optional cwd defaults to the MCP server current directory; optional provider defaults to the first available provider binary; optional model_preset, advanced raw model, effort/agent/permission_mode/settings/timeout_ms/policy): spawns a temporary session, runs one prompt to a terminal outcome, then always attempts to kill the window (best-effort). prompt/wait/one_shot can return provider_error with error_excerpt when a visible Codex provider/API error appears in the pane.

Notes:

  • stdio uses newline-delimited JSON-RPC on stdin/stdout.
  • HTTP is a stateless, Streamable-HTTP-compatible JSON request/response server at POST /mcp (GET→405, DELETE→204, OPTIONS→204, Origin/Host loopback checks, MCP-Protocol-Version 2025-03-26); no SSE, no sessions, no auth. Binding a non-loopback address requires --allow-non-loopback.
  • sessions persist after prompt; use kill for cleanup.
  • managed IDs resolve to exact tmux pane/window IDs before any action.
  • send_keys is unsafe/operator-only and does not imply progress.

yolo

Purpose: set centralized yolo policy for one pane, all panes, or a workspace-scoped subset.

Start syntax:

botctl yolo [start] (--pane %ID|session:window.pane | --all) [--follow] [--poll-ms N] [--format human|jsonl] [--live-preview] [--state-dir PATH] [--workspace PATH|UUID] [--unmanaged]

Stop syntax:

botctl yolo stop (--pane %ID|session:window.pane | --all) [--state-dir PATH] [--workspace PATH|UUID] [--unmanaged]

Examples:

botctl yolo --pane 0:6.0
botctl yolo --all --workspace .
botctl yolo stop --all

Notes:

  • updates desired yolo state in SQLite and the runtime's in-memory view
  • guarded by classified state; runtime yolo will not blindly press keys
  • accepts explicit pane targets or --all
  • --workspace scopes --all to one workspace registration set
  • --follow tails matching runtime events after setting policy
  • auto-starts a managed runtime unless --unmanaged is set

dashboard

Purpose: open the runtime-backed live TUI for Claude Code panes, screen-detected Codex CLI panes, passively resolvable OpenCode panes, Pi panes, and Antigravity panes, grouped by workspace, with per-pane and per-workspace YOLO controls for Claude and Codex.

Syntax:

botctl dashboard [--poll-ms N] [--history-lines N] [--state-dir PATH] [--exit-on-navigate] [--persistent] [--unmanaged]

Examples:

botctl dashboard
botctl dashboard --persistent

Quick tmux popup binding:

bind-key C-c display-popup -E -w 80% -h 40% botctl dashboard --persistent

Notes:

  • scans all Claude Code panes
  • captures likely Codex CLI panes and includes them only when Codex screen text is visible; a Codex /statusline with run-state gives the strongest signal, mapping Ready to ChatReady and Working/Thinking to BusyResponding
  • also scans OpenCode panes when the tmux pane title is OC | <session title> and exactly one OpenCode SQLite session row matches the pane cwd plus that title
  • accepts OpenCode titles truncated with ... as a prefix only when that prefix is unique within the same cwd
  • shows a bounded recent-message excerpt for resolved OpenCode panes from SQLite message/part rows
  • scans Pi panes by matching pi tmux commands to JSONL sessions under ~/.pi/agent/sessions (or PI_CODING_AGENT_SESSION_DIR) and shows assistant text context
  • maps running OpenCode file/glob tools that target absolute paths outside the session directory to PermissionDialog when that pending permission is visible in SQLite
  • ignores OpenCode panes when the title is missing, the database is unreadable, or the cwd/title match is missing or ambiguous
  • scans Antigravity panes when the pane command is agy and the secondary signal passes (the state directory at ~/.gemini/antigravity-cli or ANTIGRAVITY_STATE_DIR exists, or the captured frame contains an Antigravity fingerprint); shows the glyph, classified state, and cook time
  • Codex YOLO can approve command permission dialogs by sending y for Yes, proceed; OpenCode, Pi, and Antigravity support is visibility-only, and broader guarded automation remains Claude-only
  • shows current classified state, age, wait time, branch, workspace grouping, pane PID, process-tree average CPU, memory, and observed active Cook time persisted across dashboard restarts
  • when launched from tmux, defaults the selected row to the invoking pane when that pane is visible in the dashboard
  • queries the central runtime for shared pane state and yolo policy
  • --persistent keeps the dashboard alive in its own tmux session and popup-friendly attach flow
  • auto-starts a managed runtime unless --unmanaged is set

serve

Purpose: expose a runtime-backed event stream and HTTP facade for one tmux session.

It can also expose a localhost HTTP API for a polling web UI.

Syntax:

botctl serve --session NAME [--pane %ID|session:window.pane] [--reconcile-ms N] [--history-lines N] [--http ADDR] [--allowed-origin URL] [--format human|jsonl] [--state-dir PATH] [--unmanaged]

Examples:

botctl serve --session demo
botctl serve --session demo --format jsonl
botctl serve --session demo --http 127.0.0.1:8787 --allowed-origin http://localhost:3000
botctl serve --session demo --pane 0:2.3

Notes:

  • requires a running runtime process
  • this is the main session-scoped facade over runtime state
  • --format jsonl is the useful mode for tooling and automation
  • --http ADDR starts a localhost JSON API alongside the stream facade
  • repeat --allowed-origin URL to allow browser clients from those exact origins; browser origins are rejected when not listed
  • the full HTTP contract is documented in HTTP API reference
  • auto-starts a managed runtime unless --unmanaged is set

Common targeting and safety rules

  • --pane %ID targets a specific tmux pane by unique pane id.
  • --pane session:window.pane also targets a specific tmux pane using tmux's explicit pane syntax, for example 0:2.3.
  • --session NAME [--window NAME] targets a session; when a window is required, both --session and --window must be provided.
  • Several workflow commands refuse ambiguous targets.
  • Automation commands generally require the target pane to be a Claude pane and will refuse to act otherwise.
  • approve / reject / dismiss-survey and yolo are guarded workflows: they validate the classified pane state before sending keys.
  • Commands that store runtime state on disk default to $XDG_STATE_HOME/botctl when XDG_STATE_HOME is set and non-empty, otherwise ~/.local/state/botctl.
  • --state-dir PATH overrides that default state root for commands that support it.
  • Relevant stateful commands bootstrap <state-root>/state.db; prompt handoff and yolo registrations now both use SQLite-backed records there.
  • The central runtime socket lives at <state-root>/runtime.sock.
  • Each SQLite connection enables WAL mode, foreign keys, and a 5-second busy timeout.
  • Startup bootstrapping also runs in-place schema migrations for supported older state.db versions.
  • last-message is read-only with respect to provider state; it reads transcript storage and writes only the requested Markdown export file, or stdout when --out - is used.

State-to-action quick reference

StateUseRefuses or requires review
ChatReadysubmit-prompt; keep-going loop submissiondirect approval/rejection commands
PromptEditingmanual submit or clearsubmit-prompt, because it could replace unsubmitted input
BusyRespondingwait; observe with serveprompt submission and approval commands
PermissionDialogapprove, reject, YOLO, continue-session, auto-unstickunsafe permission prompts that policy cannot approve
FolderTrustPromptapprove, continue-session, auto-unstickreject; raw Enter is used for approval
SurveyPromptdismiss-survey, YOLO, continue-session, auto-unstickapprove and reject
PlanApprovalPromptmanual reviewautomatic approval
DiffDialogmanual review/interactions/:optionId, guarded workflows
ExternalEditorActiveeditor-helper when completing a prompt handoffgeneral guarded automation
UserQuestionPromptmanual answerautomatic recovery
Unknowninspect with status, doctor, or captureall guarded automation

Secondary commands

Everything below is still supported, but these commands are mostly setup, diagnostics, recovery, or deeper reference material.

Session and pane management

start

Purpose: start a tmux session running Claude.

Syntax:

botctl start --session NAME [--window NAME] [--cwd PATH] [--command CMD] [--dry-run]

Flags:

  • --session NAME (required)
  • --window NAME (default: claude)
  • --cwd PATH (default: current working directory)
  • --command CMD (default: claude)
  • --dry-run (print the tmux plan instead of starting)

Targeting: creates/starts the named session; no pane target is used.

Example:

botctl start --session demo --dry-run

attach

Purpose: resolve and report a Claude pane target.

Syntax:

botctl attach (--pane %ID|session:window.pane | --session NAME [--window NAME])
botctl attach (--pane %ID|session:window.pane | --session NAME [--window NAME]) --plain

Flags:

  • --pane %ID|session:window.pane or --session NAME [--window NAME] (required)
  • --plain (preserve current line-oriented output)

Targeting: accepts either an explicit pane or a session target; a window-only target is refused.

Safety: refuses panes not owned by Claude.

Example:

botctl attach --session demo --window claude

list

Purpose: list tmux panes.

Syntax:

botctl list [--all] [--json | --plain]

Flags:

  • --all (default: off; without it, only Claude Code panes are shown)
  • --json (emit a stable JSON object with a panes array)
  • --plain (preserve current line-oriented output; mutually exclusive with --json)

Targeting: no explicit target; scans all panes.

Example:

botctl list
botctl list --json
botctl list --plain

capture

Purpose: print a pane capture.

Syntax:

botctl capture --pane %ID|session:window.pane [--history-lines N]

Flags:

  • --pane %ID|session:window.pane (required)
  • --history-lines N (default: 200)

Targeting: explicit pane only.

Example:

botctl capture --pane 0:2.3 --history-lines 80

last-message

Purpose: dump the latest assistant message for one Claude Code, Codex CLI, OpenCode, Pi, or Antigravity pane as raw Markdown. Claude/Codex/OpenCode/Pi read persisted provider transcripts; Antigravity scrapes the pane's tmux scrollback.

Syntax:

botctl last-message --pane %ID|session:window.pane [--out PATH] [--history-lines N]

Flags:

  • --pane %ID|session:window.pane (required)
  • --out PATH (default: MESSAGE_<provider-session-id>.md in the current directory)
  • --out - (write the raw Markdown message body to stdout instead of a file)
  • --history-lines N (default: 2000) widens the captured scrollback for Antigravity pane-scrape extraction. Non-agy providers ignore this value.

Targeting: explicit pane only.

Output:

Dumped last message of 951 lines out to file:
MESSAGE_91399d1d-79e5-48a2-b355-c8b751fe9333.md

Examples:

botctl last-message --pane 0:4.1
botctl last-message --pane %19 --out review.md
botctl last-message --pane %19 --out - | pbcopy

Provider notes:

  • Claude reads the pane's Claude transcript under ~/.claude/projects, preferring the transcript opened by the pane process and falling back to the newest transcript for the pane cwd.
  • Pi reads JSONL sessions under ~/.pi/agent/sessions (or PI_CODING_AGENT_SESSION_DIR), preferring a transcript opened by the pane process tree and falling back to the newest session for the pane cwd.
  • Codex reads ~/.codex/sessions, preferring an open transcript file descriptor and falling back to the newest session whose session_meta.cwd matches the pane cwd.
  • OpenCode resolves the pane by OC | <session title> plus cwd, then reads the latest assistant text parts from OpenCode's SQLite message/part rows.
  • Antigravity uses pane-scrape extraction. It requires three horizontal-rule lines (20+ characters) to be visible in the captured scrollback: one above the last assistant turn, plus the two that bracket the live input box. The most recent complete assistant turn between the upper rule and the top of the input box is exported. If those boundaries are not all visible, the command exits with agy: no completed assistant message visible in pane scrollback; the extractor requires three horizontal-rule lines (one above the last assistant turn, plus the two that bracket the live input box) — use --history-lines to widen the scrollback window. Use --history-lines to increase the scrollback window. The output filename is MESSAGE_<conversation-id>.md (no provider prefix). Antigravity state is read from ~/.gemini/antigravity-cli/ by default; override with ANTIGRAVITY_STATE_DIR (root directory) or ANTIGRAVITY_HISTORY_FILE (direct path to history.jsonl). Antigravity YOLO is opt-in per-pane via yolo start --pane <agy-pane>; only the command-permission prompt is auto-approved (raw Enter on the default 1. Yes option, gated on current_command == "agy" and the cursor still being on option 1). Folder-trust and settings-persist prompts are detected per-shape but remain manual.
  • Tool calls, reasoning, and provider metadata are not exported; only assistant-visible text is written.

status

Purpose: inspect a pane, classify its state, and report keybinding/next-action diagnostics.

Syntax:

botctl status --pane %ID|session:window.pane [--history-lines N] [--json | --plain]

Flags:

  • --pane %ID|session:window.pane (required)
  • --history-lines N (default: 120)
  • --json (emit a stable JSON object)
  • --plain (preserve current line-oriented output; mutually exclusive with --json)

Targeting: explicit pane only.

Example:

botctl status --pane 0:2.3
botctl status --pane 0:2.3 --json
botctl status --pane 0:2.3 --plain

doctor

Purpose: diagnose a pane or session and report automation readiness.

Syntax:

botctl doctor [--session NAME] [--pane %ID|session:window.pane] [--history-lines N] [--bindings-path PATH] [--json | --plain]

Flags:

  • --session NAME (optional)
  • --pane %ID|session:window.pane (optional)
  • --history-lines N (default: 120)
  • --bindings-path PATH (optional)
  • --json (emit a stable JSON object)
  • --plain (preserve current line-oriented output; mutually exclusive with --json)

Targeting: requires at least one of --pane or --session.

Safety: refuses if both are missing.

Example:

botctl doctor --session demo
botctl doctor --session demo --json
botctl doctor --session demo --plain

Observation and serving

dashboard

Purpose: open the live dashboard TUI for Claude Code panes, screen-detected Codex CLI panes, passively resolvable OpenCode panes, Pi panes, and Claude/Codex YOLO toggles.

Syntax:

botctl dashboard [--poll-ms N] [--history-lines N] [--state-dir PATH] [--exit-on-navigate] [--persistent] [--unmanaged]

Flags:

  • --poll-ms N (default: 1000, must be at least 1)
  • --history-lines N (default: 120)
  • --state-dir PATH (optional; default machine-state root)
  • --exit-on-navigate (optional; exit after jumping to a pane)
  • --persistent (optional; keep the dashboard alive in a dedicated tmux session and attach to it)
  • --unmanaged (optional; require an already-running runtime instead of auto-starting one)

Targeting: no explicit pane target; scans all Claude Code panes, likely Codex CLI panes with visible Codex screen text, passively resolvable OpenCode panes, Pi panes, and Antigravity panes.

Safety:

  • rejects --poll-ms 0
  • rejects --persistent --exit-on-navigate because persistent mode is intended to keep the dashboard process alive

Persistent mode behavior:

  • creates or reuses a dedicated tmux session named botctl-dashboard on a separate tmux socket also named botctl-dashboard
  • attaches to that persistent dashboard session after ensuring it exists
  • when launched from tmux, captures the outer tmux socket first so the dashboard continues inspecting the outer tmux server instead of its own dedicated dashboard session
  • if you launch it from tmux display-popup, tmux controls popup size and closing the popup only detaches from the persistent dashboard
  • inside persistent mode, pressing q detaches the client instead of terminating the dashboard process

Examples:

botctl dashboard
botctl dashboard --persistent

observe

Purpose: stream a bounded observation of a session.

Syntax:

botctl observe --session NAME [--pane %ID|session:window.pane] [--events N] [--idle-timeout-ms N] [--history-lines N] [--state-dir PATH]

Flags:

  • --session NAME (required)
  • --pane %ID|session:window.pane (optional)
  • --events N (default: 25)
  • --idle-timeout-ms N (default: 1500)
  • --history-lines N (default: 120)
  • --state-dir PATH (optional; default machine-state root)

Targeting: session required; pane target is optional.

Artifacts:

  • machine artifact files are written under <state-root>/artifacts:
    • captures/<id>/capture.txt
    • tapes/<id>/control-mode.log
    • exports/<id>/report.json
  • observe output still prints the diagnostic report to stdout.
  • these runtime artifacts stay as regular files; they are not stored in state.db.

Example:

botctl observe --session demo --events 10

serve

Purpose: run the live observation loop for a session.

Syntax:

botctl serve --session NAME [--pane %ID|session:window.pane] [--reconcile-ms N] [--history-lines N] [--http ADDR] [--allowed-origin URL] [--format human|jsonl] [--state-dir PATH] [--unmanaged]

Flags:

  • --session NAME (required)
  • --pane %ID|session:window.pane (optional)
  • --reconcile-ms N (default: 1500, must be at least 1)
  • --history-lines N (default: 120)
  • --http ADDR (optional; example: 127.0.0.1:8787)
  • --allowed-origin URL (optional; repeat for each browser origin allowed to call the API)
  • --format human|jsonl (default: human)
  • --state-dir PATH (optional; default machine-state root)
  • --unmanaged (optional; require an already-running runtime instead of auto-starting one)

Output and API:

  • runtime events are streamed to stdout with the requested --format; serve no longer writes per-run tape or summary artifacts.
  • when --http is set, serve also listens for JSON requests such as:
    • GET /instances
    • GET /instances/:id
    • POST /instances/:id/prompt
    • POST /instances/:id/actions/:action
    • POST /instances/:id/interactions/:optionId

Targeting: session required; optional explicit pane target.

Safety: rejects --reconcile-ms 0.

Example:

botctl serve --session demo --format jsonl
botctl serve --session demo --http 127.0.0.1:8787 --allowed-origin http://localhost:3000

Fixtures and replay

These commands are advanced diagnostics for maintaining classifier fixtures and replaying saved cases.

record-fixture

Purpose: capture a fixture case from a live session.

Syntax:

botctl record-fixture --session NAME --case NAME [--pane %ID|session:window.pane] [--output-dir PATH] [--expected-state STATE] [--events N] [--idle-timeout-ms N] [--history-lines N]

Flags:

  • --session NAME (required)
  • --case NAME (required)
  • --pane %ID|session:window.pane (optional)
  • --output-dir PATH (default: fixtures/cases)
  • --expected-state STATE (optional)
  • --events N (default: 25)
  • --idle-timeout-ms N (default: 1500)
  • --history-lines N (default: 120)

Targeting: session required; pane optional.

Storage: fixture corpora remain regular repository files under fixtures/cases unless you choose a different --output-dir; they are intentionally separate from machine-local runtime state under <state-root>.

Example:

botctl record-fixture --session demo --case permission-dialog

classify

Purpose: classify a saved frame file.

Syntax:

botctl classify --path PATH

Flags:

  • --path PATH (required)

Targeting: file input only.

Example:

botctl classify --path fixtures/frames/demo.txt

replay

Purpose: replay and compare a saved fixture case.

Syntax:

botctl replay --path PATH

Flags:

  • --path PATH (required)

Targeting: file input only.

Example:

botctl replay --path fixtures/cases/demo

Keybindings

bindings

Purpose: print the built-in keybinding definition as JSON.

Syntax:

botctl bindings

Example:

botctl bindings

install-bindings

Purpose: install the recommended Claude keybindings.

Syntax:

botctl install-bindings [--path PATH]

Flags:

  • --path PATH (optional)

Targeting: path only.

Safety: creates the file if it is missing, merges in any missing required bindings when possible, and fails clearly on invalid JSON or key conflicts.

Example:

botctl install-bindings

send-action

Purpose: advanced plumbing command that sends one named automation action to a pane.

Syntax:

botctl send-action --pane %ID|session:window.pane --action NAME

Flags:

  • --pane %ID|session:window.pane (required)
  • --action NAME (required)

Valid actions:

  • clear-input
  • external-editor
  • submit
  • interrupt
  • confirm-previous
  • confirm-next
  • confirm-yes
  • confirm-no

Targeting: explicit pane only.

Safety: refuses non-Claude panes and unknown action names.

Example:

botctl send-action --pane 0:2.3 --action submit

Guarded workflows

approve

Purpose: approve a permission dialog. Canonical name: approve; compatibility alias: approve-permission.

Syntax:

botctl approve --pane %ID|session:window.pane [--format human|jsonl]
botctl approve-permission --pane %ID|session:window.pane [--format human|jsonl]

Flags:

  • --pane %ID|session:window.pane (required)
  • --format human|jsonl (default: human)

Targeting: explicit pane only.

Safety: validates the pane state before sending keys.

Example:

botctl approve --pane 0:2.3

reject

Purpose: decline a permission dialog. Canonical name: reject; compatibility alias: reject-permission.

Syntax:

botctl reject --pane %ID|session:window.pane [--format human|jsonl]
botctl reject-permission --pane %ID|session:window.pane [--format human|jsonl]

Flags:

  • --pane %ID|session:window.pane (required)
  • --format human|jsonl (default: human)

Targeting: explicit pane only.

Safety: validates the pane state before sending keys.

Example:

botctl reject --pane 0:2.3 --format jsonl

dismiss-survey

Purpose: dismiss a survey prompt. Canonical name: dismiss-survey.

Syntax:

botctl dismiss-survey --pane %ID|session:window.pane

Flags:

  • --pane %ID|session:window.pane (required)

Targeting: explicit pane only.

Safety: validates the pane state before sending keys.

Example:

botctl dismiss-survey --pane 0:2.3

continue-session

Purpose: continue a paused or interrupted Claude session.

Syntax:

botctl continue-session (--pane %ID|session:window.pane | --session NAME --window NAME)

Flags:

  • --pane %ID|session:window.pane or --session NAME --window NAME (required)

Targeting: accepts either one explicit pane or a fully qualified session/window target.

Safety: rejects session-only targeting and refuses ambiguous targets.

Example:

botctl continue-session --session demo --window claude

auto-unstick

Purpose: try a bounded sequence of recovery actions until the pane becomes usable.

Syntax:

botctl auto-unstick (--pane %ID|session:window.pane | --session NAME --window NAME) [--max-steps N]

Flags:

  • --pane %ID|session:window.pane or --session NAME --window NAME (required)
  • --max-steps N (default: 6, must be at least 1)

Targeting: accepts either one explicit pane or a fully qualified session/window target.

Safety: refuses ambiguous targets and --max-steps 0; it may stop early if a permission dialog would require more than one approval.

Example:

botctl auto-unstick --pane 0:2.3 --max-steps 4

keep-going

Purpose: continuously watch a pane, submit the loop prompt when Claude is ready, and return only when the loop yields ALL_DONE, PANIC, or an error.

Syntax:

botctl keep-going (--pane %ID|session:window.pane | --session NAME --window NAME) [--poll-ms N] [--submit-delay-ms N] [--state-dir PATH] [--source PATH | --text TEXT] [--no-yolo]

Flags:

  • --pane %ID|session:window.pane or --session NAME --window NAME (required)
  • --poll-ms N (default: 1000, must be at least 1)
  • --submit-delay-ms N (default: 250, must be at least 1)
  • --state-dir PATH (optional; overrides the default state root)
  • --source PATH or --text TEXT (optional; defaults to the built-in audit loop prompt)
  • --no-yolo (default: off)

Targeting: accepts either one explicit pane or a fully qualified session/window target.

Safety: refuses ambiguous targets and zero polling/submission intervals.

Custom prompt contract: custom loop prompts are wrapped with an internal botctl marker, but your prompt still needs to tell Claude to end each reply with the expected literal loop token (OKIE_DOKIE, ALL_DONE, or PANIC). Empty custom prompts are rejected.

Completion contract:

  • OKIE_DOKIE — continue looping after reporting remaining work
  • ALL_DONE — return the final completion summary and stop
  • PANIC — return blocking details and stop

Default loop behavior:

  • the built-in audit prompt tells Claude to verify completion before ALL_DONE
  • it instructs Claude to commit before ALL_DONE when there are changes to commit
  • it instructs Claude to push automatically only on branches other than main, master, develop, dev, trunk, or release/*
  • it instructs Claude to open a PR only if the user explicitly asked for one

Example:

botctl keep-going --pane 0:2.3 --no-yolo

Custom loop example:

botctl keep-going --pane 0:2.3 --source ./prompts/review-loop.txt

Prompt preparation and submission

prepare-prompt

Purpose: prepare a prompt payload for a session in the state database.

Syntax:

botctl prepare-prompt --session NAME [--state-dir PATH] [--workspace PATH|UUID] [--source PATH | --text TEXT]

Flags:

  • --session NAME (required)
  • --state-dir PATH (optional; overrides the default state root)
  • --workspace PATH|UUID (optional; defaults to the cwd workspace)
  • --source PATH or --text TEXT (exactly one required)

Targeting: session plus a resolved workspace.

Safety: refuses if both prompt inputs are provided or if neither is provided.

Workspace resolution:

  • UUID values resolve a previously known botctl workspace
  • path values may be absolute or relative to the current working directory
  • Git-backed paths collapse to the canonical worktree root
  • non-Git paths use the resolved path itself as the workspace root

Example:

botctl prepare-prompt --session demo --text "Write the summary"

editor-helper

Purpose: advanced prompt plumbing command that generates an editor target file for the prompt workflow.

Syntax:

botctl editor-helper --session NAME [--state-dir PATH] [--workspace PATH|UUID] [--source PATH] [--keep-pending] TARGET

Flags:

  • --session NAME (required)
  • --state-dir PATH (optional; overrides the default state root)
  • --workspace PATH|UUID (optional; defaults to the cwd workspace)
  • --source PATH (optional)
  • --keep-pending (optional)
  • TARGET (required positional path)

Targeting: session, workspace, and a single positional target path.

Safety: refuses unknown flags and multiple positional targets.

Example:

botctl editor-helper --session demo /tmp/botctl-prompt.txt

submit-prompt

Purpose: resolve prompt text from --text or --source, stage it in the state database, and submit it into a pane.

Syntax:

botctl submit-prompt --session NAME --pane %ID|session:window.pane [--state-dir PATH] [--workspace PATH|UUID] [--source PATH | --text TEXT] [--submit-delay-ms N]

Flags:

  • --session NAME (required)
  • --pane %ID|session:window.pane (required)
  • --state-dir PATH (optional; overrides the default state root)
  • --workspace PATH|UUID (optional; must match the target pane workspace when provided)
  • --source PATH or --text TEXT (exactly one required)
  • --submit-delay-ms N (default: 250, must be at least 1)

Targeting: session plus explicit pane; workspace defaults from the pane path.

Safety: refuses if both prompt inputs are provided, if neither is provided, or if --submit-delay-ms 0 is used.

Example:

botctl submit-prompt --session demo --pane 0:2.3 --text "Continue"

Yolo

yolo

Purpose: start or stop the long-running permission loop. Canonical name: yolo.

Syntax:

botctl yolo [start] (--pane %ID|session:window.pane | --all) [--follow] [--poll-ms N] [--format human|jsonl] [--live-preview] [--state-dir PATH] [--workspace PATH|UUID] [--unmanaged]
botctl yolo stop (--pane %ID|session:window.pane | --all) [--state-dir PATH] [--workspace PATH|UUID] [--unmanaged]

Subcommands:

  • start (optional; omitted by default)
  • stop

Start flags:

  • --pane %ID|session:window.pane or --all (exactly one required)
  • --follow (optional; tail matching runtime events after setting policy)
  • --poll-ms N (default: 1000, must be at least 1)
  • --format human|jsonl (default: human)
  • --live-preview (default: off)
  • --state-dir PATH (optional; overrides the default state root)
  • --workspace PATH|UUID (optional; filters --all or validates the target pane workspace)
  • --unmanaged (optional; require an already-running runtime instead of auto-starting one)

Stop flags:

  • --pane %ID|session:window.pane or --all (exactly one required)
  • --state-dir PATH (optional; overrides the default state root)
  • --workspace PATH|UUID (optional; filters stop --all)
  • --unmanaged (optional; require an already-running runtime instead of auto-starting one)

Targeting:

  • start can target one pane or scan all supported Claude Code and Codex panes with --all
  • start --all and stop --all remain global by default
  • --workspace limits --all operations to one workspace
  • stop --all disables tracked yolo registrations stored in <state-root>/state.db
  • neither mode allows mixing --pane and --all

Safety: start refuses --poll-ms 0; both modes refuse missing or mixed targets. Codex YOLO is limited to command permission dialogs and sends raw y for Yes, proceed; other Codex states still require manual review.

Example:

botctl yolo start --pane 0:2.3 --live-preview

Help

help

Purpose: print the command list and usage summary.

Syntax:

botctl help
botctl help exit-codes
botctl --help
botctl -h

Example:

botctl --help
botctl help safety
botctl help exit-codes