docs: add Phase 0.5 — spike tmux control mode
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.
This commit is contained in:
parent
d97bd4aeef
commit
307417b392
|
|
@ -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 <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>`.
|
||||||
|
- 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.
|
||||||
|
|
@ -6,8 +6,9 @@ its sidecar. Background / spec / audit material lives in
|
||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|---|---|
|
|---|---|
|
||||||
| [`PHASE-0-spike-stream.md`](./PHASE-0-spike-stream.md) | Stream PoC — verify tmux + pipe-pane + WebSocket. ~1 day, single agent. |
|
| [`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-1-sidecar.md`](./PHASE-1-sidecar.md) | Sidecar production-ready: all S-features, multi-agent parallel work. |
|
| [`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-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. |
|
| [`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. |
|
| [`SYNC.md`](./SYNC.md) | Live multi-agent coordination — claims, file ownership, contract changes. |
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,9 @@ The point: no central scheduler is required. A short structured edit on
|
||||||
|
|
||||||
| Phase | Status | Notes |
|
| Phase | Status | Notes |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Phase 0 — Spike Stream | done | ✅ GREEN LIGHT. See `reference/PHASE-0-report.md`. pipe-pane reliability issue noted. |
|
| Phase 0 — Spike Stream | done | ✅ GREEN LIGHT with caveat: pipe-pane unreliable. See `reference/PHASE-0-report.md`. |
|
||||||
| Phase 1 — Sidecar | ready to start | Recommend node-pty over pipe-pane based on Phase 0 findings. |
|
| 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 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. |
|
| Phase 3 — iOS Augmentation | blocked on Phase 2 | Continuous after MVP ships. |
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue