Skip to main content

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:

  • doctor reports missing or invalid bindings.
  • Guarded workflows fail before any keypresses are sent.
  • install-bindings reports 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:

  1. Inspect the required map:

    botctl bindings
  2. Merge missing bindings when possible:

    botctl install-bindings
  3. If install still fails, fix the conflicting or invalid JSON manually.

  4. 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.
  • doctor shows command_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:

  1. List all panes:

    botctl list --all
  2. Target the actual Claude pane for Claude automation.

  3. Use the dashboard for passive OpenCode visibility or Codex screen-classified visibility:

    botctl dashboard

Stale observation

Symptoms:

  • status or serve reports Unknown unexpectedly.
  • 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:

  1. Re-run status with more history:

    botctl status --pane %19 --history-lines 240
  2. Re-run diagnostics on the explicit pane:

    botctl doctor --pane %19
  3. 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, retry submit-prompt.
  • If the state is SurveyPrompt, run dismiss-survey or retry submit-prompt and let preflight handle it.
  • If the state is ExternalEditorActive, finish the editor handoff manually or with editor-helper.
  • If the state is DiffDialog, review the diff manually.

prompt fails or prints no answer

Symptoms:

  • prompt --stdin says stdin is interactive.
  • prompt refuses Unknown, PlanApprovalPrompt, DiffDialog, ExternalEditorActive, or an unsafe permission prompt.
  • prompt reports 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 --text or pipe data when stdin is a terminal.
  • Run botctl status --pane <session:window.pane> to inspect the classified state.
  • Review unsafe blockers manually; --no-yolo makes 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 yolo reports 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 --http fail with 403.
  • A non-browser curl request 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:

  • Unknown
  • PlanApprovalPrompt
  • DiffDialog
  • ExternalEditorActive
  • UserQuestionPrompt

Those states are refusals, not an invitation to guess.