diff --git a/docs/NEXT-STEPS.md b/docs/NEXT-STEPS.md new file mode 100644 index 0000000..4b6c1be --- /dev/null +++ b/docs/NEXT-STEPS.md @@ -0,0 +1,127 @@ +# Next Steps — Resume Pointer + +> **Last updated:** 2026-05-15, end of day. +> **Where we are:** Phase 0 + 0.5 done. Phase 1 doc updated for Path B. +> **Where we go next:** Freeze interface contracts, then T-1.0. + +This document is the "where did I leave off" anchor. Read this first when +resuming work. The rest of `docs/` is reference. + +--- + +## State at end of session + +| Item | Status | +|---|---| +| Phase 0 — Stream Spike | ✅ done. Verdict GREEN with caveat (pipe-pane unreliable). Branch `feat/spike-stream` kept. | +| Phase 0.5 — Control-Mode Spike | ✅ done. Verdict: **Path B — tmux control mode**. Branch `feat/spike-tmux-cc` kept. | +| Phase 1 plan | ✅ updated to Path B. T-1.1 now specifies control mode + `%output` parser. Architecture diagram, risks (R4 + R5) added. | +| Interface Contracts (IC-1..IC-4) | ⚠️ **draft**. Need orchestrator sign-off before T-1.5 / fan-out. | +| Phase 1 implementation | ⛔ not started. T-1.0 is the next dispatch. | +| iOS work | blocked, untouched. | + +Branches on remote `git.vpsj.de/jay/pi-remote-control`: +- `main` — has all docs, no implementation changes yet. +- `feat/spike-stream` — Phase 0 PoC, throwaway. +- `feat/spike-tmux-cc` — Phase 0.5 PoC, throwaway. Reference impl for T-1.1. + +--- + +## Orchestrator todo list (in order) + +These are things only the orchestrator does — not delegatable to a worker +subagent. + +### 1. Freeze interface contracts + +Open `PHASE-1-sidecar.md` §Interface Contracts and re-read IC-1..IC-4. +For each: does it still look right after the spikes? Anything to tweak? + +Things to double-check: +- **IC-1 ClientToServer**: do we want to add `{ type:"resize"; cols:int; rows:int }` so iPad-Landscape can renegotiate tmux pane size? (Spec said fixed 120×40, but if we ever want elastic, this is the place.) Recommendation: defer, fix at 120×40 for v1, revisit only if it bites. +- **IC-1 ServerToClient**: `tree` event — gruppe T is out of iOS scope, so this can be dropped from the contract OR kept as "reserved, server may emit but client ignores". Recommendation: drop to keep contract tight. +- **IC-2 REST shape**: `/sessions/:id/thumbnail` is referenced by iOS-D-01c (Phase 3). Should the endpoint return raw text/plain capture, or a structured JSON `{cols,rows,lines:[…]}`? Recommendation: raw text/plain — simpler, smaller, client parses lines itself. +- **IC-3 pairing**: `deviceToken` and `environment` are now mandatory in Phase 2. Pre-Phase-2 they're optional. Mark accordingly. +- **IC-4 TOML config**: `[apns]` section can have an `environment_default` for testing convenience? Probably no — environment is per-device. Leave as-is. + +After review: +- Edit `SYNC.md` "Frozen Interface Contracts" table: set Status `frozen` and fill `Frozen at` date. +- Commit on main. + +### 2. Dispatch T-1.0 — Server Refactor + +Single agent, blocking everyone else. Refactor existing +`extensions/remote-control/server.ts` (335 lines) and friends into the +modular layout from `PHASE-1-sidecar.md` §Architecture Sketch. + +Prompt template (adapt with concrete contract numbers): + +``` +# Task: Phase 1 T-1.0 — Server Refactor + +Working dir: /Users/jay/.pi/agent/git/git.vpsj.de/jay/pi-remote-control + +Read first: +- docs/NEXT-STEPS.md (state of play) +- docs/PHASE-1-sidecar.md §Architecture Sketch and §Task Breakdown row T-1.0 +- docs/SYNC.md (claim the task) +- existing code: extensions/remote-control/{index,server,html,messages,auth,config}.ts + +Goal: +- Carve existing server.ts into the server/ + server/routes/ + server/upgrade.ts + structure from the phase doc. +- Keep the LEGACY HTML client (html.ts) working end-to-end. Add comments + tagging these legacy paths. +- No new features. No new endpoints. Just structural refactor + ensure + existing tests / smoke usage still works. +- After your refactor lands, the directory layout matches the Phase-1 + Architecture Sketch. + +Out of scope: anything touching tmux/, buffer/, pi/, auth/{pairing,tls}.ts, +apns/, cli/. Those are for later T-1.* tasks. + +Branch: feat/p1-t1-0-server-refactor +``` + +After T-1.0 merges into main, the parallel fan-out becomes available. + +### 3. Plan the parallel fan-out + +Once T-1.0 is in main: +- 5 worker dispatches in parallel: T-1.1, T-1.2, T-1.3, T-1.4, T-1.10. +- Each gets a tight prompt referencing their row in `PHASE-1-sidecar.md` + and the relevant frozen ICs. +- T-1.1 explicitly says: use control mode, reference `spike-cc.ts` on + `feat/spike-tmux-cc`, follow R-CC-1..R-CC-5 expectations. + +T-1.5, T-1.6, T-1.7 follow as their deps come in. + +--- + +## Reading order for resumption + +1. `docs/NEXT-STEPS.md` (this file) +2. `docs/SYNC.md` — current claims, gate, contracts +3. `docs/PHASE-1-sidecar.md` — what to build +4. `docs/reference/PHASE-0-report.md` and `PHASE-0.5-report.md` — why we're + building it this way +5. Spec only if you forget the why: `docs/reference/SPEC-ios-app.md` + +--- + +## Open questions for next session + +- **OQ-1.** Drop the `tree` event from IC-1 ServerToClient, or keep reserved? (Recommendation: drop.) +- **OQ-2.** Resize message in IC-1? (Recommendation: defer.) +- **OQ-3.** Should `tmux/manager.ts` use a single long-lived control-mode connection per **server**, or per **session**? The spike used per-session for simplicity. Per-server scales better but is more code. Decide before T-1.1 starts. +- **OQ-4.** Worker for T-1.0: same `anthropic/claude-sonnet-4-5`, or escalate to a higher-context model since the refactor touches multiple files? (Recommendation: sonnet-4-5 with `context: fresh` is fine for ~500 LoC refactor.) + +--- + +## Don't do tomorrow + +- Don't merge the spike branches into main. They're reference, not code. +- Don't start T-1.1 before T-1.0 is in main. +- Don't start any iOS task until Phase 1 is at least feature-complete. +- Don't expand scope. Stick to v3 spec; new ideas go into a v4 review + round, not into open PRs. diff --git a/docs/PHASE-1-sidecar.md b/docs/PHASE-1-sidecar.md index 98fcaf6..e2800c9 100644 --- a/docs/PHASE-1-sidecar.md +++ b/docs/PHASE-1-sidecar.md @@ -6,6 +6,13 @@ > stream (see `SYNC.md`). > **Spec reference:** [`reference/SPEC-ios-app.md`](./reference/SPEC-ios-app.md) §4. +> **Streaming primitive (decided in Phase 0.5):** tmux **control mode** +> (`tmux -C attach`). Pane output is delivered via parsed `%output` +> events, which is robust across alternate-screen transitions — unlike +> `pipe-pane` (which Phase 0 found unreliable). See +> `reference/PHASE-0.5-report.md` and the spike code in branch +> `feat/spike-tmux-cc`. + ## Goal The `pi-remote-control` extension is extended into a full sidecar that can @@ -54,10 +61,10 @@ extensions/remote-control/ │ │ ├── side.ts — S-07 state side-channel │ │ └── health.ts — S-12 health │ └── upgrade.ts — WS upgrade routing per session/topic -├── tmux/ — NEW: tmux wrapper -│ ├── manager.ts — spawn/list/kill, metadata via @options -│ ├── pipe.ts — pipe-pane, FIFO read, byte streaming -│ ├── input.ts — send-keys translation +├── tmux/ — NEW: tmux wrapper (control-mode client) +│ ├── manager.ts — spawn/list/kill sessions, metadata via @options +│ ├── control.ts — `tmux -C` control-mode client, %output parser, byte streaming +│ ├── input.ts — send-keys translation (key names → tmux send-keys) │ └── snapshot.ts — capture-pane wrapper ├── buffer/ — NEW: disk ringbuffer per session │ ├── writer.ts — append, cap enforcement, watchdog @@ -88,7 +95,7 @@ column lists the files an agent may modify. | ID | Task | Touches | Depends on | Parallel With | |---|---|---|---|---| | T-1.0 | **Server refactor scaffold.** Carve `server.ts` into the `server/` and route modules above; existing HTML behaviour must still work; CI green. | `extensions/remote-control/server/**`, minimal edit of `index.ts` | — | none — must land first | -| T-1.1 | **tmux/manager + tmux/pipe + tmux/snapshot.** Spawn, list, kill, metadata via `@description`. Pipe-pane FIFO reader. Snapshot via `capture-pane`. | `tmux/**` | T-1.0 | T-1.2, T-1.3, T-1.4, T-1.5, T-1.6 | +| T-1.1 | **tmux/manager + tmux/control + tmux/snapshot.** Spawn, list, kill, metadata via `@description`. **Control-mode client** (`tmux -C attach`), `%output` parser with octal-escape decoder, broadcast bytes to subscribers. Snapshot via `capture-pane`. Reference: `feat/spike-tmux-cc` branch (`spike-cc.ts`). | `tmux/**` | T-1.0 | T-1.2, T-1.3, T-1.4, T-1.5, T-1.6 | | T-1.2 | **Sequence module + buffer/writer + buffer/reader.** Monotone chunk IDs, disk ringbuffer with caps (100MB/session, 1GB global, free-space watchdog), idle-cleanup. | `sequence.ts`, `buffer/**` | T-1.0 | T-1.1, T-1.3, T-1.4, T-1.5, T-1.6 | | T-1.3 | **Auth: tokens + pairing + TLS.** Self-signed cert generation, fingerprint, bearer-token CRUD, `pi-remote pair` CLI + QR rendering, `pi-remote auth list/revoke/name`. | `auth/**`, `cli/index.ts` (subcommands only) | T-1.0 | T-1.1, T-1.2, T-1.4, T-1.5, T-1.6 | | T-1.4 | **pi adapter.** Subscribe ExtensionAPI events, expose `getCommands`, implement `autoname.ts` spawning `pi -p`. | `pi/**`, edits in `index.ts` to wire subscriptions | T-1.0 | T-1.1, T-1.2, T-1.3, T-1.5, T-1.6 | @@ -212,6 +219,15 @@ Owner: T-1.7. `pi/events.ts`. - **R3.** `pi -p` auto-name calls cost money. Mitigation: gate behind `[autoname] enabled`, debounce, skip if user already named the session. +- **R4.** tmux control-mode protocol is text-framed; binary pane bytes are + octal-escaped (`\NNN`). Parser must handle high-throughput bursts (~50fps + during tool output). Mitigation: streaming line-parser with no full-buffer + copies; per-line decode allocates only the escaped payload. Reference + decode in `spike-cc.ts`. +- **R5.** tmux version requirement. Control mode is stable from tmux 2.0; + modern features (e.g. `pane-died` event) need 2.5+. Mitigation: + `tmux/manager.ts` checks `tmux -V` at startup, refuses to run on < 2.5 + with a clear error. ## Exit / Handover diff --git a/docs/README.md b/docs/README.md index dc09a84..bad2ceb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,8 +4,11 @@ This folder drives the implementation work for the pi-remote iOS app and its sidecar. Background / spec / audit material lives in [`reference/`](./reference/). +**Start here when resuming work:** [`NEXT-STEPS.md`](./NEXT-STEPS.md). + | File | Purpose | |---|---| +| [`NEXT-STEPS.md`](./NEXT-STEPS.md) | Resume pointer — state of play, next orchestrator actions, open questions. Read first. | | [`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. | diff --git a/docs/SYNC.md b/docs/SYNC.md index c0507d7..ca56ea6 100644 --- a/docs/SYNC.md +++ b/docs/SYNC.md @@ -78,7 +78,7 @@ add a row or open a Contract Change Request. | `extensions/remote-control/index.ts` | T-1.0, T-1.4 (events wiring only) | | `extensions/remote-control/server.ts` (legacy) | nobody after T-1.0; legacy frozen | | `extensions/remote-control/server/**` | T-1.0 (refactor), T-1.5, T-1.6, T-1.7 | -| `extensions/remote-control/tmux/**` | T-1.1 | +| `extensions/remote-control/tmux/**` | T-1.1 (control mode, not pipe-pane — see Phase 0.5) | | `extensions/remote-control/buffer/**` | T-1.2 | | `extensions/remote-control/sequence.ts` | T-1.2 | | `extensions/remote-control/auth/**` | T-1.3, T-1.10 (device tokens only) | @@ -97,13 +97,18 @@ Phase 2 kicks off. ## Frozen Interface Contracts -| ID | Defined in | Owner of changes | -|---|---|---| -| IC-1 — WebSocket frame protocol | `PHASE-1-sidecar.md` §Interface Contracts | T-1.5 lead, with sign-off from any active T-2.x owner | -| IC-2 — HTTP REST shape | `PHASE-1-sidecar.md` §Interface Contracts | T-1.5..T-1.7 leads | -| IC-3 — Pairing payload | `PHASE-1-sidecar.md` §Interface Contracts | T-1.3 lead | -| IC-4 — Config TOML schema | `PHASE-1-sidecar.md` §Interface Contracts | T-1.7 lead | -| IC-2.1 — `SessionConnection` Swift surface | `PHASE-2-ios-mvp.md` §Interface Contracts | T-2.5 lead | +| ID | Defined in | Status | Frozen at | Owner of changes | +|---|---|---|---|---| +| IC-1 — WebSocket frame protocol | `PHASE-1-sidecar.md` §Interface Contracts | **draft** — needs orchestrator sign-off before T-1.5 starts | — | T-1.5 lead, with sign-off from any active T-2.x owner | +| IC-2 — HTTP REST shape | `PHASE-1-sidecar.md` §Interface Contracts | **draft** | — | T-1.5..T-1.7 leads | +| IC-3 — Pairing payload | `PHASE-1-sidecar.md` §Interface Contracts | **draft** | — | T-1.3 lead | +| IC-4 — Config TOML schema | `PHASE-1-sidecar.md` §Interface Contracts | **draft** | — | T-1.7 lead | +| IC-2.1 — `SessionConnection` Swift surface | `PHASE-2-ios-mvp.md` §Interface Contracts | **draft** — freeze at Phase 2 kickoff | — | T-2.5 lead | + +**Freeze protocol:** when the orchestrator is ready to fan out work that +depends on a contract, they (a) re-read the contract spec, (b) update the +Status column to `frozen` and fill in the `Frozen at` date, (c) commit +that change to main. After that, modifications require a CCR. Once a contract is *frozen* (i.e. at least one consumer task has started work that depends on it), changes require a CCR.