Files
web-terminal/docs/ROADMAP.md
Yaojia Wang ca9eaa8f1f
Some checks failed
ios / package-tests (APIClient) (push) Has been cancelled
ios / package-tests (HostRegistry) (push) Has been cancelled
ios / package-tests (SessionCore) (push) Has been cancelled
ios / package-tests (WireProtocol) (push) Has been cancelled
ios / testsupport-tests (push) Has been cancelled
ios / app-tests (push) Has been cancelled
ios / ipad-tests (push) Has been cancelled
ios / integration-tests (push) Has been cancelled
ios / ui-test (push) Has been cancelled
ios / ios17-floor-tests (push) Has been cancelled
relay-tripwire / cross-tenant-tripwire (push) Has been cancelled
docs: mark all of Wave 5 done (fan-out, access token, android parity)
2026-07-13 05:59:29 +02:00

11 KiB
Raw Blame History

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 ≈ 12 days · M ≈ 34 days · L ≈ 12 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 reads path); 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 Bash command or Edit/Write diff above Approve/Reject, so remote one-tap approval stops being blind (today you could tap Approve on rm -rf build). The core walk-away trust gap. Touches: src/http/hook.ts (tool_input is already parsed at :104 — derive a bounded preview for Bash/Edit/Write/MultiEdit) → /hook/permission + pendingApprovals in src/server.ts:423 (attach + re-send to late joiners, like gate already does) → optional bounded preview on the status ServerMessage in src/types.tsmanager → approval bar in public/tabs.ts (reuse public/diff.ts renderer + 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-links in 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/queue calling the existing writeInput (src/session/session.ts:201); a small queue in manager.ts; dequeue in the existing Stop/SessionEnd hook branch (src/server.ts:414); FE near public/quick-reply.ts. Injection is identical to a keystroke → byte-shuttle preserved, broadcasts to mirrors. Effort: M. Risk: gate firing on claudeStatus==='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 vs main before landing, not just uncommitted changes. src/http/diff.ts already deferred this (FR-B1.9) and named its mitigation: git rev-parse --verify allow-list before any revision reaches the CLI. Touches: optional base on getDiff() (guarded git rev-parse --verify <base> + trailing --, then git diff <base>...); branch-picker in public/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. No gh usage exists in src/ yet; gh emits JSON (no parsing pain). Touches: new src/http/gh.ts (mirror diff.ts's runGit); GET /projects/pr?path= guarded by isValidGitDir; PrStatus in src/types.ts; FE chip in project detail. Capability-probe + empty-degrade when gh absent/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 alertcostUsd already flows via statusLine (handleStatusLine); add COST_BUDGET_USD + a one-shot latch (like stuckNotified) + warn styling in public/preview-grid.ts. The rail that makes unattended auto-continue safe. SM.
    • "While you were away" reconnect digest — read-side aggregate over manager.list()
      • telemetry/timeline/status → "3 done, 1 waiting, $6, 2 PRs" on reconnect. SM.
    • Recent-commits log per projectgit log --oneline -n N (NUL-delimited) via a guarded GET /projects/log; inert-text render. SM.

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/pruneWorktrees in src/http/worktrees.ts (same execFile no-shell + timeout, validate target in git worktree list & not main, reuse realpath containment); DELETE /projects/worktree + POST /projects/worktree/prune (Origin-guarded); make the existing locked/prunable tags actionable. Effort: SM. 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: ML.


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 partscreateWorktree + 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 develop A constant-time-compared (crypto.timingSafeEqual over SHA-256, fixed-length guard) WEBTERM_TOKEN checked on the WS handshake (alongside, not replacing, Origin) + a central gate over every remote HTTP route, set as an HttpOnly; SameSite=Strict; Secure-when-https cookie after one-time GET /?token= or POST /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 in src/server.ts. Honest tradeoff: a bar-raiser, not a TLS/Tailscale substitute — on bare ws:// 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-client module 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. SM.
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. ML.
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) We already run as a tmux client on the user's default tmux server (sessions web_<id>), so tmux ls already sees manual/iTerm tmux sessions. Add a discovery list + "attach external tmux session" entry in the launcher → spawn a client PTY tmux attach -t <name>, wrapped in the session model. SM.

Kept in sync by the maintainer. Ideas are grounded against the code as of develop — verify file/line references before starting (they drift).