ARD-0043: Parallel worktree workspaces — the multi-agent cockpit deep end (not a chat-thread subsystem)¶
- Status: Accepted
- Date: 2026-06-19
- Deciders: Tom (Claude facilitating, via
/grill-me) - Prompted by: "can we add multiple chat threads per project + a
/resumeto jump back into prior chats?" - Amends: ARD-0022 — the single continuous thread stays the default (and the non-engineer model); multi-workspace is an additive engineer opt-in, not an overturn. Details the deep end of ARD-0041 (the "N agents across N worktree-sandboxes" capability). Composes with ARD-0042 (each workspace is an independently attributable/hostable unit) and the ARD-0036 egress floor.
- Supersedes framing: the "multiple chat threads +
/resume" framing is replaced by parallel worktree workspaces.
Context¶
The /grill-me session (2026-06-19) resolved this, starting from two code findings that reframed the ask:
- Single-thread resume already works.
thread.gois one append-only JSONL per slug;GET /api/threadhydrates the full history on reopen;provider.gopersists the claude session id and--resumes it across turns. So "jump back into prior chats" for the one thread is already done — there is no standalone/resumeto build./resumeis only meaningful as "pick among several prior threads." - ARD-0022's "hidden auto-branching / per-turn commits / undo" are NOT built.
policy.godoes reactiveallowed_pathsenforcement (git checkout HEAD -- <path>+git cleanto revert out-of-allowlist writes);/api/undois an explicit v0 stub. So "thread = branch" cannot reuse existing infra — there is none.
So the whole question reduces to "do we allow multiple parallel lines of work per project?" The grill walked the tree:
- Who/why (Q1): an engineer need (parallel/independent work), not a non-engineer one. The single continuous thread stays the default so the non-engineer "Slack DM with the AI" simplicity ARD-0022 chose is untouched.
- Simultaneous or sequential (Q2): simultaneous. Two agents working at once require filesystem isolation — and that is ARD-0041's multi-agent cockpit (N agents across N worktrees). Simultaneous multi-thread is therefore not a separate feature; it is the cockpit deep end.
- Composition (Q3): a workspace = a worktree-backed
Projectregistry entry, reusing the existing per-slug proxy routing and the shipped dashboard + tabs (#36) unchanged — a parallel workspace is just another card/tab. The "thread/resume" concept dissolves: a workspace is inherently persistent, isolated, and resumable. - Isolation unit (Q4): a full boring sandbox per workspace (container + worktree + egress floor + guardrails). Sharing one container across agents reintroduces the lateral-movement risk #33's
cross_sandboxwork just closed and violates ARD-0005/0006.
Decision¶
Build "multiple threads + /resume," as actually wanted (simultaneous parallel work), as parallel worktree workspaces — the deep end of the ARD-0041 cockpit — not a chat-thread subsystem.
- A workspace = its own git worktree + branch, its own full boring sandbox (container, egress floor, guardrails), its own
boring-ui-backend+ Unix socket, and its own JSONL thread — registered as aProject(slug e.g.myapp~featureX,path= the worktree). - Reuses unchanged: per-slug proxy routing, the #36 dashboard + tabs, and the existing single-thread persistence/
--resumewithin each workspace. Parallel workspaces simply appear as more cards/tabs;/resume= reopen a workspace. - ARD-0022 preserved: one continuous thread per workspace; one workspace (the "Slack DM") is the non-engineer default. Multi-workspace is the engineer opt-in.
- Branching is per-workspace, not per-turn: a workspace is one branch, committed at sensible boundaries — far simpler than ARD-0022's never-built "hidden auto-branch per turn."
- New build: workspace lifecycle (fork into a parallel workspace: create worktree+branch → spawn sandbox+backend → register; plus teardown), a dynamic registry register/deregister path (proxy endpoint or CLI callback — none exists today), and a concurrency cap (sane max N sandboxes, surfaced in the UI).
- Isolation: full sandbox per workspace; security > practicality > time-to-running, so the N-container cost is accepted and bounded by the cap.
Consequences¶
Positive¶
- Reuses the just-shipped cockpit (dashboard + tabs + proxy routing) — most of the UI is already done.
- True isolation per parallel agent; composes with ARD-0042 (each workspace independently hostable/attributable) and gets its own egress floor.
- Sidesteps the unbuilt per-turn branching entirely (one branch per workspace).
Negative / accepted¶
- N full containers cost RAM + spawn latency — accepted per the pillar order; mitigated by a concurrency cap that is shown, not silent.
- Merge-back is deferred: v1 leans on plain git (each workspace is a branch; reconcile via the normal PR flow). Richer in-cockpit merge UX is a named follow-up, not part of this slice.
Alternatives Considered (rejected)¶
- Nested chat-threads without isolation (shared working tree). Rejected: simultaneous edits (Q2) collide; the parallel need demands FS isolation.
- Worktrees inside one shared container. Rejected: agents share a kernel namespace and can reach each other / the host — reintroduces the lateral-movement risk #33 closed; violates ARD-0005/0006.
- Conversation-only / sequential multi-thread. Rejected: doesn't serve the confirmed simultaneous-parallel need, and single-thread resume already exists, so it would add a thread-picker for little gain.
- Building
/resumeas a standalone feature. Rejected: single-thread resume already works;/resumeonly means "reopen a workspace."