docs(prd-0020): start + attach to agents from the dashboard #44
Reference in New Issue
Block a user
Delete Branch "dashboard-start-attach-agents"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
PRD that collapses the two-terminal workflow (
./cli.py startin one terminal,./cli.py dashboardin another) into a single dashboard invocation. From inside the dashboard you can:nto open an agent-picker modal and spin up a new bottleEnteron a dashboard-owned agents-pane row to re-attach viadocker exec -it claude(the "handoff" mechanism from the recent research doc)xto explicitly stop just that bottleqto quit, which tears down every bottle the dashboard startedThe critical design shift: the bottle's lifetime is owned by the dashboard process, not by any single claude session. Exit claude → back to dashboard with the bottle still running. Today's
./cli.py startcouples them tightly via its ExitStack; the dashboard owns one ExitStack across the whole session.Mechanism (from PR #43's research)
This PRD picks option 1 (handoff) from
docs/research/claude-code-pane-in-dashboard.md:Option 2 (embedded emulator) and option 3 (external multiplexer) stay out of scope.
Sized into 5 chunks
_launch_bottleso prepare + preflight + attach are separable pieces the dashboard can call piecewise (no behavior change).nkey).x).qcallsstack.close()before exit).Open questions
Seven, largest being modal-vs-drop-and-resume for the preflight Y/N (prototype both during chunk 2) and what to do when a claude session exits because the container died unexpectedly (snapshot + preserve + status-line message, but the dashboard hook isn't designed yet).
PRD 0020 chunk 1. `cli/start.py`'s `_launch_bottle` did three things in one function: prepare + preflight, attach claude, and settle state on teardown. Split them so the dashboard (PRD 0020 chunk 2+) can reuse the prepare + attach pieces piecewise without going through the CLI's one-shot orchestrator: - `prepare_with_preflight(spec, *, stage_dir, render_preflight, prompt_yes, dry_run)` — injects render + prompt callables so the CLI binds them to stderr/stdin while the dashboard binds them to a curses modal. Returns `(plan, identity)`; identity is set after `backend.prepare` returns so callers can reap the prepare-time state dir on abort via `settle_state` in their finally — preserving today's preflight-N cleanup. - `attach_claude(bottle, *, remote_control)` — runs claude inside the bottle and returns its exit code. The dashboard calls this from inside a `curses.endwin` → … → `stdscr.refresh()` handoff. - `capture_session_state` / `settle_state` lose their leading underscore; the dashboard will call them on session-end + explicit-stop respectively. `_launch_bottle` becomes a thin orchestrator over those helpers. No behavior change; all 453 unit tests pass and `./cli.py start implementer --dry-run` produces identical preflight output.n) flowPRD 0020 chunk 2. Pressing `n` opens a modal that lists every agent from the manifest with `(N running)` suffixes for ones that already have bottles up. Type to filter (substring, case-insensitive); j/k or arrows to navigate; Enter to confirm; Esc clears the filter on first press, exits the picker on the second. On confirmation, the dashboard runs: - `prepare_with_preflight` from chunk 1 with curses-modal render + prompt callables (the preflight modal centers the plan summary + captures [y/N]). - `backend.launch(plan).__enter__()` — enters but doesn't bind the context to a `with`. The (cm, bottle, identity) tuple lands in the main loop's `bottles` dict keyed by slug. - `curses.endwin()` → `attach_claude(bottle)` → `stdscr.refresh()` handoff. The agent's claude session takes over the terminal; on exit the dashboard re-renders with the bottle now visible in the agents pane. Crucially the context manager is held alive in `bottles` — never `__exit__`'d at quit. Chunk 4 will wire `x` to that exit; for now bottles started from the dashboard stay running until explicit cleanup. Matches the PRD's "q does not tear down" decision. Footer surfaces `[n] new agent`. 461 unit tests pass (8 new for `_filter_agents` and `_running_counts`).