Troubleshooting
Common operator failures and what they usually mean.
Start with the smallest command that proves what botctl can see:
botctl list --all
botctl doctor --pane %19
botctl status --pane %19
Use --json on list, doctor, and status when you need structured output for a script.
Missing keybindings
Symptoms:
doctorreports missing or invalid bindings.- Guarded workflows fail before any keypresses are sent.
install-bindingsreports invalid JSON or a key conflict in the existing file.
Cause:
botctl reads Claude keybindings from ~/.claude/keybindings.json. It will not overwrite a custom file or invent a key sequence when a required action is missing.
Fix:
-
Inspect the required map:
botctl bindings -
Merge missing bindings when possible:
botctl install-bindings -
If install still fails, fix the conflicting or invalid JSON manually.
-
Re-run diagnostics:
botctl doctor --pane %19
Ambiguous targets
Symptoms:
- A command says the target is ambiguous.
- Session-only targeting finds no active pane.
Cause:
Automation needs one exact tmux pane. Session names are only a convenience for resolving a pane.
Fix:
botctl list --all
botctl status --pane %19
If you must use a session target, include the window:
botctl attach --session demo --window claude
Non-Claude panes
Symptoms:
- Refusal mentions the current command is not
claude. doctorshowscommand_matches_claude=false.
Cause:
Claude-only workflows refuse shells, editors, OpenCode panes, and unrelated tmux panes. Codex support is limited to screen classification and YOLO command permission approval.
Fix:
-
List all panes:
botctl list --all -
Target the actual Claude pane for Claude automation.
-
Use the dashboard for passive OpenCode visibility or Codex screen-classified visibility:
botctl dashboard
Stale observation
Symptoms:
statusorservereportsUnknownunexpectedly.- The visible UI and captured text disagree.
Cause:
Live classification still depends on capture-pane text plus a recent-lines heuristic. Stale scrollback can hide the current UI.
Fix:
-
Re-run status with more history:
botctl status --pane %19 --history-lines 240 -
Re-run diagnostics on the explicit pane:
botctl doctor --pane %19 -
If you need continuous reconciliation, use
serve:botctl serve --session demo --pane %19
submit-prompt fails
Symptoms:
- Submission reports that no prompt-submission transition was observed.
- The pane is not
ChatReady.
Cause:
submit-prompt only submits from ChatReady, except for supported preflight recovery such as survey dismissal. It verifies that the pane transitions after submission.
Fix:
botctl doctor --pane %19
botctl status --pane %19
Then:
- If the state is
ChatReady, retrysubmit-prompt. - If the state is
SurveyPrompt, rundismiss-surveyor retrysubmit-promptand let preflight handle it. - If the state is
ExternalEditorActive, finish the editor handoff manually or witheditor-helper. - If the state is
DiffDialog, review the diff manually.
prompt fails or prints no answer
Symptoms:
prompt --stdinsays stdin is interactive.promptrefusesUnknown,PlanApprovalPrompt,DiffDialog,ExternalEditorActive, or an unsafe permission prompt.promptreports that Claude became ready but no new assistant transcript message was found.
Cause:
prompt is a guarded TUI workflow, not a headless claude -p wrapper. It needs real input, a Claude-owned pane, safe classified states, working tmux paste/send-keys support, and a fresh transcript message before it will print to stdout.
Fix:
botctl prompt --text "Say exactly hello"
printf 'Say exactly hello' | botctl prompt --stdin
botctl prompt --text "Say exactly hello" --no-yolo
Then inspect the left-running tmux session if needed:
botctl list --all
botctl doctor --pane %19
- Use
--textor pipe data when stdin is a terminal. - Run
botctl status --pane <session:window.pane>to inspect the classified state. - Review unsafe blockers manually;
--no-yolomakes supported blockers fail instead of auto-recovering. - If stale/no transcript output persists, attach to the tmux session and verify Claude wrote a response in the same workspace.
YOLO already active
Symptoms:
- Starting
yoloreports an existing YOLO registration or tracked pane.
Cause:
YOLO registrations are stored in the botctl state database. A previous loop may still be registered for the same pane or workspace.
Fix:
botctl yolo stop --pane %19
botctl yolo --pane %19
For workspace-scoped loops:
botctl yolo stop --all --workspace .
botctl yolo --all --workspace .
tmux problems
Symptoms:
- Pane lookup fails.
- Capture or send-keys errors mention tmux.
Cause:
The pane, window, or session may have been renamed or destroyed, or botctl may be looking at a different tmux server.
Fix:
tmux list-panes -a -F '#{pane_id} #{session_name}:#{window_index}.#{pane_index} #{pane_current_command} #{pane_current_path}'
botctl list --all
If the pane ID changed, rerun the botctl command with the new pane ID.
HTTP API browser request fails
Symptoms:
- Browser requests to
serve --httpfail with403. - A non-browser
curlrequest works.
Cause:
Browser access is allowed only for exact origins passed with --allowed-origin URL.
Fix:
botctl serve --session demo --http 127.0.0.1:8787 --allowed-origin http://localhost:3000
Use the exact scheme, host, and port that the browser sends in the Origin header.
When to stop and review manually
Always review manually when the state is:
UnknownPlanApprovalPromptDiffDialogExternalEditorActiveUserQuestionPrompt
Those states are refusals, not an invitation to guess.