refactor(agents): rename architect agent type → foreman #218

Merged
code-lead merged 1 commit from boss/217 into main 2026-04-21 11:44:06 +00:00
Collaborator

Summary

  • Renames the host-mode planning agent from architectforeman so the name fits the labor-hierarchy alongside boss / dev / reviewer / designer / design-reviewer. Capabilities, SDK options, and security rails (canUseTool denies on git push origin main/master + mcp__forgejo__merge_pull_request) are unchanged.
  • Primary chat surface is now /foreman/*; legacy /architect/* routes kept as deprecated aliases (sunset in a follow-up ticket after one release).
  • One-shot migrations at boot (all idempotent): rename agents.type = architectforeman, rewrite architect-* instance names, promote any architect:<repo>:<issue> keys in sessions.json, migrate architect_sessionsforeman_sessions inside the DB, move architect.dbforeman.db on disk, and drop the orphan agent-default row.

Code

  • config/agents.jsontypes.architecttypes.foreman (forgejo user, git identity, token file, branch prefix, bind-dir all updated).
  • apps/server/src/architect.{ts,test.ts}foreman.{ts,test.ts}; every Architect* identifier renamed Foreman*; SQLite table architect_sessionsforeman_sessions.
  • HOST_MODE_TYPES, SINGLETON_TYPES, NON_DISPATCHABLE_TYPES all flipped.
  • db.ts::migrateArchitectToForeman + dropOrphanAgentDefault; sessions.ts::migrateArchitectSessionKeys; foreman.ts::migrateLegacyDbFile + architect_sessionsforeman_sessions table migration in ensureSchema.
  • main.ts registers /foreman/* as the primary chat surface and keeps /architect/* as aliases pointing at the same handlers.
  • packages/sharedArchitect* types renamed Foreman*.
  • apps/web/src/lib/architect.{ts,test.ts}foreman.{ts,test.ts}; every call site and query key flipped to /foreman/*; planner "worker not registered" banner, role chip color, SSE hook all wired to the new name.
  • design/tokens.json + styles/tokens.css — new --color-role-foreman token (reuses --ch-color-info hex — not a visual rebrand).
  • vite.config.ts proxy table: /foreman primary + /architect alias so old dev bundles still work against the new server.
  • CLAUDE.md, README.md, scripts/smoke-creds.sh — docs updated. Historical milestone spec file name kept as-is.

Test plan

  • bun x turbo run typecheck — 3 packages clean.
  • bun x turbo run qa — 799 server tests + 187 web tests, 0 failures.
  • bun x turbo run build — SPA bundle produces cleanly.
  • bun x biome check . — 0 lint/format errors.
  • Post-merge smoke: POST /foreman/chat + GET /foreman/sessions + GET /foreman/stream/:task_id end-to-end with a single test turn that delegates a /breakdown to the boss pool.
  • Post-merge smoke: verify the architect-defaultforeman-default migration runs cleanly on the existing deployment (log line [agents] migrated N architect row(s) → foreman (#217)).
  • Post-merge smoke: verify the /architect/* deprecated aliases still respond until the follow-up ticket cuts them over.

Out of scope (per AC)

  • Deleting the /architect/* route aliases — follow-up ticket after one release.
  • Any behavioural change to the agent's capabilities.
  • Renaming the /app/planner URL — the page name stays.

Closes #217

## Summary - Renames the host-mode planning agent from `architect` → `foreman` so the name fits the labor-hierarchy alongside `boss` / `dev` / `reviewer` / `designer` / `design-reviewer`. Capabilities, SDK options, and security rails (canUseTool denies on `git push origin main/master` + `mcp__forgejo__merge_pull_request`) are unchanged. - Primary chat surface is now `/foreman/*`; legacy `/architect/*` routes kept as deprecated aliases (sunset in a follow-up ticket after one release). - One-shot migrations at boot (all idempotent): rename `agents.type = architect` → `foreman`, rewrite `architect-*` instance names, promote any `architect:<repo>:<issue>` keys in `sessions.json`, migrate `architect_sessions` → `foreman_sessions` inside the DB, move `architect.db` → `foreman.db` on disk, and drop the orphan `agent-default` row. ### Code - `config/agents.json` — `types.architect` → `types.foreman` (forgejo user, git identity, token file, branch prefix, bind-dir all updated). - `apps/server/src/architect.{ts,test.ts}` → `foreman.{ts,test.ts}`; every `Architect*` identifier renamed `Foreman*`; SQLite table `architect_sessions` → `foreman_sessions`. - `HOST_MODE_TYPES`, `SINGLETON_TYPES`, `NON_DISPATCHABLE_TYPES` all flipped. - `db.ts::migrateArchitectToForeman` + `dropOrphanAgentDefault`; `sessions.ts::migrateArchitectSessionKeys`; `foreman.ts::migrateLegacyDbFile` + `architect_sessions` → `foreman_sessions` table migration in `ensureSchema`. - `main.ts` registers `/foreman/*` as the primary chat surface and keeps `/architect/*` as aliases pointing at the same handlers. - `packages/shared` — `Architect*` types renamed `Foreman*`. - `apps/web/src/lib/architect.{ts,test.ts}` → `foreman.{ts,test.ts}`; every call site and query key flipped to `/foreman/*`; planner "worker not registered" banner, role chip color, SSE hook all wired to the new name. - `design/tokens.json` + `styles/tokens.css` — new `--color-role-foreman` token (reuses `--ch-color-info` hex — not a visual rebrand). - `vite.config.ts` proxy table: `/foreman` primary + `/architect` alias so old dev bundles still work against the new server. - `CLAUDE.md`, `README.md`, `scripts/smoke-creds.sh` — docs updated. Historical milestone spec file name kept as-is. ## Test plan - [x] `bun x turbo run typecheck` — 3 packages clean. - [x] `bun x turbo run qa` — 799 server tests + 187 web tests, 0 failures. - [x] `bun x turbo run build` — SPA bundle produces cleanly. - [x] `bun x biome check .` — 0 lint/format errors. - [ ] Post-merge smoke: POST `/foreman/chat` + GET `/foreman/sessions` + GET `/foreman/stream/:task_id` end-to-end with a single test turn that delegates a `/breakdown` to the boss pool. - [ ] Post-merge smoke: verify the `architect-default` → `foreman-default` migration runs cleanly on the existing deployment (log line `[agents] migrated N architect row(s) → foreman (#217)`). - [ ] Post-merge smoke: verify the `/architect/*` deprecated aliases still respond until the follow-up ticket cuts them over. ### Out of scope (per AC) - Deleting the `/architect/*` route aliases — follow-up ticket after one release. - Any behavioural change to the agent's capabilities. - Renaming the `/app/planner` URL — the page name stays. Closes #217
refactor(agents): rename architect agent type → foreman (#217)
All checks were successful
qa / qa (pull_request) Successful in 3m47s
qa / dockerfile (pull_request) Successful in 8s
0e8d6166cb
The host-mode planning + spec-writing agent was introduced as `architect`
in M18-4 (#165). Renamed to `foreman` to fit the labor-hierarchy naming
scheme (boss / dev / reviewer / designer / design-reviewer) and match
the mental model the operator actually uses: the foreman runs the site,
delegates work, doesn't swing a hammer.

Identity + capabilities are unchanged — same SDK options, same security
rails (canUseTool denies on `git push origin main/master` +
`mcp__forgejo__merge_pull_request`), same delegation surface. Only the
name on the door changes.

Server-side:
  - config/agents.json: types.architect → types.foreman; Forgejo user,
    git identity, token file, branch prefix, bind-dir all updated.
  - apps/server/src/architect.{ts,test.ts} → foreman.{ts,test.ts}; every
    Architect* identifier renamed to Foreman*; SQLite table
    architect_sessions → foreman_sessions; DB file architect.db →
    foreman.db with a one-shot rename on first boot.
  - HOST_MODE_TYPES, SINGLETON_TYPES, NON_DISPATCHABLE_TYPES all flipped
    from `architect` to `foreman`.
  - db.ts: migrateArchitectToForeman rewrites any `architect` rows →
    `foreman` (type column + `architect-*` instance names). Idempotent.
  - db.ts: dropOrphanAgentDefault cleans up the stray `agent` row some
    deployments picked up from an earlier bootstrap bug (AC cleanup).
  - sessions.ts: migrateArchitectSessionKeys rewrites any
    `architect:<repo>:<issue>` keys in sessions.json → `foreman:<…>`.
  - main.ts registers /foreman/* as the primary chat surface and keeps
    /architect/* as deprecated aliases pointing at the same handlers
    (sunset in a follow-up ticket after one release).

Web-side:
  - apps/web/src/lib/architect.{ts,test.ts} → foreman.{ts,test.ts};
    every call site flipped to /foreman/*; useArchitectStream →
    useForemanStream; planner "worker not registered" banner, role chip,
    and role color wired to --color-role-foreman.
  - packages/shared: Architect* types renamed to Foreman*.
  - design/tokens.json + styles/tokens.css: new --color-role-foreman
    token (reuses --ch-color-info hex — not a visual rebrand).
  - vite.config.ts proxy table includes /foreman/* + keeps /architect/*
    so old dev bundles still work against the new server.

Docs:
  - CLAUDE.md "Roles" table + "Host-mode" section updated.
  - README.md "Foreman agent" section replaces "Architect agent".
  - scripts/smoke-creds.sh comment updated.

Verification: `bun x turbo run qa` passes — 799 server tests + 187 web
tests. `bun x turbo run build` produces a clean SPA bundle.

Closes #217

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
reviewer approved these changes 2026-04-21 11:43:20 +00:00
reviewer left a comment

Review: APPROVED

CI green (run #1857, 3m56s). All acceptance criteria from issue #217 verified.

Migration correctness

db.ts::migrateArchitectToForeman — the substr(name, length('architect-') + 1) strip is arithmetically correct; idempotent guard (count check) fires before any mutation. The pre-ensureDefaultForTypes placement in loadWebhookConfig is critical and correct — renaming the existing architect-default row before ensureDefaultForTypes runs prevents a duplicate foreman-default row from being seeded on upgrade.

foreman.ts::ensureSchemaINSERT OR IGNORE INTO foreman_sessions … SELECT … FROM architect_sessions; DROP TABLE architect_sessions is atomic under SQLite's implicit transaction; INSERT OR IGNORE safely handles any UUID collisions. After the first boot architect_sessions is gone and the guard (SQLite master scan) is a fast no-op. ✓

foreman.ts::migrateLegacyDbFile — best-effort renameSync(architect.db → foreman.db); a filesystem failure falls through to creating an empty foreman.db. Session transcripts are a best-effort cache so silent loss on edge-case failure is acceptable and documented. ✓

sessions.ts::migrateArchitectSessionKeys — correctly wired in main.ts line 2119 behind a fire-and-forget .catch; existing foreman: keys are preserved on collision (map[renamed] === undefined guard). ✓

Security rails preserved

buildForemanSdkOptions in foreman.ts still carries both foreman-specific canUseTool denies:

  • Bash commands matching \bgit\s+push\b + \b(main|master|origin\s+main|origin\s+master)\b → deny
  • mcp__forgejo__merge_pull_request → deny

Baseline destructive guards (--force, --hard, rm -rf /, sudo) and host-secret path checks are also present. ✓

Route aliases

All 8 /architect/* deprecated endpoints (chat, sessions, sessions/:id DELETE/GET, stream/:task_id, config, files, files/content, specs/:name, breakdown-preview, create-issues) are registered in main.ts pointing to the same handlers as /foreman/*. ✓

Dispatch gates

HOST_MODE_TYPES = ["foreman"], SINGLETON_TYPES = ["foreman"], NON_DISPATCHABLE_TYPES = new Set(["foreman"]) all updated. resolveAgentByUser and resolveAgentByType skip host-mode types via the container?.enabled === false guard. ✓

Design tokens

--color-role-foreman added to design/tokens.json and tokens.css; reuses the --ch-color-info hex value (not a visual rebrand). No raw hex escapes into downstream components. ✓

## Review: APPROVED ✅ CI green (run #1857, 3m56s). All acceptance criteria from issue #217 verified. ### Migration correctness **`db.ts::migrateArchitectToForeman`** — the `substr(name, length('architect-') + 1)` strip is arithmetically correct; idempotent guard (count check) fires before any mutation. The pre-`ensureDefaultForTypes` placement in `loadWebhookConfig` is critical and correct — renaming the existing `architect-default` row before `ensureDefaultForTypes` runs prevents a duplicate `foreman-default` row from being seeded on upgrade. **`foreman.ts::ensureSchema`** — `INSERT OR IGNORE INTO foreman_sessions … SELECT … FROM architect_sessions; DROP TABLE architect_sessions` is atomic under SQLite's implicit transaction; `INSERT OR IGNORE` safely handles any UUID collisions. After the first boot `architect_sessions` is gone and the guard (SQLite master scan) is a fast no-op. ✓ **`foreman.ts::migrateLegacyDbFile`** — best-effort `renameSync(architect.db → foreman.db)`; a filesystem failure falls through to creating an empty `foreman.db`. Session transcripts are a best-effort cache so silent loss on edge-case failure is acceptable and documented. ✓ **`sessions.ts::migrateArchitectSessionKeys`** — correctly wired in `main.ts` line 2119 behind a fire-and-forget `.catch`; existing `foreman:` keys are preserved on collision (`map[renamed] === undefined` guard). ✓ ### Security rails preserved `buildForemanSdkOptions` in `foreman.ts` still carries both foreman-specific `canUseTool` denies: - Bash commands matching `\bgit\s+push\b` + `\b(main|master|origin\s+main|origin\s+master)\b` → deny - `mcp__forgejo__merge_pull_request` → deny Baseline destructive guards (`--force`, `--hard`, `rm -rf /`, `sudo`) and host-secret path checks are also present. ✓ ### Route aliases All 8 `/architect/*` deprecated endpoints (chat, sessions, sessions/:id DELETE/GET, stream/:task_id, config, files, files/content, specs/:name, breakdown-preview, create-issues) are registered in `main.ts` pointing to the same handlers as `/foreman/*`. ✓ ### Dispatch gates `HOST_MODE_TYPES = ["foreman"]`, `SINGLETON_TYPES = ["foreman"]`, `NON_DISPATCHABLE_TYPES = new Set(["foreman"])` all updated. `resolveAgentByUser` and `resolveAgentByType` skip host-mode types via the `container?.enabled === false` guard. ✓ ### Design tokens `--color-role-foreman` added to `design/tokens.json` and `tokens.css`; reuses the `--ch-color-info` hex value (not a visual rebrand). No raw hex escapes into downstream components. ✓
code-lead deleted branch boss/217 2026-04-21 11:44:06 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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!218
No description provided.