AI coding agent context: how to document project decisions
By Flavio Copes
A practical way to preserve project decisions, rejected alternatives, and unfinished questions so you and your coding agents can pick up the work later.
An agent asks why a project uses a particular database. You remember having a long conversation about it. You remember that the choice made sense. Finding the reason takes longer than you expected.
It could be in an old chat that covered four other questions before the database discussion. You remember the conclusion more clearly than the constraint that led to it.
The code tells the agent which database you chose. It cannot reliably tell either of you why.
This is an ordinary problem in software projects. Working with agents gives us another reason to address it, because we move between conversations while the application keeps accumulating decisions.
I want a project to carry enough of its own history that I can stop working on it for a while and return without reconstructing every discussion.
Your future self also needs context
When we discuss agent memory, we often focus on the model’s limitations.
There is also the person using it. You can spend a morning deciding how uploads should work and then switch to a different project. A month later, a cheaper service appears. You reopen the upload code and wonder why you did not use it in the first place.
A fresh agent can make a convincing case for that service. If the old constraint is missing, both of you may agree to a migration that recreates a problem you already considered.
Most discussions contain temporary guesses and irrelevant detours that we can leave behind. Preserve the decision and the information needed to judge it later.
For uploads, that might be a requirement to keep original files in a region supported by your customers’ contracts. A note about that requirement is more useful than pages of discussion about SDK preferences.
Separate a decision from an investigation
During a useful technical conversation, several things can sound settled before they are.
You explore an alternative. The agent explains how to implement it. You ask about a possible downside. Then you move to another question.
The next summary can accidentally describe the explored alternative as the approved plan.
I would label unfinished work explicitly. A proposal says what we are considering. An accepted decision says what we agreed to do. An open question says what still needs an answer.
Those distinctions do not require a formal process. A line saying “We have not decided whether to migrate existing files” can prevent a large mistake.
It also gives the next conversation an honest starting point. The agent can continue the investigation without interpreting the presence of sample code as permission to implement it.
Keep the reason close to the project
A repository is a useful home for decisions that affect its code.
The record travels with the application, has a change history, and can link to the files it explains. An agent with access to the project can read it without searching through unrelated conversations.
The idea has a long history. Michael Nygard described architecture decision records as short documents for significant choices. His approach includes context, a decision, its status, and consequences. Older records remain available when a newer decision replaces them.
I like starting smaller than a large documentation system. One docs/decisions.md file is enough until its entries become difficult to find. At that point, individual files under docs/decisions/ can make sense.
Choose a location the project already uses for documentation. Creating another knowledge store gives you another place to keep current.
Record what would make you reconsider
A useful decision explains its limits.
“We use local storage because it is simpler” is too vague to help later. Perhaps we want offline access, or we want to avoid maintaining an account service. Name the requirement that mattered to this project.
For a hypothetical desktop notes application, I would write something like this:
We store notes as local files because this release has no accounts or collaboration. Users can read their files without the app. We considered a hosted database, but it would introduce account recovery and ongoing service maintenance. Revisit this when shared editing becomes an approved requirement.
That paragraph gives a future agent something to evaluate. We can revisit the account requirement when collaboration becomes an approved feature, with a clear reason for changing the architecture.
The rejected option belongs in the record because otherwise it looks like something nobody considered. The condition for reconsidering belongs there because otherwise an old choice can become a permanent rule by accident.
You are allowed to change your mind. The record makes the change easier to explain.
Rejected alternatives deserve a fair description
It is easy to write an alternative off as “too complicated” after choosing something else.
That loses useful information. A service can be excellent and still be a poor fit for a particular project. The framework you rejected may solve problems you do not have yet, while a manual step remains acceptable at the current scale.
Write the project constraint that ruled it out. If the objection was based on an estimate, label it as an estimate. If you tried it and hit a documented limit, link to that evidence.
I would avoid asking an agent to invent the rationale after the decision. It can produce a plausible explanation from the code, and plausible explanations are easy to accept when you have forgotten the conversation.
“Reason not recorded” is useful information. It tells me I need to answer a question. An invented reason quietly becomes the basis for future work.
A task handoff contains different information
A decision record should not become a running transcript of unfinished implementation.
Suppose we have chosen local files for the notes application. During the implementation, an agent updates the editor but leaves the import dialog unfinished.
That belongs in the task handoff. It should name the files changed, what was checked, and what remains. The decision record can stay focused on why local files are the chosen storage model.
Mixing these together creates documents where an old “next step” looks current months later. It also makes the architectural reasoning harder to find beneath a list of completed edits.
I would keep durable decisions in the documentation and active work in a short task record. When the task ends, remove or close its outstanding items. The accepted decision can remain useful for years.
Give the agent a way to find the records
Writing a file does not guarantee the next agent reads it.
I would put a short pointer in AGENTS.md. It can say where decisions live and ask the agent to check relevant records before changing the affected area.
The pointer should be brief. Copying every decision into the instruction file creates two versions to maintain. It also makes the instructions harder to scan.
For a larger project, an index can help. A storage heading can link to the upload and retention decisions. An authentication heading can link to the session model. The index tells the agent where to look without loading every historical discussion into each task.
Names matter too. A file called local-note-storage.md is easier to discover than discussion-final-v3.md. A title should describe the decision’s subject in words someone would search for.
Side questions can stay in the conversation
Sometimes an important decision starts as a side question.
You are fixing a bug and ask whether the current data model is still a good fit. The agent explains a few options. The discussion helps you understand the system, even though you decide to leave the implementation alone.
I would keep that conversation where it is useful while working. Moving every question into a separate thread can make the immediate discussion harder to follow.
Before ending the session, however, I would ask whether any conclusion deserves a record. Most side questions do not. A decision to keep an unusual design because another feature depends on it probably does.
This lets the conversation stay natural. You do not need to stop after every useful sentence to maintain documentation. Capture the few conclusions that will matter when the surrounding conversation is gone.
Summaries need review too
An agent can draft the decision note. I would still read it.
The important errors are often small changes in certainty. “We considered adding accounts” becomes “Accounts are planned.” “This option seems expensive” becomes “The cost is prohibitive.” “Keep it for now” becomes an unconditional rule.
A good summary preserves uncertainty where uncertainty remains. It should distinguish something we observed from something we expect.
I would also check that the note includes the downside of the chosen option. Local files avoid running an account service, but sharing notes across devices now requires another mechanism. If the document records only advantages, it reads like a justification written after the fact.
Once I accept the note, it can guide future agents. Until then, it is a proposed summary of the conversation.
Old records need an explicit status
Suppose the notes application later adds shared editing.
We now choose a hosted backend for shared documents while keeping personal notes local. The old local-file decision still explains the earlier architecture, but it no longer describes the whole application.
I would mark that record as superseded in the relevant area and link to the new one. The replacement should explain what requirement changed.
Do not make the reader work out chronology from two contradictory documents. A date helps, but a clear status is better. An accepted decision from last year can still apply. A newer proposal might never have been approved.
When an agent finds conflicting records, it should report the conflict before making a broad change. Guessing which statement reflects the owner’s intent is an expensive way to resolve documentation drift.
Some context should stay out
A decision record can refer to private information without copying it into the repository.
For example, it can say a customer contract requires a particular retention period and link to the approved internal source. It does not need the customer’s personal details or the contract pasted into a public file.
For credentials, “The deployment token is available through the project’s secret manager” explains where an authorized tool gets access. Leave the token itself out of the note.
I would also leave out temporary frustration with a product or a person. Write the technical limitation you encountered and the consequence for the project. That remains useful after you have forgotten the difficult afternoon.
Start with one recurring decision
I would pick one decision that keeps coming up.
Perhaps an agent repeatedly proposes replacing a small dependency. Perhaps I keep explaining why the app has no account system. I would write that decision while I still remember the reason.
Then I would give the agent a specific question and ask it to find the answer in the project. If it cannot locate the record, I would improve the filename or the pointer. If it finds the record but misunderstands the scope, I would rewrite the relevant paragraph.
This is easier to maintain than reconstructing the project’s entire past in one sitting. Git history can help recover what changed, but missing reasons still need an honest answer from the person who made the choice. The Git course explains the history tools if you need them.
I would keep the habit small. At the end of a substantial design discussion, ask what we decided, what remains open, and what would make us revisit it. Save the answer where the next session can find it, then read it before moving on.
Want me to talk about your product? You can sponsor this site.
Related posts about ai: