Skip to main content

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:

  1. Open dashboard to see Claude Code panes, screen-detected Codex CLI panes, passively resolvable OpenCode panes, Pi panes, and Antigravity panes.
  2. Use yolo on the pane or workspace you want babysat.
  3. Use serve when you need a live event stream or machine-readable observation.
  4. Use last-message when 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

SituationWorkflow
You want botctl to launch Claude CodeManaged session flow
Claude Code is already running in tmuxResolve an existing pane
A pane is blocked on a known promptBlocker recovery flow
You need to stage or submit prompt textPrompt flow overview
You want a one-shot Claude answer but still want TUI observabilityTUI-backed one-shot prompt
You want an MCP client to drive a persistent Claude TUIMCP persistent sessions
You need a durable event streamObserve versus serve
You need the full latest assistant replyExport the last assistant message

Managed session flow

Use this when botctl launches Claude for you.

  1. Start the managed session:

    botctl start --session demo --cwd /path/to/project
  2. Find the pane and inspect the session:

    botctl list
    botctl doctor --session demo
    botctl status --pane %19
  3. 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.

  1. List panes, including non-managed ones:

    botctl list --all
  2. Resolve only a specific explicit pane:

    botctl attach --pane %19

    Or, if tmux already gave you the pane target:

    botctl attach --pane 0:2.3
  3. Verify the pane before acting:

    botctl doctor --pane %19
    botctl 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 stateCommandNotes
PermissionDialogapprove or rejectapprove uses the user's Claude confirmation binding for Claude panes; Codex YOLO sends raw y only for Codex command permission dialogs.
FolderTrustPromptapproveSends raw Enter, not the user's confirm-yes binding.
AgyCommandPermissionPromptyolo 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.
SurveyPromptdismiss-surveySends raw 0.
ChatReady or BusyResponding after a pausecontinue-sessionRefuses unsupported states.
Repeated safe blockersauto-unstickBounded recovery loop; stops rather than guessing.
PlanApprovalPrompt, DiffDialog, ExternalEditorActive, UserQuestionPrompt, or Unknownmanual reviewNo 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:

  • Unknown is a refusal state; do not guess.
  • approve accepts PermissionDialog and FolderTrustPrompt.
  • 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:

  1. TUI-backed one-shot execution — use prompt to launch Claude, submit the prompt, wait for the answer, and print assistant text to stdout.
  2. One-shot submission to an existing pane — pass --text or --source directly to submit-prompt.
  3. Manual staging — use prepare-prompt, then editor-helper when Claude requests an external editor target.
  4. Loop submission — use keep-going when you want botctl to 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

  • observe is bounded: it returns a fixed sample of events and pane state.
  • runtime is the long-lived owner of tmux control mode and periodic pane snapshots.
  • serve is the foreground facade for one session over that shared runtime state.
  • serve now 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.pane is 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.
  • Unknown means stop and inspect.

For deeper rationale and current limits, see architecture and troubleshooting.