refactor(architect): make docker-exec relay mandatory in runArchitectTurn (AR-3) #1204
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/agent-hooks!1204
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "code-lead/1198"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #1198.
Summary
AR-3 closes the in-process SDK code path that pre-#1132 served
/architect/chatand/architect/spec. The relay was wired in #1132 by havingArchitectAgentDispatchpass aDockerExecClaudeAgentintorunArchitectTurnexplicitly, but the runner still defaulted toSdkClaudeAgentwhen called without an explicitclaudeAgent— an in-process escape hatch that no production caller used but that any future caller could trip into.This PR moves the construction into
runArchitectTurn's default so the relay is enforced at the runner boundary itself:runArchitectTurnnow defaultsclaudeAgenttonew DockerExecClaudeAgent({ agentName })(wasnew SdkClaudeAgent()). The in-process SDK import is gone from the architect runner.ArchitectAgentDispatchdrops the redundant explicitclaudeAgentconstruction — the runner is now the single source of truth for the relay.Acceptance criteria
/architect/chatis rewired todocker execintoclaude-hooks-architect-default. Handler input schema + SSE stream shape unchanged — the change is the runner's defaultClaudeAgentPort./architect/spec(file write / breakdown-preview) is unchanged — those handlers route throughforge.writeFile/forge.readFile, never through the SDK; the relay was already complete on that side since #1133.if (host_mode)branch in the chat/spec handler, noSdkClaudeAgentfallback inrunArchitectTurn.reconcileOne("architect-default")still works exactly like every other agent.role === "host"read remains in any chat / spec handler (verified by grep againstapps/server/src/http/handlers/architect.ts+apps/server/src/domain/agent/architect.ts).Tests
Three new structural guards in
apps/server/src/http/handlers/architect.test.tsunderAR-3 (#1198) — in-process SDK path is deleted:domain/agent/architect.tsmust not importSdkClaudeAgent.domain/agent/architect.tsmust importDockerExecClaudeAgent(the new default).infrastructure/agents/architect-agent-dispatch.tsmust not constructDockerExecClaudeAgentitself — the runner owns that.Existing coverage for the relay shape (
docker-exec-adapter.test.ts) and dispatch routing (agent-dispatch-port.test.ts) is unchanged.Test plan
bun test apps/server/src— 3357 → 3360 pass, 0 fail (3 new structural tests + all existing pass).just qa— typecheck + lint + format + sql-layer + paraglide + i18n-string + flow-schema all green.Out of scope
role: "host"→"planner"(#1199).HOST_MODE_TYPES/HostContainerLifecycle/getArchitectWorkerhost filter (#1200).🤖 Generated with Claude Code
Review — AR-3: make docker-exec relay mandatory in
runArchitectTurnAPPROVED ✅ — CI green, all AC checked, no blocking issues.
What the PR does
Moves the
DockerExecClaudeAgentconstruction from the call site (ArchitectAgentDispatch) intorunArchitectTurn's own default so the in-process SDK fallback is fully deleted rather than just unused. Any future caller ofrunArchitectTurnthat omitsclaudeAgentnow gets the relay automatically — there is no escape hatch back toSdkClaudeAgent.The change is purely a responsibility shift; the runtime behaviour of every existing production caller is unchanged (they all went through
ArchitectAgentDispatch, which was already passingDockerExecClaudeAgentexplicitly).Code quality
Core change (
architect.tsline 722)Clean and correct.
opts.agentNameis the right key — it matches whatArchitectAgentDispatchhas always passed as the container name, so no naming drift.ArchitectAgentDispatchcleanup — the seven-line comment block for the old explicitclaudeAgentarg is replaced by a four-line AR-3 note. No dead code left behind.Structural test suite — the three new tests in
architect.test.tsare deliberately static-analysis guards rather than runtime tests, which is the right call here: the invariant is "this import must/must not exist", and a file-content check is the simplest way to pin it without adding Docker infrastructure to CI.One small observation on test 3 (the dispatch-file guard): the regex strips block comments (
/* … */) before checking fornew DockerExecClaudeAgent(but does not strip line comments (// …). This means a developer who writes// new DockerExecClaudeAgent(in a line comment insidearchitect-agent-dispatch.tswould cause the test to fail spuriously. In practice this is extremely unlikely to happen by accident, and the assertion direction (banning construction) makes a false positive less harmful than a false negative would be, so this is a minor nit rather than a blocking concern.Acceptance criteria — verified ✅
/architect/chatrewired todocker execvia runner defaultDockerExecClaudeAgent/architect/specunchanged (routes throughforge.writeFile/readFile)SdkClaudeAgentin runnerrole === "host"read in chat/spec handlersOut-of-scope items acknowledged
#1199(renamerole: "host") and#1200(deleteHOST_MODE_TYPESetc.) are correctly deferred — this PR is already exactly the right size.No changes requested. Ready to merge.