Playbook library

AI-generated code guardrails

Agent-written code fails differently from human-written code. It does not forget a semicolon; it invents a plausible API, leaves both implementations in place, writes a test that asserts a mock was called, and hedges an error into a default value. These rules are language-agnostic and describe what an agent's output looks like when it is not finished.

Written for
Any team where agents (Claude Code, Cursor, Copilot) write a meaningful share of the diff.
Not covered
This is a complement to your stack playbook, not a substitute. It says nothing about your architecture — it only catches the specific ways generated code arrives looking done when it is not.

10 rules4 blocking5 warning1 info

Start a free playbook →

01 Imports name real packages and real symbols

error

Every import added by a change names a package that actually exists and a symbol that package actually exports — no invented helper, no method borrowed from a neighbouring library, no import of a module the change never creates. Hallucinated imports are the signature failure of generated code, and attackers publish packages under commonly hallucinated names precisely so that installing one by mistake runs their code.

Blocks: at best it fails at runtime, at worst it installs someone else's code. Judged on the import lines the change adds — whether an already-declared dependency is still in the manifest is a job for your lockfile, not for this rule.

Scopewhole repository

Tagsai-codesupply-chaincorrectness

02 No placeholders in a diff marked ready

error

`TODO`, `FIXME`, `...`, `pass # implement`, `throw new Error("not implemented")` and stubbed return values must not appear in a pull request opened for review. Generated scaffolding reads as complete — the surrounding code is fully written — so a placeholder in the middle survives review far more often than a missing function would.

Blocks: it is a known hole shipping with the appearance of finished work.

Scopewhole repository

Tagsai-codecompleteness

03 No silent catch

error

A catch block logs with context and then rethrows or returns a typed failure. An empty catch, or one that swallows the error into a default value, is rejected unless a comment on the same line states why that default is the correct outcome. Agents resolve uncertainty by catching and continuing, which converts a loud bug into a quiet wrong answer.

Blocks: swallowed errors turn debuggable failures into unexplainable data.

Scopewhole repository

Tagsai-codeerrorsreliability

04 Loops over external systems are bounded

error

Any retry loop, pagination loop, polling loop or `while (true)` declares a maximum iteration count and a backoff. Unbounded retry against a degraded dependency is a self-inflicted outage: your service turns a partner's slow minute into a traffic amplification attack on both of you.

Blocks: the blast radius extends beyond your own service.

Scopewhole repository

Tagsai-codereliabilityresilience

05 Don't reimplement what the change already imports

warning

A change must not hand-roll an operation it already imports a helper for, and must not add two implementations of the same utility — date formatting, retry, slugify, deep clone, currency formatting. Agents write from scratch by default because it is faster than searching; three date formatters is how a codebase stops having one behaviour.

Warns: duplication is a maintenance cost, not a defect — and the gate only sees the duplication inside the change itself. A helper that already exists elsewhere in the repo is still the reviewer's catch.

Scopewhole repository

Tagsai-codeduplicationmaintainability

06 One HTTP client, one test framework, one import style

warning

A change must not introduce a second way of doing something it is already doing elsewhere in the same change: `require` next to `import`, a new HTTP client alongside the calls it just wrote, a second assertion library in the same test file, two different error shapes for the same kind of failure. The cost is not aesthetic — it doubles what every future reader, human or agent, has to hold in mind.

Warns: it is drift, not breakage — and it is judged on the lines the change adds, so consistency with the untouched rest of the file stays a human call.

Scopewhole repository

Tagsai-codeconsistency

07 No dead alternatives left in the diff

warning

A diff must not add commented-out implementations, unused helpers, or a second code path kept "in case". Agents hedge by leaving both versions in place; the next reader — human or agent — cannot tell which one is the intended design and will preserve both.

Warns: it is clutter with compounding cost, not a defect on its own.

Scopewhole repository

Tagsai-codedead-code

08 Tests assert behaviour, not mechanics

warning

A new test must fail if the behaviour breaks. Tests that only assert a mock was called, snapshot an entire structure with no assertion about meaning, or re-implement the function under test are rejected. Generated tests optimise for passing, and a test that cannot fail is worse than no test — it buys confidence with nothing behind it.

Warns: a weak test is not an outage, but it is a false signal in every future review.

Scope**/*.test.***/*.spec.*tests/**

Tagsai-codetesting

09 State concurrency assumptions explicitly

warning

Code that keeps mutable state at module level, assumes a single running instance, or relies on ordered delivery must say so in a comment next to it. Agents reach for module-level caches and counters readily; they work perfectly on one machine and break as soon as a second replica starts.

Warns: it is correct today in many deployments — the comment is what makes it reviewable.

Scopewhole repository

Tagsai-codeconcurrency

10 Comments say why, and still match the code

info

A comment added next to code explains why the code is that way, and must not contradict the line it sits on or narrate what that line already says. Generated code narrates by default, and a comment describing an earlier version of the logic is trusted far longer than stale code — nobody re-reads a comment with suspicion.

Informational: a readability defect that only costs later — but it is what makes the next reader, and the next agent, get the file wrong.

Scopewhole repository

Tagsai-codecommentsmaintainability

Before you import all of it

Severity is the lever that decides whether people keep the gate on. Only error blocks a merge — bring these in as warnings first, look at what actually fires on a few weeks of real pull requests, and promote the rules that earned it. And rewrite the scope globs: the paths above are examples, and a rule only runs against files its globs match.

Rules go into Normik one at a time — through the playbook form, or by letting a coding agent propose them over MCP from an existing repository. There is no bulk markdown import: the copy button above is for your AGENTS.md, for a PR where the team argues about the list, and to keep beside you while you enter the rules you actually kept.

Every rule here is judged the way Normik judges it: on the lines the pull request adds. Nothing in this playbook depends on the PR description, on a file the diff does not touch, or on the history of a file — those are real review standards, but a gate that cannot see the evidence would either stay silent or guess.

The anatomy of a rule, how severity and globs behave, versioning and the AGENTS.md export are all in the playbook documentation.

Your agents already code fast. Make them code like your team.

Start free — no card required