0001 — Conventions are executable
A convention that only exists in a document is a convention you have not shipped. The ladder from generator to prose, and why prose is last.
Context
Every codebase has conventions. Almost all of them live in a README, a wiki page or a reviewer's memory, and they decay at a predictable rate: the document goes stale, the reviewer leaves, the new joiner never reads it, and six months later half the codebase does it the old way and nobody can say when that started.
Agents make this sharper rather than softer. An agent reads what it is given, does the work, and reports success. It cannot be shamed in review and it will not notice a convention it was never told about. A rule it cannot verify is a rule it will break confidently.
Decision
Every convention is enforced at the highest rung of this ladder that can hold it, and prose is the last resort:
- A generator that writes it — the convention is the default, and following it takes no effort at all
- A type that makes violating it not compile
- A database constraint that refuses
- A lint rule that fails
- A structure check that fails
- A document that explains it
Rung six is an admission that the first five could not hold it. That framing is
in conventions.mdx verbatim: prose is "last resort, and an admission of
defeat."
The corollary, from for-agents.mdx: "A rule that ends up in a document is a
rule you have not really shipped."
Consequences
Most of the other records here are an application of this one. The action builder
(0004) is rung two. Row-level
security (0002) is rung three. lq check
(0008) is how rungs four and five get run
often enough to matter.
It also explains a cost. Enforcing a convention properly is far more work than writing it down, so this codebase has fewer conventions than a comparable one and argues harder about each. That is intended.
The flywheel depends on it. Because every feature is scaffolded to a canonical shape and guardrails stop it drifting, codemods can rewrite customer code across releases — which is the one thing no competitor can offer, because their customers' code has no known shape. The upgrade path (0005, 0007) is a consequence of this decision, not a separate feature.
The measurement that tested it
Feedback timing turns out to matter as much as enforcement. From for-agents.mdx:
"Feedback arriving in the same turn as the mistake gets fixed; feedback arriving
at review time gets argued with." That is why the PostToolUse hook runs
lq check --changed after every edit rather than leaving it to CI.
The same page caps CLAUDE.md at roughly 130 lines on measured grounds —
adherence falls off a cliff past about 200 — which is itself an argument for
getting rules off rung six.
Decisions
Why this codebase is shaped the way it is — the alternatives that were rejected, and, where there was one, the specific bug that settled the argument.
0002 — Tenancy is enforced by Postgres
A query that forgets its tenant filter returns zero rows, because the database refuses. Not because a reviewer noticed.