Gateway Module — `curator/`
1. Purpose
The curator/ module stores and serves agent health cards — the per-agent snapshot the Hermes-side Curator computes during the Self-Improvement Pipeline (SIP Phase 1, Dispatch 818): dispatch volume, quality score + trend, stall/affinity/escalation rates, priority-skill health, binding-ref validity, open proposals, and tune history. The Curator bulk-upserts a batch of cards after each run; the dashboard armoury tab and agent-tune consumers read them back. It is a thin CRUD-over-one-table module keyed by agent_name (UNIQUE), with JSON array fields stringified on write and parsed on read.
2. File Inventory
| File | Lines | Responsibility |
|---|---|---|
repository.ts | 152 | INSERT … ON CONFLICT(agent_name) DO UPDATE upsert + list/get; JSON (de)serialisation |
routes.ts | 77 | 1 POST bulk-upsert + 2 GET list/single |
types.ts | 115 | Zod input schemas + row/record interfaces + repository contract |
| Total | 344 | (No index.ts — the router is wired directly in server/index.ts via createCuratorRouter(curatorRepo).) |
3. Public API Surface
REST Endpoints
Mounted at /api/curator (index.ts line 762). Auth (post-AK-415):
| Method | Path | Auth | Body / Query | Response |
|---|---|---|---|---|
| POST | /api/curator/health-cards | Bearer (write only) | BulkHealthCardInputSchema (cards: 1–8) | 201 { data: { upserted: N, run_id } } |
| GET | /api/curator/health-cards | Bearer | ?agent_name= (optional filter) | { data: CuratorHealthCardRecord[] } |
| GET | /api/curator/health-cards/:agent_name | Bearer | — | { data: record } or 404 |
Note: /api/curator is the "worked idiom" the AK-415 closure generalised from — it was already Bearer-gated on GET before the mega-OR was deleted.
MCP Tools
None.
4. Internal API
createCuratorRepository(db): CuratorRepository—upsertHealthCards(cards)(wrapped in adb.transaction, returns the re-fetched parsed records),getHealthCards(agentName?),getHealthCard(agentName).createCuratorRouter(repo): Router.
5. Background Services
None. Write is push-driven from the Hermes Curator; reads are request-driven.
6. Data Contracts
CuratorHealthCardInputSchema—agent_name,domain,dispatch_volume_30d(int ≥0),quality_score(0–1),quality_trend(up/down/stable),stall_rate/affinity_rate/escalation_rate(0–1),priority_skills_health(array of{ skill, status ∈ Active|Low-use|Dormant|Dead }),binding_refs_health(array of{ ref, valid }),last_definition_update(nullable),open_proposals(int),open_proposal_types(string[]),active_monitoring(nullable),tune_history(array of{ rule_id, date, status ∈ completed|rolled_back }),curator_run_id.BulkHealthCardInputSchema—{ cards: array(min 1, max 8) }(8 = the CyberShinobi roster size).- Row vs record split:
CuratorHealthCardRowholds the JSON array fields as strings;CuratorHealthCardRecordis the parsed application shape.
Storage pattern: INSERT … ON CONFLICT(agent_name) DO UPDATE SET … (upsert). This requires the agent_name UNIQUE constraint declared in db.ts — without it the upsert throws "ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint" (Dispatch 1011 R-8). JSON array fields are JSON.stringify'd on write, JSON.parse'd on read.
7. Dependencies
- Gateway modules consumed:
shared/(formatZodError); thecurator_health_cardstable (schema indb.ts). - External libraries:
better-sqlite3,express,zod. - Environment variables: none.
8. Test Coverage
| Layer | File | Cases |
|---|---|---|
| Repository | test/curator-repository.test.ts (281 L) | (upsert, JSON round-trip, filter) |
| Routes | test/curator-routes.test.ts (374 L) | 21 it blocks |
Covers bulk upsert idempotency (re-upsert same agent updates in place), 1–8 card bounds, JSON field round-trips, and 404 on missing card.
9. Known Limitations
- Bulk-upsert batch capped at 8 cards (the roster size); a future roster expansion needs the
.max(8)bumped. - Module has no
index.tslayer factory — repository + router are wired inline inserver/index.ts, a minor inconsistency with the vault-index/analytics layer pattern. - Schema history: the module was removed and restored verbatim from the vault mirror (Dispatch 1011, R-8, AK-328) after the R-10 cutover — a provenance note, not a live limitation.
10. Change History
| Date | Dispatch | Summary |
|---|---|---|
| 2026-07-04 | 2297 | Initial module spec (smoke-clone-3, LisaOS audit campaign Phase 4) |
| — | 1011 (R-8, AK-328) | Verbatim restore from vault mirror into lisa-os main |
| — | 818 (SIP Phase 1) | Module created — agent health cards |