← Back to Writing

Lesson 2: Record Technical Decisions and Their Reasons

About this artifact

essayon-the-recordmaintained

method · since 2026

What you'll learn: document technical choices, rejected alternatives, and conditions for reconsidering. Instruct agents to retrieve those records before proposing changes. What you need: the specs/ directory from Lesson 1, an empty decision/ folder, and the agent you already use. Time: allow ten minutes for setup and about five per decision. Cost: zero new dollars if your existing agent subscription covers the work.

The idea#

A decision record explains a technical choice and the reasons behind it. The code may show that your site uses static files, but it may not explain why you rejected a server, which costs you accepted, or when a server would become appropriate.

Keep one file per settled choice and list the files in an index. Add a standing instruction that tells the agent to read the index and open relevant records before making changes. When a request conflicts with an accepted decision, the agent should cite it and stop for your decision.

This depends on retrieval and compliance. A file can be missing, outdated, or ignored. The exercise tests whether a fresh session follows the instruction for one conflicting request; it does not establish that every future session will do so.

An agent without decision records reads the code and proposes a rejected option. An agent following the standing instruction reads the index, opens D-003, cites the conflicting decision, and stops before editing.

Why start here#

A feature spec states the result you intend to build. A decision record explains a choice that may affect many features. Keep them separate and link the relevant record from a spec when it constrains the implementation.

Start with decisions you repeatedly explain: the deployment approach, a dependency you declined, or a service you chose to avoid. Record the actual reason. “We prefer this framework” tells the next session less than the compatibility or maintenance requirement that determined the choice.

The template#

Save this as specs/decision/_template.md:

# D-000: <what we decided, as a noun phrase>

Status: draft        Date: YYYY-MM-DD
(draft until checked against the code; then accepted; later superseded by D-NNN)

## Context
What forced a choice, in one paragraph: budget, time, one person, a failure.

## Decision
One sentence, present tense. "We build the site as static files served from object storage."

## Alternatives considered
- <option>: rejected because <one line>.
- <option>: rejected because <one line>.

## Consequences
What this makes easier. What it costs. What it forbids.

## What would change our mind
The observable condition that reopens this decision: a number, an event, or a date.

Save this as specs/decision/README.md:

# Decisions

One file per settled choice. Read this table before proposing a change.
The index is the allocator: claim the next row here first, then create the
file with that number. Agents request a number; they never pick one.
Superseded records keep their file and number. Nothing is reused.

| Id | Title | Status | Decision |
|---|---|---|---|
| D-001 | ... | accepted | ... |

Reserve each number in the index before creating its file. The table is a record of reservations, with no automatic locking. When several agents are working, coordinate who updates it and check for duplicate identifiers before accepting their changes.

Add this to the file your agent reads at session start, beside the instruction from Lesson 1:

Before proposing or making any change, read specs/decision/README.md and open any
record the request touches. If the change would reverse an accepted decision, cite
its id, say whether its "What would change our mind" condition has been met, and stop.

If the tool does not load a standing file, paste the index and instruction at the start of the session. In either setup, the agent still needs access to the referenced files. The index gives a summary; the full record contains the reasons and reconsideration condition.

Each part, and the mistake it prevents#

Status tells readers whether a record is a proposal, an accepted choice, or a superseded decision. For this exercise, document choices already made and check them against the code before marking them accepted. Do not describe a proposed migration as the current implementation.

Context names the constraint that affected the choice. Budget, maintenance time, compatibility, or a previous failure can explain why an otherwise reasonable alternative was rejected. Include enough detail for a later reader to judge whether that constraint still applies.

Decision states the choice in one sentence. Alternatives considered records the options you evaluated and the reason for rejecting each. Ask the agent to draft those sections from the original discussion, then verify that it has not invented an option or rationale.

Consequences records the benefit and the inconvenience you accepted. The reconsideration section names an observable event, threshold, or date. “When we grow” is too vague to evaluate. A specific new requirement gives the next reviewer a reason to reopen the choice.

Keep superseded files, retain their identifiers, and link to the replacement decision. I found identifier collisions on two separate days: two files shared one number, then three shared another. Several records had been added together, and nobody checked the numbers again for months. Reserving numbers helps only when contributors consult the same index.

A worked example#

Save as specs/decision/D-003-static-site-export.md:

# D-003: Static site export instead of a server

Status: accepted        Date: 2026-09-10

## Context
One person, a personal site, about twelve dollars a month for hosting. Pages
change a few times a week. Nothing on the site is per-user.

## Decision
We build the site to static files and serve them from object storage behind a CDN.

## Alternatives considered
- Managed Node host: rejected because it adds a monthly bill and a process to
  patch for pages that never change per request.
- Serverless rendering: rejected because cold starts and per-request code buy
  nothing for content that is identical for every visitor.

## Consequences
Deploys are a file sync. Anything that needs per-user state, a form or a search
box, becomes a separate small API rather than a server behind the site.

## What would change our mind
A page needs per-user rendering, or the CDN bill passes twenty dollars in a month.

Add this index row: | D-003 | Static site export instead of a server | accepted | Static files on object storage behind a CDN |

The example names a hosting choice, two rejected options, the accepted limit on per-user behavior, and two conditions for reconsidering. Its dollar amounts belong to the example; use your own constraints when writing a record. A request for per-user rendering should cause the agent to open D-003 and ask whether you want to reconsider it before changing the architecture.

From the field#

On May 17 and 18, I audited 166 decision records across my repositories and produced seven fix pull requests. One accepted record said the backend used a vendor's agent toolkit as its default runtime. The code never had. A later decision routed calls directly to the vendor's API, but the older record still said to adopt the toolkit. New sessions kept proposing it.

I marked that record superseded and retained its file and number. I also closed two placeholder records that existed only to satisfy forward references, with notes saying not to revive them. The audit exposed two problems: records that contradicted the implementation, and sessions proposing changes without consulting the relevant history. Both needed correction.

Exercise#

Create specs/decision/, copy the template and index, and add the standing instruction to the file your agent loads. Confirm that the instruction names the right path.

Choose one decision you made this month. Reserve its number in the index. Let the agent draft Context and Alternatives from the discussion where you made the choice. Write the Decision and reconsideration condition yourself, check the result against the code, and mark it accepted. Repeat for two choices you keep explaining to new sessions. Omit entries that have no actual choice or rejected alternative.

Open a fresh session that loads your standing file. Request a change that conflicts with one accepted decision without mentioning the record. For the example, ask to switch to a server for per-user rendering. Inspect what the agent reads and says before it edits any files.

You're done when#

You have three records with distinct identifiers, accurate status, rejected alternatives, and observable reconsideration conditions. In the fresh session, the agent opens the relevant file, cites its identifier, evaluates the condition, and stops for your decision before editing.

If it starts implementing immediately, inspect whether it loaded and followed the instruction. If it only repeats the index row, require it to open the full record. Supplying the record yourself bypasses the retrieval step you are testing. Save the result as evidence for that session and request.

Common mistakes#

An accepted record that contradicts the code can direct later work toward the wrong design. Check the implementation when you accept or revise a record. Preserve the difference between a decision already applied and a migration still proposed.

Keep the index short enough to scan and the reasons in the individual files. Review agent-drafted rationales against the original discussion. When circumstances change, record a replacement decision and link the old one forward.

Next lesson#

Enforce Project Rules with Automated Checks adds scripts that detect specified violations and a local Git hook that runs them before a push.

Questions this post answers

What belongs in a decision record?
Record the constraint that required a choice, the decision, alternatives and their rejection reasons, accepted consequences, and an observable condition for reconsidering. Mark the record draft, accepted, or superseded so readers can distinguish current decisions from proposals and history.
Will decision records stop an agent from reversing a choice?
Only if the agent retrieves and follows the relevant record. Add a standing instruction to read the index and open matching records before proposing changes. Test retrieval in a fresh session; the instruction itself does not enforce compliance.
How do I avoid duplicate decision numbers?
Reserve the next number in the shared index before creating its file. Coordinate reservations when several agents are working at once; the Markdown table does not lock or allocate numbers automatically. Keep superseded files and their numbers.
How do I test whether agents can find the decisions?
Open a fresh session that loads the standing instruction. Request a change that conflicts with an accepted record without naming the record. Confirm that the agent opens it, cites its identifier, evaluates the reconsideration condition, and stops for your decision before editing.