Software Development with AI 11 min read Updated Jul 16, 2026

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 Prompt

Nobody 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 it
ADR-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.

Tools for this guide

Each generates the prompt described above — you run it in your own AI assistant.

Ready-made resources

Reusable prompts and templates for the exact steps in this guide.

Take it further

When this task is one step inside a larger workflow or build.

FAQ

How much of the ADR should the AI actually write?

The shape, the pressure, and the prose — not the substance. It's genuinely good at three jobs: giving the record its sections and making you fill each one, arguing the rejected option at full strength so you're not knocking over a strawman, and spotting the place where you stated an assumption as though it were established. What it can't supply is everything the record is made of. It wasn't in the design review, it doesn't know the load balancer dies at thirty seconds until you tell it, and it has no way to look at your system and find out. Hand it thin context and you get a confident, generic record about a decision that could belong to anyone — which is precisely the document your year-three reader can't use.

Where does an ADR stop and a decision log start?

They overlap on the fields and diverge on the reader, and the reader is what should decide which you're writing. A decision log captures the calls you make as you make them — in any domain, product or technical — so the reasoning survives your own memory and carries into your next chat or your next teammate. An ADR is a software artifact: one architecture choice, committed next to the code it explains, written for an engineer who will read it years from now with no access to anyone who was there. That distance is what adds the parts a log doesn't have — a status and a supersession chain, because the record has to survive being overtaken; decision drivers marked hard or soft, because your reader needs to know which sentences were walls and which were judgments; and consequences separated from risks, because they need to know what you knowingly bought. If you're writing it for yourself next month, you want a log. If you're writing it for someone you'll never meet, in year three, you want an ADR.

The decision turned out to be wrong. Do I fix the ADR?

No — and this is the rule that makes a series of records worth keeping. You write a new ADR that supersedes it, flip the old one's status to superseded, add a pointer between them, and change nothing else. The body stays exactly as wrong as it was. That feels uncomfortable and it's the entire value: a record with an edited body has no history, so nobody can separate what you knew at the time from what someone corrected afterwards, and a record you can't trust to be contemporaneous isn't evidence of anything. The truthful chain — here's what we believed in year one, here's the constraint that changed, here's what we believe now — is worth more to your reader than any single tidy document, because it shows them how the thinking moved and what moved it.

Does anything here read my architecture or check that the decision is sound?

No. The tools build prompts in your browser and nothing else — there's no connection to your repository, your source control, your diagrams, or your running system, and no step where anything goes and discovers what your architecture actually is. Everything in the record comes from you: the context, the numbers you measured, the options you weighed, the call you made. And nothing here validates the call. A well-formed ADR with a clear rationale and a decision that turns out to be a mistake is a completely normal artifact — the record's job is to make the reasoning legible, not to make it right. Whether the architecture is sound is a question for the engineers who own it, and it stays that way after the record is written.