5.2 KiB
Phase 0.5 — Spike: tmux Control Mode
Status: ready to start. Owner: single agent, end-to-end. Branch:
feat/spike-tmux-cc. Estimated effort: ~2 hours. Trigger: Phase 0 found thattmux pipe-paneis not reliable across alternate-screen transitions. This phase evaluates the alternative.
Background
Phase 0 (PHASE-0-spike-stream.md, report at
docs/reference/PHASE-0-report.md) validated the high-level design:
pi-in-tmux works, ANSI streaming over WebSocket works, latency is
excellent, SSH and WS stay in sync.
But: tmux pipe-pane is fragile. After alternate-screen usage
(/settings, full-screen menus) the pipe can detach silently; the
client sees a frozen stream. This is a Phase-1-blocker for the
tmux/pipe.ts task.
Two known alternatives:
- (A) Keep pipe-pane, add a watchdog that polls
#{pane_pipe}and re-arms when it falls to0. Simple but races: bytes produced between detach and detection are lost. - (B) Use tmux control mode (
tmux -CC). tmux exposes a structured event stream to a control client; pane output arrives as framed events. This is the protocol iTerm2 uses for its tmux integration. Multi-client attach still works for normal SSH users.
This spike decides between A and B with evidence.
Goal
Verify that tmux control mode can reliably deliver pane bytes to a Node client across the conditions where pipe-pane fails. Produce a short report and a Go decision for one of the two paths.
Acceptance Criteria
- A new branch
feat/spike-tmux-ccwith throwaway PoC code. - A Node script that:
- Spawns a tmux session running
pi. - Connects to that session as a control client (
tmux -CC). - Parses the control-mode protocol enough to extract
%outputevents from the pi pane. - Streams those bytes to stdout (no WebSocket needed for the spike — raw stdout is fine).
- Spawns a tmux session running
- A test session that triggers the Phase-0 failure mode:
- Pi running normally → bytes flow.
- User runs
/settings(alternate-screen) → bytes still flow. - User exits settings → bytes still flow.
- Run for ≥5 minutes with mixed interactions.
- Report
docs/reference/PHASE-0.5-report.mdanswering:- R-CC-1. Does control mode deliver pane output reliably across alternate-screen transitions?
- R-CC-2. Latency compared to pipe-pane (rough — same order of magnitude is enough)?
- R-CC-3. Does a parallel
tmux attachSSH client still work while a control-mode client is connected? (P-2 critical.) - R-CC-4. Is the control-mode protocol parser non-trivial? Order of complexity estimate.
- R-CC-5. Verdict: Path B (control mode) or Path A (pipe-pane + watchdog) for Phase 1, with reasoning.
Out of Scope
- No WebSocket layer (raw stdout suffices to prove the streaming).
- No reconnect, sequence, snapshot, buffer.
- No send-keys.
- No reuse of Phase-0 spike code — start clean.
- No production-quality parser — minimal viable parser for
%outputevents is enough.
Implementation Notes
- tmux control mode launch:
or attach to an existing detached session:tmux -CC new-session -s pi-cc 'pi'tmux new-session -d -s pi-cc 'pi' tmux -CC attach -t pi-cc - Control-mode protocol overview (consult
man tmux, search "CONTROL MODE"):- Server emits lines like
%output %1 <octal-escaped-bytes>for pane output. - Other events:
%session-changed,%window-add,%begin/%end,%layout-change, etc. — most can be ignored for the spike. - Client sends regular tmux commands as plain text; replies are
framed by
%begin <ts> <num> <flags>…%end <ts> <num> <flags>.
- Server emits lines like
- Parse just
%outputlines, decode the octal escapes (\NNNin tmux's output → bytes), write bytes to stdout. - Spawn tmux as a child process from Node, talk via stdin/stdout pipes.
File Plan
- New:
extensions/remote-control/spike-cc.ts(or.js, whichever is faster). ~100–200 lines. - New:
docs/reference/PHASE-0.5-report.md. - No changes to Phase-0 spike files.
Test Protocol (the spike's own QA)
Run for ≥ 5 minutes, in parallel:
- Terminal A:
npm run spike-cc(your spike runner). - Terminal B:
tmux attach -t pi-cc— verify normal SSH-style attach still works alongside the control client. - Terminal A side: confirm bytes keep flowing through these events:
- Type a prompt and let pi respond.
- Run
/settings, navigate around, exit. - Run a longer pi tool call.
- Resize Terminal B and observe whether the stream stays clean.
If at any point bytes stop flowing without an obvious tmux process exit: the spike failed for Path B and the verdict is Path A.
Exit / Handover
- Push branch, push report.
- Update
docs/SYNC.md:- Remove your active claim.
- History entry.
- Phase Gate Table: Phase 0.5 →
done, with verdict noted.
- Based on verdict:
- If Path B: open follow-up note in SYNC about updating
PHASE-1-sidecar.mdT-1.1 to specify tmux control mode intmux/pipe.ts. - If Path A: same, but specifying pipe-pane + watchdog.
- If Path B: open follow-up note in SYNC about updating
In either case, do not modify PHASE-1-sidecar.md yourself —
that's an orchestrator-level edit and triggers a contract change
review.