From 307417b392353a0020f8c1cbe3cd186d652b39df Mon Sep 17 00:00:00 2001 From: jay Date: Fri, 15 May 2026 04:06:25 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20add=20Phase=200.5=20=E2=80=94=20spike?= =?UTF-8?q?=20tmux=20control=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 0 found that tmux pipe-pane is unreliable across alternate-screen transitions. Before Phase 1 commits to a streaming primitive, a short follow-up spike evaluates tmux control mode (`tmux -CC`) as an alternative to pipe-pane + watchdog. Verdict drives T-1.1 design. --- docs/PHASE-0.5-spike-tmux-control-mode.md | 135 ++++++++++++++++++++++ docs/README.md | 5 +- docs/SYNC.md | 5 +- 3 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 docs/PHASE-0.5-spike-tmux-control-mode.md diff --git a/docs/PHASE-0.5-spike-tmux-control-mode.md b/docs/PHASE-0.5-spike-tmux-control-mode.md new file mode 100644 index 0000000..2b1940d --- /dev/null +++ b/docs/PHASE-0.5-spike-tmux-control-mode.md @@ -0,0 +1,135 @@ +# 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 that `tmux pipe-pane` is 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 to `0`. 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-cc` with 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 `%output` + events from the pi pane. + - Streams those bytes to stdout (no WebSocket needed for the spike — + raw stdout is fine). +- A test session that triggers the Phase-0 failure mode: + 1. Pi running normally → bytes flow. + 2. User runs `/settings` (alternate-screen) → bytes still flow. + 3. User exits settings → bytes still flow. + 4. Run for ≥5 minutes with mixed interactions. +- Report `docs/reference/PHASE-0.5-report.md` answering: + - **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 attach` SSH 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 `%output` + events is enough. + +## Implementation Notes + +- tmux control mode launch: + ```bash + tmux -CC new-session -s pi-cc 'pi' + ``` + or attach to an existing detached session: + ```bash + 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 ` 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 ` … `%end `. +- Parse just `%output` lines, decode the octal escapes (`\NNN` in 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: +1. Terminal A: `npm run spike-cc` (your spike runner). +2. Terminal B: `tmux attach -t pi-cc` — verify normal SSH-style attach + still works alongside the control client. +3. 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.md` T-1.1 to specify tmux control mode in + `tmux/pipe.ts`. + - **If Path A:** same, but specifying pipe-pane + watchdog. + +In either case, do **not** modify `PHASE-1-sidecar.md` yourself — +that's an orchestrator-level edit and triggers a contract change +review. diff --git a/docs/README.md b/docs/README.md index fc7ae08..dc09a84 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,8 +6,9 @@ its sidecar. Background / spec / audit material lives in | File | Purpose | |---|---| -| [`PHASE-0-spike-stream.md`](./PHASE-0-spike-stream.md) | Stream PoC — verify tmux + pipe-pane + WebSocket. ~1 day, single agent. | -| [`PHASE-1-sidecar.md`](./PHASE-1-sidecar.md) | Sidecar production-ready: all S-features, multi-agent parallel work. | +| [`PHASE-0-spike-stream.md`](./PHASE-0-spike-stream.md) | Stream PoC — verify tmux + pipe-pane + WebSocket. ~1 day, single agent. **Done**, see `reference/PHASE-0-report.md`. | +| [`PHASE-0.5-spike-tmux-control-mode.md`](./PHASE-0.5-spike-tmux-control-mode.md) | Follow-up spike: tmux control mode (`-CC`) vs pipe-pane + watchdog. Decides Phase 1 streaming path. ~2h, single agent. | +| [`PHASE-1-sidecar.md`](./PHASE-1-sidecar.md) | Sidecar production-ready: all S-features, multi-agent parallel work. Blocked on Phase 0.5. | | [`PHASE-2-ios-mvp.md`](./PHASE-2-ios-mvp.md) | iOS app MVP — Groups A, B, C-01/02, D, E, F. Multi-agent parallel. | | [`PHASE-3-ios-augmentation.md`](./PHASE-3-ios-augmentation.md) | iOS feature polish — slash palette, voice, thumbnails, search, etc. | | [`SYNC.md`](./SYNC.md) | Live multi-agent coordination — claims, file ownership, contract changes. | diff --git a/docs/SYNC.md b/docs/SYNC.md index 1965777..32495fd 100644 --- a/docs/SYNC.md +++ b/docs/SYNC.md @@ -36,8 +36,9 @@ The point: no central scheduler is required. A short structured edit on | Phase | Status | Notes | |---|---|---| -| Phase 0 — Spike Stream | done | ✅ GREEN LIGHT. See `reference/PHASE-0-report.md`. pipe-pane reliability issue noted. | -| Phase 1 — Sidecar | ready to start | Recommend node-pty over pipe-pane based on Phase 0 findings. | +| Phase 0 — Spike Stream | done | ✅ GREEN LIGHT with caveat: pipe-pane unreliable. See `reference/PHASE-0-report.md`. | +| Phase 0.5 — Spike tmux Control Mode | ready to start | Decides streaming path before Phase 1. See `PHASE-0.5-spike-tmux-control-mode.md`. | +| Phase 1 — Sidecar | blocked on Phase 0.5 | Streaming path must be decided before T-1.1 starts. | | Phase 2 — iOS MVP | blocked on Phase 1 | Sidecar must be reachable and stable. | | Phase 3 — iOS Augmentation | blocked on Phase 2 | Continuous after MVP ships. |