Every published ai coding workflow is a list of rules: put your conventions in a context file, plan before editing, review the diff, run the checks. None of it is wrong, and none of it is a workflow. A workflow is the subset that executes whether or not anybody remembered it. npm run check:gates counts all three quantities on this repository — rules written, instruments that can fail, and triggers that fire without being asked — and the third number is zero. If you are still choosing the tool this workflow would run on, the assistants pillar is the decision above this one.
Key takeaways
- 273 normative rules across 491.5 kB of governing documents. 18 of them (7%) are in the 8.0 kB the agent holds without being asked.
- 36 committed checks, 0 automated triggers. No CI, no git hooks, no npm lifecycle scripts, no check inside
npm run build. - One "check" could not fail. It printed a warning about silently truncated context and exited zero, so every listing counted it as a gate. Found by this audit and fixed the same day.
- The instruments are lopsided: 23 of 36 read
scripts/, 10 readcontent/, and only 6 readapp/. - 7.6 rules per gate is the ratio the project actually runs on, and it is generous — most of the 273 have no instrument at all.
The short answer
Write fewer rules and wire more triggers. The failure mode of an ai development workflow is not that the rules are bad — the rules here are specific, tested and mostly correct. It is that a rule with no gate behind it is a rule that holds exactly as long as attention does, and attention is the resource an agent session consumes fastest.
Three moves, in order of return: put the rules that must never break into the always-loaded context file, give each one an instrument that exits non-zero, then attach those instruments to something that runs on its own. This project has done the first two and not the third, which is why it can report the ratio honestly.
npm run check:gates # → 273 written rules across 491.5 kB # → 36 instruments that can fail # → 0 that fire on their own
The three numbers an ai coding workflow runs on
The script reads the governing documents, every scripts/check-*.mjs, and everything that could plausibly invoke one.
| Document | Size | Tokens | Rules | Loading |
|---|---|---|---|---|
CLAUDE.md | 8.0 kB | ~2k | 18 | always loaded |
content-rules.md | 45.5 kB | ~12k | 87 | on demand |
roadmap.md | 438.0 kB | ~112k | 168 | on demand |
| total | 491.5 kB | ~126k | 273 |
A rule is counted as a sentence carrying a normative modal — never, always, must, must not, do not, required, mandatory, non-negotiable. That is a keyword test over prose and not an inventory; a rule spread across three sentences counts once, and a sentence that merely mentions "never" counts as a rule. The report leans on the ratio between the columns rather than the absolute count, and the ratio is robust to the miscounts.
7% of the rules are in the context the agent always holds
CLAUDE.md is loaded into every session in full — Anthropic's memory documentation is explicit that it has no truncation limit, which is why keeping it small is a design decision rather than tidiness. At 8.0 kB it costs roughly 2,000 tokens per session and carries 18 rules.
The other 255 rules live in 483.5 kB that has to be opened. In practice it is opened when a task obviously touches it, which means the rules governing rare situations are the ones least likely to be in context when a rare situation arrives.
That is not hypothetical here. Two of this project's worst self-inflicted failures were both rules that existed, in writing, in a document nobody had open:
- A standards section instructed authors to mark deferred links with a bare
<!-- -->HTML comment. MDX does not parse HTML comments, three articles followed the instruction, and the build aborted on all routes. The correct form was already documented in a different article on this same site. - A stale permission line survived six days past the decision that revoked it and cost nine articles their cover images, because the line said covers could be added later and the rule said they could not.
Both are the same shape: a written rule, correct at the time, in a file that is not in context, contradicted by a newer written rule in a different file that is also not in context. Why an agent appears to ignore its own configuration is usually this, before it is anything about the model.
A check that cannot fail is not a gate
The instrument audit classifies each check-*.mjs by whether any exit path is non-zero. A script whose only exit is process.exit(0) reports a problem and returns success — it can tell you something is wrong and cannot stop you.
On its first run this found one:
1 problem(s):
- scripts/check-context-weight.mjs: no non-zero exit path — it reports,
and a listing of "checks" counts it as a gate
check:context-weight measures the per-session context floor and prints a warning when the auto-memory index exceeds the documented 200-line / 25 kB read limit, past which content is silently dropped on the next load. It printed WARN and exited clean. For its whole life it had been listed among this project's checks, cited as one, and could not fail. It now exits non-zero on both of its warning conditions, and that change is in the same commit as this article.
This is the failure mode to look for in your own repository, because it is invisible from the outside. Every check:* in a package.json looks identical in a listing. The difference between a gate and a report is one integer, and nothing surfaces it.
What the instruments actually read
Each check is scanned for the path literals it opens, which gives a rough map of what the project has an automated opinion about.
| Tree | Instruments that read it |
|---|---|
scripts/ | 23 |
content/ | 10 |
components/ | 7 |
lib/ | 7 |
app/ | 6 |
.claude/ | 6 |
public/ | 3 |
db/ | 2 |
Twenty-three of thirty-six instruments read scripts/ — mostly their own committed fixtures, which is how a measurement stays reproducible after the thing it measured changed. That is legitimate and it also means the majority of this project's checking apparatus is pointed at its own evidence rather than at its running code.
app/ is read by 6 and db/ by 2. The article route — the one module that needs all five side conditions and the highest-traffic page on the site — is covered by checks that assert on its rendered output, and by nothing that asserts on its logic. That is a defensible position and it should be a chosen one.
Nothing here runs without being asked
| Trigger | Count | Where it would live |
|---|---|---|
| CI workflows | 0 | .github/workflows |
| git hooks (non-sample) | 0 | .git/hooks |
| husky hooks | 0 | .husky |
| npm lifecycle scripts | 0 | pre*/post* in package.json |
| lint-staged | 0 | package.json |
checks inside npm run build | 0 | package.json build |
Zero. Thirty-six instruments, every one of which runs when a person types its name.
The fixes are not exotic. npm's lifecycle scripts would run a check before every build with one line; a pre-commit hook would run it before every commit. Neither is here, and the reason is the ordinary one: each was going to be added after the current article shipped, eighteen batches in a row.
This is the concrete version of a pattern this site keeps measuring in itself. A single prompt on this project has produced 236 tool calls and 75 file edits with nobody watching, and the run-length distribution has an empty middle — sessions are either short or very long, with almost nothing between. A long unattended run is precisely the condition under which "the operator remembers to run the check" stops being a mechanism.
The workflow that survived contact with the work
Stripped of everything unenforced, what this project actually runs is four steps, and they are worth stating because they are the honest version:
- The always-loaded file is the only rulebook with teeth. 18 rules in 8.0 kB, each one a trap that cost real time before it was written down. What belongs in that file and what does not is the highest-leverage decision in the whole workflow.
- Plan before a long run, or accept a long run. Plan mode appeared zero times across 87 recorded sessions here, which is not unrelated to the thirteen runs that exceeded 100 actions.
- Verify on the artifact, not the process. Every check that has caught a defect asserted on something the build produced. Three green exit codes on a file with two dead CSS classes is why: the toolchain's silence is indistinguishable from its approval.
- Read what arrived the same day. Four files were generated, committed and deleted within 48 hours — all of them features nobody asked for. That cost is front-loaded and it is a reading task.
Best practices
- Cap the always-loaded file and treat the cap as the budget. Anything that will not fit is a rule you are choosing not to enforce; decide that deliberately rather than by accretion.
- Give every rule that matters an exit code. If you cannot describe the command that fails when the rule is broken, the rule is advice. Writing the guard alongside the rule is what keeps the two from drifting.
- Audit your checks for exit paths, once. It takes a regex over
process.exitand it found a real one here on the first run. - Attach one trigger before you write the next check. Thirty-six manual gates are worth less than three automatic ones, and this project is the evidence.
- Date every rule and delete the ones it contradicts. Both of the failures above were a live rule and a stale rule coexisting. The stale one wins whenever it is the one in context.
- Point at least one instrument at each tree you care about. Two trees here are read by fewer than three checks, and neither gap was a decision anybody made.
Common mistakes we made
- We counted instruments and called it enforcement. The whole point of this measurement is the third column, and the first draft of the script did not have one — it reported 36 checks and would have let the article claim a workflow that does not run.
- We assumed every check could fail. One could not, and it had been cited in this project's own documentation as a check for weeks. The audit that found it took twenty lines.
- We put the rules where they were easiest to write. 168 of 273 rules live in the planning document because that is where the decision was being made at the time. It is a 438 kB file and the least likely of the three to be open.
- We deferred the trigger eighteen times. Every batch added instruments and none added automation, which is the same compounding-deferral pattern this project has recorded against its own deploy for nine weeks. Writing the check is the enjoyable part; wiring it is not.
What we are not claiming
Unenforced rules are not worthless. CLAUDE.md demonstrably changes what the agent does, and none of its 18 rules has an exit code. Persuasion is a real mechanism. It is a different mechanism from a gate, and the mistake is counting them together.
"Normative sentence" is a scale, not an inventory. The keyword test miscounts in both directions. It is used for the ratio between rules and gates, which survives the noise; no single count above should be quoted as an exact number of rules.
One repository, one operator, one agent. A team workflow has review, approval and shared CI, and every one of those is a trigger this measurement would score above zero. What changes when more than one person is involved is a different article and a different set of constraints.
The instruments include this one. check:gates is one of the 36 it counts, and it has no automated trigger either.
Conclusion
Audit your own three numbers before adopting anyone's ai coding workflow: rules written, rules with an exit code, and triggers that fire on their own. If the third is zero, the workflow is a set of intentions with good documentation, which is what this project's was until the audit that produced this article. Fix it in the cheapest order — cap the always-loaded file, give the rules that matter an exit code, then wire one trigger. The wiring is the step everybody defers, and it is the only one that survives a long session. It is also the step that decides whether the throughput is worth anything: the same repository produced 183,788 words in 33 days and has delivered none of them.
Frequently asked questions
What is a good AI coding workflow?
Where should AI coding rules actually live?
Why does the AI ignore my instructions in long sessions?
Do I need CI to have an AI coding workflow?
How do I know if a check is really enforcing anything?
Muhammad Kashif
Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.




