Everything here is an answer to forgetting

The model is brilliant for four hours and then the session ends and takes all of it with it. Four layers of tooling later, the interesting engineering turned out not to be in the prompting at all.

Everything here is an answer to forgetting

There is a particular kind of frustration in working with these tools that nobody warns you about at the start, and it is not that the model is stupid. It is that the model is brilliant for four hours and then the session ends and every bit of it evaporates, the reasoning, the dead ends already ruled out, the decision you spent forty minutes arriving at together. You come back the next morning and the thing greets you like a stranger, cheerfully willing to suggest the exact approach you rejected yesterday for good reasons you no longer have written down anywhere.

The transcript technically survives, and for a while I thought that was the answer. It isn't, and the reason is worth being precise about, because a transcript is a record of everything that happened, not a record of what mattered. The one sentence that says what to do next is buried under two hours of exploration, half of which was wrong, and you cannot find it again unless you already remember that the conversation existed at all. Searching a pile of transcripts is its own small research project, which means in practice you do the cheaper thing, which is to start over and rebuild the context by talking. That is the tax, and it is levied daily.

So over about six months the tooling I have built around Claude Code has quietly turned into a set of answers to that one problem, and I only noticed the pattern in retrospect. Every durable piece of it exists because something structurally cannot survive the gap between one session and the next.

The first answer is a memory directory, which is about as unglamorous as it sounds, roughly a hundred markdown files each holding exactly one fact. A port number, a gotcha, a standing preference of mine, a decision that has already been made and should not be reopened. Each one has a name and a one-line description at the top, and an index file lists them, one line per fact, around eighty-five lines in total. That index is what gets loaded into the start of every single session, and the individual files are only opened when a line in the index suggests they are relevant, which keeps the standing cost to something like a page of text rather than a hundred files.

The property that makes it trustworthy is that nothing automatic writes to it. There is no hook harvesting facts out of my conversations, which means everything in there was deliberately put there in the exact words worth keeping, and reading it back costs nothing at all, no network and no model in the loop. The cost lands on me instead, as discipline, and there are three rules I hold to. A changed fact edits its existing file instead of earning a second one, because two files saying nearly the same thing split future recall between two half-truths. A fact known to be wrong gets deleted, because a stale memory is rather worse than no memory at all, it arrives with exactly the same confidence as a true one. And anything derivable from the code or the git history does not get written at all, since a shadow copy of the codebase is just a second thing to keep in step.

The second answer is a narrative memory layer, self-hosted on the same server as everything else, which does the thing the files deliberately don't, which is that it writes itself. Every ten turns of a conversation the transcript gets posted off to it, and it extracts what happened into a graph of facts and observations I can query semantically, without my ever having decided in the moment that something was worth keeping. What comes back, though, is its reading of what happened rather than the original text, and that single property decides everything about how the two stores divide the work.

The rule I settled on is that a story goes to the narrative layer and an exact value goes to a file, and nothing is ever written to both. A paraphrase is perfectly adequate for why a decision was made, and useless for what exactly the flag was called, because the one thing a summarising store cannot promise is that a precise string comes back precisely. Writing a fact into both stores feels like belt and braces and is actually two copies that will eventually disagree, at which point I have to work out which one is lying. The narrative layer earns its place on two things a local file cannot do, that nobody has to remember to write it, and that the same memory answers me from my phone or a browser as well as from the terminal.

The third answer covers the handoff, and it is the one I use most. When I need to stop mid-task I say one word, and a script writes a document recording the state of mind and not the state of the code: where we stopped, why we stopped there rather than fifty lines later, the single next concrete action, the open questions, and the decisions already settled so that a fresh session doesn't reopen them. The work itself does not go in that document, it goes into a checkpoint commit, because git is lossless about artifacts and hopeless about intent, a diff shows precisely what changed and never once shows what you were about to do next.

The part of that which took me longest to get right was not the writing, it was discovery. A parked project is worthless if the next session doesn't know it exists, and I had been relying on semantic search to surface it, which works most of the time and therefore fails rather precisely when you have stopped watching for it. The fix was rather embarrassingly dull, a small JSON file listing the parked projects and a hook that reads it and prints the list into the first breath of every new session, so recall no longer depends on anything remembering to recall.

The routing decision: a story goes to the narrative layer and is paraphrased, an exact value or rule goes to a file and stays verbatim, intent about unfinished work goes to a handoff, a repeated procedure goes to a runbook, and anything derivable from code goes nowhere.
One fact, one home. The last box is the one that keeps the whole thing from bloating.

The fourth answer is procedural rather than factual, and it is a folder of runbooks, thirty-five of them now, each one a purpose, a list of steps, and a list of dated gotchas underneath. The gotchas are the valuable half of that, and they accumulate the way scar tissue does. Any time a run hits a new trap the fix gets folded into that runbook in the same session, which means the second time I hit the same wall I read two sentences instead of rediscovering it over an hour, and the session slugs get injected at startup so a fresh session knows which procedures exist without being told. It is documentation, which is a rather unfashionable answer, but the alternative I actually tested was relying on the model to remember, and it does not.

Underneath all four sits one rule that makes the set coherent rather than merely numerous, which is that every kind of thing has exactly one home, written down in a table I keep in the global instructions. A universal rule lives in that file, a standard process is a runbook, a durable fact is a memory file with an index line, a development goal is its own document, something I want to buy goes on a wishlist, and anything derivable from code or git gets written nowhere. When two of those disagree about the same fact, that is a bug to fix rather than a nuance to preserve, and treating it that way is the only reason the whole arrangement hasn't turned into four places to check.

It has a cost and I would rather state it than pretend the design is free. The failure mode of an exact store is confident staleness, a fact that was perfectly true in June being loaded verbatim into a session in August and believed instantly, and nothing automatic enforces the hygiene rules that prevent it. The last audit I ran found thirteen memory files referenced by no index line at all, orphaned and invisible, which is the quiet version of the same problem. Recall from the narrative layer costs five to seven seconds every time it fires, which is rather the price of self-hosting it on a four-core box and not something I have found a lever for. The discipline is the load-bearing part, and discipline is rather the first thing to erode when a week gets busy.

What I would say to anyone building in this direction is that the interesting engineering turned out not to be in the prompting at all. It was in working out which layer each piece of knowledge belongs in, and then being strict about it, because the model is not the part of this system with a memory problem. I am. The tooling above is what I built so that the two of us can stop paying for it every morning.


Nathan Wong is in Singapore, building AI automation and low-code tooling, most of it self-hosted on an Unraid server called Obelisk. Portfolio