v3.2.2 Karnak
Released: 2026-07-02
Summary
This cycle extends Codev in several independent directions. On the integration front, the VS Code extension gains a bidirectional controller surface: a Tower-driven command relay that lets external controllers drive the focused editor (#1091), and outbound activity hooks that publish window-focus and builder-active events to URLs you declare (#1105). On multi-architect robustness, each architect now keeps its own conversation across restarts via a persisted per-architect session id (#1116), and Codex joins Claude as a selectable first-class architect harness (#1059). The Codev Markdown Preview review workflow becomes fully functional: an inline composer for authoring comments (#1121) plus per-card edit and preview-side delete (#1132), with author preservation and optimistic concurrency on every mutation. The Agents view adds a three-way group-by axis (stage, area, architect) and routes Add Architect through the main orchestrator (#1106), and a new Open Issue by ID command (#1123) opens any issue across GitHub, GitLab, Gitea, and Linear.
Under the hood, the per-workspace state.db is retired in favor of the single user-global global.db, with an automatic, once-ever boot-time migration (#1127), and a Tower SSE reject-on-cap fix ends a reconnect cascade that was exhausting ephemeral ports (#1126). The gemini/agy consult lane is usable again in CMAP reviews after two on-task and verdict-scoring fixes (#1085). This is a patch release on the Karnak codename line: the state.db consolidation upgrades transparently on first Tower start, with no user action required.
Agents view: a three-way group-by axis and conversational Add Architect (#1104, PR #1106)
The Builders tree is now called Agents, and its title-bar button cycles the grouping axis between three modes instead of toggling between two:
- Stage (the default action axis): groups by lifecycle stage —
SPECIFY → PLAN → IMPLEMENT → REVIEW → PR → VERIFIED— for "where do I need to act?" triage. Row prefix carries the complementaryarea/*label. - Area (the domain axis): groups by
area/*label matching the Backlog view, for "what's happening in this subsystem?" triage. Row prefix carries the complementary lifecycle phase. - Architect (the new ownership axis): groups by the architect that spawned each builder (
spawnedByArchitect),mainfirst then alphabetical. Row prefix carries the complementary lifecycle stage. Answers "who's running what?" — the question multi-architect workspaces couldn't answer at a glance before.
The cycling button's icon shows the axis you'll switch to on the next click (VS Code toolbar buttons have no pressed state, so the icon-as-next-target affordance keeps the cycle obvious without one): the area $(tag) icon visible in stage mode, a custom octopus icon visible in area mode, and the stage $(milestone) icon visible in architect mode. The octopus is the architect-axis glyph — one body with many arms representing one orchestrator spawning many builders — and renders as a theme-adapting monochrome SVG pair (light / dark) matching the codev-light / codev-dark convention.
In architect mode only architects that own in-flight builders appear as group headers — childless architects (like REVIEWER between assignments) don't clutter the work view. The full architect roster, including childless ones, remains in Workspace > Architects which is the canonical full-roster surface for launching architect terminals and adding new architects. The view-id renames codev.builders → codev.agents to match the new framing; setting keys (codev.buildersAutoCollapse, codev.buildersFileViewAsTree, codev.buildersGroupBy, codev.buildersAutoReveal) intentionally retain their builders* prefix — they're internal setting names and renaming them would force a user-facing migration with no behavioural benefit.
A separate but related change ships in the same PR: Add Architect is now a conversation with main, not a direct CLI call. The Codev: Add Architect action (and the Cmd+K A / Ctrl+K A keybinding from v3.2.1) no longer runs afx workspace add-architect directly. It now asks the main architect — the workspace orchestrator that owns backlog triage, release decisions, and architect-roster management — to create the new architect:
- VS Code prompts for the architect name (validated against the same rule Tower enforces server-side, shared with the CLI for parity).
- The extension dispatches
client.sendMessage('architect:main', 'Please add a <name> architect.'). - Main receives the request, decides whether the specialisation makes sense (may push back, may ask for scope), 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 existing
architects-updatedSSE — no extension-side refresh needed.
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; 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. The handler refuses with an informational modal pointing at afx workspace start (or the CLI fallback afx workspace add-architect --name <name>) when no main session is active — the action's contract is "ask main to add", so without main there's nothing to ask.
Originally the design was a nested architect tier (architect → area/phase → builder, with passive architects rendering as leaf rows). At the dev-approval gate the running tree showed three problems: it duplicated Workspace > Architects, the single-architect collapse rule introduced a layout shift on adding a second architect, and architect-tier headers competed with area/stage headers for visual hierarchy. The pivot to the flat 3-way axis resolves all three, with the honest trade that ownership becomes a button away rather than always visible per-row. The PR description and the issue body name the trade-off explicitly so it's not invisible at release time.
Codex as a first-class architect harness (PR #1059)
The architect harness — the CLI Codev wraps as its long-running orchestrator process — is now selectable between claude (the default) and codex via .codev/config.json's shell.architect / shell.architectHarness fields, matching the same config-driven mechanism builders have used since v2. Pick the engine that fits your workflow; both flow through the same Tower-managed PTY model with role-prompt injection and identical Spec 786 multi-architect addressing.
The core fix routes session-discovery and --resume argument construction through a new optional HarnessProvider.buildResume capability so non-Claude architects no longer build invalid <cmd> --resume <claude-uuid> invocations against stale Claude .jsonl files. That class of crash-loop, hit when a stray Claude transcript existed in ~/.claude/projects/ for a workspace that wasn't running Claude, is now closed by construction: only the Claude harness implements buildResume, so codex spawns fresh with role injection instead.
Harness auto-detection is override-aware: getArchitectHarness and getBuilderHarness resolve the harness from the override-aware command (cliOverrides → TOWER_ARCHITECT_CMD → .codev/config.json), so --architect-cmd codex or TOWER_ARCHITECT_CMD=codex with no explicit shell.architectHarness still resolves the codex harness, not claude. An explicit shell.architectHarness or shell.builderHarness wins over auto-detection. (Before this fix, an override launched the non-claude CLI but resolved the claude harness, which is what re-armed the resume crash-loop.)
Scope notes:
- Gemini stays builder-only. The Gemini CLI is retiring, so the originally-scoped gemini-architect support was removed from this PR; gemini's
GEMINI_SYSTEM_MDbuilder surface is untouched.doctorwarns whengeminiis configured as an architect. - OpenCode stays builder-only. Same reason as v3.2.x: opencode's file-based role injection (
opencode.jsoninstructionsfield) requires an ephemeral worktree, which the long-running architect session doesn't have. - Unrecognized override commands (e.g.
TOWER_ARCHITECT_CMD=bash, a wrapper script, or any custom launcher with no explicitshell.architectHarness) still default to the claude harness. Mitigation: setshell.architectHarnessexplicitly when using an unrecognized launcher command.
Community contribution.
Multi-architect conversation resume: each architect keeps its own session across restarts (PR #1116)
In v3.2.x, a workspace running more than one architect (main + one or more named siblings via afx workspace add-architect) silently lost conversation context for every architect on any in-process Claude crash, Tower restart, or machine reboot. The cause: every architect's session JSONL shares the same ~/.claude/projects/<encoded-workspacePath>/ directory because they all share the same cwd, and the heuristic-based "newest jsonl by mtime" lookup the resume path used couldn't disambiguate which transcript belonged to which architect. The conservative fallback was to skip resume entirely when more than one architect was registered — and that turned off main's conversation resume too, just for having a sibling around.
This release closes the gap by persisting a per-architect session id in state.db. The architect table now carries a session_id column (migration v12); at spawn time, Tower generates a UUID, passes it to claude via --session-id <uuid>, and stores it on the architect row. At every restart / revive site — launchInstance for main on workspace start, addArchitect for siblings, and the shellper auto-restart options bake — Tower reads the stored id and passes --resume <uuid>, which lands each architect in its own prior conversation, regardless of how many other architects share the cwd.
What gets fixed by surface:
- Tower restart with shellper survival: already worked (process-level reattach); still works.
- Claude crash inside a still-alive shellper (the silent path): was the most insidious failure — a sibling architect could lose context mid-session, without any external event the operator could notice. Now the shellper auto-restart honours the stored session id and resumes cleanly.
- Machine reboot or shellper kill → workspace cold start: was the cold-loss path. Now both
launchInstanceandaddArchitectresume from the stored id; sibling architects come back into their own conversations, not fresh sessions. main's resume in a multi-architect workspace: the conservativesafeToResume.length <= 1guard is gone. Adding a sibling no longer turns offmain's resume; each architect's id disambiguates.
For specialised siblings (reviewer, casa, demos, etc.), the practical impact is sharper than for main. Their specialisation comes from a brief sent as their first user message after afx workspace add-architect — that brief lives in the conversation, not on disk. Before this release, a sibling that lost its conversation also lost its job description; it came back as a generic architect that didn't know its lane. Now the brief survives every revival surface.
Legacy architect rows (created before migration v12) have no stored session id; on their first revival they fall back to a fresh spawn with role injection — exactly the v3.2.x behaviour — and then carry a stored id forward from that point. No regression; the resume only improves over time as rows get their id populated.
The harness wiring is agent-neutral: the persisted column is session_id (not claude_session_id), and the new HarnessProvider.session? interface lets each harness opt in to session-resume semantics — claude opts in (--session-id to mint, --resume to revive); codex and gemini opt out and spawn fresh, with no schema change needed when their CLIs grow native session-resume support.
Codev Markdown Preview: inline composer for review comments (#1107, PR #1121)
Adding a review comment from the Codev Markdown Preview no longer flashes a top-of-window Quick Pick input to collect the comment body. The + affordance next to a block now opens an inline composer anchored below the block itself, keeping the anchor visible while you type. Multi-line input, Enter to submit, Esc to cancel, focus restoration on dismiss. The composer inherits the preview's prose typography so the input reads like the document it's commenting on, not like a modal chrome slot.
A subtle related fix landed in the same change: new comments on a block that already has a thread now write at the bottom of that thread (newest-last in reading order), matching the composer's visual position. Previously the write went to the top of the thread while the composer appeared below — a visible mismatch on any block with more than one prior comment. The markerAppendLine helper the composer uses is host-agnostic (@cluesmith/codev-core/review-markers), so any future host that mounts the canvas — the dashboard, IDEs beyond VS Code — writes markers in the same append-below-thread order automatically.
The editor Comments-API path (reply-to-thread from the source-editor gutter) still prepends new markers at the top of the thread for now; that's tracked as a small follow-up (#1122) to align the two authoring surfaces on the same append semantics.
Edit and delete review comments from the Markdown Preview — the reviewer is now fully functional (#1055, PR #1132)
The Codev Markdown Preview could add review comments but not change them. This completes the loop: rendered comment cards now carry per-card edit and delete affordances, and comments are also editable from the editor's Comments-API thread via a pencil on each comment. Edit reopens the comment body in the same inline composer shipped earlier this cycle (pre-filled with the current text); preview-side delete removes the marker in place. You can now author, edit, and remove feedback entirely from the rendered preview.
Comments are stored as <!-- REVIEW(...): body --> marker lines in the markdown, and the identity model is line + content: a comment is located by its recorded line together with its author and a body prefix. Two invariants hold on every mutation:
- Author preservation. The author written back is always the one already on the on-disk marker, never the identity of whoever is editing. This holds on both edit surfaces (editor thread and preview).
- Optimistic concurrency. Before any edit or delete writes, the target marker at the recorded line is re-verified against its expected author and body. If the file changed since the surface last rendered — the comment moved, or a different comment stacked on the same block was edited — the write is refused and the preview refreshes rather than mutating the wrong marker. Stacked comments on a single block are therefore addressed individually, never confused for one another. The prefix comparison is whitespace-insensitive on both sides, so a hand-authored marker with irregular internal spacing still matches its rendered card.
The preview auto-refreshes on file changes, so an edit or delete applied from one surface reconciles the other without a manual reload.
Open a specific issue by typing its ID (#1096, PR #1123)
New Codev: Open Issue by ID... command bound to Cmd+K I / Ctrl+K I by default. Prompts for a numeric issue identifier (accepts 1234 or #1234, with whitespace tolerance), fetches the issue via Codev's forge-agnostic getIssue path, and opens its canonical page in your browser. Works on any issue — open, closed, archived, or one you've never had loaded in the backlog. Palette-discoverable; keybinding falls into the existing Cmd+K family alongside Cmd+K A (Add Architect) and Cmd+K B (forward selection to builder).
Works across forges: the GitHub, GitLab, Gitea, and Linear adapters all now emit an issue url field on the shared forge contract, so the same command opens the right canonical page regardless of which forge your workspace is bound to. If a forge doesn't supply a URL, the command falls back to Codev's in-editor issue preview instead of erroring — the affordance stays useful even under sparse metadata. PRs are handled by the same command on forges where issues and PRs share a URL space (GitHub); the browser resolves the numeric id to whichever kind it is.
The existing Codev: Search Backlog Quick Pick is untouched — it remains the right choice for filtering across the loaded backlog set. Open Issue by ID is the direct-input companion for when you know the exact number.
State.db retired: single user-global database with automatic migration (#1118, PR #1127)
Codev's per-workspace .agent-farm/state.db file is retired. All the tables it carried (architect, builders, utils, annotations) now live in the single user-global ~/.agent-farm/global.db, with rows tagged by workspace_path exactly as they were internally. The path lie ("state.db lives inside my workspace, so it must only hold my workspace's data") is gone; the file location matches the data's actual scope, and the "some architects are missing their state after a restart" symptom that multi-workspace users saw is closed at the source.
What changes for users. Nothing in day-to-day flows: afx spawn, afx send, afx workspace start/stop, the sidebar, the dashboard — all continue working, with the underlying storage now consistent regardless of which directory Tower was started from. The consolidation is transparent.
Upgrade migration — automatic on first Tower start. No user action required. The first time Tower starts after the upgrade, a runBootConsolidation step in the server's boot sequence resolves this boot's active .agent-farm/state.db (whichever workspace Tower launched into), copies its rows into global.db using INSERT OR REPLACE with latest-started_at-wins conflict resolution, and renames the source to state.db.pre-merge-<timestamp> (WAL / SHM sidecars renamed alongside it). The whole thing runs in one SQLite transaction; a strict _consolidation marker in global.db guarantees it never runs twice on the same machine, even across daily Tower restarts. For fresh installs with no prior state.db, the marker is still written and Tower proceeds normally — zero-migration path.
For multi-workspace users with fragmented state.db files. Boot-time consolidation handles the active state.db only — the one Tower's cwd resolves to at first-boot. If your machine accumulated state.db files across multiple project directories (a v3.2.x-era pattern where Tower's start-cwd determined the file location), those satellites stay on disk after the automatic migration. They aren't lost: sweep them explicitly with afx db consolidate <path> --apply per file. The command is idempotent and honours the same rename semantics as boot-time, so multi-workspace users converge on the same clean state as fresh installs after one sweep.
New CLI surface. afx db consolidate <path> dry-runs a preview (side-effect-free — opens global.db read-only), and --apply commits + renames. Useful for inspection before the automatic migration runs, or for sweeping the satellite files above.
Two surface fixes caught during review. (1) afx workspace stop on one workspace no longer wipes every other workspace's builders — the delete is now correctly scoped by workspace_path. (2) afx send from any builder worktree continues to work after the migration; a cross-workspace audit found the last direct state.db open in the codebase (in send.ts's anti-spoofing identity resolution) and repointed it at global.db scoped by workspace_path. Missed by all three consult models; caught by the builder's own audit.
Legacy state.db files are left renamed on disk, not deleted, so users who want to inspect or preserve the pre-merge state can. The .agent-farm/ directory inside each workspace stays for forward-compat.
Builder worktree write-guard: deterministic protection against main-checkout pollution (#1018, PR #1098)
Strict-mode builders run in isolated git worktrees nested inside the main checkout. The Write / Edit tools require absolute paths, so the builder model must synthesize one; the current runtime sometimes anchors that path at the inferred canonical repo root instead of the worktree cwd, dropping the .builders/<id>/ segment. The wrong path is a real writable directory (the main checkout's working tree), so the mis-write succeeds silently. Byte-identical trees at branch base mean wrong-rooted reads succeed silently too, so nothing corrects the model until a later git add in the worktree fails with a pathspec error. The polluted file just sits in main's working tree.
This is not a Codev regression; it is intrinsic path-synthesis drift in the builder runtime that moves across model and CLI upgrades. Instructions and per-agent memory do not hold across that drift. Only a deterministic guard does.
The guard ships as a per-worktree Claude Code PreToolUse settings hook. At spawn time, the harness generates .claude/settings.local.json plus a self-contained Node guard script (.claude/hooks/worktree-write-guard.cjs) inside the new worktree. The guard:
- Rejects any
WriteorEditwhose absolute path resolves outside the worktree root, naming the worktree root in the rejection message so the model re-roots on the next attempt. Silent main-checkout pollution becomes a loud, correctable failure. - Allowlists scratch directories (
/tmp,/private/tmp,$HOME/.claudefor builder memory writes). - Reads the worktree root from
CODEV_WORKTREE_ROOTbaked at spawn time (absolute), withgit rev-parse --show-toplevelas the runtime fallback. Both are canonicalised throughrealpathso the macOS/tmpversus/private/tmpsymlink difference is normalised. - Resolves the longest-existing-ancestor before joining the tail, so paths to non-existent new files canonicalise correctly.
- Fails open on any error (bad JSON, unresolvable root, missing git). A safety net must never brick a builder; worst case reverts to today's unguarded behavior.
Coverage is deterministic across all Claude builder spawn modes: the harness installation runs in both startBuilderSession and buildWorktreeLaunchScript, in both the role-bearing and no-role branches. The --resume path is intentionally excluded, since it reuses an existing worktree already guarded at its original spawn. A throwaway-builder verification matrix at dev-approval confirmed: a Write to the main checkout blocks with a re-root message, a legitimate /tmp write passes, a worktree-rooted Write passes and lands in the worktree, a ~/.claude/... memory write passes, and a genuine sibling-thread cross-checkout read still works (reads are unaffected by this issue).
A role-doc backstop in roles/builder.md and codev-skeleton/roles/builder.md names the failure mode so the model has a chance to self-correct even when the guard is removed or bypassed. Backstop only; instructions do not hold across model drift.
Scope decision recorded at the plan gate: builder-only. The consult sub-agent read surface (issue #1092) is the architectural cousin of this guard but is intentionally out of scope. The guard module is factored so its boundary logic can later back a consult-side hook without duplication. #1092 stays open as a separate, lower-severity issue (mostly self-healing: the SDK's not-found error includes a cwd note that lets the model re-root, asymmetric to the silent-success path #1018 addresses).
Tower SSE: reject-on-cap breaks the reconnect cascade that was causing port exhaustion (#1124, PR #1126)
Tower's Server-Sent Events endpoint would evict its oldest client when it hit a per-Tower connection cap (previously 50). The evicted client then auto-reconnected, pushing the count back to cap, evicting another — a chain reaction that could run at ~800 connections per second and leave 2,900+ sockets in TIME_WAIT, consuming ~10% of the OS ephemeral port range on affected workstations. Users saw dashboard and VS Code extension connections cycling, delayed events, and occasional "no ephemeral port available" errors.
Four coordinated changes fix it:
- Reject at cap, don't evict. When the cap is hit, Tower returns HTTP 503 with
Retry-After: 5instead of evicting an active client. Rejection is a dead end; eviction was a chain reaction. - Raise the cap from 50 to 200. SSE connections are lightweight; 50 was too low for the realistic workstation profile (dashboard + multiple VS Code windows + a couple of builders each holding a stream).
- Space out reconnections via a
retry: 5000SSE directive telling browsers to wait 5s before reconnecting rather than the default ~3s. - Per-client max-age jitter (±60s) so scheduled evictions don't fire in synchronized bursts.
Also: the per-client connect/disconnect INFO logging that had been producing ~774K lines every 2.5 days is gone; the heartbeat still runs for dead-client detection.
agy consults stay on-task and no-verdict results no longer churn the porch review loop (#1032 / #1033, PR #1085)
Two related fixes for the gemini/agy consultation lane that improve review-loop reliability:
- Headless on-task preamble (
packages/codev/src/commands/consult/index.ts). When Codev invokes agy for a review-time consult, the prompt now begins with a read-only headless-mode constraint block: don't list directories, don't check git, don't run exploratory commands, don't activate local skills, read only the files named in the prompt, and end the response with a parseableVERDICT:line. Applied on both the inline and large-prompt (temp-file) paths. Targets the "agy latches onto a local skill and emits no verdict" failure mode that the earlier argv-ordering fix (#1081) didn't address. - No-verdict → COMMENT, not REQUEST_CHANGES (
packages/codev/src/commands/porch/verdict.ts). A consult that ran but produced no parseableVERDICT:line now scores asCOMMENT(non-blocking) rather thanREQUEST_CHANGES. Previously a missing verdict was scored as a change-request and churned the porch review loop.
Together these two changes make the agy lane usable again in CMAP reviews without spurious iteration.
Activity hooks: VS Code publishes events to URLs you declare (PR #1105)
The outbound-direction sibling of the controller-agnostic command relay (#1091). The VS Code extension now publishes two abstract activity events to URL templates you declare in personal config: window-focus (fires when a Codev workspace's VS Code window gains focus) and builder-active (fires when you switch focus to a specific builder via terminal, sidebar selection, or its diff editor). Each event interpolates {workspace} and {builder} into the URL template (URL-encoded; absent keys collapse to empty) and asks the OS to open the result, so anything that can register a URL scheme — a hardware controller, a desktop companion app, a hosted control page, a webhook receiver — can react to which workspace and which builder you're focused on.
Example personal config (~/.codev/config.json to follow you across every workspace, or .codev/config.local.json to scope to one repo):
Three security postures bake in by default:
- Hooks resolve from personal config layers only.
~/.codev/config.json(global) and.codev/config.local.json(gitignored per-project) feed the hook resolver; the committed.codev/config.jsonis excluded. Hooks open URLs, so a hook URL committed in a malicious repo would be a zero-click execution surface on workspace open. Personal-layers-only closes that. - The extension is fully disabled in untrusted workspaces (VS Code Restricted Mode). The
package.jsonuntrustedWorkspacescapability is intentionally omitted entirely (not set to'limited') so VS Code's own trust gate covers every Codev surface, not just hooks — the committedworktree.devCommand(the runnable-worktree dev-server command) is a sibling attack surface that the same gate now also closes. - URL opens route through
vscode.env.openExternal. Hooks reach the local client when you're using remote dev (SSH / WSL / Codespaces), where the handler app actually lives, instead of running on the extension host. Cross-platform shell-quoting pitfalls (a Windowscmd /c start "" urltreating an&in the URL as a command separator) go away in the same change.
Inert by default — no activityHooks declared means zero behaviour change. A url whose handler isn't registered fails fast and pauses hooks for the window after one warning, rather than relaunching a doomed process on every event. builder-active is de-duplicated across the three subscription sources (terminal focus, sidebar selection, diff focus) so rapid navigation within one builder doesn't relaunch the same URL repeatedly.
The shared codev-config-watcher (a rename of the earlier worktree-config-watcher, behaviour-preserving) carries the SSE event that signals an edit to .codev/config(.local).json, so an activity-hooks edit fans out the same codev-config-updated event the worktree-config view already reacts to — one watcher per workspace, not one per consumer.
Tower command relay: external controllers can drive the active VS Code editor (#1087 / #1088 / #1089, PR #1091)
A new Tower-side command channel lets external controllers (a Stream Deck device, a hosted page, a CLI script, anything that can POST to Tower) drive the active VS Code window with a canonical set of verbs. Codev's VS Code extension exposes an allowlist-gated provider that subscribes to a Tower SSE stream and dispatches a small set of verbs to existing commands. This is the substrate that the separate Codev Stream Deck integration sits on; Codev does not ship a Stream Deck client itself, just the protocol surface.
What ships in this PR:
- A new wire contract for
CommandRequestcarrying{ verb, args, workspace? }. The verb-map is the security allowlist: only declared verbs reach the provider. Live verb set as of this release includes the four palette-and-keyboard commands listed below plusview-diff,spawn-builder,run-dev,workspace-dev-start, andworkspace-dev-stop. - A Tower HTTP route
POST /api/commandthat broadcasts the request as an SSE envelope to active providers. The route sits behind Tower's existingisRequestAllowedauth gate so it inherits Tower's posture rather than bypassing it. - A VS Code-side provider (
command-relay.ts) that subscribes to the SSE stream, gates onvscode.window.state.focusedfor single-active-provider semantics (the focused window wins; an unfocused window stays idle), applies workspace scoping (drops events whoseworkspacefield doesn't matchgetWorkspacePath()), and dispatches to the existing command viaexecuteCommand. The workspace filter mirrors the precedent set bybuilder-spawnedcross-workspace handling inbuilder-spawn-handler.ts. - Four new commands wired into the relay's allowlist plus the command palette plus keyboard surfaces:
codev.forwardCurrentFileToBuilder(forwards the cursor's current file path to the active builder PTY),codev.forwardCurrentHunkToBuilder(forwards the cursor's current hunk),codev.diffFirstFileandcodev.diffFirstHunk(jump to the first file or first hunk in a View Diff session, completing the existing keyboard walk shipped in PR #1067 and PR #1075). - A shared SSE envelope deduplication helper (
sse-envelope.ts) so multi-subscriber streams don't double-dispatch.
The workspace-scoping field is defensive infrastructure landed ahead of demand: no controller populates it today, so the focus-gate is the only filter in active use. As soon as a controller starts addressing specific workspaces, the provider already does the right thing without further extension-side code change. The privileged verbs (spawn-builder, run-dev, workspace-dev-start, workspace-dev-stop) are safe to ship today because the focus-gate prevents accidental cross-workspace dispatch, and the workspace field is ready when controller-side addressing lands.
CMAP-3 caught and the author addressed two findings at review time: the four new commands now appear in the manifest (so they're palette-discoverable and keybindable, not just relay-callable), and the workspace-scope filter was added as described above (originally the relay was focus-gate-only, which the reviewer flagged as insufficient for multi-workspace setups). The defensive workspace filter is the second-place issue from the reviewer's three-option recommendation, kept in scope because it's separable from controller-side scoping and prevents a real wrong-target risk on the privileged verbs.
Polish
- Architect group-header click opens the architect terminal (#1108, PR #1109). In the Agents view's architect-axis grouping mode, clicking an architect group header now opens that architect's terminal — parity with the existing builder-row click-to-open affordance. The expand-collapse chevron remains a separate target, so the two gestures don't conflict. Only the architect axis gets the affordance; stage and area group headers name no launchable entity and stay as pure containers.
Other fixes (dashboard, porch, infrastructure)
afx sendfails loud on an unverifiable builder id instead of silently misrouting to main (#1094, PR #1095). Previously, sending to a typo'd or stale builder id quietly fell back to the main architect — the message went to the wrong recipient with no indication to the sender. The fix returns a clearNOT_FOUNDerror naming the unrecognized id, so the sender notices the mistake immediately instead of discovering it later (or not at all).consult --type integrationanchors the diff on the integration-branch base (#1113, PR #1114). Integration-type reviews compare the working tree against the integration branch; the previous behaviour drifted the diff base over time as the integration branch advanced, causing scope to creep beyond what the reviewer expected. The diff base is now anchored deterministically, so consult's integration reviews stay scoped to the actual integration delta.- CLAUDE.md / AGENTS.md hot-tier context now uses
@importlines instead of an inlined managed block (#1119, PR #1120). The previous approach materialised the hot-tier content (arch-critical.md+lessons-critical.md) directly intoCLAUDE.mdandAGENTS.mdas an auto-generated block. That created a drift footgun: editing a hot file and forgettingcodev updateleft the inlined block silently stale. The block now emits two@importlines that Claude Code expands into context at session launch, so the hot files are the single source of truth and the root docs can't drift from them. Existing adopters' inlined blocks auto-migrate to the@importform on their nextcodev init/codev update. Porch's phase-prompt injection is untouched — it reads the hot files live for models that don't expand@import(consult, agent SDK); only the interactive docs surface changes.
Breaking changes
None.
Install
npm install -g @cluesmith/codev@3.2.2
afx tower stop && afx tower startThe VS Code extension ships separately via the Marketplace: the Codev extension by cluesmith.codev, version 3.2.2.
Contributors
- @mohidmakhdoomi: Codex as a first-class architect harness (PR #1059), letting Codev wrap Codex as the long-running orchestrator process alongside Claude.
- @amustafa: Tower SSE reject-on-cap (PR #1126), breaking the reconnect cascade that was exhausting ephemeral ports. First contribution to Codev, thank you.
- @waleedkadous: the gemini/agy consult lane on-task preamble and no-verdict scoring (PR #1085),
afx sendfail-loud on unverifiable ids (PR #1095),consult --type integrationdiff-base anchoring (PR #1114), and the CLAUDE.md / AGENTS.md hot-tier@importmigration (PR #1120). - The Codev architect plus builders working under the PIR, AIR, and BUGFIX protocols across the remaining PRs in this release.
{ "activityHooks": [ { "on": ["window-focus", "builder-active"], "url": "<scheme>://...?workspace={workspace}&builder={builder}", "background": true } ] }