Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
047209e
chore(porch): 1338 init spir
mohidmakhdoomi Aug 3, 2026
fb12970
[Spec 1338] Initial specification draft
mohidmakhdoomi Aug 3, 2026
4a99cd6
chore(porch): 1338 specify build-complete
mohidmakhdoomi Aug 3, 2026
8dc771e
[Spec 1338] Specification with multi-agent review
mohidmakhdoomi Aug 3, 2026
d55249e
chore(porch): 1338 spec-approval gate-requested
mohidmakhdoomi Aug 3, 2026
4f4b6fb
chore(porch): 1338 spec-approval gate-approved
mohidmakhdoomi Aug 3, 2026
909099a
chore(porch): 1338 plan phase-transition
mohidmakhdoomi Aug 3, 2026
419b700
[Spec 1338] Initial implementation plan
mohidmakhdoomi Aug 3, 2026
78feabb
chore(porch): 1338 plan build-complete
mohidmakhdoomi Aug 3, 2026
56ed7d3
[Spec 1338] Plan with multi-agent review
mohidmakhdoomi Aug 3, 2026
281c583
chore(porch): 1338 plan-approval gate-requested
mohidmakhdoomi Aug 3, 2026
c937164
chore(porch): 1338 plan-approval gate-approved
mohidmakhdoomi Aug 3, 2026
22865e2
chore(porch): 1338 implement phase-transition
mohidmakhdoomi Aug 3, 2026
12746b9
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 3, 2026
5e8e75d
chore(porch): 1338 advance plan phase → phase_2
mohidmakhdoomi Aug 3, 2026
e222b9e
[Spec 1338][Phase: phase_1] feat: retire built-in gemini harness in s…
mohidmakhdoomi Aug 3, 2026
d200edf
[Spec 1338][Phase: phase_2] feat: fail closed at spawn/launch boundaries
mohidmakhdoomi Aug 3, 2026
906ff8c
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 3, 2026
b87c1b6
[Spec 1338][Phase: phase_2] test: assert a rejected gemini spawn leav…
mohidmakhdoomi Aug 3, 2026
1152783
[Spec 1338][Phase: phase_2] fix: fail closed on architect restart/rec…
mohidmakhdoomi Aug 3, 2026
8716f0a
[Spec 1338][Phase: phase_2] docs: iter1 rebuttal + thread update
mohidmakhdoomi Aug 3, 2026
6aa31dd
chore(porch): 1338 implement re-iter (iter 2)
mohidmakhdoomi Aug 3, 2026
94ae5a5
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 3, 2026
9ec14c4
[Spec 1338][Phase: phase_2] fix: fail closed on clean-exit relaunch o…
mohidmakhdoomi Aug 3, 2026
1179f14
[Spec 1338][Phase: phase_2] docs: iter2 rebuttal + thread update
mohidmakhdoomi Aug 3, 2026
963ed56
chore(porch): 1338 implement re-iter (iter 3)
mohidmakhdoomi Aug 3, 2026
53ca129
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 3, 2026
89d25fc
chore(porch): 1338 advance plan phase → phase_3
mohidmakhdoomi Aug 3, 2026
9ccb017
[Spec 1338][Phase: phase_3] feat: doctor flags retired harness for bo…
mohidmakhdoomi Aug 3, 2026
401af81
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 3, 2026
3119e93
[Spec 1338][Phase: phase_3] fix: doctor honors the custom-gemini esca…
mohidmakhdoomi Aug 3, 2026
92d1f5d
[Spec 1338][Phase: phase_3] docs: iter1 rebuttal + thread update
mohidmakhdoomi Aug 3, 2026
479d4e4
chore(porch): 1338 implement re-iter (iter 2)
mohidmakhdoomi Aug 3, 2026
2598622
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 4, 2026
1648db6
chore(porch): 1338 advance plan phase → phase_4
mohidmakhdoomi Aug 4, 2026
9bc6398
[Spec 1338][Phase: phase_4] docs: retire the built-in Gemini CLI harn…
mohidmakhdoomi Aug 4, 2026
a7cc65b
[Spec 1338][Phase: phase_4] docs: thread — phase_3 approved, phase_4 …
mohidmakhdoomi Aug 4, 2026
3917395
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 4, 2026
d796f94
[Spec 1338][Phase: phase_4] docs: fix Gemini retirement guidance in R…
mohidmakhdoomi Aug 4, 2026
dd3d3e8
[Spec 1338][Phase: phase_4] docs: iter1 rebuttal + thread update
mohidmakhdoomi Aug 4, 2026
78be320
chore(porch): 1338 implement re-iter (iter 2)
mohidmakhdoomi Aug 4, 2026
2ee1965
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 4, 2026
27f9522
[Spec 1338][Phase: phase_4] docs: fix escape-hatch snippet to use GEM…
mohidmakhdoomi Aug 4, 2026
806e87f
[Spec 1338][Phase: phase_4] docs: iter2 rebuttal + thread update
mohidmakhdoomi Aug 4, 2026
0804c2a
chore(porch): 1338 implement re-iter (iter 3)
mohidmakhdoomi Aug 4, 2026
6980081
chore(porch): 1338 implement build-complete
mohidmakhdoomi Aug 4, 2026
5a68236
chore(porch): 1338 all plan phases complete → review
mohidmakhdoomi Aug 4, 2026
d660c92
[Spec 1338][Phase: review] fix: align retirement-guidance touchpoints…
mohidmakhdoomi Aug 4, 2026
62dfcd0
[Spec 1338][Phase: review] docs: refresh governance docs for the gemi…
mohidmakhdoomi Aug 4, 2026
0a915bd
[Spec 1338][Phase: review] docs: add review document + thread update
mohidmakhdoomi Aug 4, 2026
8d34ba4
chore(porch): 1338 record PR #1342
mohidmakhdoomi Aug 4, 2026
905383f
[Spec 1338][Phase: review] docs: thread — PR #1342 opened
mohidmakhdoomi Aug 4, 2026
4fcc19f
chore(porch): 1338 review build-complete
mohidmakhdoomi Aug 4, 2026
5da4183
[Spec 1338][Phase: review] revert: drop CHANGELOG entry (upstream rel…
mohidmakhdoomi Aug 4, 2026
507c407
[Spec 1338][Phase: review] fix: fail closed on --shell too (unconditi…
mohidmakhdoomi Aug 4, 2026
b97d96a
[Spec 1338][Phase: review] fix(doctor): interpolate role.name in cust…
mohidmakhdoomi Aug 4, 2026
a2b8b90
[Spec 1338][Phase: review] fix(tower): log retired-harness reason whe…
mohidmakhdoomi Aug 4, 2026
f009d11
[Spec 1338][Phase: review] docs: record integration-review adjustment…
mohidmakhdoomi Aug 4, 2026
f29c1cc
[Spec 1338][Phase: review] chore: commit porch consultation context a…
mohidmakhdoomi Aug 4, 2026
902ee11
[Spec 1338][Phase: review] fix: log swallowed harness error + correct…
mohidmakhdoomi Aug 4, 2026
c36f2df
[Spec 1338][Phase: review] docs: refresh review metrics + log follow-…
mohidmakhdoomi Aug 4, 2026
7bd4267
chore(porch): 1338 pr gate-requested
mohidmakhdoomi Aug 4, 2026
d6a0554
[Spec 1338][Phase: review] fix(tower): gate architect restartOnExit o…
mohidmakhdoomi Aug 5, 2026
37277cf
[Spec 1338][Phase: review] fix(tower): keep retired sibling architect…
mohidmakhdoomi Aug 5, 2026
24bcb25
[Spec 1338][Phase: review] fix(config): route deferred harness-prefli…
mohidmakhdoomi Aug 5, 2026
bea8649
[Spec 1338][Phase: review] fix(harness): own-property guard on BUILTI…
mohidmakhdoomi Aug 5, 2026
050335b
[Spec 1338][Phase: review] docs: thread — upstream maintainer review …
mohidmakhdoomi Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ OpenCode supports 75+ LLM providers (OpenAI, Anthropic, Google, Ollama, etc.). W
- OpenCode reads `AGENTS.md` for project instructions (already present in Codev projects)
- OpenCode is only supported as a **builder** shell, not as an architect shell

Other shells (Codex, Gemini) are also supported via the harness system. See `packages/codev/src/agent-farm/utils/harness.ts` for details, or define a custom harness in `.codev/config.json`.
Codex is also supported via the harness system. See `packages/codev/src/agent-farm/utils/harness.ts` for details, or define a custom harness in `.codev/config.json`. (The built-in **Gemini CLI** harness is **retired** — see the note under Autonomous Builder Flags below.)

## Architect-Builder Pattern

Expand Down Expand Up @@ -433,7 +433,6 @@ Builders need permission-skipping flags to run autonomously without human approv
| CLI Tool | Flag | Purpose |
|----------|------|---------|
| Claude Code | `--dangerously-skip-permissions` | Skip permission prompts for file/command operations |
| Gemini CLI | `--yolo` | Enable autonomous mode without confirmations |

Configure in `.codev/config.json` (created by `codev init` or `codev adopt`):
```json
Expand All @@ -445,19 +444,45 @@ Configure in `.codev/config.json` (created by `codev init` or `codev adopt`):
}
```

Or for Gemini (the standalone **Gemini CLI** as a *builder/architect* coding agent — a separate
concern from the `gemini` **consult lane**, which now uses the Antigravity CLI `agy`). Note: Google
retired the Gemini CLI for Pro/Ultra/free tiers on 2026-06-18, so this builder harness will stop
working for those tiers — prefer a Claude or Codex builder, or an enterprise Gemini CLI. (Tracked as
a follow-up; out of scope for the consult-lane migration.)
The built-in **Gemini CLI** harness is **retired** as a builder/architect shell: Google ended
consumer Gemini CLI access (Pro, Ultra, and free tiers) on 2026-06-18, so it is no longer offered as
a supported built-in shell. Switch to a supported harness — `claude` or `codex` for either role, or
`opencode` for builders (OpenCode is not supported as an architect shell). For example, Codex for
both roles:
```json
{
"shell": {
"architect": "gemini --yolo",
"builder": "gemini --yolo"
"architect": "codex",
"builder": "codex"
}
}
```
If you retain Gemini CLI access (a Standard/Enterprise subscription or API-key auth), you can still
run it by defining a **custom harness** named `gemini` in `.codev/config.json` **and selecting it
explicitly** with `shell.builderHarness` / `shell.architectHarness`. The explicit selector is
**required**: a bare auto-detected `gemini` command (e.g. `shell.builder: "gemini --yolo"` with no
`builderHarness`) stays retired, because auto-detection resolves the built-in namespace only.
```json
{
"shell": {
"builder": "gemini --yolo",
"builderHarness": "gemini"
},
"harness": {
"gemini": {
"roleArgs": [],
"roleEnv": { "GEMINI_SYSTEM_MD": "${ROLE_FILE}" },
"roleScriptFragment": "",
"roleScriptEnv": { "GEMINI_SYSTEM_MD": "${ROLE_FILE}" }
}
}
}
```
The Gemini CLI reads its system prompt from the `GEMINI_SYSTEM_MD` environment variable pointing at
the role file, so the custom harness injects via `roleEnv` / `roleScriptEnv` (with empty `roleArgs`) —
reproducing exactly what the retired built-in harness did.
See `packages/codev/src/agent-farm/utils/harness.ts` for the custom-harness fields. This is separate
from the `gemini` **consult lane**, which is unaffected and now uses the Antigravity CLI `agy`.

**Warning**: These flags allow the AI to execute commands and modify files without asking. Only use in development environments where you trust the AI's actions.

Expand Down
454 changes: 454 additions & 0 deletions codev/plans/1338-retire-gemini-cli-as-a-builder.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Phase 2 (1338) — Rebuttals, iteration 1

Reviews: **Gemini APPROVE**, **Codex REQUEST_CHANGES (HIGH)**, **Claude APPROVE (HIGH)**.
Disposition: **both Codex points accepted and fixed in commit `11527838`.** No point rejected.
Codex found two *reachable* fail-closed gaps on the restart/reconnect paths that the initial
"unreachable" analysis (and my own phase_2 design note) missed — both are now fixed and
regression-tested. Claude's and Gemini's approvals stand; Claude's non-blocking observations are
dispositioned below. Each claim was re-verified against source before revising.

---

## Codex (REQUEST_CHANGES) — both accepted, both fixed

### C1 — Fail-OPEN on reconnect: retired architect can still relaunch the Gemini binary
**Accepted (important, real bug).** Verified: `resolveArchitectRestart` (tower-utils.ts:441)
propagates `RetiredHarnessError`, and BOTH reconnect consumers in `tower-terminals.ts`
(`_reconcileTerminalSessionsInner` at the startup-reconcile site, and `getTerminalsForWorkspace`
at the on-the-fly reconnect site) wrapped that call in a `try/catch` that caught **all** harness
errors and fell back to `{ command: cmdParts[0], args: cmdParts.slice(1) }`. For a gemini architect
`cmdParts[0]` **is** the retired `gemini` binary, so Tower would auto-restart straight into it with
no role injection — a direct violation of fail-closed retirement. My phase_2 design had reasoned
these paths "unreachable" because the *initial* launch throws first; Codex correctly showed they are
reachable when a config is edited to gemini **mid-session**, or when **Tower restarts** and reads a
gemini architect config (no initial launch happened in this process).

**Change (commit `11527838`):** Extracted the two duplicated consumer blocks into one exported
helper, `buildArchitectReconnectRestartOptions` (tower-utils.ts:589), co-located with the
`resolveArchitectRestart` family. It **fails closed** on `RetiredHarnessError` (tower-utils.ts:630):
returns `undefined`, so the session reconnects to a live shellper if one exists but Tower **never
configures an auto-restart into the retired binary**. Any *other* harness-resolution error still
degrades to the plain configured command (identity preserved via `cleanEnv` / `CODEV_ARCHITECT_NAME`,
Spec 786) — that transient-failure behavior is deliberately unchanged. The single `includeFreshLaunch`
parameter preserves each call site's prior behavior exactly: startup reconcile passes `true`
(tower-terminals.ts:684, wires the #1264 clean-exit rerun), on-the-fly reconnect passes `false`
(tower-terminals.ts:920, no clean-exit rerun — as before). The #832 resume-bake and #1149
crash-loop fallback are carried through unchanged.

### C2 — Uncaught throw on clean-exit relaunch: Tower exception
**Accepted (important, real bug).** Verified: `buildArchitectFreshLaunch().next()` resolved
`getArchitectHarness` unguarded, and `SessionManager` invokes it with **no** try/catch
(`session-manager.ts:1175`: `session.options.freshLaunch?.next() ?? null`, inside an async
clean-exit handler). So an architect whose config flipped to gemini, then exited cleanly, would
throw `RetiredHarnessError` into that handler — an uncaught Tower exception.

**Change (commit `11527838`):** Guarded the `getArchitectHarness` call inside `next()`
(tower-utils.ts:544). On `RetiredHarnessError` it logs a WARN and returns the **plain** original
launch `{ args: baseArgs, env: baseEnv }` — no throw, and no re-injection of the retired harness
(`baseArgs` come from the *original supported-harness* launch, so they can never be a gemini command).
Any non-retirement error is a genuine fault and is rethrown unchanged.

### C3 — "Regression tests for both reconnect and clean-exit relaunch paths"
**Accepted.** Added **+7** tests to `tower-utils.test.ts`:
- `buildArchitectFreshLaunch retirement (#1338)` (2): gemini → `next()` does **not** throw and
returns the plain launch; codex → resolves normally (regression).
- `buildArchitectReconnectRestartOptions retirement (#1338)` (5): gemini → `undefined` regardless of
`includeFreshLaunch`; codex → real restart options with `command`/env preserved; `includeFreshLaunch`
toggles `freshLaunch`; a non-retirement harness error → plain-command fallback (proves the
fail-closed change did **not** regress the transient-error path).

---

## Claude (APPROVE, HIGH) — non-blocking observations dispositioned

Claude approved and asked that two items be recorded in the review artifact; both are handled here
and will be carried into the final `codev/reviews/1338-*.md`:

- **(a) Preflight centralized at the `spawn()` dispatcher** rather than per-`createWorktree`-entry.
**Intentional deviation from the plan's letter** — one guard above handler dispatch
(`spawn.ts`, `mode !== 'shell'`) gives equivalent coverage of all five worktree-creating handlers
**and** `createWorktree`'s own internal `getBuilderHarness` (spawn-worktree.ts:912), with one call
site instead of five. Recorded; will appear in the review's Deviations section.
- **(b) `session-manager.ts:1175` `freshLaunch?.next()` is unguarded by design / unreachable.**
This is precisely the path **Codex's C2 proved reachable** (config flipped to gemini before a clean
exit). So rather than accept it as an unreachable non-issue, the C2 fix now **guards it at the
source** (`buildArchitectFreshLaunch().next()`). Claude's non-blocking note and Codex's HIGH finding
converge on the same site; it is now actively fail-closed, not merely assumed unreachable.

Claude's other minor notes are acknowledged, no change: **#2** (harness resolved twice on the happy
spawn path — negligible config read) and **#3** (`afx setup` / `installHarnessWorktreeFiles` still call
`getBuilderHarness` raw — out of Phase 2 scope; the CLI catch prints the retirement `.message` cleanly,
so a pre-existing gemini worktree degrades to a readable message rather than a crash).

---

## Gemini (APPROVE)
No changes requested. Gemini independently confirmed the builder preflight, the `buildArchitectArgs`
fail-closed launch boundary, the `siblingRegistrationIsLive` guard, and the `tower-instances`
`addArchitect`/`launchInstance` clean-error surfacing.

---

## Verification after fixes
- `pnpm --filter @cluesmith/codev build` → exit 0 (tsc + vite clean).
- `tower-utils.test.ts` → 61 passed (includes the +7 above).
- Consumer suites `tower-terminals.test.ts` + `tower-instances.test.ts` + `bugfix-430-tower-restart.test.ts`
→ 133 passed (the reconnect/restart refactor introduces no regression).
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
### Iteration 1 Reviews
- gemini: APPROVE
- codex: REQUEST_CHANGES — Builder preflight is correct, but Tower restart paths can still launch Gemini or crash.
- claude: APPROVE — Phase 2 fails closed at every spawn and architect-launch boundary with no orphaned state and no Tower-crash path; tests and typecheck are green.

### Builder Response to Iteration 1
# Phase 2 (1338) — Rebuttals, iteration 1

Reviews: **Gemini APPROVE**, **Codex REQUEST_CHANGES (HIGH)**, **Claude APPROVE (HIGH)**.
Disposition: **both Codex points accepted and fixed in commit `11527838`.** No point rejected.
Codex found two *reachable* fail-closed gaps on the restart/reconnect paths that the initial
"unreachable" analysis (and my own phase_2 design note) missed — both are now fixed and
regression-tested. Claude's and Gemini's approvals stand; Claude's non-blocking observations are
dispositioned below. Each claim was re-verified against source before revising.

---

## Codex (REQUEST_CHANGES) — both accepted, both fixed

### C1 — Fail-OPEN on reconnect: retired architect can still relaunch the Gemini binary
**Accepted (important, real bug).** Verified: `resolveArchitectRestart` (tower-utils.ts:441)
propagates `RetiredHarnessError`, and BOTH reconnect consumers in `tower-terminals.ts`
(`_reconcileTerminalSessionsInner` at the startup-reconcile site, and `getTerminalsForWorkspace`
at the on-the-fly reconnect site) wrapped that call in a `try/catch` that caught **all** harness
errors and fell back to `{ command: cmdParts[0], args: cmdParts.slice(1) }`. For a gemini architect
`cmdParts[0]` **is** the retired `gemini` binary, so Tower would auto-restart straight into it with
no role injection — a direct violation of fail-closed retirement. My phase_2 design had reasoned
these paths "unreachable" because the *initial* launch throws first; Codex correctly showed they are
reachable when a config is edited to gemini **mid-session**, or when **Tower restarts** and reads a
gemini architect config (no initial launch happened in this process).

**Change (commit `11527838`):** Extracted the two duplicated consumer blocks into one exported
helper, `buildArchitectReconnectRestartOptions` (tower-utils.ts:589), co-located with the
`resolveArchitectRestart` family. It **fails closed** on `RetiredHarnessError` (tower-utils.ts:630):
returns `undefined`, so the session reconnects to a live shellper if one exists but Tower **never
configures an auto-restart into the retired binary**. Any *other* harness-resolution error still
degrades to the plain configured command (identity preserved via `cleanEnv` / `CODEV_ARCHITECT_NAME`,
Spec 786) — that transient-failure behavior is deliberately unchanged. The single `includeFreshLaunch`
parameter preserves each call site's prior behavior exactly: startup reconcile passes `true`
(tower-terminals.ts:684, wires the #1264 clean-exit rerun), on-the-fly reconnect passes `false`
(tower-terminals.ts:920, no clean-exit rerun — as before). The #832 resume-bake and #1149
crash-loop fallback are carried through unchanged.

### C2 — Uncaught throw on clean-exit relaunch: Tower exception
**Accepted (important, real bug).** Verified: `buildArchitectFreshLaunch().next()` resolved
`getArchitectHarness` unguarded, and `SessionManager` invokes it with **no** try/catch
(`session-manager.ts:1175`: `session.options.freshLaunch?.next() ?? null`, inside an async
clean-exit handler). So an architect whose config flipped to gemini, then exited cleanly, would
throw `RetiredHarnessError` into that handler — an uncaught Tower exception.

**Change (commit `11527838`):** Guarded the `getArchitectHarness` call inside `next()`
(tower-utils.ts:544). On `RetiredHarnessError` it logs a WARN and returns the **plain** original
launch `{ args: baseArgs, env: baseEnv }` — no throw, and no re-injection of the retired harness
(`baseArgs` come from the *original supported-harness* launch, so they can never be a gemini command).
Any non-retirement error is a genuine fault and is rethrown unchanged.

### C3 — "Regression tests for both reconnect and clean-exit relaunch paths"
**Accepted.** Added **+7** tests to `tower-utils.test.ts`:
- `buildArchitectFreshLaunch retirement (#1338)` (2): gemini → `next()` does **not** throw and
returns the plain launch; codex → resolves normally (regression).
- `buildArchitectReconnectRestartOptions retirement (#1338)` (5): gemini → `undefined` regardless of
`includeFreshLaunch`; codex → real restart options with `command`/env preserved; `includeFreshLaunch`
toggles `freshLaunch`; a non-retirement harness error → plain-command fallback (proves the
fail-closed change did **not** regress the transient-error path).

---

## Claude (APPROVE, HIGH) — non-blocking observations dispositioned

Claude approved and asked that two items be recorded in the review artifact; both are handled here
and will be carried into the final `codev/reviews/1338-*.md`:

- **(a) Preflight centralized at the `spawn()` dispatcher** rather than per-`createWorktree`-entry.
**Intentional deviation from the plan's letter** — one guard above handler dispatch
(`spawn.ts`, `mode !== 'shell'`) gives equivalent coverage of all five worktree-creating handlers
**and** `createWorktree`'s own internal `getBuilderHarness` (spawn-worktree.ts:912), with one call
site instead of five. Recorded; will appear in the review's Deviations section.
- **(b) `session-manager.ts:1175` `freshLaunch?.next()` is unguarded by design / unreachable.**
This is precisely the path **Codex's C2 proved reachable** (config flipped to gemini before a clean
exit). So rather than accept it as an unreachable non-issue, the C2 fix now **guards it at the
source** (`buildArchitectFreshLaunch().next()`). Claude's non-blocking note and Codex's HIGH finding
converge on the same site; it is now actively fail-closed, not merely assumed unreachable.

Claude's other minor notes are acknowledged, no change: **#2** (harness resolved twice on the happy
spawn path — negligible config read) and **#3** (`afx setup` / `installHarnessWorktreeFiles` still call
`getBuilderHarness` raw — out of Phase 2 scope; the CLI catch prints the retirement `.message` cleanly,
so a pre-existing gemini worktree degrades to a readable message rather than a crash).

---

## Gemini (APPROVE)
No changes requested. Gemini independently confirmed the builder preflight, the `buildArchitectArgs`
fail-closed launch boundary, the `siblingRegistrationIsLive` guard, and the `tower-instances`
`addArchitect`/`launchInstance` clean-error surfacing.

---

## Verification after fixes
- `pnpm --filter @cluesmith/codev build` → exit 0 (tsc + vite clean).
- `tower-utils.test.ts` → 61 passed (includes the +7 above).
- Consumer suites `tower-terminals.test.ts` + `tower-instances.test.ts` + `bugfix-430-tower-restart.test.ts`
→ 133 passed (the reconnect/restart refactor introduces no regression).


### IMPORTANT: Stateful Review Context
This is NOT the first review iteration. Previous reviewers raised concerns and the builder has responded.
Before re-raising a previous concern:
1. Check if the builder has already addressed it in code
2. If the builder disputes a concern with evidence, verify the claim against actual project files before insisting
3. Do not re-raise concerns that have been explained as false positives with valid justification
4. Check package.json and config files for version numbers before flagging missing configuration
Loading
Loading