Every AI coding agent I've used shares one habit: it writes the plausible thing. The code compiles. The tests pass. And a senior engineer reviewing it would reach for a red pen. any where a union belongs. Tests that assert on implementation so they survive any refactor. catch (e) {} blocks that quietly swallow production errors.
The fix isn't a better model or a cleverer prompt. It's a set of rules at the repo level, written in a format the agent is guaranteed to read.
What rules files are
Cursor reads .cursor/rules/*.mdc. Claude Code reads CLAUDE.md and AGENTS.md. The .mdc format is plain markdown with YAML frontmatter. Here's the opening of the TypeScript rule file from the AgentForge sample pack:
---
description: "Strict TypeScript discipline for production code"
globs: "**/*.{ts,tsx}"
alwaysApply: true
---
Three fields carry the weight. description tells the agent in one sentence what the file is for. globs scopes it, so a TypeScript rule never fires on a Python file. alwaysApply: true loads it into every session. Agents skip a 2,000-line rules file. They read a 40-line one.
Write a discipline contract, not a wish list
Claude Code follows instructions frighteningly well, and that cuts both ways. Tell it "write good code" and it will be confidently, grammatically wrong.
An AGENTS.md contract fixes that. Start with a baseline of rules: think before you act, take small verifiable steps, never claim what you haven't verified, no drive-by refactoring. Then add a verification ladder with six rungs. Does it compile? Does the changed behavior work? Does it break anything adjacent? Does it follow the codebase's conventions? Does it hold at the boundaries? Is it observable in production? The first three are mandatory for every change.
Then the failure protocol, which is the line that pays for itself:
First failure: fix and re-verify. Second failure: re-derive, your mental model is wrong, form at least two new hypotheses. Third failure: stop, revert to last known-good, document, and re-approach from a different angle.
Agents iterate fast and they'll happily burn tokens on a broken hypothesis. A rule that forces a stop is cheap insurance.
Rules that actually change output
The discipline that matters most lives in the specific rules. From the sample TypeScript file:
Never use
any. When you cannot name a type, useunknownand narrow it with type guards before use.
Never suppress errors with@ts-ignore/@ts-expect-error.
Type every function signature explicitly, parameters and return types.
Handle every branch of a discriminated union with exhaustiveness checking.
The last one is a typed-error pattern that converts future bugs into compile errors:
type OrderStatus = "pending" | "approved" | "rejected" | "refunded";
function handleStatus(status: OrderStatus) {
switch (status) {
case "pending": return queueForReview();
case "approved": return fulfill();
case "rejected": return notifyCustomer();
default: return assertNever(status);
}
}
function assertNever(x: never): never {
throw new Error(`Unexpected: ${x}`);
}
Add a fifth status and the build fails until every case is handled. The agent can't silently skip it, and neither can you.
Errors get the same treatment. catch (e) {} is an anti-pattern; the sample rule says log, rethrow, or return an explicit error, never swallow. And e is unknown, so narrow it with a type guard before touching it. That one habit removes a whole class of silent production failures.
Testing that proves behavior
Tests are where agents generate the most waste. The sample testing file sets the standard: test behavior through public interfaces, name tests after the behavior they prove, and assert on outcomes, not calls. Write the assertion first, then the code that makes it pass. That's the closest thing to TDD an agent can follow mechanically. A good name reads like a spec:
it("rejects orders above the account credit limit", () => {
const result = placeOrder({
userId: "u1",
totalCents: 900_000,
creditLimitCents: 100_000,
});
expect(result).toMatchObject({
status: "rejected",
reason: "credit_limit_exceeded",
});
});
And the hard rule: every bugfix ships with a regression test that fails on the old code and passes on the fix. If you can't write one, you haven't understood the bug.
Try it on your own project
The files quoted above, plus the full AGENTS.md contract, are free. Drop them in a repo and watch what your agent does differently. If the structure holds up for you the way it did for me, the full pack extends it to 24 files across frontend, backend, testing, DevOps, database and agent workflows, with project templates and a one-command installer.
Free sample: https://github.com/DaymondHyper/agentforge
Full pack ($29 one-time, no subscription): https://dedyclan.gumroad.com/l/agentforge
Top comments (0)