An AI coding agent has no memory between sessions unless you build it one, which makes it something like a very fast intern with amnesia: sharp in the moment, and a stranger to itself by morning. Close the terminal and the reasoning behind yesterday's decision is gone, along with the fact that you already tried the obvious approach and it broke something, and the feedback you gave about a pattern you never want to see again. The agent starts from zero every time, which means you start from zero every time too, re-explaining context you already paid for once.
I got tired of that tax and built a system for it: a small set of conventions, shared across every project I run an agent against, that gives the agent somewhere to put what it learns.
The failure mode this is solving
Three specific things kept going wrong, on a loop, before I had this in place.
The agent would ask me a clarifying question mid-task that it could have answered itself by reading the code, or that did not need answering at all because any competent default was fine. Multiply that by every session and it is a constant low-grade interruption, worse than doing the work myself for anything small.
A decision would get made, silently, inside a diff. Six weeks later a different session would undo it, because the reasoning behind the original choice existed nowhere except a commit message nobody reads on a random Tuesday, and the code alone does not explain why it is the way it is rather than the more obvious way.
And feedback I gave in the moment, a correction, a preference, a "no, not like that," would apply to that one session and evaporate. The next agent would make the same mistake, because nothing captured that I had already ruled it out and why.
The philosophy, before the mechanics
Three rules do most of the work, and they are all about where judgment happens relative to interruption.
Decide, don't ask. Pick the option a competent engineer would pick, write the assumption down, keep going. Stop only for something destructive, something involving real money or production, or a genuine fifty-fifty fork with no clearly better option. Everything else is a default, not a question.
Batch, never interrupt. Open questions go into one list at the end of a response, not as a mid-task interruption that breaks flow. If five things were ambiguous, I want to resolve five things once, not get stopped five separate times.
Look backwards first. Before changing existing code, find out why it is the way it is. Search the decision records, then the git history, before assuming the current shape is an accident rather than a choice. Reasoning disappears the moment code gets overwritten by someone who did not know it was there.
Put together, the point is an agent that behaves like a colleague with institutional memory, not one that behaves like a very fast intern who has never seen the codebase before and needs everything re-explained.
The four places memory actually lives
Decisions. One file per non-obvious choice, in a docs/decisions/ folder, numbered and immutable: a later change supersedes a decision, it never rewrites one. Each record states the options that were actually considered, which one was picked, and why, so a future session can find the reasoning instead of reverse-engineering it from the diff. The first decision record in this system, fittingly, is the one that documents adopting the system itself.
Feedback. A reaction, a correction, a stated preference gets quoted verbatim before it gets interpreted, because the interpretation is where nuance gets lost, and having the original words on record means a later session can re-derive the right lesson even if my first interpretation of my own feedback was slightly off.
Changelog. Every user-visible change gets a one-line fragment in its own file, not a hand-edited shared changelog. The reason is mechanical: multiple sessions or parallel worktrees writing to one file is a guaranteed merge conflict, and a fragment per change sidesteps it entirely. Something assembles the fragments into the real changelog later.
A handoff note, for work that spans more than one session: what is done, what is next, oriented enough that picking the work back up does not require replaying the whole conversation that led here.
The layer that keeps borrowed advice from winning by default
The other half of this system is a set of skills, which are really just packaged instructions for how to approach a category of work: reviewing an interface, writing accessible markup, structuring a layout. Most of the useful ones are written by other people and shared publicly, which is a shortcut worth taking. It is also a trap if you take it uncritically, because those skills encode someone else's stack.
A generic frontend skill will assume Tailwind, CSS modules, oklch() color functions, a particular animation library, because that is what most projects use. None of that is true here. Following that advice literally would mean rewriting working CSS to match conventions this project never adopted, for no reason better than the instructions said so.
The fix is a precedence rule, not a rewrite of the borrowed skills. Borrowed instructions live in one folder, pinned by a content hash so an update is a deliberate, visible act rather than a silent drift. This repo's own corrections live in a separate folder that explicitly outranks the borrowed one, the same way a project's own conventions should outrank generic advice whenever the two disagree. Without a stated precedence, the house style loses by attrition, one plausible-sounding suggestion at a time, because "this is standard practice" is a very persuasive argument even when it is standard practice for a different kind of project.
Why this is the same problem as the design side
I have written elsewhere about the judgment layer in AI-generated design output: the layer that decides whether something is right, not just plausible, and that a model cannot supply on its own. This system is the same idea applied one level up, to the process rather than a single output. Instead of checking each result by hand every time, I encoded the judgment once, as a set of standing rules and a place to record exceptions, so the checking happens by default instead of by memory. The agent still needs a human in the loop. It just needs fewer reminders about which human decisions have already been made.