M18-4: Architect agent bootstrap (host-mode, singleton) #165

Closed
opened 2026-04-20 16:02:57 +00:00 by code-lead · 0 comments
Collaborator

As an operator, I want a new architect agent type that runs in the host process (no container), has filesystem access to the repo, can call the service's own HTTP API, and exposes a persistent chat session the UI can talk to, so that spec writing / breakdown / assignment become an interactive workflow instead of webhook-only dispatch.

Acceptance criteria

Agent type

  • config/agents.json::types.architect entry:
    • forgejo_user: "architect" (new Forgejo account; operator provisions the token file)
    • default_model: "claude-opus-4-7[1m]" (1M context — spec work needs it)
    • container: { enabled: false } — bypasses the container-reconcile flow
    • plugins: [] — no per-agent plugin set (runs with the host's ~/.claude config)
    • default_system_prompt — purpose, scope, guard-rails (full text in #M18-5)
  • Singleton: db.ts seeds one architect-default row; Agents CRUD UI refuses to create a second architect instance (409 Conflict)
  • ResolvedAgent gains a host_mode: boolean flag derived from container.enabled === false
  • agent-runner.runAgentTask branches: host mode skips container.ts::exec, invokes SDK query() inline in the service process with cwd: process.cwd()

Security & isolation

  • Host mode is only available to a hardcoded set of types (for now: architect). Any other type with container.enabled: false fails loadWebhookConfig at startup
  • Architect's SDK invocation inherits the service's env but loads its OWN credentials dir (~/.config/claude-hooks/agent-env/architect/). Operator provisions via just agent-env-sync architect
  • Skill surface restricted: architect can call breakdown, read/write specs/*.md, POST to its own service's /breakdown, /task, /cancel. Explicitly cannot merge PRs or push to main
  • scripts/smoke-creds.sh learns to probe architect (host-mode: filesystem + token file, not container exec)

Sessions & chat

  • New endpoints on apps/server:
    • POST /architect/chat — body { session_id?, message }. If session_id absent, creates a new one. Returns { session_id, task_id } and starts streaming SSE at /architect/stream/:task_id
    • GET /architect/sessions — list persisted sessions (id, first-message preview, last-updated, turn count)
    • GET /architect/sessions/:id — full transcript
    • DELETE /architect/sessions/:id — drop
  • Sessions stored in SQLite (architect_sessions table: id, created_at, updated_at, title, messages JSON)
  • SSE event shape matches existing pushEvent envelope so renderers can be shared with the monitor

Docs

  • CLAUDE.md "Roles" table gains architect row
  • README "Architect agent" section — purpose, limits, how to provision its token, how it differs from other agents

Tests

  • architect.test.ts — start a session, send a message, mock the SDK, assert the stream event shape
  • Routing sanity: architect CANNOT be targeted by webhook dispatch (unit test against webhook-routing.ts)

Out of scope

  • Chat UI itself — #M18-5
  • Multi-user sessions — singleton operator only
  • Running in a container — explicit non-goal (architect needs host access)

Dependencies

  • Blocks on #M18-2 (monorepo + packages/shared types).
  • Can parallel with #M18-3.
  • Unblocks #M18-5.

References

  • Spec: specs/m18-ui-rewrite-and-architect.md §Story M18-4
As an operator, I want a new **architect** agent type that runs **in the host process** (no container), has filesystem access to the repo, can call the service's own HTTP API, and exposes a persistent chat session the UI can talk to, so that spec writing / breakdown / assignment become an interactive workflow instead of webhook-only dispatch. ## Acceptance criteria ### Agent type - [ ] `config/agents.json::types.architect` entry: - `forgejo_user: "architect"` (new Forgejo account; operator provisions the token file) - `default_model: "claude-opus-4-7[1m]"` (1M context — spec work needs it) - `container: { enabled: false }` — bypasses the container-reconcile flow - `plugins: []` — no per-agent plugin set (runs with the host's `~/.claude` config) - `default_system_prompt` — purpose, scope, guard-rails (full text in #M18-5) - [ ] **Singleton**: `db.ts` seeds one `architect-default` row; Agents CRUD UI refuses to create a second architect instance (`409 Conflict`) - [ ] `ResolvedAgent` gains a `host_mode: boolean` flag derived from `container.enabled === false` - [ ] `agent-runner.runAgentTask` branches: host mode skips `container.ts::exec`, invokes SDK `query()` inline in the service process with `cwd: process.cwd()` ### Security & isolation - [ ] Host mode is only available to a hardcoded set of types (for now: `architect`). Any other type with `container.enabled: false` fails `loadWebhookConfig` at startup - [ ] Architect's SDK invocation inherits the service's env but loads its OWN credentials dir (`~/.config/claude-hooks/agent-env/architect/`). Operator provisions via `just agent-env-sync architect` - [ ] Skill surface restricted: architect can call `breakdown`, read/write `specs/*.md`, POST to its own service's `/breakdown`, `/task`, `/cancel`. Explicitly cannot merge PRs or push to `main` - [ ] `scripts/smoke-creds.sh` learns to probe architect (host-mode: filesystem + token file, not container exec) ### Sessions & chat - [ ] New endpoints on `apps/server`: - `POST /architect/chat` — body `{ session_id?, message }`. If `session_id` absent, creates a new one. Returns `{ session_id, task_id }` and starts streaming SSE at `/architect/stream/:task_id` - `GET /architect/sessions` — list persisted sessions (id, first-message preview, last-updated, turn count) - `GET /architect/sessions/:id` — full transcript - `DELETE /architect/sessions/:id` — drop - [ ] Sessions stored in SQLite (`architect_sessions` table: id, created_at, updated_at, title, messages JSON) - [ ] SSE event shape matches existing `pushEvent` envelope so renderers can be shared with the monitor ### Docs - [ ] CLAUDE.md "Roles" table gains `architect` row - [ ] README "Architect agent" section — purpose, limits, how to provision its token, how it differs from other agents ### Tests - [ ] `architect.test.ts` — start a session, send a message, mock the SDK, assert the stream event shape - [ ] Routing sanity: architect CANNOT be targeted by webhook dispatch (unit test against `webhook-routing.ts`) ## Out of scope - Chat UI itself — #M18-5 - Multi-user sessions — singleton operator only - Running in a container — explicit non-goal (architect needs host access) ## Dependencies - **Blocks on #M18-2** (monorepo + `packages/shared` types). - **Can parallel with #M18-3.** - **Unblocks #M18-5.** ## References - Spec: `specs/m18-ui-rewrite-and-architect.md` §Story M18-4
Sign in to join this conversation.
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/claude-hooks#165
No description provided.