Codegen & Anti-Drift
Salience makes the agent more likely to follow a convention; enforcement catches it when it doesn't. Codegen is the third lever — it sidesteps both by generating code that is correct by construction, and it keeps every generated artifact from drifting away from the project's true shape.
Correct-by-construction entity codegen
Adding a domain slice by hand means writing a schema, a repository, and a service, then
remembering to add the table to the ORM schema — four chances to break a convention.
stackr add entity does all of it the right way:
stackr add entity <service> <entity> # e.g. stackr add entity blog commentone commandschema.tsrepository.tsservice.tsadditive AST mergeexisting tables untoucheddrizzle-kit generatestackr migrations ackCorrect-by-construction: the generated code always compiles and already follows the conventions the harness enforces.
It generates domain/<entity>/{schema,repository,service}.ts and merges the new
table into that service's ORM schema, so the new repository type-checks immediately. The
generated code already follows every backend rule: the schema exports both the TypeBox
schema and its Static type, and every repository operation wraps its try/catch in
ErrorFactory.databaseError.
The operation is atomic: it validates read-only, computes the full change set in memory, dry-runs it (re-parsing a merged Prisma schema to catch breakage), then commits with an atomic file swap. If anything fails, the project is left byte-identical.
Then run the migration
A schema change needs a migration. add entity records a pending migration and
prints the exact command. Run it, then acknowledge it:
cd blog/backend && drizzle-kit generate && drizzle-kit migrate
stackr migrations ack blogUntil you ack, subsequent stackr subcommands refuse to run — so a schema change can't
silently fall out of sync with the database. (See the
add entity guide for the full walkthrough.)
Anti-drift
Every harness artifact — the nested AGENTS.md, the editor rules, the skills, the
ast-grep config — is rendered by one generator from stackr.config.json. Both
create-stackr and stackr add service drive that same generator, so the artifacts can
never describe a service set that no longer exists.
You can re-derive everything at any time:
stackr migrate context # re-render all agent-facing artifacts from config
stackr migrate context --dry-run
stackr doctor # report drift between config and the project
stackr doctor --fix # re-render to resolve itRegeneration is idempotent: the generator computes the whole plan in memory and runs
the same executor used at init, so running it again on the same stackr.config.json
produces byte-identical output. Artifacts for a removed service are deleted, not left
orphaned.
Gate drift in CI
stackr doctor exits non-zero when the artifacts have drifted from the
config, so you can run it as a CI check. Combined with
lint:sg, it keeps both the
conventions and the context files honest on every push.
Why there's no version field
Because the layout is detected from disk and every artifact is a pure function of
stackr.config.json, there is no "context-layer version" to migrate. The current config
is the spec; regenerating is always safe.