Skip to main content
Relates to 0126 (the generator and the kind folders; module is one more kind of the generator, and member shapes do not change), 0158 (the committed manifest that the catalogue is rendered from) and 0007 (the contract docblocks).

Context

A new feature starts as a blank folder that each author fills differently. An agent that adds a module needs a machine-readable statement of what the module contributes, and a catalogue written by hand would become a second source of truth beside the code. The owner settled on 2026-10-21 that the code is the truth, the catalogue is generated from it, and a plan is data that is consumed once.

Decision

  1. Code is the truth; the catalogue is generated. The committed app-manifest.json (0158) holds what each module contributes. stackra catalogue renders the catalogue from that manifest, as YAML for machines and Markdown for review, plus a small hand-written overlay. The overlay holds what code cannot hold: summary, home.reason, source citations and open questions. Each service has one catalogue, and each package has one with the same shape.
  2. Plans live in spec folders. A module that does not exist yet is planned in .agents/specs/<sta-n>/module-plan.yaml, with the same schema as the catalogue. pnpm new module consumes the plan once to emit stubs. It does not keep the plan as a second copy.
  3. The generator. pnpm new module <svc> <feature> reads the module’s plan, when one exists, and emits:
    • the module file, its README, definePermissions, defineEvents, settings and contracts;
    • @Model stubs with TODO fields;
    • @Action and @Query stubs with a key@1, Zod placeholders, a permission and a risk level;
    • an @Resource stub;
    • an action body that throws not_implemented;
    • a module boot test.
  4. Contract docblocks. Every emitted file opens with a contract block (0007) taken from the plan, so a file says what it is for before anyone edits it.
  5. Idempotent. A re-run adds the files that are missing and never overwrites a file that exists. A re-run that finds nothing missing changes nothing.
  6. No empty folders. A kind folder is created with its first file (0126 decision 3).
  7. Drift is a to-do list. stackra catalogue --diff shows the plan against the code. A difference is a task for the author. The generator never rewrites code to match a plan, and the plan never overrides the code.
  8. Pilot catalogues move to plans. A hand-written catalogue file is split into one plan file per module as each module is built. The published catalogue is always the generated one.

Consequences

  • A module starts in a shape that passes the validator, and each stub fails loudly until it is implemented.
  • The catalogue cannot drift from the code, because it is rendered from the manifest. A plan that has not been built shows up as a diff.
  • Authors who change a module’s contributions change the code and the manifest follows; there is no second catalogue to keep in step.
  • Plans need a schema, which pnpm validate checks.

Enforcement

planned — tools/scripts/__tests__/scaffold.test.mjs renders a module twice and asserts that the second run creates no file and changes none, and that every emitted file opens with a contract block. Planned: pnpm validate checks each module-plan.yaml against its schema, and stackra catalogue --diff runs in CI as a report, not a gate.

Supersedes and sources

Supersedes: none. Relates to 0126, 0007 and 0158. Sources: owner settlement in chat, 2026-10-21 (programming model question Q10).