AT-1: Schema + builtin-sync for agent_type tables #743

Closed
opened 2026-05-02 17:24:42 +00:00 by claude-desktop · 0 comments
Collaborator

Bundle directive

This story ships in one PR with #750 (SVC-1) and #754 (LBL-1) — the foundation layer that introduces the three new resolver entry points (getAgentType, getServiceConfig, getLabelCatalogForRepo), the three matching builtin-sync passes, and the three migration files. They share a single round of edits to domain/agent-config/resolver.ts and domain/agent-config/builtin-sync.ts, so bundling avoids merge conflicts and lets one review pass cover the whole layer.

The PR closes all three issues (Closes #743 #750 #754).


As a platform engineer, I want the per-kind tables that hold per-type identity, container, and routing config plus a builtin-sync pass that mirrors config/agents.json::types{} into them on boot, so that runtime reads can move off the in-memory cfg.types[…] map onto a DB-backed scope ladder consistent with skills / prompts / plugins.

Acceptance criteria

Schema

  • migrations/<n>-agent-type.ts creates agent_type, agent_type_container, and agent_type_routing with the columns, scope checks (builtin → global → agent_type → instance per table — service-wide tables only builtin/global), and unique constraints listed in specs/config-to-db.md § Architecture.
  • agent_type.token_secret_id column exists as a forward placeholder for TOK-1; nullable.
  • Schema migration is idempotent across reboots and a no-op when columns already exist.

Builtin sync

  • domain/agent-config/builtin-sync.ts grows syncAgentTypeBuiltins(agentsJsonPath) that walks types{} and upserts one row per type at scope='builtin' plus a joined container row + routing row per type.
  • Re-running the sync on unchanged input returns { inserted: 0, updated: 0 }.
  • A type that vanishes from the factory image is not deleted from the DB — its scope='builtin' row gets enabled=false (mirrors the plugin-binding shadow pattern) so existing instances keep resolving.

Resolver

  • domain/agent-config/resolver.ts grows getAgentType(name): ResolvedAgentType | null that joins the most-specific agent_type + agent_type_container + agent_type_routing rows across the scope ladder.
  • ResolvedAgentType shape matches today's cfg.types[name] (same field names, same JSON-decoded shapes) so AT-2's call-site swap is mechanical.

Tests

  • Unit: idempotent sync, scope ladder merge, removed-type shadow.
  • Integration: a fresh DB + a mutated agents.json boot syncs new rows; an existing agent_type-scope override is preserved across restart (operator-edited git_email for dev survives a re-sync that updates the builtin's default_system_prompt).

Out of scope

  • Swapping consumers — covered by AT-2.
  • Token migration — covered by TOK-1.
  • Dashboard CRUD UI — covered by AT-6.

References

  • Spec: specs/config-to-db.md § Architecture, § Story AT-1.
  • Precedent: SC-1 (issue closed under milestone #28) — schema + builtin-sync pattern.
  • Bundled with: #750 (SVC-1), #754 (LBL-1).
## Bundle directive This story ships in **one PR with #750 (SVC-1) and #754 (LBL-1)** — the foundation layer that introduces the three new resolver entry points (`getAgentType`, `getServiceConfig`, `getLabelCatalogForRepo`), the three matching builtin-sync passes, and the three migration files. They share a single round of edits to `domain/agent-config/resolver.ts` and `domain/agent-config/builtin-sync.ts`, so bundling avoids merge conflicts and lets one review pass cover the whole layer. The PR closes all three issues (`Closes #743 #750 #754`). --- As a platform engineer, I want the per-kind tables that hold per-type identity, container, and routing config plus a builtin-sync pass that mirrors `config/agents.json::types{}` into them on boot, so that runtime reads can move off the in-memory `cfg.types[…]` map onto a DB-backed scope ladder consistent with skills / prompts / plugins. ## Acceptance criteria ### Schema - [ ] `migrations/<n>-agent-type.ts` creates `agent_type`, `agent_type_container`, and `agent_type_routing` with the columns, scope checks (`builtin → global → agent_type → instance` per table — service-wide tables only `builtin`/`global`), and unique constraints listed in `specs/config-to-db.md` § Architecture. - [ ] `agent_type.token_secret_id` column exists as a forward placeholder for TOK-1; nullable. - [ ] Schema migration is idempotent across reboots and a no-op when columns already exist. ### Builtin sync - [ ] `domain/agent-config/builtin-sync.ts` grows `syncAgentTypeBuiltins(agentsJsonPath)` that walks `types{}` and upserts one row per type at `scope='builtin'` plus a joined container row + routing row per type. - [ ] Re-running the sync on unchanged input returns `{ inserted: 0, updated: 0 }`. - [ ] A type that vanishes from the factory image is **not deleted** from the DB — its `scope='builtin'` row gets `enabled=false` (mirrors the plugin-binding shadow pattern) so existing instances keep resolving. ### Resolver - [ ] `domain/agent-config/resolver.ts` grows `getAgentType(name): ResolvedAgentType | null` that joins the most-specific `agent_type` + `agent_type_container` + `agent_type_routing` rows across the scope ladder. - [ ] `ResolvedAgentType` shape matches today's `cfg.types[name]` (same field names, same JSON-decoded shapes) so AT-2's call-site swap is mechanical. ### Tests - [ ] Unit: idempotent sync, scope ladder merge, removed-type shadow. - [ ] Integration: a fresh DB + a mutated `agents.json` boot syncs new rows; an existing `agent_type`-scope override is preserved across restart (operator-edited `git_email` for `dev` survives a re-sync that updates the builtin's `default_system_prompt`). ## Out of scope - Swapping consumers — covered by AT-2. - Token migration — covered by TOK-1. - Dashboard CRUD UI — covered by AT-6. ## References - Spec: `specs/config-to-db.md` § Architecture, § Story AT-1. - Precedent: SC-1 (issue closed under milestone #28) — schema + builtin-sync pattern. - Bundled with: #750 (SVC-1), #754 (LBL-1).
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/claude-hooks#743
No description provided.