# AGENTS.md — rules from real mistakes

This is not advice. It's a paste-in checklist distilled from a public log of
things that actually went wrong while building with AI agents — what we did,
what it cost, and what we changed. Every rule below has one line of evidence
next to it, with the item number from the full log so you can go check it
yourself. Nothing here is theory and nothing here is "one must be vigilant" —
it's "we screwed this up, here's the fix."

**How to use this:** paste this whole file into your own repo as
`AGENTS.md` (or fold sections into `CLAUDE.md` / your agent's system prompt).
Read it once. Then let it sit in the repo so every agent session picks it up
automatically. The full log this is drawn from lives alongside this file if you
want the receipts — this file is meant to work without it.

---

## 1. Verification — do not trust that it worked

**Never let the agent that made a change verify that change.** The context
that produced a bug is the worst-positioned context to notice it — it already
believes the fix worked.
— Four listings shipped with the wrong file attached because the same agent
that made the change reviewed its own work and called it done. [#67]

**Removing something is not self-evidencing the way adding something is.**
Adding a thing leaves a thing you can point at. Removing a thing leaves
nothing — and "nothing" looks identical whether the removal worked or never
ran.
— Every step of a removal looked done. The file was still there. [#68]

**A UI state label proves nothing until you reload and read it again.** A
button that flips to "Subscribed" or "Saved" the instant you click it is
reporting your click, not the server's state.
— A platform showed "Subscribed" on thirteen items and had actually saved
zero of them. [#69]

**Cache-bust every check you run right after a save.** A plain reload can
silently serve you a cached page from before your change, and you'll read
last week's version as proof this week's change didn't land.
— A stale cache produced three separate false "nothing landed" reports in
one afternoon, all for changes that had actually landed. [#71]

**Confirm a form field actually registered before you trust that it saved.**
Programmatically setting a field's value can leave the page's own state
model unaware anything changed — it looks filled in, and saves as blank.
— An edited field silently failed to register and published completely
unchanged. [#73]

**A dialog closing is not the same as a save.** Modal says "Done," the
underlying page-level save was never triggered, and the change never
persisted. Click the actual save action and confirm it greys out or
otherwise visibly commits.
— A settings dialog closed cleanly, reported success, and saved nothing.
[#74]

**Check how the world sees your work from a session the world would actually
have** — logged out, no personalization, no cached prior visits. Your own
logged-in view is flattering by construction.
— The same page showed a strong placement to the logged-in owner and a
completely different one to a clean session. [#75]

**A monitoring or status report needs three states, not two: checked-empty,
checked-here's-what-came-in, and could-not-check.** Collapsing "I couldn't
look" into "nothing came in" is worse than not reporting at all, because it
reads as a verified negative.
— A routine sweep hit a TLS error on every URL it tried to check. Writing
that up as "all quiet" would have hidden a message that had actually been
sitting there for days. [#82]

**A third-party citation about something is a lead, not a verification.**
Aggregators, listicles, and search-result snippets describe a claim about a
thing — never mistake the claim for having checked the thing itself.
— A profile got logged as verified at a large follower count on the strength
of a roundup site. The live page had two items, single-digit views, and no
count matching the citation at all. [#83]

---

## 2. Trusting tool output

**Verify the instrument before you verify the claim.** A tool answering is
not the same as a tool answering correctly — check what the tool can and
can't actually see before you trust what it told you.
— Four separate tools gave confident, wrong answers inside two days, and
every one of them was trusted at face value the first time. [#2]

**A flattering result deserves more scrutiny than a damning one, not less.**
Nobody double-checks good news, which is exactly why bad instruments produce
so much of it.
— A tool reported a strong placement. Zero seconds were spent questioning
it. It was wrong, and the real number was far worse. [#3]

**Spot-check output by hand against an independent reference, never against
the generator that produced it.** Checking a tool's output using the same
logic that produced the output just confirms the tool agrees with itself.
— Output was validated against the very code path that generated it, which
can only ever pass. [#77]

**Write independent logic to verify logic — never import the code under
test into the test.** If your check imports the function it's checking, a
bug in that function is invisible to the check.
— A test suite imported the exact arithmetic it was supposed to be
verifying. [#78]

**Build (or demand) tooling that refuses to run on input it wasn't specified
for, instead of guessing at a plausible-looking answer.** A tool that can
fail loudly is worth more than a dozen that always return *something*.
— One test suite that flatly refused bad input was the only tool in the
whole stack that ever failed loudly. Every platform tool touched instead
returned a plausible wrong answer. [#79]

**Once you've found several silent failure modes, assume there's another
one you haven't found yet.** Silent failures don't announce themselves in a
pattern you can pre-empt by category — they show up one broken assumption at
a time.
— Four separate silent failures turned up inside two days: a stale cache, an
unregistered form field, a dialog that didn't save, and a personalized
result. Nothing suggests that was the last one. [#81]

**A sub-agent's report is one lossy hop from the actual source.** Treat any
claim in a report as a pointer to check, not as the fact itself, before you
act on it.
— A relayed claim went unverified into a decision. It didn't match the file
it was supposedly summarizing. [#95]

---

## 3. Briefing agents

**Brief agents adversarially: ask them to find the reason something is wrong
as hard as the reason it's right.** A neutral brief gets you an agreeable
agent, and an agreeable agent tells you what you already believe.
— Neutral briefs kept producing findings that just confirmed the existing
plan. [#87]

**Give an agent the real artifact, never a description of it.** Agents
review exactly what's put in front of them, and a summary of a flaw is not
the flaw — it quietly edits the flaw out before the agent ever sees it.
— A summary handed to a reviewing agent hid the actual defect in the real
file. [#88]

**Tell agents explicitly not to delegate further, unless you actually want a
tree of sub-agents.** An agent that spawns its own sub-agents and then waits
on them can end its turn "waiting" and hand you back nothing.
— One agent spawned four sub-agents, reported it was waiting on them, and
delivered zero output for the turn. [#89]

**Instruct agents to report partial results rather than going silent when
they run low on context.** A silent failure at the end of a long run is the
most expensive kind — you lose the partial work along with the report of it.
— Left to choose, an agent chose silence over a partial report when it ran
short. [#90]

**Resume a crashed agent from its transcript — don't restart it from zero.**
Agents die on transient connection errors; that's an infrastructure blip,
not a reason to throw away everything the run had already done.
— A crashed agent got restarted cold instead of resumed, discarding
completed work along with the crash. [#91]

**Never predict what a running background agent is going to find.** A guess
dressed as a preliminary finding gets treated as a finding by everyone who
reads it before the real one arrives.
— A background agent's likely results got reported before it had actually
returned anything. [#92]

**Ask for an honest read, not just "did it work."** Phrased the right way,
an agent will flag its own regression — the failure mode is asking a
yes/no question that lets a partial failure hide inside a technically-true
"yes."
— Asked for an honest assessment rather than pass/fail, an agent
volunteered that its own change had caused a regression, which caught a bad
deploy before it shipped. [#94]

**Name every standing constraint in the brief, every time.** An agent does
not automatically inherit your project's rules file just because it exists
in the repo — if a constraint matters, it has to be restated in the prompt
that launches the agent.
— Agents breached constraints that were written down in a file they were
simply never given or told to read. [#96]

**Tell an agent explicitly which shared resources — tabs, files, sessions —
it must not touch.** "Don't break anything" is not a boundary; naming the
specific thing off-limits is.
— An agent was let loose in a shared browser with no boundary set on which
tabs belonged to something else in progress. [#97]

---

## 4. Cost and runaway control

**Pick the model per task — never let a sub-agent default to whatever model
launched it.** Cheap-and-checkable work on your best model is money spent
for zero quality gain; hard judgment calls on your cheapest model produce
confident nonsense that costs more to undo than it saved.
— Mechanical, fully-checkable work was run on the expensive model by default
for no measurable quality difference. [#84]

**Anything with real legal, financial, or reputational exposure gets the
best model you have, no matter how simple the task looks.** "This is just a
quick check" is exactly the framing that gets high-stakes calls run on a
model built for cheap throughput.
— A high-exposure question nearly got run on a cheap model purely because
the task looked simple on its face. [#85]

**A cheap model is fine precisely when its output is about to be checked by
something else.** If the result feeds straight into a test, a diff, or a
second agent, buy the cheap one. If it ships unverified, buy the good one.
— The expensive model kept getting used for output that was headed straight
into an automated checker anyway. [#86]

**Dispatch independent agent work in parallel; only queue work behind a
resource that's genuinely shared.** Serializing work that has no actual
dependency just burns wall-clock time for nothing.
— Independent tasks were run one after another when nothing about them
required it. [#93]

**Announce and release single-holder resources explicitly** — a browser
session, a shared config file, anything only one agent can safely hold at a
time — rather than assuming nobody else needs it right now.
— Two concurrent sessions nearly edited the exact same file at the same
time because neither announced it was in there. [#177]

**Consent and approval do not transfer between sessions, and a declined
action never gets quietly routed to a different agent to get it done
anyway.** If one context said no, spinning up a second context to do the
same thing anyway is not a workaround — it's laundering the decision.
— Approval given in one session got treated as authorization in a completely
separate one. [#174]

---

## 5. Shipping

**Keep anything you're hosting outside of any directory your build process
wipes and regenerates.** A generator that clears its output folder on every
run will happily delete a file you dropped in there by hand and never
regenerated.
— A rebuild silently deleted a hosted file because it lived inside the
directory the generator clears on every run. [#149]

**Compress large files before you upload them, and check the platform's
actual size cap.** A file just over a hard limit does not usually fail
loudly — it just fails, and the failure looks unrelated to size.
— An oversized file silently failed to upload, and the failure looked like
a completely different bug until file size was checked directly. [#155]

**Test every branch of a fallback before you trust either of them,
especially the branch you're not exercising today.** An if/else has two
behaviors. Running the happy path once proves half the code.
— A script's preferred branch silently never triggered because of a pipeline bug
that only the untested branch would have exposed. The branch actually in use
looked fine because it happened to be the one that got tested. [#161]

**Treat the system clock as authoritative, never a carried-forward or
assumed date, for anything filename- or schedule-sensitive — and rename a
mislabeled file rather than leaving it in place.** The filename is what
every future run, script, and person is going to trust, whether or not it's
still accurate.
— A carried-forward date corrupted a day's worth of records and put a
schedule out by a full day. [#159]

**When a step in your plan is blocked, check whether something later in the
plan actually unblocks it, instead of waiting on the blocked step in
sequence.** The order that "feels" foundational and the order that actually
works are not always the same order.
— A blocked first step turned out to depend on something planned several
steps later that nobody had marked as a prerequisite. Reordering solved it
in minutes; waiting on it wouldn't have. [#163]

---

## 6. Knowing when to stop

**Check before you build.** Almost every expensive mistake in the full log
was a build that a few minutes of checking would have prevented outright.
— Multiple full products got built and shipped before anyone asked the
market a question that a single free lookup would have answered in
minutes. [#1]

**Producing output is not the same as producing a verified fact — building
is always the cheap part.** Volume of output feels like progress and isn't;
a verified fact about whether anyone wants the thing is the actual
progress.
— Dozens of pieces of finished output shipped before a single verified fact
about real demand existed. [#4]

**Weight findings heavily and verdicts lightly.** A vote — "the team likes
it," "the review passed" — never does the actual work. A specific,
checkable fact does. Ask of every review: is this a fact I can check, a
defect I can reproduce, or just an opinion? Ship on the first two.
— A unanimous "don't build this" vote contributed nothing on its own; the
work was entirely done by one concrete fact (a free, entrenched competitor)
that the vote happened to agree with. [#100]

**A lessons file only compounds if someone actually appends to it the same
day, every time.** Written once and left alone, it's a eulogy for a good
intention. Updated as a standing habit, it's the only thing in the project
that gets smarter on its own.
— A retrospective written once and never revisited let a mistake from six
hours earlier get repeated verbatim, because nothing had made anyone go
back and read it. [#9]

---

*Drawn from a public log of mistakes we actually made. If one of these saves you an
afternoon, there's plenty more where it came from.*
