Skip to main content

Automation

botctl automation is intentionally guarded. It only acts when it has an explicit pane target, a Claude-owned pane, a supported classified state, and the required keybindings.

Model

Automation is split into separate checks:

  1. Targeting — resolve an explicit pane id, or a session/window target that resolves to one active pane.
  2. Ownership — refuse if the pane is not currently running claude.
  3. Classification — inspect the pane state before sending keys.
  4. Policy — only execute a workflow from the state it supports.
  5. Keybinding routing — resolve the user's Claude keybindings instead of assuming a hard-coded map.

This is why raw send-keys success is not enough: a keypress can land in the wrong app, the wrong Claude state, or the wrong workflow.

Explicit targeting and ownership

Prefer --pane %ID for all automation. --pane session:window.pane is also accepted when you already have tmux's explicit pane target. Session-based targeting is only a convenience for resolving the active pane.

Before any guarded workflow runs, botctl checks that the pane is owned by Claude. If the pane is running anything else, automation refuses.

Keybinding policy

botctl reads ~/.claude/keybindings.json and routes actions from the user's bindings.

  • bindings prints the recommended mapping.
  • install-bindings is non-destructive.
  • If a Claude keybinding file already exists, install-bindings merges in missing required bindings when it can.
  • If the existing file is invalid or a required key is already used for something else, install fails clearly instead of overwriting the file.
  • Missing bindings are surfaced by doctor, and action routing fails clearly when required bindings are absent.

Guarded workflows

Guarded workflows validate state before acting:

  • submit-prompt requires ChatReady
  • approve accepts PermissionDialog and FolderTrustPrompt; approve-permission is a compatibility alias
  • reject requires PermissionDialog; reject-permission is a compatibility alias
  • dismiss-survey requires SurveyPrompt

Refusal states are part of the safety model:

  • Unknown — manual review required
  • UserQuestionPrompt — manual review required
  • PlanApprovalPrompt — manual review required
  • DiffDialog — manual review required
  • ExternalEditorActive — manual review required

FolderTrustPrompt is a special case. Approval uses raw Enter, not the normal confirm-yes binding.

SurveyPrompt is also special. Dismissal uses the raw 0 key, not a Claude keybinding-resolved action.

State and action matrix

StateSafe automated actionNotes
ChatReadysubmit-prompt; keep-going loop submissionPrompt submission verifies that the pane transitions after the submit sequence.
PromptEditingnoneSubmit or clear the unsubmitted prompt manually. submit-prompt refuses this state because it could replace typed input.
BusyRespondingwaitcontinue-session can report the pane as already usable.
PermissionDialogapprove, reject, YOLOApproval is allowed only when the prompt is classified as a permission dialog and policy allows the action.
FolderTrustPromptapprove; auto-unstick; keep-going with YOLO enabledUses raw Enter because Claude's folder trust prompt confirms the selected default directly.
SurveyPromptdismiss-survey, YOLO, auto-unstick, keep-going with YOLO enabledUses raw 0.
PlanApprovalPromptnoneReview manually.
DiffDialognoneReview manually.
ExternalEditorActiveeditor-helper only when you are intentionally completing a prompt handoffGeneral automation refuses this state.
UserQuestionPromptnoneAnswer the question manually or submit a new prompt after the pane returns to ChatReady.
UnknownnoneInspect the pane or improve classifier coverage.

Refusal semantics

botctl refuses when:

  • the target is ambiguous
  • the pane is not Claude-owned
  • classification is Unknown
  • the workflow does not match the current state
  • required Claude keybindings are missing or invalid

That refusal is deliberate: it is safer to stop than to guess.

Refusals use exit code 2 when the command was understood but the guarded workflow intentionally declined to act. Runtime failures such as tmux, filesystem, state database, or keybinding read errors use exit code 1.

keep-going, auto-unstick, and yolo

These commands are recovery loops, not magic fixers.

  • auto-unstick walks a pane through a bounded number of safe recovery steps.
  • keep-going watches a pane, submits the built-in audit prompt by default or a custom loop prompt through --source / --text, and can optionally respond to supported blockers.
  • keep-going expects each loop reply to end with exactly one terminal token: OKIE_DOKIE, ALL_DONE, or PANIC.
  • the built-in keep-going prompt tells Claude to verify completion, commit before ALL_DONE, push on branches other than main, master, develop, dev, trunk, or release/*, and open a PR only when the user explicitly asked for one
  • --no-yolo turns PermissionDialog and FolderTrustPrompt into manual-review exits.
  • yolo is the long-running loop for supported permission dialogs and survey dismissal.
  • for Codex panes, yolo only approves command permission dialogs by sending raw y for Yes, proceed

Limits:

  • auto-unstick and keep-going still require Claude-owned panes
  • they still refuse on ambiguous or unsupported states
  • they do not bypass classifier or keybinding checks
  • yolo does not auto-handle FolderTrustPrompt
  • Codex YOLO only approves command permission dialogs; it does not submit prompts or run Claude keybinding workflows
  • keep-going will stop on manual-review blockers when --no-yolo is set