The server half shipped 2026-07-30 as feature A (4892fa7/f6ef19e/d39a0ab) and both native clients are at zero. This is NOT a regression — OrphanSessionInfo is deliberately a separate type rather than a flag on LiveSessionInfo, and src/server.ts:600 names the reason: the clients decode /live-sessions, so a variant shape there would have broken them. It is worth planning anyway because SessionManager.shutdown only detaches the tmux client for tmux-backed sessions (manager.ts:410-417), so a server restart or a desktop-app quit turns every session into an orphan. The web launcher lists them and re-adopts on tap; the phone still shows an empty list — which is the walk-away case this product exists for. The plan doc carries the eleven traps a client implementer will hit, each one a shipped review finding or a documented server subtlety — notably that preview returns cols/rows of literally 0 (both clients currently size thumbnails from that response), that a 429 must not collapse to "no orphans", and that the destructive confirmation must come from count-idle rather than card count (that one nearly ended 33 shells while the dialog said 24). Also corrects two now-false claims found while cross-referencing: the ROADMAP row for tmux discovery was half-stale, and ANDROID_CLIENT_PLAN's do-not-consume list still listed POST /projects/worktree (both clients consume it now) and GET /sessions (iOS consumes it, Android does not — so "match iOS" now argues for building it, not against).
11 KiB
Roadmap
Status (2026-07-13): ALL of Wave 1-5 (11 items) implemented + committed on
develop— see docs/PROGRESS_LOG.md for per-feature commits. Remaining: only the deferred backlog table (smaller, several now cheap on the shipped PTY-inject + approval-preview primitives).
Prioritized backlog of features to build next, derived from a grounded analysis of the codebase + the existing planning docs (5 exploration lenses → 24 candidates → this synthesis). Each item keeps what it touches (real files/subsystems) and a rough effort so it's actionable, not aspirational.
The throughline: the product already captures everything — Claude Code hooks, statusLine telemetry, the activity timeline, git diff, live-sessions — but under-acts on it. The highest-leverage work turns passive capture into a trustworthy remote review-and-drive surface, without touching the byte-shuttle. Two small primitives unlock a whole family of features: a server-side PTY-inject call and a preview on the approval bar.
Effort key: S ≈ 1–2 days · M ≈ 3–4 days · L ≈ 1–2 weeks. Order = suggested build sequence (dependencies noted).
Recently shipped (context)
- Split-grid watch board (v0.8, desktop) — 1×2/1×3/2×2/2×3 layouts, click-to-focus,
per-quadrant inline approve / maximize / read-only monitor, drag-to-quadrant,
resizable splitters, saved presets. (
public/grid-layout.ts,grid-presets.ts,cell-monitor.ts,tabs.ts.) - Fixed: browser worktree-create was 400ing (frontend sent
repoPath, server readspath); now aligned + regression-tested (public/projects.ts,test/worktree-form.test.ts).
Wave 1 — ship first (high-trust / high-delight, independent)
-
Approval preview — see-what-you-approve ⭐ (strongest) Show the pending
Bashcommand orEdit/Writediff above Approve/Reject, so remote one-tap approval stops being blind (today you could tap Approve onrm -rf build). The core walk-away trust gap. Touches:src/http/hook.ts(tool_inputis already parsed at:104— derive a bounded preview for Bash/Edit/Write/MultiEdit) →/hook/permission+pendingApprovalsinsrc/server.ts:423(attach + re-send to late joiners, likegatealready does) → optional boundedpreviewon thestatusServerMessage insrc/types.ts→manager→ approval bar inpublic/tabs.ts(reusepublic/diff.tsrenderer +sanitizeField). Pure side-channel. Effort: M. Risk: truncate + strip control chars + cap bytes,textContent/diff-render only, unknown tools fall back to today's name-only bar. -
Clickable URLs & file paths in the terminal Tap the dev-server URL or file path Claude prints instead of soft-keyboard copy gymnastics (paths reuse
POST /open-in-editor). TECH_DOC named@xterm/addon-web-linksin v0.2; never built. Touches: frontend only —public/terminal-session.ts(add the addon + a path-matcher regex →/open-in-editor). Zero server change. Effort: S.
Wave 2 — the unlocking primitive
- Server-side PTY-inject + queued follow-up prompt (unlocks a family)
A thin Origin/loopback-guarded route that writes text into a session's PTY, plus a
per-session queue that fires one entry when Claude goes idle ("now run the tests", then
"now open a PR"). Walk-away = give a task and leave; queuing lets the session advance itself.
Touches: new
POST /live-sessions/:id/queuecalling the existingwriteInput(src/session/session.ts:201); a small queue inmanager.ts; dequeue in the existing Stop/SessionEnd hook branch (src/server.ts:414); FE nearpublic/quick-reply.ts. Injection is identical to a keystroke → byte-shuttle preserved, broadcasts to mirrors. Effort: M. Risk: gate firing onclaudeStatus==='idle'+ settle delay; surface the queue in UI. Foundation for templated launches, auto-continue, issue-intake (backlog).
Wave 3 — read-only side-channel batch (review from the phone)
-
Diff against a base branch (
?base=<rev>) Review a whole agent branch vsmainbefore landing, not just uncommitted changes.src/http/diff.tsalready deferred this (FR-B1.9) and named its mitigation:git rev-parse --verifyallow-list before any revision reaches the CLI. Touches: optionalbaseongetDiff()(guardedgit rev-parse --verify <base>+ trailing--, thengit diff <base>...); branch-picker inpublic/diff.ts. Effort: S/M. -
PR + CI/checks status via
gh(read-only) Per-project/session chip: PR state · checks passing · mergeable — glance from the phone, re-engage only when red. Noghusage exists insrc/yet;ghemits JSON (no parsing pain). Touches: newsrc/http/gh.ts(mirrordiff.ts'srunGit);GET /projects/pr?path=guarded byisValidGitDir;PrStatusinsrc/types.ts; FE chip in project detail. Capability-probe + empty-degrade whenghabsent/unauthed. Effort: M. -
Quick wins (small, cheap, high-delight)
- Sync chip on project cards — ahead/behind + last-commit, folded into the existing
per-repo metadata pass in
src/http/projects.ts(no new route). S. - Cost budget guard + push alert —
costUsdalready flows via statusLine (handleStatusLine); addCOST_BUDGET_USD+ a one-shot latch (likestuckNotified) + warn styling inpublic/preview-grid.ts. The rail that makes unattended auto-continue safe. S–M. - "While you were away" reconnect digest — read-side aggregate over
manager.list()- telemetry/timeline/status → "3 done, 1 waiting, $6, 2 PRs" on reconnect. S–M.
- Recent-commits log per project —
git log --oneline -n N(NUL-delimited) via a guardedGET /projects/log; inert-text render. S–M.
- Sync chip on project cards — ahead/behind + last-commit, folded into the existing
per-repo metadata pass in
Wave 4 — close the git loop
-
Worktree lifecycle: remove / prune (create is now fixed) Delete losing worktrees + land the winner from any device — closes the create-only loop. Touches:
removeWorktree/pruneWorktreesinsrc/http/worktrees.ts(same execFile no-shell + timeout, validate target ingit worktree list& not main, reuse realpath containment);DELETE /projects/worktree+POST /projects/worktree/prune(Origin-guarded); make the existinglocked/prunabletags actionable. Effort: S–M. Risk: destructive — require--force+ confirm for dirty trees, reject the main worktree, safe error messages. -
Stage / commit / push from the diff viewer Claude's done, you reviewed on the phone — now commit + push without typing git into a mobile terminal. Highest-risk git write; bound the MVP to per-file stage-toggle + commit + push-current-branch only; defer discard/checkout; realpath-contain paths, cap msg length, push only to existing upstream or
-u, CSRF-guarded. Effort: M–L.
Wave 5 — bigger bets
-
Worktree fan-out board (the north star: 真并行不互踩) Fan one task across N branch/agent lanes of one repo, watch them race, approve/kill per lane, keep the winner. Mostly composition of shipped parts —
createWorktree+ live-sessions + the split-grid watch board + statusLine gauges + per-quadrant inline approve; server side is a thin "sessions grouped by repo/worktree" endpoint. Cost is UI. Effort: L. Depends on Wave 4. -
App-level access token (leave-the-LAN bar-raiser) — shipped on
developA constant-time-compared (crypto.timingSafeEqualover SHA-256, fixed-length guard)WEBTERM_TOKENchecked on the WS handshake (alongside, not replacing, Origin) + a central gate over every remote HTTP route, set as anHttpOnly; SameSite=Strict; Secure-when-httpscookie after one-timeGET /?token=orPOST /auth(rate-limited 10/min/IP), disabled when unset (keeps LAN zero-config byte-identical). Charset/length-validated at load; loopback/hook*ingest exempt.src/http/auth.ts+ wiring insrc/server.ts. Honest tradeoff: a bar-raiser, not a TLS/Tailscale substitute — on barews://the token is cleartext and replayable; only hardens the TLS-terminated relay/tunnel path. Effort: M. -
Android Projects / Diff / Worktree screens (client parity) Android's whole v0.6/v0.7 projects-git UI is SDK-gated/off in
settings.gradle.kts. Zero server change (the:api-clientmodule already speaks the endpoints), but the largest scope. Sequence after the server-side git features so it's one parity pass. Effort: L.
Deferred backlog (your own recorded intent, surfaced from the docs)
Consciously punted in the planning docs; several become cheap once the two unlocking primitives (PTY-inject, approval-preview) land.
| Feature | Deferred in | Note |
|---|---|---|
| Line-level review comments → agent | FEATURE_WALKAWAY_WORKBENCH.md §B1.6 / US-B1.4 |
Tap a diff line, type feedback, composed with file:line and sent via TerminalSession.send. No new route. Pairs with diff-vs-base. M. |
| GitHub issue → new session/worktree | FEATURE_PROJECT_MANAGER.md §9 |
Pick an issue → spawn a session (optionally fresh worktree) with title+body as the prompt. Rides PTY-inject + host gh. Treat issue text as untrusted bytes. M. |
| Templated one-tap launches (repo + prompt + mode) | implied by attach.cwd + Projects launchers |
"Triage repo X in plan mode" as one tap. Rides PTY-inject + a template store. M. |
| Auto-continue on idle (bounded) | no idle automation today | Opt-in auto-inject "continue" up to N times under a cost ceiling. Rides PTY-inject + budget guard. Build last, low default cap, never auto-approve. S–M. |
| Cross-session cost rollup / trends | FEATURE_WALKAWAY_WORKBENCH.md §B2.6 |
Bounded ring beside the latest-only field + GET /telemetry/summary + dashboard panel. Overlaps the budget-guard quick win. M. |
| Mission Control: cross-session feed + durable run log | (no cockpit persistence today) | Merged reverse-chron feed + append-only on-disk tail (reuse subscription-store.ts JSONL/atomic write, byte-capped) so overnight runs survive restart. The "while you were away" digest is its first slice. M–L. |
| Per-project task backlog | task tracking unbuilt | Per-repo TODO store mirroring prefs-store.ts; one tap spawns Claude pre-filled. Local state, not a GitHub Issues sync (YAGNI). M. |
| Host tmux session discovery + attach | user request (this is not raw-iTerm; needs tmux) | Half shipped 2026-07-30 as feature A (4892fa7/f6ef19e/d39a0ab): the server enumerates its own untracked web_<id> tmux sessions (GET /orphan-sessions + 4 routes) and the web launcher shows them in a "可恢复" section — one tap re-adopts via the existing attach(id) path. Remaining (a) — iOS + Android consume it: see plans/w7-orphan-session-clients.md. M. Remaining (b) — the original ask, still unbuilt: foreign tmux sessions (manual/iTerm, not named web_*) are still invisible; feature A deliberately only catalogues our own. S–M. |
Kept in sync by the maintainer. Ideas are grounded against the code as of develop — verify
file/line references before starting (they drift).