| name | debug-pane |
| description | Snapshot a channelhub session's tmux pane PLUS its recent autopilot errors and registry state in one structured dump. Use when the user reports an autopilot/permission/spawn problem on a specific session, or when you need fast forensic context before forming a hypothesis. |
Debug a channelhub session
Replaces the manual 4-tool dance (tmux capture-pane, sqlite3, grep sessions.json, grep daemon log) with one structured collection step. Use
this BEFORE proposing any fix.
Inputs
You need: session name (e.g. sap, ap-test, eticket-v3). The user
usually says it; if not, ask once. Run tmux ls | grep ^hub- to see what's
live.
Procedure
NAME="<session-name>"
TMUX="hub-${NAME}"
echo "=== 1. Visible pane (no scrollback) ==="
tmux capture-pane -t "${TMUX}" -p 2>&1 | tail -40
echo
echo "=== 2. Pane WITH scrollback (200 lines) — for /btw history forensics ==="
tmux capture-pane -t "${TMUX}" -p -S -200 2>&1 | tail -60
echo
echo "=== 3. Registry state (~/.claude/channels/hub/sessions.json) ==="
python3 -c "
import json
with open('$HOME/.claude/channels/hub/sessions.json') as f: m = json.load(f)
for k,v in m.items():
if v.get('name') == '${NAME}':
print(f' path: {k}')
print(json.dumps(v, indent=2))
break
else:
print(' NOT REGISTERED')
"
echo
echo "=== 4. Last 5 autopilot errors for this session ==="
sqlite3 "$HOME/.claude/channels/hub/errors.sqlite" \
"SELECT id, datetime(ts/1000,'unixepoch','localtime') AS when_, status, reason, length(captured_pane) AS pane_len, duration_ms FROM autopilot_errors WHERE session_name = '${NAME}' ORDER BY ts DESC LIMIT 5" 2>/dev/null \
|| echo " errors.sqlite not present or no rows"
echo
echo "=== 5. Last 30 daemon log lines mentioning this session ==="
tmux capture-pane -t hub-daemon -p -S -300 2>&1 | grep -E "${NAME}|/$(basename ${NAME})" | tail -30
Analyze
After the dump, work top-down:
| Step | What you're looking for |
|---|
| 1 | Is Claude idle (❯ prompt + ? for shortcuts)? Or stuck on a permission menu (❯ 1. Yes)? Or showing esc to interrupt (busy)? |
| 2 | Stale /btw overlays in scrollback — if the parser sees these without our recent fix, it returns OLD answers. Identify any ↑/↓ to scroll footers that are NOT in the visible pane. |
| 3 | autopilot.enabled? trust level? priorTrust set? riskOverride? |
| 4 | Most recent failure status. If parse_error, retrieve the full captured_pane: sqlite3 ... "SELECT captured_pane FROM autopilot_errors WHERE id = N" |
| 5 | Daemon's view — did /btw fire? what's the timing? any permission_request storm? |
Reply to the user
Lead with the diagnosis, not the data dump. Format:
🔍 sap diagnosis
- Session state: [idle | stuck on permission | mid-task]
- Autopilot: [on/off, trust=X, started Nm ago]
- Last 3 autopilot results: [answered | parse_error | timeout | escalate]
- Hypothesis: <one sentence>
- Smoking gun: <file:line OR captured_pane snippet>
Then offer the next step (fix / continue investigating / ask for clarification).
Don't
- Don't dump all 5 sections to the user verbatim — that's noise. They want the
diagnosis. Keep raw data behind a collapsed code block at most.
- Don't propose a fix in the same message — separate diagnosis from action so
the user can reject the hypothesis cheaply.
- Don't include
captured_pane blobs in chat (they can be 100KB+). Reference
the row id and let the user query if they want it.