TL;DR
My AI coding agent kept "fixing" things I had broken on purpose — reverting deliberate design decisions back to textbook defaults, over and over. The fix wasn't better prompting. It was giving the agent a memory of why decisions were made: lightweight Architecture Decision Records (ADRs) wired directly into its context. Six months later, the agent hasn't relitigated a single settled decision. Here's the exact setup, the format that works, and 5 lessons. 🚀
The Problem: My Agent Kept "Fixing" Deliberate Decisions
I run a fully autonomous implementation system — an AI agent (built on Claude Code) that picks up tasks, writes code, runs tests, and opens changes for review with minimal supervision. It's been running for months across several projects, and most of the time it's great.
But there was one failure mode that drove me up the wall.
Every codebase accumulates decisions that look wrong unless you know the history:
- We use polling instead of webhooks for one integration — because the vendor's webhooks silently drop events under load. We learned that the hard way during an outage.
- One module does synchronous file writes in a hot path — because the async version had a data-loss race we could reproduce maybe once in 200 runs.
- We pin a dependency to an old major version — because the new one breaks a subtle serialization behavior we depend on.
To a fresh pair of eyes, every one of these looks like a bug. And an AI agent is permanently a fresh pair of eyes.
So my agent would touch a nearby file, notice the "obviously wrong" pattern, and helpfully modernize it. Polling → webhooks. Sync writes → async. Old pin → latest version. Each individual change looked like a competent refactor. Each one reintroduced a bug we'd already paid for once.
The worst part: it wasn't random. It was recurrent. The agent has no episodic memory across sessions, so it rediscovered the same "improvement" every few weeks, like a groundhog day of well-intentioned regressions. My review load wasn't "check the new feature" — it was "re-argue settled decisions with someone who forgot the argument."
I tried the obvious fix first: I stuffed rules into my CLAUDE.md (the instruction file Claude Code loads at session start). "Do not change the polling integration. Do not make file writes async. Do not upgrade dependency X."
It sort of worked, and completely didn't scale:
- ❌ The rules file grew into a wall of context-free commandments. Instruction-following degrades as instruction count grows — the more rules I added, the more got ignored.
- ❌ Rules without reasons get worked around. Told "don't switch to webhooks," the agent once built a webhook layer behind the polling code "to prepare for future migration." Technically compliant. Exactly what I didn't want.
- ❌ Every rule sat in every session's context, even when 90% were irrelevant to the task at hand.
The insight that unlocked it: the agent didn't need more rules. It needed the history — the same thing a new human teammate needs. And software engineering already has a boring, 15-year-old tool for exactly this: Architecture Decision Records.
How I Solved It: ADRs as Agent Memory
An ADR is just a short markdown file recording one decision: context, decision, consequences. Humans have used them forever. It turns out they're an almost perfect memory format for AI agents — if you make three adjustments.
1. The format: optimize for a reader that greps
Here's my full template. Note the Scope field — that's the load-bearing addition for agents:
# ADR-014: Use polling, not webhooks, for order-sync integration
Status: accepted (2026-03)
Scope: src/integrations/orders/**, src/jobs/order_poll*
## Decision
We poll the vendor API every 30s instead of subscribing to webhooks.
## Context
Vendor webhooks silently dropped ~2% of events under load
(confirmed with vendor support, ticket from our March incident).
Missed events caused unfulfilled orders. Polling is chattier but
lossless — the poller reconciles against a cursor, so nothing is missed.
## Consequences
- Accept ~30s max latency on order sync. This is fine for our SLA.
- Do NOT "upgrade" this to webhooks, even as a fallback layer.
A hybrid was tried; it doubled the failure modes.
## Revisit if
Vendor ships webhook delivery receipts / retry semantics.
The agent-specific adjustments:
-
Scopeis a glob, not prose. "This decision covers the billing module" is useless to a machine deciding relevance.src/integrations/orders/**is checkable in one line. -
Consequencesstates the forbidden action explicitly, including the workaround you're worried about. Remember my agent building webhooks behind the polling layer? The "even as a fallback layer" line exists because of that incident. -
Revisit ifkeeps the decision honest. Agents (and humans) respect a decision more when it's framed as contingent rather than dogma. And it gives the agent a legitimate exit: one of mine once correctly flagged that aRevisit ifcondition had been met. That's the system working.
2. The wiring: index in context, bodies on demand
Don't paste ADRs into your prompt. The whole point is keeping per-session context small. My CLAUDE.md contains only this:
## Design decisions (MANDATORY)
Settled decisions live in docs/adr/. INDEX.md maps file globs
to ADR numbers. Before modifying any file:
1. Check INDEX.md for globs matching the file.
2. Read the matching ADRs *before* writing code.
3. Never revert or work around an accepted decision. If your task
conflicts with one, STOP and flag the conflict in your summary
instead of coding around it.
4. If you make a new non-obvious design choice, append a draft ADR
(Status: proposed) and add it to INDEX.md.
And docs/adr/INDEX.md is a ~30-line lookup table:
| Globs | ADR |
|--------------------------------|-----------------|
| src/integrations/orders/** | ADR-014 |
| src/storage/writer* | ADR-009 |
| package.json (dep: serializer) | ADR-011, ADR-017|
The flow, end to end:
flowchart LR
A[Task assigned] --> B[Agent checks INDEX.md<br/>for matching globs]
B -->|match| C[Reads ADR body]
B -->|no match| D[Proceeds normally]
C -->|no conflict| D
C -->|task conflicts<br/>with ADR| E[STOP: flag conflict<br/>for human review]
D --> F[New non-obvious choice?]
F -->|yes| G[Drafts proposed ADR]
Cost per session: ~40 lines of index in context, plus 1–2 ADR bodies (~300 tokens each) only when relevant. Compare that to a rules file where every commandment taxes every session.
3. The ratchet: the agent writes ADRs too
Rule 4 above is the compounding part. When the agent makes a judgment call — picks a retry strategy, chooses denormalization, adds a cache — it drafts a Status: proposed ADR. I review these with the diff (approving or deleting one takes about a minute), and accepted ones become memory that binds future sessions.
After six months my repos have 20–40 ADRs each. Roughly a third were drafted by the agent. The decision log now grows as a side effect of normal work, which is the only way documentation ever actually stays alive.
Lessons Learned
Agents don't need more rules; they need the why. A rule without context gets pattern-matched away or "helpfully" worked around. A recorded reason — with the incident that produced it — gets respected. This mirrors human teams exactly, which shouldn't have surprised me, but did.
Relevance beats completeness in context. Moving from "all rules, always" to "small index + on-demand bodies" improved compliance and cut context bloat. The glob-scoped index is the highest-leverage 30 lines in my repo.
Give the agent a legal escape hatch, or it will build an illegal one. "STOP and flag the conflict" matters as much as "never revert." Absolute prohibitions with no outlet are how you get webhook layers hidden behind polling code. My agent has flagged real conflicts several times — twice it was right and the ADR got amended.
Make the agent pay into the system it benefits from. Agent-drafted ADRs are what made this sustainable. If writing decision records had stayed a human-only chore, the log would have gone stale in a month, and stale ADRs are worse than none — the agent trusts them.
"Boring" pre-AI practices are quietly becoming AI infrastructure. ADRs are from 2011. Nothing here is novel — that's the point. Practices designed for onboarding forgetful humans (ADRs, runbooks, conventional commits) turn out to be exactly what stateless agents need. Before inventing an agent-memory system, check whether one already exists in a dusty corner of software practice. 💡
What's Next
Two experiments in flight:
- Auto-linking ADRs in review. A small check that comments on any diff touching an ADR-scoped glob, quoting the relevant decision — so human reviewers get the same memory boost the agent does.
-
Decision decay detection. A periodic agent task that re-checks each ADR's
Revisit ifclause against current reality (vendor changelogs, dependency releases) and flags decisions that may have expired.
I'm also curious whether this scales down: even on tiny solo projects, I've started writing a three-line ADR whenever I do something deliberately weird. Cheap insurance against both future-me and future-agent.
Wrap-up
If your AI agent keeps relitigating decisions you've already settled: stop adding rules, start recording reasons. A docs/adr/ folder, a glob-scoped index, and three instructions in your agent config — that's the whole system.
If this was useful, follow me here on Dev.to — I write regularly about running autonomous coding agents in real projects: what breaks, what works, and what I'd do differently. And if you haven't tried agentic coding yet, Claude Code is where I'd start. ✅
Setup referenced in this post: Claude Code (CLI, 2026 builds) with Node.js 22.x — the pattern itself is tool-agnostic and works with any agent that loads instruction files.
What's the decision in your codebase an AI agent would "fix" first? Drop it in the comments — I'll bet at least one of you has a webhook/polling story too. 👇
Top comments (0)