Architect: DockerExecClaudeAgent chat relay #1132

Closed
opened 2026-05-13 20:00:55 +00:00 by claude-desktop · 0 comments
Collaborator

As the operator, I want architect chat turns relayed through docker exec into the persistent container so that the Claude SDK runs inside the container rather than in the host service process.

Depends on the container being provisioned (architect container + reconciliation issue).

Spec: specs/architect-dockerize.md

Acceptance criteria

DockerExecClaudeAgent

  • A new DockerExecClaudeAgent class implements ClaudeAgentPort by running docker exec -i architect-default <claude invocation> and piping stdin/stdout through.
  • It is a drop-in replacement — same streaming AsyncIterable<TaskEvent> interface as SdkClaudeAgent.
  • runArchitectTurn uses DockerExecClaudeAgent in production via the existing claudeAgent?: ClaudeAgentPort injection point (no interface change; tests keep injecting fakes without Docker).

Session continuity

  • Session resume works across separate POST /architect/chat requests: claude_session_id stored in SQLite is passed to the exec invocation and the SDK resumes correctly.
  • CLAUDE_CONFIG_DIR inside the container resolves to the mounted /claude-config path.

Abort and steer

  • POST /architect/abort/:task_id kills the running docker exec process cleanly; the abort event propagates to the SDK and runArchitectTurn returns status: "cancelled".
  • POST /architect/steer/:task_id continues to work via steerInputIterator — no change to the steer channel wiring.

Tool policy

  • buildArchitectRunRequest tool policy blocks Read and Bash paths under /claude-config (prevent the agent from reading its own mounted token).
  • touchesHostSecret (or equivalent) is updated to include /claude-config in its deny list.

Tests

  • All existing architect.test.ts tests pass — the fake ClaudeAgentPort injection keeps them Docker-free.
  • New test: DockerExecClaudeAgent emits correctly-shaped TaskEvents when the mocked docker exec subprocess writes valid SDK output to stdout.
  • just qa passes.

Out of scope

  • Removing the host-mode code paths and isLocal FS branch — that is a follow-up cleanup issue once this relay is confirmed working in production.
  • Changes to the /architect/* HTTP surface or workspace UI.

References

  • Spec: specs/architect-dockerize.md — "Chat relay" and "Tool policy adjustments" sections
  • apps/server/src/domain/agent/architect.tsrunArchitectTurn, buildArchitectRunRequest
  • apps/server/src/infrastructure/agent/sdk-adapter.tsSdkClaudeAgent (reference implementation)
As the operator, I want architect chat turns relayed through `docker exec` into the persistent container so that the Claude SDK runs inside the container rather than in the host service process. Depends on the container being provisioned (architect container + reconciliation issue). Spec: `specs/architect-dockerize.md` ### Acceptance criteria #### DockerExecClaudeAgent - [ ] A new `DockerExecClaudeAgent` class implements `ClaudeAgentPort` by running `docker exec -i architect-default <claude invocation>` and piping stdin/stdout through. - [ ] It is a drop-in replacement — same streaming `AsyncIterable<TaskEvent>` interface as `SdkClaudeAgent`. - [ ] `runArchitectTurn` uses `DockerExecClaudeAgent` in production via the existing `claudeAgent?: ClaudeAgentPort` injection point (no interface change; tests keep injecting fakes without Docker). #### Session continuity - [ ] Session resume works across separate `POST /architect/chat` requests: `claude_session_id` stored in SQLite is passed to the exec invocation and the SDK resumes correctly. - [ ] CLAUDE_CONFIG_DIR inside the container resolves to the mounted `/claude-config` path. #### Abort and steer - [ ] `POST /architect/abort/:task_id` kills the running `docker exec` process cleanly; the abort event propagates to the SDK and `runArchitectTurn` returns `status: "cancelled"`. - [ ] `POST /architect/steer/:task_id` continues to work via `steerInputIterator` — no change to the steer channel wiring. #### Tool policy - [ ] `buildArchitectRunRequest` tool policy blocks `Read` and `Bash` paths under `/claude-config` (prevent the agent from reading its own mounted token). - [ ] `touchesHostSecret` (or equivalent) is updated to include `/claude-config` in its deny list. #### Tests - [ ] All existing `architect.test.ts` tests pass — the fake `ClaudeAgentPort` injection keeps them Docker-free. - [ ] New test: `DockerExecClaudeAgent` emits correctly-shaped `TaskEvent`s when the mocked `docker exec` subprocess writes valid SDK output to stdout. - [ ] `just qa` passes. ### Out of scope - Removing the host-mode code paths and `isLocal` FS branch — that is a follow-up cleanup issue once this relay is confirmed working in production. - Changes to the `/architect/*` HTTP surface or workspace UI. ### References - Spec: `specs/architect-dockerize.md` — "Chat relay" and "Tool policy adjustments" sections - `apps/server/src/domain/agent/architect.ts` — `runArchitectTurn`, `buildArchitectRunRequest` - `apps/server/src/infrastructure/agent/sdk-adapter.ts` — `SdkClaudeAgent` (reference implementation)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/agent-hooks#1132
No description provided.