Workflows
This guide collects the shipped operator flows.
For command syntax, see command reference. For prompt handoff details, see prompt handoff.
Claude Code panes support guarded automation and prompt workflows. Codex CLI panes are supported through screen-capture classification with narrow YOLO approval for command permission dialogs. OpenCode panes are supported passively in the dashboard when botctl can safely match the tmux pane to OpenCode's SQLite session database. Pi panes are supported passively when a pi tmux pane can be matched to a JSONL session under ~/.pi/agent/sessions. Antigravity (agy) panes are supported for dashboard visibility, per-shape state classification (AgyCommandPermissionPrompt, AgyFolderTrustPrompt, AgySettingsPersistPrompt), pane-scrape last-message extraction, and opt-in YOLO command-permission auto-approve. Opt-in is per-pane via yolo start --pane <agy-pane>; folder-trust and settings-persist remain manual.
Main operator loop
For most real use, the loop is:
- Open
dashboardto see Claude Code panes, screen-detected Codex CLI panes, passively resolvable OpenCode panes, Pi panes, and Antigravity panes. - Use
yoloon the pane or workspace you want babysat. - Use
servewhen you need a live event stream or machine-readable observation. - Use
last-messagewhen the visible pane excerpt is not enough.
dashboard, yolo, and serve auto-start the managed runtime when needed; start runtime directly only when you want to manage its lifecycle yourself or use --unmanaged clients.
Typical commands:
botctl dashboard
botctl yolo --pane 0:6.0
botctl serve --session demo --format jsonl
botctl last-message --pane 0:6.0 --out -
runtime is the single owner of live pane observation, shared yolo supervision, and guarded actions. dashboard, yolo, and serve start it automatically in managed mode when needed, or you can run it yourself and use --unmanaged clients.
Choose a workflow
| Situation | Workflow |
|---|---|
You want botctl to launch Claude Code | Managed session flow |
| Claude Code is already running in tmux | Resolve an existing pane |
| A pane is blocked on a known prompt | Blocker recovery flow |
| You need to stage or submit prompt text | Prompt flow overview |
| You want a one-shot Claude answer but still want TUI observability | TUI-backed one-shot prompt |
| You want an MCP client to drive a persistent Claude TUI | MCP persistent sessions |
| You need a durable event stream | Observe versus serve |
| You need the full latest assistant reply | Export the last assistant message |
Managed session flow
Use this when botctl launches Claude for you.
-
Start the managed session:
botctl start --session demo --cwd /path/to/project -
Find the pane and inspect the session:
botctl listbotctl doctor --session demobotctl status --pane %19 -
Attach with tmux when you want the terminal UI:
tmux attach -t demo
Resolve an existing pane
Use this when Claude is already running inside tmux and you want to verify the pane before acting.
OpenCode panes are handled differently: the dashboard only includes them passively when the pane title has the form OC | <session title> and that title plus the pane cwd uniquely match OpenCode's SQLite session table. OpenCode titles truncated with ... are accepted as prefixes only when still unique within the same cwd. Resolved OpenCode panes show recent SQLite message context in the details panel and can show PermissionDialog when SQLite shows a running file/glob tool targeting an absolute path outside the session directory. OpenCode and Pi panes can be selected and opened from the dashboard, but automation and YOLO are not enabled for them.
Codex CLI panes are screen-classified from captured terminal text. The dashboard captures likely Codex panes and includes them only when the screen shows Codex-specific text. A Codex /statusline with run-state is the most accurate signal: Ready maps to ChatReady, while Working and Thinking map to BusyResponding. Codex panes can be selected and opened from the dashboard, and Codex YOLO can approve command permission dialogs by sending y for Yes, proceed; broader automation remains Claude-only.
-
List panes, including non-managed ones:
botctl list --all -
Resolve only a specific explicit pane:
botctl attach --pane %19Or, if tmux already gave you the pane target:
botctl attach --pane 0:2.3 -
Verify the pane before acting:
botctl doctor --pane %19botctl status --pane %19
Export the last assistant message
Use last-message when the visible pane capture is too short and you need the latest assistant reply as Markdown:
botctl last-message --pane %19
botctl last-message --pane 0:4.1 --out review.md
botctl last-message --pane 0:4.1 --out -
Without --out, the export is written in the current directory as MESSAGE_<provider-session-id>.md. The command prints only the line count and file path:
Dumped last message of 951 lines out to file:
MESSAGE_91399d1d-79e5-48a2-b355-c8b751fe9333.md
Use --out - to stream the raw Markdown body to stdout for piping. Claude reads ~/.claude/projects, Codex reads ~/.codex/sessions, OpenCode reads the latest assistant text parts from its SQLite storage after resolving the pane title and cwd, Pi reads the latest assistant text blocks from JSONL sessions under ~/.pi/agent/sessions (or PI_CODING_AGENT_SESSION_DIR), and Antigravity uses pane-scrape extraction (requires three horizontal-rule lines to be visible in the pane scrollback: one above the last assistant turn, plus the two that bracket the live input box). The export contains assistant-visible text, not tool calls or transcript metadata.
Blocker recovery flow
Use the direct pane-targeted actions only when the classified state matches the flow.
| Classified state | Command | Notes |
|---|---|---|
PermissionDialog | approve or reject | approve uses the user's Claude confirmation binding for Claude panes; Codex YOLO sends raw y only for Codex command permission dialogs. |
FolderTrustPrompt | approve | Sends raw Enter, not the user's confirm-yes binding. |
AgyCommandPermissionPrompt | yolo start --pane <agy-pane> | Opt-in YOLO sends raw Enter only when the cursor is on the captured > 1. Yes default and current_command == "agy". Folder-trust and settings-persist agy shapes are not auto-approved. |
SurveyPrompt | dismiss-survey | Sends raw 0. |
ChatReady or BusyResponding after a pause | continue-session | Refuses unsupported states. |
| Repeated safe blockers | auto-unstick | Bounded recovery loop; stops rather than guessing. |
PlanApprovalPrompt, DiffDialog, ExternalEditorActive, UserQuestionPrompt, or Unknown | manual review | No safe automatic recovery is defined. |
approve and reject are the canonical names. approve-permission and reject-permission remain compatibility aliases for older scripts.
Examples:
botctl approve --pane %19
botctl reject --pane %19
botctl dismiss-survey --pane %19
botctl continue-session --pane %19
botctl auto-unstick --pane %19
Notes:
Unknownis a refusal state; do not guess.approveacceptsPermissionDialogandFolderTrustPrompt.- Folder trust approval is special and uses raw
Enter. - Prefer explicit pane IDs over session names for recovery.
Prompt flow overview
There are four prompt paths today:
- TUI-backed one-shot execution — use
promptto launch Claude, submit the prompt, wait for the answer, and print assistant text to stdout. - One-shot submission to an existing pane — pass
--textor--sourcedirectly tosubmit-prompt. - Manual staging — use
prepare-prompt, theneditor-helperwhen Claude requests an external editor target. - Loop submission — use
keep-goingwhen you wantbotctlto keep asking Claude to audit the current task until Claude reports a terminal token.
Manual staging now keeps the session's pending prompt in <state-root>/state.db under a workspace-scoped placeholder instance rather than a separate prompt file.
TUI-backed one-shot prompt
Use prompt when you want command-line one-shot behavior but still want the safety and inspectability of a real Claude TUI in tmux:
botctl prompt --text "Summarize this repo"
botctl prompt --source task.md --append-system-prompt rules.md
printf 'Say exactly hello' | botctl prompt --stdin --cwd /path/to/project
botctl prompt --text hi -- --model sonnet --name "Just testing"
prompt launches a new detached tmux window in the owning session, creates that session automatically when needed, waits for ChatReady, pastes the resolved prompt into the interactive TUI through tmux, handles only the same safe survey/folder-trust/permission blockers as YOLO unless --no-yolo is set, waits for a fresh final assistant reply, and prints only assistant text to stdout. The owning session defaults to the shared botctl session; pass --session NAME to override it. Successful runs kill only the captured prompt window after loading the fresh assistant message. Failed prompt windows stay alive for inspection. Pass --verbose for launch/wait progress on stderr. Arguments after -- pass through to Claude. Use submit-prompt instead when you already have an existing pane you want to target.
Existing-pane one-shot example:
botctl submit-prompt --session demo --pane %19 --text "Summarize the current repo"
Manual staging example:
botctl prepare-prompt --session demo --text "Summarize the current repo"
botctl editor-helper --session demo /tmp/claude-editor.txt
Workspace example:
botctl prepare-prompt --session demo --workspace . --text "Summarize the current repo"
botctl yolo start --all --workspace .
Loop example:
botctl keep-going --pane %19
botctl keep-going --pane %19 --no-yolo
botctl keep-going --pane %19 --source ./prompts/review-loop.txt
The default keep-going prompt expects Claude to end each loop response with OKIE_DOKIE, ALL_DONE, or PANIC. Custom prompts must preserve that token contract.
For the editor-helper, survey preflight, and state-dir variants, see prompt handoff.
Observe versus serve
observeis bounded: it returns a fixed sample of events and pane state.runtimeis the long-lived owner of tmux control mode and periodic pane snapshots.serveis the foreground facade for one session over that shared runtime state.servenow has a localhost HTTP API, but it is still not the full daemon/SSE product.
Use observe when you want a bounded diagnostic sample; use serve when you want a live foreground stream backed by the shared runtime.
In practice, observe is a secondary diagnostic tool. runtime is the owner, and serve is the main live observation facade.
Safety rules
- Explicit pane IDs are preferred.
session:window.paneis also supported for explicit pane targeting.- Never automate an ambiguous target.
- Claude ownership must be established before automation.
- Guarded workflows validate the classified state before sending keys.
Unknownmeans stop and inspect.
For deeper rationale and current limits, see architecture and troubleshooting.