You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Shipped via PR #1106 (merged 2026-06-28). Design pivoted at the PIR dev-approval gate from the originally-proposed nested architect tier to a flat 3-way group-by axis (stage / area / architect). The "Proposal" section below describes what actually shipped; the "Originally proposed (superseded at dev-gate)" section preserves the original design for context.
Problem
The Codev sidebar currently has two parallel surfaces that hide a real relationship between them:
Builders tree — area- or phase-grouped list of in-flight builders
Workspace > Architects subsection — flat list of running architect sessions (MAIN, REVIEWER, etc.)
Each builder has a spawnedByArchitect owner (the affinity model that routes gates, blocked-on questions, and afx send architect messages back to the spawner). That ownership is invisible in the Builders tree today: nothing on a builder row indicates which architect spawned it. As more workspaces run multiple specialised architects, ownership of in-flight work becomes increasingly load-bearing for triage.
Proposal (shipped form)
Replace the Builders tree with one Agents view (view-id renamed codev.builders → codev.agents) that groups by exactly one of three axes at a time. The architect axis exposes the ownership relationship structurally when invoked; the other two axes preserve today's stage / area triage.
"What's happening in this subsystem?" — domain triage
architect (the ownership axis)
architect names (MAIN first, then alphabetical)
[<stage>]
"Who's running what?" — ownership / load triage
Cycling group-by button
A single title-bar button cycles the axis on click — stage → area → architect → stage. The button's icon shows the next axis (so the user sees what they'll switch to, not what's currently active — VS Code toolbar buttons have no "pressed" state, so this is the affordance that works without one).
Implementation is three commands with mutually-exclusive when clauses keyed on codev.buildersGroupBy:
codev.agentsCycleGroupFromStage (icon $(tag), visible when grouped by stage) → sets area
codev.agentsCycleGroupFromArea (icon: octopus, visible when grouped by area) → sets architect
codev.agentsCycleGroupFromArchitect (icon $(milestone), visible when grouped by architect) → sets stage
The octopus is a custom theme-adapting SVG (light/dark monochrome pair, currentColor fallback) representing one orchestrator with many arms. Hardcoded colour was rejected in favour of theme-adaption matching the rest of the Codev sidebar vocabulary.
Architect-axis behaviour
Only architects that own in-flight builders produce a group. A childless architect simply doesn't appear (the full roster lives in Workspace > Architects). This is the intentional "work view shows owners of work, not the full roster" rule.
Main-first ordering.main is always the first group; other architects follow alphabetically.
Null-owner builders fold into main. Every afx spawn records an owner (default main); a null spawnedByArchitect is a data-integrity edge (worktree without a state.db row, pre-Multi-architect support: per-architect identity + builder-to-architect message routing #755 legacy) that the affinity router already folds into main — architectGrouping() matches that behaviour rather than introducing an "unassigned" group.
The architect axis is roster-agnostic. It buckets by the spawnedByArchitect field on builders without cross-checking the live roster. A builder whose owning architect was removed mid-cycle would still group under that architect's name (low-risk edge; could be revisited later if it becomes a real source of confusion).
What survives
Existing axes (stage and area) and their toggle behaviour are preserved; the architect axis is purely additive.
rollupGroupState / worstBuilderState (builder-row.ts:56-107) work uniformly across all three axes — the architect-grouped header rolls up blocked / waiting / active counts the same way area and stage groups do.
Builder file-tree children (BuilderFileTreeItem, BuilderFolderTreeItem) hang off builder rows in every axis.
Workspace > Architects subsection (workspace.ts:84-92) is unchanged. It remains the canonical full-roster surface for launching architect terminals, including architects with no in-flight work.
What changed
View-id renamecodev.builders → codev.agents. All view == when-clauses migrated. The setting keys (codev.buildersAutoCollapse, codev.buildersFileViewAsTree, codev.buildersGroupBy, codev.buildersAutoReveal) intentionally retain their builders* prefix — they're internal setting names, not view ids, and renaming them would force a user-facing migration with no behavioural benefit.
OverviewData.architects: ArchitectState[] (packages/types/src/api.ts) — the live roster ships on the overview payload so the extension reads it synchronously from the existing cache. liveArchitects helper in tower-routes.ts is the single source of truth, reused by handleOverview and dashboard-state. The no-workspace branch emits all required collection fields (architects: [], recentlyClosed: [], etc.) to honour the "never undefined" contract.
Workspace view delineation
The Codev sidebar's Workspace view has its own Architects subsection, distinct from the renamed codev.agents tree. It survives unchanged, reframed by purpose:
Workspace > Architects = workspace configuration / full roster. Lists every registered architect including childless ones, with terminal-open and the + Add Architect action.
Agents (renamed) = in-flight work. Shows only architects that own in-flight builders (in architect-axis mode), or stage / area groupings (in the other two axes).
Both views read from the same architect roster (Tower's architects-updated SSE event), so they stay in sync automatically.
Launch path for MAIN's terminal: Workspace > Architects subsection (one click). The Agents view does not surface architect rows directly outside architect-axis mode, so launching is via Workspace > Architects regardless of grouping.
Architect creation: conversational, not direct
The Codev: Add Architect action does not call afx workspace add-architect directly. It becomes a request routed to the main architect, who decides whether to act on it.
The rationale: architect creation is a workspace-orchestration event — it changes the roster, the specialisation matrix, and the conversation routing. Main is the workspace orchestrator (owns backlog triage, release decisions, sibling-architect dispatch); architect creation belongs in main's lane for the same reason cross-cutting work and release decisions do. Letting any developer create an unbriefed architect via direct CLI call leads to architect proliferation, missing briefs, and roster drift in main's state.
Codev: Add Architect UX (from Workspace > Architects, Cmd+K A, or the command palette):
VS Code shows an input box for the architect name (validateArchitectName shared with core enforces the same rule Tower uses server-side).
The extension resolves main from overview.architects; if no main session is active, refuses with a modal pointing the user at afx workspace start or the CLI fallback path.
The extension dispatches client.sendMessage('architect:main', 'Please add a <name> architect.').
Main receives the request, decides whether the specialisation makes sense, runs afx workspace add-architect --name <name> from its own terminal, sends the brief as the new architect's first message, and updates its working memory.
The roster updates automatically via the architects-updated SSE — no extension-side refresh needed.
What stays available as fallbacks:
afx workspace add-architect --name <name> — CLI surface unchanged. Power users who want to bypass main intentionally still can.
Main is required to be active. This is deliberate — the action's contract is "ask main to add", so without main there's nothing to ask.
Add Architect + does NOT appear on the Agents view title bar
A + on Agents would be ambiguous between "add a builder" and "add an architect" — the Agents view holds both kinds of children. Add Architect stays on Workspace > Architects only, which is the configuration / roster surface where the affordance is unambiguous.
Originally proposed (superseded at dev-gate)
The original proposal was a nested adaptive architect tier: a 3-level hierarchy (Architect → Area/Phase → Builder) when more than one architect was active, collapsing to today's 2-level area-or-phase grouping when single-architect. Each architect would appear as a root node carrying a worst-of rollup of its builders' states, with passive architects rendering as leaf rows (collapsibleState: None) so they remained message-able.
At the PIR dev-approval gate the human (architect) reviewed the running nested tree and directed a pivot. The concerns:
Duplication with Workspace > Architects. Showing every architect at the Agents root duplicated the full-roster view that already lives in Workspace > Architects.
Single-architect collapse awkwardness. The "render the architect tier only when N > 1" rule introduced a layout shift when adding a second architect — the same workspace went from area-rooted to architect-rooted on the second afx workspace add-architect.
Icon-collision and visual-weight problems. Architect-tier headers competed with area/stage headers for visual hierarchy in a busy tree.
The pivot to a flat 3-way group-by axis resolves all three: ownership becomes an axis the user can switch to (one click) rather than a permanent visual tier; childless architects naturally don't appear in the work view (they live in Workspace > Architects); no layout shift between single-architect and multi-architect workspaces (the architect axis is always available, the groups just count differently).
Tradeoff named honestly
The flat axis moves ownership from "always visible" to "one click away." When the user is in stage or area mode (likely the day-to-day defaults), ownership is not surfaced per-row. The earlier "ownership at a glance" framing of the problem isn't fully met by the shipped design — it becomes "ownership is a button away." This was the tradeoff the dev-gate accepted in exchange for the simpler UX and resolved duplication concerns.
Implementation notes (as shipped)
architectGrouping() in packages/vscode/src/views/builder-grouping.ts — pure, vscode-free strategy. Buckets by spawnedByArchitect || 'main', main-first then alphabetical, no flatten-lone-group, row prefix is the complementary lifecycle stage. Unit-tested in builder-grouping.test.ts (6 cases).
Conversational Add Architect in packages/vscode/src/commands/add-architect.ts — pure helpers (resolveMainArchitect, addArchitectRequestMessage, ADD_ARCHITECT_RECIPIENT) with the VS Code UI in extension.ts. Unit-tested in add-architect.test.ts.
OverviewData.architects enrichment via liveArchitects() in tower-routes.ts, single source of truth shared by handleOverview and dashboard-state. No-workspace branch contract-complete (regression assertion in tower-routes.test.ts:977-981).
Custom octopus icon as three SVGs (icons/architect{,-light,-dark}.svg) — radial 8-arm geometry, 16x16, stroke-width 2.7, theme-adapting via VS Code's light/dark icon pair pattern.
Cycle commands in extension.ts are three thin handlers each calling a setGroupBy(axis) helper that writes the codev.buildersGroupBy configuration value.
Status
Shipped via PR #1106 (merged 2026-06-28). Design pivoted at the PIR dev-approval gate from the originally-proposed nested architect tier to a flat 3-way group-by axis (stage / area / architect). The "Proposal" section below describes what actually shipped; the "Originally proposed (superseded at dev-gate)" section preserves the original design for context.
Problem
The Codev sidebar currently has two parallel surfaces that hide a real relationship between them:
Each builder has a
spawnedByArchitectowner (the affinity model that routes gates, blocked-on questions, andafx send architectmessages back to the spawner). That ownership is invisible in the Builders tree today: nothing on a builder row indicates which architect spawned it. As more workspaces run multiple specialised architects, ownership of in-flight work becomes increasingly load-bearing for triage.Proposal (shipped form)
Replace the Builders tree with one Agents view (view-id renamed
codev.builders→codev.agents) that groups by exactly one of three axes at a time. The architect axis exposes the ownership relationship structurally when invoked; the other two axes preserve today's stage / area triage.Group-by axes
stage(default — the action axis)SPECIFY/PLAN/IMPLEMENT/REVIEW/PR/VERIFIED[<area>]area(the domain axis)area/*labels matching Backlog[<phase>]architect(the ownership axis)MAINfirst, then alphabetical)[<stage>]Cycling group-by button
A single title-bar button cycles the axis on click —
stage → area → architect → stage. The button's icon shows the next axis (so the user sees what they'll switch to, not what's currently active — VS Code toolbar buttons have no "pressed" state, so this is the affordance that works without one).Implementation is three commands with mutually-exclusive
whenclauses keyed oncodev.buildersGroupBy:codev.agentsCycleGroupFromStage(icon$(tag), visible when grouped by stage) → setsareacodev.agentsCycleGroupFromArea(icon: octopus, visible when grouped by area) → setsarchitectcodev.agentsCycleGroupFromArchitect(icon$(milestone), visible when grouped by architect) → setsstageThe octopus is a custom theme-adapting SVG (light/dark monochrome pair,
currentColorfallback) representing one orchestrator with many arms. Hardcoded colour was rejected in favour of theme-adaption matching the rest of the Codev sidebar vocabulary.Architect-axis behaviour
mainis always the first group; other architects follow alphabetically.main. Everyafx spawnrecords an owner (defaultmain); a nullspawnedByArchitectis a data-integrity edge (worktree without a state.db row, pre-Multi-architect support: per-architect identity + builder-to-architect message routing #755 legacy) that the affinity router already folds into main —architectGrouping()matches that behaviour rather than introducing an "unassigned" group.spawnedByArchitectfield on builders without cross-checking the live roster. A builder whose owning architect was removed mid-cycle would still group under that architect's name (low-risk edge; could be revisited later if it becomes a real source of confusion).What survives
stageandarea) and their toggle behaviour are preserved; the architect axis is purely additive.rollupGroupState/worstBuilderState(builder-row.ts:56-107) work uniformly across all three axes — the architect-grouped header rolls upblocked / waiting / activecounts the same way area and stage groups do.BuilderFileTreeItem,BuilderFolderTreeItem) hang off builder rows in every axis.workspace.ts:84-92) is unchanged. It remains the canonical full-roster surface for launching architect terminals, including architects with no in-flight work.What changed
codev.builders→codev.agents. Allview ==when-clauses migrated. The setting keys (codev.buildersAutoCollapse,codev.buildersFileViewAsTree,codev.buildersGroupBy,codev.buildersAutoReveal) intentionally retain theirbuilders*prefix — they're internal setting names, not view ids, and renaming them would force a user-facing migration with no behavioural benefit.OverviewData.architects: ArchitectState[](packages/types/src/api.ts) — the live roster ships on the overview payload so the extension reads it synchronously from the existing cache.liveArchitectshelper intower-routes.tsis the single source of truth, reused byhandleOverviewanddashboard-state. The no-workspace branch emits all required collection fields (architects: [],recentlyClosed: [], etc.) to honour the "never undefined" contract.Workspace view delineation
The Codev sidebar's Workspace view has its own Architects subsection, distinct from the renamed
codev.agentstree. It survives unchanged, reframed by purpose:+ Add Architectaction.Both views read from the same architect roster (Tower's
architects-updatedSSE event), so they stay in sync automatically.Launch path for MAIN's terminal: Workspace > Architects subsection (one click). The Agents view does not surface architect rows directly outside architect-axis mode, so launching is via Workspace > Architects regardless of grouping.
Architect creation: conversational, not direct
The
Codev: Add Architectaction does not callafx workspace add-architectdirectly. It becomes a request routed to themainarchitect, who decides whether to act on it.The rationale: architect creation is a workspace-orchestration event — it changes the roster, the specialisation matrix, and the conversation routing. Main is the workspace orchestrator (owns backlog triage, release decisions, sibling-architect dispatch); architect creation belongs in main's lane for the same reason cross-cutting work and release decisions do. Letting any developer create an unbriefed architect via direct CLI call leads to architect proliferation, missing briefs, and roster drift in main's state.
Codev: Add ArchitectUX (from Workspace > Architects,Cmd+K A, or the command palette):validateArchitectNameshared with core enforces the same rule Tower uses server-side).mainfromoverview.architects; if no main session is active, refuses with a modal pointing the user atafx workspace startor the CLI fallback path.client.sendMessage('architect:main', 'Please add a <name> architect.').afx workspace add-architect --name <name>from its own terminal, sends the brief as the new architect's first message, and updates its working memory.architects-updatedSSE — no extension-side refresh needed.What stays available as fallbacks:
afx workspace add-architect --name <name>— CLI surface unchanged. Power users who want to bypass main intentionally still can.Add Architect
+does NOT appear on the Agents view title barA
+on Agents would be ambiguous between "add a builder" and "add an architect" — the Agents view holds both kinds of children. Add Architect stays on Workspace > Architects only, which is the configuration / roster surface where the affordance is unambiguous.Originally proposed (superseded at dev-gate)
The original proposal was a nested adaptive architect tier: a 3-level hierarchy (
Architect → Area/Phase → Builder) when more than one architect was active, collapsing to today's 2-level area-or-phase grouping when single-architect. Each architect would appear as a root node carrying a worst-of rollup of its builders' states, with passive architects rendering as leaf rows (collapsibleState: None) so they remained message-able.At the PIR dev-approval gate the human (architect) reviewed the running nested tree and directed a pivot. The concerns:
afx workspace add-architect.The pivot to a flat 3-way group-by axis resolves all three: ownership becomes an axis the user can switch to (one click) rather than a permanent visual tier; childless architects naturally don't appear in the work view (they live in Workspace > Architects); no layout shift between single-architect and multi-architect workspaces (the architect axis is always available, the groups just count differently).
Tradeoff named honestly
The flat axis moves ownership from "always visible" to "one click away." When the user is in stage or area mode (likely the day-to-day defaults), ownership is not surfaced per-row. The earlier "ownership at a glance" framing of the problem isn't fully met by the shipped design — it becomes "ownership is a button away." This was the tradeoff the dev-gate accepted in exchange for the simpler UX and resolved duplication concerns.
Implementation notes (as shipped)
architectGrouping()inpackages/vscode/src/views/builder-grouping.ts— pure, vscode-free strategy. Buckets byspawnedByArchitect || 'main', main-first then alphabetical, no flatten-lone-group, row prefix is the complementary lifecycle stage. Unit-tested inbuilder-grouping.test.ts(6 cases).packages/vscode/src/commands/add-architect.ts— pure helpers (resolveMainArchitect,addArchitectRequestMessage,ADD_ARCHITECT_RECIPIENT) with the VS Code UI inextension.ts. Unit-tested inadd-architect.test.ts.OverviewData.architectsenrichment vialiveArchitects()intower-routes.ts, single source of truth shared byhandleOverviewand dashboard-state. No-workspace branch contract-complete (regression assertion intower-routes.test.ts:977-981).icons/architect{,-light,-dark}.svg) — radial 8-arm geometry, 16x16, stroke-width 2.7, theme-adapting via VS Code's light/dark icon pair pattern.extension.tsare three thin handlers each calling asetGroupBy(axis)helper that writes thecodev.buildersGroupByconfiguration value.Protocol
PIR. Plan → Implement (with dev-approval gate) → Review (with PR + CMAP advisory pass) → pr gate.
Related
architect:mainaddressing.spawnedByArchitectfield this work groups by.