How to Write an Architecture Decision Record (ADR) With AI
In year three someone finds the queue and asks why it's there. Nobody left knows. An ADR is the note that answers them — the constraint that eliminated the alternative, the consequences you accepted on purpose, and what would have to change for the decision to be wrong.
Build an ADR PromptNobody left knows why the queue is there
Three years in, someone opens the reporting service and finds a message queue doing one job. It looks like overkill. There's a worker to deploy, a worker to monitor, and a step in the local setup that exists only because of it. So the obvious question gets asked in a pull request — why don't we just generate the report in the request and delete all this? — and nobody can answer. The two engineers who made the call have left. The commit message says "move report generation to worker." Git blame gives a date and a name and nothing else. What happens next is one of two bad outcomes: the queue stays forever because nobody dares touch what they don't understand, or it gets removed by someone confident and reasonable who is about to rediscover, in production, the thirty-second load balancer timeout that put it there in the first place.
Both outcomes come from the same missing paragraph. Not a diagram, not documentation of how the system works — someone can read the code for that. What's missing is the *why*: what was true at the time, which options were on the table, and what made one of them impossible. That paragraph is an architecture decision record, and the person it's written for hasn't joined the company yet. The model is good at giving that paragraph a shape and pushing on the parts you left vague, but only from what you hand it: the context you were operating in, the constraints, the options you actually weighed, the evidence behind them, and the call you made. NewPrompt is where the prompt gets built, in your browser — it has no way to see your repository, your architecture diagrams, your source control, or your running system, and it doesn't go and find out what your architecture is. Anything the model suggests about which option to pick is a suggestion from someone who wasn't in the room; the decision belongs to the engineers, the architect, or the team who will live with it. An ADR doesn't make a decision correct — it makes it legible. There's no promise attached that the choice was right, that it scales, or that the architecture is any good. And an ADR is a record written after the deciding, not the deciding itself: what you know goes in one part, what you assumed goes in another, and the two never get mixed.
The reader hasn't joined yet
Picture them, because the whole format is downstream of who they are. An engineer in year three, reading the repo, holding a ticket that would undo your work. They don't have the meeting. They don't have the Slack thread. They don't know what the numbers were. They're not trying to admire your decision — they're deciding whether they're allowed to change it, and they will decide either way, with or without your help.
That reader explains why context is dated and never updated: they need what was true *then*, not now, because their question is whether the reason still holds. It explains why the rejected options matter more than the chosen one — the chosen one is visible in the code; what's invisible is that you considered their idea and something killed it. It explains why the consequences have to include the ones that hurt: a record listing only benefits reads as a document that was sold to them, and gets discounted whole. And it explains why an ADR is immutable. A document you edit is a document with no history, so nobody can separate what you knew in year one from what someone patched in during year two. You don't fix an ADR that's been overtaken. You write a new one that supersedes it, and the old one stays exactly as wrong as it always was — because the record of a decision that turned out badly is worth more than no record at all.
Step 1: Write the constraints before the options
Most weak ADRs list options and then argue. Strong ones name the decision drivers first — the things that were true regardless of what you picked, and against which every option gets measured. Some are hard limits with numbers on them: a request dies at the load balancer after thirty seconds, the compliance rule says data stays in-region, the budget is what it is. Some are about the team rather than the system: four engineers, none of whom operates a queue today. Some are about what you're optimizing for and, more usefully, what you're not.
Writing them first changes the work, because a constraint with a number attached does something an argument can't: it eliminates. "Generating in the request is slower" is a preference and someone will argue with it. "The report takes forty seconds and the load balancer kills the request at thirty" is a wall, and it disqualifies an option without anyone needing to have taste. That's the distinction to make the model hold, because it will happily blur the two — asked to justify a decision it produces a paragraph of reasonable-sounding preference, and preference is exactly what your year-three reader can overrule. Give it the constraints, the numbers you measured, where they came from, and mark the ones you're unsure of. Be equally specific about what's missing: if nobody measured the median, say nobody measured the median. And write down every driver that eliminates something, because an option rejected against a driver you never listed is an option your reader will think you rejected on a whim.
Step 2: Give every rejected option its best case
The rejected alternatives are the part of an ADR that gets read, and the part most likely to be written badly. The failure is a strawman: the option you didn't take is described in its weakest form, dismissed in half a line, and the record reads like a justification assembled afterwards. Your reader can tell. They can also tell when an option they'd have picked isn't listed at all, and the conclusion they draw is that nobody thought of it — which costs you more than disagreeing with them would.
So state each rejected option the way its advocate would, then say what killed it, and be explicit about which kind of killing it was. Some options fail a constraint outright: that's a fact, and it settles the question. Some lose a trade-off: that's a judgment, and it settles nothing — it means you'd weigh differently, and your reader might. Marking those two differently is the most useful thing the record does, because in year three the constraint might be gone. If the load balancer timeout becomes configurable, the option that was impossible is now merely a preference, and your reader needs to know which sentences they're allowed to reopen. This is also where the model earns its place: ask it to argue the case *for* the option you rejected, at full strength, before you write why you didn't take it. The Software Architect Role Prompt is a copy-paste role prompt that puts the model in that seat rather than letting it reach for code — its stance is that architecture is the set of decisions that are expensive to reverse, and it asks for each significant decision with the alternatives weighed and the trade-off accepted. It's a stance you paste, not the record itself; the Role Prompt Generator is the tool that builds prompts like it.
Step 3: Separate what will happen from what might
This is the section that makes an ADR worth more than a note about a decision, and it's the one people collapse. A consequence is not a risk. A risk is something that might happen and might not — the queue could back up under a load you haven't seen. A consequence is something that *will* happen, that you already know about, and that you are choosing to accept: from the day this ships, you operate a queue and a worker. That is not a maybe. It's a bill, it arrives every month forever, and a record worth trusting says so in the indicative mood.
Ask for both, and keep them apart in the prompt, because a model given "consequences" drifts into risk language — "this may increase operational complexity" — and that hedge is where the cost disappears. The negative ones are what your reader most needs, and they read as certainties: every new engineer's local setup grows a step; a failed report is two processes to correlate instead of a stack trace; the user no longer gets the file in the response, so someone has to build a way to tell them it's ready.
The positive ones deserve the same discipline, and they are not the same as the reason you decided. "Reports stop being bounded by the request timeout" is a certainty. "This sets us up to scale" is a hope with a nice suit on. If a benefit can't be written in the indicative — this happens, from this day — it belongs in the rationale as an argument, not in the consequences as a fact.
Step 4: Name the assumptions that could collapse
Every architecture decision rests on something nobody proved. The forty-second figure came from one run against one account in March. The team is four people. Report volume is low enough that cost never entered the conversation. None of those are constraints — they're assumptions, they were true when you wrote them, and they're exactly what your reader needs, because the ticket in their hand usually means one of them stopped being true.
So write them down as assumptions, say where each came from, and turn the important ones into a revisit trigger: not "revisit periodically," which is how a record never gets revisited, but a condition someone would actually notice. "If the load balancer timeout becomes configurable, the constraint that eliminated the synchronous option is gone — reopen this" is a trigger. So is a number: volume passing a stated figure. "When it becomes a problem" is not, and it's the form a model will reach for unprompted. A good trigger is also honest about asymmetry: reverting this decision means removing a worker other things now depend on, which is a bigger job than adding it was, so the bar for reopening isn't the bar you cleared to decide. Ask the model to name the assumptions in your own reasoning — it's genuinely useful at spotting the claim you leaned on and stated as though it were established — then check the list yourself, because it can only see what you wrote down. The assumption nobody typed is invisible to it too.
Step 5: Date it, number it, and don't rewrite it
An ADR is a record with a lifecycle, and the lifecycle is what makes a series of them useful rather than a folder of opinions. Each record gets a sequence number, a date, and a status: proposed while it's being argued, accepted once the call is made, superseded when a later record replaces it. The rule that does the work is that a superseded ADR is not corrected, deleted, or quietly improved. Its status line changes and it gains a pointer to the record that replaced it — those two fields are the only things that ever move. The body stays exactly as it was written. What you get is a chain your reader can walk: this is what we thought in year one, this is what changed, this is what we think now. Edit the body instead and you've thrown away the only property that made it evidence.
That's also why the sections are worth pinning explicitly rather than trusting to memory. The Markdown Output Builder builds a prompt that produces a document with the sections you name, in the order you name them — and it's worth being straight about what that means here. Its document types cover READMEs, specs and the rest; none of them is an ADR, so you start from the custom type, which arrives empty, and define status, context, decision drivers, options considered, decision and consequences yourself. What makes it the right tool anyway is the strict consistency setting, whose rules are that every section appears, the order holds, nothing gets merged, and the exact heading text is used with no rewording. For one document that's fussiness. For the fortieth record in a numbered series that someone greps in year three, it's the difference between a series and a pile. It builds prompt text; you run it in your own AI assistant, and the record becomes real when you commit it next to the code it explains.
Common mistakes
Each of these produces a record that exists and answers nothing:
- Writing the decision as a recommendation. If it reads "we should probably use a queue," nobody in year three knows whether it was ever decided. An ADR is written after the call, in the past tense, by the people who made it.
- Strawmanning the option you didn't take — or omitting it. The alternative described at its weakest tells your reader you were justifying rather than deciding, and the obvious option that isn't listed tells them nobody considered it.
- Rejecting an option against a driver you never wrote down. If the thing that killed it isn't in the drivers, your reader reads the rejection as taste, and taste is what they'll overrule.
- Consequences that are all upside. A record with five benefits and no costs is a sales document, and it gets discounted entirely. The costs are what prove you knew what you were buying.
- Writing an ADR for a decision that was cheap to reverse. A series only stays readable if every record earns its number. Recording the easily-undone dilutes the ones that matter, and nobody greps a folder of noise.
- Numbering by date instead of sequence. Two decisions on the same afternoon, a filename collision, and a chain that can't be walked. The number is an identity, not a timestamp — the date is already its own field.
- Letting the model make the call. It wasn't in the room, it doesn't carry the pager, and NewPrompt doesn't read your architecture or approve anything — the option it likes is a suggestion.
Recording why report generation moved to a queue
The decision from the opening, written as the record the year-three engineer needed.
One architecture decision at ADR grain: three hard drivers that eliminate two options outright, a fourth option rejected on a trade-off rather than a wall, consequences written as certainties instead of hedged into risks, and a revisit trigger with a number on itADR-0014 Generate reports in a background worker
Status: Accepted | 2026-03-11 | supersedes: none
CONTEXT (what was true in March 2026 -- not updated since)
Users click "Export report" and wait for a file in the response.
Measured: the largest account's report took ~40s. One run, in March.
Nobody timed anything else -- not the median, not a second account.
Team: 4 engineers. Nobody operates a queue today.
Volume: ~30 reports/day. Cost never entered the conversation.
DECISION DRIVERS
[hard] the load balancer kills any request at 30s. platform-managed;
not configurable by us. this is a wall, not a view.
[hard] it must work for the largest account, not the median one.
they are the customer who asked for the feature.
[hard] reports are parameterised by a date range the user picks at
request time. the output space is unbounded -- we cannot
pre-compute an answer to a question nobody has asked yet.
[soft] 4 engineers. new infrastructure is a real ongoing cost.
[soft] optimizing for: it works for everyone. NOT for throughput,
latency, or anything at scale. 30/day is not a scale problem.
OPTIONS CONSIDERED
A. Generate synchronously in the request (what we do today)
best case: zero new infrastructure. the user gets the file in the
response -- the simplest product behaviour there is, already built
and working today for every account except one.
rejected: FAILS DRIVER 1. 40s > 30s. it cannot serve the account
that asked for the feature. a wall, not a weighing.
B. Pre-generate every report on a schedule
best case: no queue, no worker, and the file is instant.
rejected: FAILS DRIVER 3. the date range is chosen at request
time, so pre-generating means enumerating an unbounded space.
it doesn't answer the question being asked.
D. Make the report finish inside 30s
best case: it deletes the problem instead of routing around it.
no queue, no worker, no notification path, and we keep the
product behaviour we already have. the strongest option here.
rejected: TRADE-OFF, NOT A WALL. we'd be buying a 10s margin on
the account that already sets the worst case -- and buying it
again every time they grow. that's a judgment, not a fact, and
it's the one a year-three reader could reasonably overrule.
unlike A and B, nothing here makes it impossible.
C. Hand the job to a background worker via a queue <- chosen
DECISION
Report generation moves to a queued background worker. The request
returns a job id.
RATIONALE
A fails driver 1; B fails driver 3. Two different walls, and neither
is a preference we could be argued out of. That leaves C and D. We
took C because D buys a margin we would have to keep re-buying on
the one account whose growth we don't control. We are not choosing C
because it scales -- at 30/day nothing needs to scale.
CONSEQUENCES -- things that WILL happen (not risks)
negative:
- we operate a queue and a worker from the day this ships:
deploy, monitor, page. a permanent bill, not a maybe.
- every new engineer's local setup grows a step. forever.
- a failed report becomes two processes to correlate instead of
one stack trace. debugging gets worse, permanently.
- the user no longer gets the file in the response. someone has
to build a "your report is ready" path. that is product work
nobody scheduled and nobody budgeted.
positive:
- report runtime stops being bounded by the request timeout. from
this day, the 30s wall is not what decides whether a report can
be produced.
RISKS -- things that MIGHT happen
- the queue backs up under a load we have not seen. unlikely at
30/day, and unmeasured.
- the worker fails silently and nobody notices until a user asks
where their file went. we have no alerting on it yet.
ASSUMPTIONS (true in March; none of them proven)
- the 40s figure is ONE run, on ONE account, once.
- report volume stays low enough that cost is irrelevant.
- the 30s timeout stays platform-managed and out of our control.
REVISIT IF
- the platform makes the 30s timeout configurable. that removes the
wall that eliminated A, and A becomes live again.
- report volume passes ~500/day (it is ~30 today). at that point the
worker needs capacity planning and this record is about a
different system.
note the asymmetry: adding the worker was additive. removing it
later means unpicking whatever else has started using it. the bar to
reopen is higher than the bar was to decide.
DECIDED BY
the two engineers who own the reporting service, in a design review.
the model drafted this record from their notes; it did not pick C,
and it had no way to know about the 30s wall until they wrote it in.
Where this fits in NewPrompt
A single record is one move inside a larger design pass, and the AI Project Architecture Workflow is that pass: put the model in an architect's seat, work the trade-offs one decision at a time, then document the decisions and their why — in its own words, "a document the team can return to when someone asks 'why is it built this way?'" That last step is this guide's job, at a different grain. The workflow's output is one architecture document covering a whole design, written once; an ADR is one decision per record, dated, numbered, and superseded rather than revised. It supplies the prompts and the order — you run them in your own AI tool, and as it puts it plainly, the architecture call and owning its consequences stay with you. The pieces here are two: the Markdown Output Builder builds the prompt from sections you define yourself, and the Software Architect Role Prompt is the stance that makes the model argue in trade-offs instead of reaching for an implementation.
The builder's document types — README, spec, changelog and the rest — don't include an ADR, which is why you start from the custom type and define the sections yourself rather than loading something someone already shaped. That's worth knowing before you go looking for it, and it's not a gap to route around by grabbing the nearest document prompt: an architecture document and an ADR answer different questions, and the difference is the whole point here.
That difference is also the line against the neighbour that sounds closest. Documenting your system architecture describes what the system *is* — living, rewritten when the system changes, stale the moment it isn't. An ADR describes why one choice was made, is frozen at its date, and cannot go stale, because it never claimed to be current. One tells you how the thing works. The other tells you which of its oddities were deliberate.
The best reader of the record you're writing is the one who disagrees with it. Not the colleague who nods — the engineer in year three holding the ticket to rip the queue out, who is often right, because the constraint that forced your hand may genuinely be gone. An ADR isn't a defence of the decision and it isn't a monument to it. It's the minimum someone needs to overturn it responsibly: here's what was true, here's what we couldn't do anything about, here's what we knowingly paid, and here's the specific thing that would make this wrong. Write it that way and the record survives being wrong, which is the only test that matters — because a decision that stays right forever never needed the record in the first place.