Issue 2 — VSCode sidebar: view diff + run/stop dev server for any builder
Problem
The Codev VSCode extension (packages/vscode/) surfaces builders in the Codev sidebar via the Needs Attention and Builders tree views. Users can approve gates (codev.approveGate, Cmd+K G), send messages (codev.sendMessage, Cmd+K D), attach to builder terminals (codev.openBuilderTerminal), and perform other state-level actions — but they cannot review a builder's code without dropping to a terminal.
Today to review a builder's work, a VSCode user must:
- Open a terminal
cd .builders/<name>/
- Run
git diff main manually
- Separately run
pnpm dev or similar if they want to test it
- Deal with port/env setup themselves
This breaks the sidebar-native flow and is especially painful for the upcoming PIR protocol's code-review gate (tracked in Issue 3), but also degrades day-to-day inspection for every existing protocol. This issue adds three VSCode commands exposed via sidebar context menus that eliminate the manual terminal trip.
Proposed solution
Three new commands in the Codev VSCode extension. Each is exposed in the right-click context menu on builders in the Needs Attention and Builders tree views.
Command 1 — codev.reviewDiff
Opens VSCode's native diff editor showing main...HEAD for the selected builder's worktree.
Behavior:
- Resolve the selected builder's worktree path from the tree item
- List changed files: shell out to
git -C <worktree> diff --name-only main...HEAD
- For each changed file, use
vscode.commands.executeCommand('vscode.diff', leftUri, rightUri) where:
leftUri points to the main branch version of the file (via VSCode's built-in git: URI scheme provided by the vscode.git extension)
rightUri is the file in the worktree
- VSCode opens its native side-by-side diff editor with syntax highlighting and +/- counts
Fallback approach if the vscode.diff API proves awkward: spawn a terminal in the worktree and run git diff main | less -R. Start with the native diff attempt; fall back if the URI resolution is complex.
Command 2 — codev.runWorktreeDev
Spawns the worktree's devCommand as a Tower-managed dev PTY (same mechanism as afx dev from Issue 1). Detects an existing Codev dev PTY and prompts to swap.
Behavior:
- Resolve the selected builder's worktree path and look up
worktree.devCommand from .codev/config.json via the existing Codev config loader
- Error with a VSCode notification if
devCommand is unset
- Query Tower for existing dev-type PTYs. If one is found:
- Show a
vscode.window.showWarningMessage modal: "Currently running dev for <other-builder>. Stop it and start <this-builder>?" with Yes / No buttons
- On Yes: kill the existing dev PTY via Tower's REST API, then proceed
- On No: cancel
- Create a new Tower PTY (same mechanism as
afx dev) with cwd = worktree path, command = devCommand, type = 'dev'
- The spawned PTY auto-opens as a VSCode terminal tab via the existing Tower→VSCode terminal bridge (see
packages/vscode/src/terminal-manager.ts), named "Dev: <builder-id>"
Users must stop main's dev themselves before running this (main is outside Tower). The dev PTY inherits main's ports and URLs by design — see Issue 1 for the serial-swap rationale.
Command 3 — codev.stopWorktreeDev
Stops the currently running Codev-managed dev PTY (the one started by codev.runWorktreeDev or afx dev). Counterpart to Command 2.
Behavior:
- Query Tower for PTYs with
type: 'dev'
- If one is found, kill it via Tower's REST API
- If none found, show an informational notification: "No Codev-managed dev server is running."
Context menu integration
Add context menu items on the codev.needsAttention and codev.builders tree views, gated by contextValue. Extend the view providers (packages/vscode/src/views/needs-attention.ts and packages/vscode/src/views/builders.ts) to set distinct contextValue strings per builder state so menus can show the right actions:
builder-active — for builders not blocked at a gate
builder-plan-gate — for builders awaiting plan-approval (used by PIR, tracked in Issue 3)
builder-code-review-gate — for builders awaiting code-review (PIR)
builder-pr-gate — for builders awaiting PR review
Context menu mapping:
- Active or plan-gate builder: Approve Gate (existing), Send Message (existing), Open Builder Terminal (existing), View Diff (new)
- Code-review gate builder: View Diff, Run Dev Server, Stop Dev Server, Approve Gate, Send Message, Open Builder Terminal
- PR gate builder: Approve Gate, View Diff, Open Builder Terminal
Existing commands codev.approveGate, codev.sendMessage, codev.openBuilderTerminal, codev.cleanupBuilder are reused unchanged.
Note: at the plan-approval gate, the primary review artifact is the GitHub issue comment, not a code diff. So "View Diff" for plan-gate builders is optional (they may not have any diff yet if they haven't written code). Show it only when there are committed changes on the branch — check if the worktree's HEAD differs from main before offering the action.
Files to touch
New
packages/vscode/src/commands/review-diff.ts — implements codev.reviewDiff
packages/vscode/src/commands/run-worktree-dev.ts — implements codev.runWorktreeDev
packages/vscode/src/commands/stop-worktree-dev.ts — implements codev.stopWorktreeDev
Modified
packages/vscode/package.json — register the three new commands in contributes.commands; add context menu items in contributes.menus.view/item/context keyed on viewItem
packages/vscode/src/extension.ts — register the three new commands on activation (wire them to their implementation modules, following the pattern established by existing codev.approveGate at packages/vscode/src/commands/approve.ts)
packages/vscode/src/views/needs-attention.ts — set distinct contextValue per builder state
packages/vscode/src/views/builders.ts — same
packages/vscode/src/test/extension.test.ts — smoke tests for the three new commands (resolve builder, invoke command, verify expected side effect — Tower PTY spawn for dev, diff editor opens for reviewDiff, etc.)
Acceptance criteria
codev.reviewDiff opens diff editor: right-click a builder with committed changes → "View Diff" → VSCode's native diff editor opens showing the changed files from main...HEAD. Syntax highlighting works. Multiple files open as separate diff tabs (or navigable list, whichever VSCode's diff API produces).
codev.reviewDiff handles empty diff: right-click a builder with no committed changes → show a notification: "No changes to review yet." No error thrown.
codev.runWorktreeDev spawns Tower PTY: right-click a builder → "Run Dev Server" → Tower PTY created in the worktree running worktree.devCommand. PTY appears as a VSCode terminal tab named "Dev: <builder-id>".
codev.runWorktreeDev prompts on swap: with a dev PTY already running for builder A, right-click builder B → "Run Dev Server" → modal appears asking to stop A. Yes → kills A, spawns B. No → cancels.
codev.runWorktreeDev handles missing devCommand: if worktree.devCommand is unset in .codev/config.json, show a notification with a helpful pointer: "Configure worktree.devCommand in .codev/config.json to use this action."
codev.stopWorktreeDev kills the dev PTY: with a Codev dev PTY running, invoking the command terminates it. With none running, shows an informational notification.
- Context menu items are gate-aware: builder blocked at
code-review shows View Diff + Run Dev Server + Stop Dev Server + Approve + Send Message. Builder blocked at plan-approval shows Approve + Send Message (+ View Diff if there are commits). Builder active without a gate shows only the always-available items.
- Existing commands unchanged:
codev.approveGate (Cmd+K G) and codev.sendMessage (Cmd+K D) continue to work identically. No regressions in codev.openBuilderTerminal, codev.cleanupBuilder, codev.spawnBuilder, etc.
- Tests: smoke tests verify command registration, command invocation, and expected side effects.
Non-goals (explicitly out of scope)
- A dedicated
codev.rejectGate command — rejection in Codev happens via codev.sendMessage (feedback loop), matching SPIR's established pattern at spec-approval / plan-approval gates. No new gate command needed.
- A
codev.openWorktree command (open worktree as separate VSCode window) — users who want this can code .builders/<name>/ from a terminal; not worth a dedicated command.
- Changes to the dashboard (outside VSCode) — the dashboard already renders Tower terminals including dev PTYs; no UI work needed there.
- Keybindings for the new commands — no default keybinding; users can customize via
keybindings.json if they want.
Benefits to existing protocols (value delivered without any new protocol)
- Any builder (bugfix, air, spir, aspir) becomes reviewable from the VSCode sidebar with one click — no terminal trip
- SPIR builders at the plan-approval gate could have their branch inspected via "View Diff" if they've started committing code (though SPIR's primary artifact is the spec/plan file)
- Any builder's worktree can be spun up as a dev server via "Run Dev Server"
Reference implementations / existing patterns
- Existing command pattern:
packages/vscode/src/commands/approve.ts — shows how to register a VSCode command that shells out to porch via spawn, uses the ConnectionManager to fetch overview data, and shows notifications
- Tower REST API client in VSCode:
packages/vscode/src/connection-manager.ts — provides getClient() and getOverview(workspacePath)
- Tower terminal bridge (Tower PTY → VSCode terminal):
packages/vscode/src/terminal-manager.ts
- Tree view provider pattern with
contextValue: packages/vscode/src/views/builders.ts already uses it; follow the same pattern for new state-specific values
vscode.diff command API: https://code.visualstudio.com/api/references/vscode-api#commands (executeCommand with 'vscode.diff')
Dependencies
- Requires Issue 1 merged first:
codev.runWorktreeDev reuses the Tower dev-PTY concept (type: 'dev') and the swap-detection logic introduced by afx dev
codev.runWorktreeDev reads worktree.devCommand from the config block added in Issue 1
codev.stopWorktreeDev relies on the Tower dev-PTY type being recognizable
Blocks
- Issue 3 (PIR protocol) consumes all three commands in its code-review gate UX. PIR can technically ship without them (review would be purely terminal-based), but the intended UX is sidebar-driven.
Issue 2 — VSCode sidebar: view diff + run/stop dev server for any builder
Problem
The Codev VSCode extension (
packages/vscode/) surfaces builders in the Codev sidebar via the Needs Attention and Builders tree views. Users can approve gates (codev.approveGate, Cmd+K G), send messages (codev.sendMessage, Cmd+K D), attach to builder terminals (codev.openBuilderTerminal), and perform other state-level actions — but they cannot review a builder's code without dropping to a terminal.Today to review a builder's work, a VSCode user must:
cd .builders/<name>/git diff mainmanuallypnpm devor similar if they want to test itThis breaks the sidebar-native flow and is especially painful for the upcoming PIR protocol's code-review gate (tracked in Issue 3), but also degrades day-to-day inspection for every existing protocol. This issue adds three VSCode commands exposed via sidebar context menus that eliminate the manual terminal trip.
Proposed solution
Three new commands in the Codev VSCode extension. Each is exposed in the right-click context menu on builders in the Needs Attention and Builders tree views.
Command 1 —
codev.reviewDiffOpens VSCode's native diff editor showing
main...HEADfor the selected builder's worktree.Behavior:
git -C <worktree> diff --name-only main...HEADvscode.commands.executeCommand('vscode.diff', leftUri, rightUri)where:leftUripoints to the main branch version of the file (via VSCode's built-ingit:URI scheme provided by thevscode.gitextension)rightUriis the file in the worktreeFallback approach if the
vscode.diffAPI proves awkward: spawn a terminal in the worktree and rungit diff main | less -R. Start with the native diff attempt; fall back if the URI resolution is complex.Command 2 —
codev.runWorktreeDevSpawns the worktree's
devCommandas a Tower-managed dev PTY (same mechanism asafx devfrom Issue 1). Detects an existing Codev dev PTY and prompts to swap.Behavior:
worktree.devCommandfrom.codev/config.jsonvia the existing Codev config loaderdevCommandis unsetvscode.window.showWarningMessagemodal: "Currently running dev for<other-builder>. Stop it and start<this-builder>?" withYes/Nobuttonsafx dev) withcwd= worktree path, command =devCommand,type='dev'packages/vscode/src/terminal-manager.ts), named "Dev:<builder-id>"Users must stop main's dev themselves before running this (main is outside Tower). The dev PTY inherits main's ports and URLs by design — see Issue 1 for the serial-swap rationale.
Command 3 —
codev.stopWorktreeDevStops the currently running Codev-managed dev PTY (the one started by
codev.runWorktreeDevorafx dev). Counterpart to Command 2.Behavior:
type: 'dev'Context menu integration
Add context menu items on the
codev.needsAttentionandcodev.builderstree views, gated bycontextValue. Extend the view providers (packages/vscode/src/views/needs-attention.tsandpackages/vscode/src/views/builders.ts) to set distinctcontextValuestrings per builder state so menus can show the right actions:builder-active— for builders not blocked at a gatebuilder-plan-gate— for builders awaiting plan-approval (used by PIR, tracked in Issue 3)builder-code-review-gate— for builders awaiting code-review (PIR)builder-pr-gate— for builders awaiting PR reviewContext menu mapping:
Existing commands
codev.approveGate,codev.sendMessage,codev.openBuilderTerminal,codev.cleanupBuilderare reused unchanged.Note: at the plan-approval gate, the primary review artifact is the GitHub issue comment, not a code diff. So "View Diff" for plan-gate builders is optional (they may not have any diff yet if they haven't written code). Show it only when there are committed changes on the branch — check if the worktree's HEAD differs from main before offering the action.
Files to touch
New
packages/vscode/src/commands/review-diff.ts— implementscodev.reviewDiffpackages/vscode/src/commands/run-worktree-dev.ts— implementscodev.runWorktreeDevpackages/vscode/src/commands/stop-worktree-dev.ts— implementscodev.stopWorktreeDevModified
packages/vscode/package.json— register the three new commands incontributes.commands; add context menu items incontributes.menus.view/item/contextkeyed onviewItempackages/vscode/src/extension.ts— register the three new commands on activation (wire them to their implementation modules, following the pattern established by existingcodev.approveGateatpackages/vscode/src/commands/approve.ts)packages/vscode/src/views/needs-attention.ts— set distinctcontextValueper builder statepackages/vscode/src/views/builders.ts— samepackages/vscode/src/test/extension.test.ts— smoke tests for the three new commands (resolve builder, invoke command, verify expected side effect — Tower PTY spawn for dev, diff editor opens for reviewDiff, etc.)Acceptance criteria
codev.reviewDiffopens diff editor: right-click a builder with committed changes → "View Diff" → VSCode's native diff editor opens showing the changed files frommain...HEAD. Syntax highlighting works. Multiple files open as separate diff tabs (or navigable list, whichever VSCode's diff API produces).codev.reviewDiffhandles empty diff: right-click a builder with no committed changes → show a notification: "No changes to review yet." No error thrown.codev.runWorktreeDevspawns Tower PTY: right-click a builder → "Run Dev Server" → Tower PTY created in the worktree runningworktree.devCommand. PTY appears as a VSCode terminal tab named "Dev:<builder-id>".codev.runWorktreeDevprompts on swap: with a dev PTY already running for builder A, right-click builder B → "Run Dev Server" → modal appears asking to stop A. Yes → kills A, spawns B. No → cancels.codev.runWorktreeDevhandles missing devCommand: ifworktree.devCommandis unset in.codev/config.json, show a notification with a helpful pointer: "Configureworktree.devCommandin.codev/config.jsonto use this action."codev.stopWorktreeDevkills the dev PTY: with a Codev dev PTY running, invoking the command terminates it. With none running, shows an informational notification.code-reviewshows View Diff + Run Dev Server + Stop Dev Server + Approve + Send Message. Builder blocked atplan-approvalshows Approve + Send Message (+ View Diff if there are commits). Builder active without a gate shows only the always-available items.codev.approveGate(Cmd+K G) andcodev.sendMessage(Cmd+K D) continue to work identically. No regressions incodev.openBuilderTerminal,codev.cleanupBuilder,codev.spawnBuilder, etc.Non-goals (explicitly out of scope)
codev.rejectGatecommand — rejection in Codev happens viacodev.sendMessage(feedback loop), matching SPIR's established pattern at spec-approval / plan-approval gates. No new gate command needed.codev.openWorktreecommand (open worktree as separate VSCode window) — users who want this cancode .builders/<name>/from a terminal; not worth a dedicated command.keybindings.jsonif they want.Benefits to existing protocols (value delivered without any new protocol)
Reference implementations / existing patterns
packages/vscode/src/commands/approve.ts— shows how to register a VSCode command that shells out toporchviaspawn, uses theConnectionManagerto fetch overview data, and shows notificationspackages/vscode/src/connection-manager.ts— providesgetClient()andgetOverview(workspacePath)packages/vscode/src/terminal-manager.tscontextValue:packages/vscode/src/views/builders.tsalready uses it; follow the same pattern for new state-specific valuesvscode.diffcommand API: https://code.visualstudio.com/api/references/vscode-api#commands (executeCommand with'vscode.diff')Dependencies
codev.runWorktreeDevreuses the Tower dev-PTY concept (type: 'dev') and the swap-detection logic introduced byafx devcodev.runWorktreeDevreadsworktree.devCommandfrom the config block added in Issue 1codev.stopWorktreeDevrelies on the Tower dev-PTY type being recognizableBlocks