9.8 KiB
Generation Playbook
Step-by-step instructions for generating and regenerating artifacts in this repository.
Read AGENTS.md and docs/source-of-truth.md first.
Pipeline overview
Tier 1 — Single Source of Truth (hand-authored, never generated)
domain/toir.api.dsl ──┐ enums, DTOs, endpoints, HTTP methods,
│ entity field mappings, primary keys
│
▼
Tier 2 — Deterministic Preprocessing (npm scripts, no LLM)
api-summary.json ←─ npm run generate:api-summary
openapi.json ←─ npm run generate:openapi (auxiliary)
│
▼
Tier 1 (api.dsl) + Tier 2 (context) + prompts/*.md ──► LLM Generation
prompts/general-prompt.md
prompts/backend-rules.md ──► server/src/modules/<entity>/
prompts/frontend-rules.md ──► client/src/resources/<entity>/
prompts/prisma-rules.md ──► server/prisma/schema.prisma
prompts/auth-rules.md ──► (auth seam reference)
prompts/runtime-rules.md ──► (env/docker reference)
prompts/validation-rules.md ──► (validation gate reference)
│
▼
Tier 4 — Validation Gate
node tools/validate-generation.mjs --artifacts-only
Prerequisites
Before any generation run:
domain/*.api.dslis current and valid.- Refresh the Tier 2 intermediate context:
npm run generate:api-summary - Run
node tools/validate-generation.mjs --artifacts-onlyto confirm the baseline passes.
Standard generation workflow
Step 1 — Refresh Tier 2 derived artifacts
# From repo root
npm run generate:api-summary
Step 2 — Read generation inputs (context budget)
prompts/general-prompt.mdis the master generation prompt. It contains all core type mappings, naming conventions, DTO/controller/service/frontend rules, mutation boundaries, and the complete generation workflow. Load it as the single entrypoint.For artifact-specific details (Prisma FK rules, auth JWKS chain, detailed validation groups), load the relevant companion file:
prompts/prisma-rules.md,prompts/auth-rules.md,prompts/validation-rules.md, orprompts/runtime-rules.md.See
prompts/general-prompt.md §CONTEXT BUDGETfor the full budget model.
prompts/general-prompt.md— master generation prompt (always load)api-summary.json §<entity>— compact entity index (fast-path context anchor)domain/*.api.dsl §API.<EntityName>— only the api block + its referenced DTOs + enums (entity-scoped)- If needed:
prompts/prisma-rules.md(Prisma) orprompts/auth-rules.md(auth seams)
Before generating any DTO or component: quote the relevant DSL field definitions verbatim first, then generate from those quotes. This prevents training-data contamination.
Step 3 — Generate Prisma schema
Generate server/prisma/schema.prisma from domain/*.api.dsl following prompts/prisma-rules.md.
If the schema changed, run Prisma migration in server/:
cd server
npx prisma migrate dev --name <description>
Step 4 — Generate backend modules
For each api block in domain/*.api.dsl, generate:
server/src/modules/<kebab>/<entity>.module.tsserver/src/modules/<kebab>/dto/create-<kebab>.dto.ts— fields from theDTO.<Entity>Createblock in api.dslserver/src/modules/<kebab>/dto/update-<kebab>.dto.ts— fields from theDTO.<Entity>Updateblock in api.dslserver/src/modules/<kebab>/<entity>.service.ts— CRUD operations using Prisma; respect type mappings fromprompts/backend-rules.mdserver/src/modules/<kebab>/<entity>.controller.ts— one method perendpointin theapiblock; HTTP verb and path from thelabel
Register the module in server/src/app.module.ts.
Step 5 — Generate frontend resources
For each api block in domain/*.api.dsl, generate:
client/src/resources/<kebab>/<Entity>List.tsx— columns fromDTO.<Entity>(response shape)client/src/resources/<kebab>/<Entity>Create.tsx— fields fromDTO.<Entity>Createclient/src/resources/<kebab>/<Entity>Edit.tsx— fields fromDTO.<Entity>Updateclient/src/resources/<kebab>/<Entity>Show.tsx— fields fromDTO.<Entity>
Register the resource in client/src/App.tsx.
Step 6 — Verify (two-stage gate)
Stage 1 — Structural gate:
node tools/validate-generation.mjs --artifacts-only
Checks file existence, field names, class-validator decorators, auth guards, and RA component types.
Full structural verification (requires installed deps):
node tools/validate-generation.mjs
Stage 2 — Eval harness:
npm run eval:generation
Fixture-based semantic checks. See tools/eval/README.md.
Both must pass before the task is complete.
Adding a new entity
- Add the entity's enums, DTOs, and
apiblock todomain/toir.api.dsl. - Run
npm run generate:api-summary. - Before generating: create
tools/eval/fixtures/<kebab>/meta.json,backend.assertions.json, andfrontend.assertions.jsonwith expected patterns. - Run
npm run eval:generation— it will fail (entity files don't exist yet). That's expected. - Generate backend and frontend artifacts (Steps 3–5).
- Run
npm run eval:generationagain — now it should pass. - Run
node tools/validate-generation.mjs --artifacts-only— both gates must pass.
This is eval-driven development: write the failing eval first (step 3), then generate to make it pass (step 6). A passing eval confirms the LLM followed the rules.
Changing an existing entity
If the domain model changes (new field, changed type, new FK, new enum):
- Update
domain/toir.api.dsl(enums, DTO attributes,mapreferences). - Run
npm run generate:api-summary. - Regenerate
server/prisma/schema.prisma, run migration. - Regenerate the affected modules and resources (Steps 4–6).
If only the API contract changes (different nullability, new endpoint, different HTTP method):
- Update
domain/toir.api.dslonly. - Run
npm run generate:api-summaryto refreshapi-summary.json. - Run Steps 4–6. No Prisma migration needed.
Artifact traceability matrix
| Artifact | DSL source | Prompt rule | Validator check |
|---|---|---|---|
server/prisma/schema.prisma |
domain/*.api.dsl |
prompts/prisma-rules.md |
§validateBuildChecks (file exists) |
api-summary.json |
domain/*.api.dsl |
— (deterministic) | §validateBuildChecks (freshness) |
server/src/modules/<e>/*.ts |
domain/*.api.dsl |
prompts/backend-rules.md |
§validateApiDslCoverage |
server/src/modules/<e>/dto/create-<e>.dto.ts |
DTO.<E>Create fields |
prompts/backend-rules.md §DTO-field-coverage |
§validateApiDslCoverage (field names) |
server/src/modules/<e>/dto/update-<e>.dto.ts |
DTO.<E>Update fields |
prompts/backend-rules.md §DTO-field-coverage |
§validateApiDslCoverage (field names) |
client/src/resources/<e>/<E>*.tsx |
domain/*.api.dsl |
prompts/frontend-rules.md |
§validateApiDslCoverage |
client/src/auth/keycloak.ts |
— (Tier 4 handwritten) | prompts/auth-rules.md |
§validateAuthChecks |
toir-realm.json |
— (Tier 4 handwritten) | prompts/auth-rules.md |
§validateRealmChecks |
docker-compose.yml |
— (Tier 4 handwritten) | prompts/runtime-rules.md |
§validateRuntimeContractChecks |
Verification commands reference
| Command | When to use |
|---|---|
npm run generate:api-summary |
After any change to domain/*.api.dsl |
npm run generate:openapi |
To regenerate OpenAPI 3.0.3 documentation |
node tools/validate-generation.mjs --artifacts-only |
After every generation run (required) |
node tools/validate-generation.mjs |
Before committing; requires installed deps |
node tools/validate-generation.mjs --run-runtime |
End-to-end; requires running DB |
OpenRouter invocation
Set environment variables before any LLM-mode tool call:
OPENAI_API_KEY=<openrouter-key>
OPENAI_BASE_URL=https://openrouter.ai/api/v1
OPENAI_MODEL=<model-id>
The OPENAI_BASE_URL variable is consumed by tools/api-format-to-openapi/convert.mjs --mode llm.
For agent-driven generation via Cursor or direct API calls, the standard workflow above
applies regardless of model provider.
Auxiliary tools
tools/api-summary-to-openapi.mjs
Generates openapi.json (OpenAPI 3.0.3) from api-summary.json deterministically.
This is a documentation/integration artifact, not part of the core generation pipeline.
npm run generate:openapi
tools/api-format-to-openapi/
Auxiliary integration tool for external consumers using the api-format JSON schema.
Not connected to the main DSL pipeline. See docs/AID_EXPORT_README.md for details.