Field notes · Engineering
How to run an engineering project staffed entirely by amnesiacs
Your best engineer forgets everything between sessions. The job was never managing the project — it was building the amnesiac a memory.
The amnesiac
The colleague who forgets everything.
You’ve hired the best engineer you’ve ever worked with. It’s also a machine, and it forgets everything between sessions. Frighteningly fast — it reads a forty-file subsystem in the time it takes you to find the right file, never gets bored, never gets defensive in review. But every session it starts cold, having forgotten all of it: your codebase, the architecture you agreed on yesterday, the bug that ate your Tuesday, its own name.
It writes your code and forgets it did — not by accident, but by architecture: it thinks inside a context window with a hard edge, and a long enough conversation always reaches that edge. You’re not managing one brilliant colleague. You’re managing an unbroken series of brilliant amnesiacs, rehiring an identical one every twenty minutes.
Regardless of which LLM you’re using and how, nothing here changes — amnesia is a property of the species (for now), not the brand, and not the price tier: the cheap models and the frontier ones forget exactly alike. These agents are stateless: each session boots from an empty context window and knows only what you load into it. Close the session and that working memory is gone. Everything that follows is engineering around that one fact.
The crucible
What amnesia costs on a real migration.
None of this is hypothetical. We learned it the hard way porting Virunga — the service that tracks every vehicle in our fleet: forty thousand lines of NestJS, seventy-two HTTP routes, eighty-three CQRS handlers, seventeen Pub/Sub subscriptions — into our monorepo and deleting the original behind it. Doing that with a stateless agent is a recipe for chaos without a rigid system for state: the cutover has to be byte-for-byte faithful — the same outputs, the same edge cases, the same long-standing bugs the rest of the system already leans on — and an agent that forgets everything between sessions drifts on the first detail it didn’t write down.
Humans get away with terrible project bookkeeping because we cheat. Jira rots, the wiki lies, the real status lives in three people’s heads — and it’s fine, because we carry warm context across days. You sit down, and before the coffee’s done you already know where you were. The amnesiac has no coffee and no yesterday. It resumes stone cold, every session, from whatever you wrote down and nothing else.
It’s worth being precise about how the forgetting happens within a session, because it isn’t theatrical — it’s plumbing. Run a conversation long enough and the context window fills; the tooling compacts instead of stalling, quietly swapping the transcript for a summary of itself and carrying on. The catch: that summary is the machine paraphrasing its own memory, and a paraphrase is a rumor. It will assure you everything went green; only the code knows whether it did — and the two don’t always agree.
All of which takes the question every team answers badly and survives anyway — where does project state actually live? — and quietly turns it from a matter of taste into a matter of survival.
Sort by speed
Sort your state by how fast it changes.
Once you see it that way, the whole thing collapses into a cold-start I/O problem: a new hire who has to re-derive the entire situation from written artifacts in the first five minutes, and then do good work. And the trick to feeding that new hire is not writing more down. It’s writing each thing down in the place that changes at the same speed the thing itself does.
Because truth moves at different speeds. The plan — the phases, the work-queue, the things that must not break — changes slowly, if it’s any good at all. “Where exactly are we” changes every session. The code changes every commit. Stop fighting that. Sort your state by how fast it moves, slowest to fastest, and three surfaces fall out on their own — the map, the territory, and the thing that actually runs:
- Linear is the map. Changes slowly. The durable, human-facing orientation layer: the phases, the work-queue, the standing hazards, the decisions that are a human’s to make. The thing a PM, a teammate, and a cold agent can all read to get their bearings.
- Palimpsest is the territory. Changes every session. It’s our name for the fast, messy, agent-facing working memory: per-handler status, the bug ledger, the method, the spec that keeps moving under you, a newest-first log of what just happened. It lives in a separate repo — an engineering journal — deliberately kept out of the code tree, dated and rewritten constantly: you overwrite the current view without mercy, but never delete the dated record of what was once true. (The name is the point: a palimpsest is a manuscript scraped clean and written over, the older text still ghosting through.)
- Git is the actual behavior. Changes every commit — faster than either. The only artifact that physically cannot lie, because it’s the thing that runs. Don’t keep a prose copy of what the code does; it’s stale the second you ship.
(There’s a slower-moving fourth: the immutable decision — why we chose X over Y. That lives as an ADR in the code repo, frozen, superseded only by a new dated one. It’s a sibling of the code, not part of the daily triad, but it’s where a decision goes to become permanent.)
The pair that can drift is the territory and the map. The oldest rule in the book keeps them honest: one fact, one home. The per-handler state lives in exactly one place, palimpsest’s status.md. Linear points at it. It never, ever copies it. The day you copy it, you own two truths, and one of them is already wrong.
Why a separate repo, and not a folder in the code tree? Docs beside the code rot the moment the code moves — and worse, an agent reads a code-adjacent design as current and authoritative, then hallucinates from the stale version. A stale doc dressed as current is just another rumor. So the journal lives apart: its own repo, with a README that says what belongs in it. The territory for one initiative is a handful of dated files:
palimpsest/ # a separate repo — the engineering journal └─ orchestration/virunga-port/ ├─ status.md # newest-first log: where we are, right now ├─ spec.md # the moving spec — what we're building, redrawn as it shifts ├─ census.md # the full surface — every unit, done vs. left ├─ legacy-bug-ledger.md # the landmines — bugs the port must reproduce ├─ fan-out-readiness.md # build order / what's safe to start next └─ <unit>-build.md # one doc per resumable unit (×N)
Two ways to fail
Mirror everything into issues, or bury everything in the territory.
There are exactly two ways to screw this up, and they’re mirror images of each other.
Put everything in Linear. Mirror that whole surface into issues and you’ve put fast-moving truth on a slow-moving board — and it breaks three ways at once. The issues go stale the instant the agent grinds a module, because the work moves every session and a hand-kept board doesn’t. They duplicate state the code and the territory already hold, so two copies drift and one is lying. And the one thing the map is for — a glance that says what’s next, what’s blocked, what must not break — drowns under fifty fine-grained issues. You’ve built a second source of truth, at considerable effort, and it’s wrong by Tuesday.
Put everything in palimpsest. Tempting — it’s where the real state already lives. But now there’s no human window: no PM-readable progress, no “what’s blocked,” no durable anchor that survives outside a throwaway git worktree, nowhere to park a decision that’s a human’s to make. The agent is perfectly happy. Everyone else is blind.
The fix isn’t a compromise somewhere in the middle. It’s a clean split by altitude. Coarse, slow, human-facing goes on the map. Fine, fast, agent-facing goes in the territory. The map points down at the territory and keeps its mouth shut about the details.
The one rule
What earns a place on the map.
Which leaves one question: what actually deserves a spot on the map? One rule decides.
One issue = one resumable unit of work OR one standing hazard OR one human decision
That’s the whole anti-sprawl doctrine. Apply it mechanically. On the Virunga port, it shook out to:
- Resumable units — the things each worth about one session: the remaining CRUD, import + saga, stats, the payment consumer, plus the cross-cutting wiring and cutover work.
- Standing hazards — the two landmines we are genuinely afraid of: a faithful legacy bug where an unscoped
deleteManyerases a whole tenant’s telematics history on a double-tapped refresh (yes, faithful — the cutover has to behave identically, bugs and all), and a port deviation where a failed conversion silently deletes the pending record and still returns a 200. These must survive across sessions and never be rediscovered the hard way. - Human decisions — the open judgment calls. Is this consumer actually dead? Drop it, or port it?
Everything that’s done stops being an issue, because there’s nothing left to resume. It just closes, and the progress takes care of itself. The Linear board went from a fantasy fifty to a real fifteen. It’s a work-queue, not a census.
The landing spot
An issue says what, never where-we-are — and the one the amnesiac reads first is worth all the rest combined.
One discipline keeps the whole thing from rotting: an issue body says what, never where-we-are. Paste live progress into it — “80% done, PR’s green, two handlers left” — and you’ve re-created the two-truths problem: the issue is lying by the next session, because the work moved and the paste didn’t. So the body carries only what stays true: the scope, the frozen contracts, the bugs that have to be reproduced. What’s moving — what’s done, what’s next, where the branch stands — lives in palimpsest and Git, and the issue just points at them.
That sounds like a restriction. It’s actually where the leverage hides — because of which issue gets read first. The amnesiac lands somewhere, and that somewhere is a Linear issue. So make it a README, not just a title. One read and a cold agent is oriented; so is a human skimming on their phone. That single description is worth more than every other issue on the board combined, because it is the one thing guaranteed to be read first.
The port’s epic has exactly that kind of description. Here it is two ways — the real one that runs the migration (sensitive parts redacted), and the blank template you can lift for your own work:
Port Virunga (FleetVehicle domain) → the monorepo
Decommission the standalone Virunga service: port its FleetVehicle domain in behind a frozen contract, cut every consumer over, then delete the original.
Resume here
Live state lives in palimpsest, not Linear: orchestration/virunga-port/status.md, newest entry wins. This issue is the map; palimpsest is the territory. Worktree █████████ · branch ███████ · open PR ↗
Method
- Ground → author the record/replay oracle → hand the grind to a cheap, fast model (orchestrated by █████) → adjudicate, fix-with-red → land. The golden master is the acceptance gate.
- Tiers: the cheap model does the grind; a frontier model authors the oracle, adjudicates, and verifies.
Doctrine that must survive
- Bug-for-bug. Every legacy bug is pinned by a replay case; to fix one, flip its pin deliberately — after cutover, never during.
- Frozen contract. ████████████████ stays byte-identical; a downstream service still consumes it.
- Two landmines gate cutover: an unscoped
deleteManythat wipes a tenant's telematics on a double-tapped refresh; a failed convert that deletes the pending record and still returns a 200.
Phase map
M1 cores · M2 surface · M3 wiring · M4 cutover & decommission
# <initiative> — cold-start README (pinned as the Linear epic's description) The one-line goal — what changes, behind what contract, the end state. ## Resume here Live state → palimpsest status.md (newest entry wins). The board is the map. Worktree <path> · branch <branch> · open PR <link>. ## Method ground → write the oracle → hand the grind to a cheap model → adjudicate → land. (Which model tier owns which job.) ## Doctrine that must survive The frozen contracts. The landmines — stated once so they're never rediscovered. ## Phase map The milestone structure. Progress shows as issues close, never typed here.
Every line in that body is still true next week. Notice what’s missing: no percent-done, no current blocker, no changelog. Whether a phase is finished is Linear’s to show, derived from the issues that close. The blow-by-blow lives one link away, in the territory, where it’s allowed to change by the hour.
This is where the model stops being a diagram and becomes something you do with your hands. Because the state lives in the right places, I /clear early and often — the deliberate, head-up version of the compaction that would otherwise sneak up on me. (It’s Claude Code’s command for resetting a session to a blank page; every agent has its equivalent.) Throwing a session away costs nothing, because nothing load-bearing lived there — and keeping one costs plenty: every turn reprocesses the whole swollen context window, so a long session costs more per step and thinks worse as it fills. The next one starts from one line:
ground on <linear_issue_link> and continue
That’s the entire handoff. The fresh session reads the map, follows the pointer into the territory, checks both against the code, and it’s back to where the last one stood — without me burning a few thousand tokens re-narrating a project to a machine that was always going to forget the narration anyway. The amnesia stops being a tax. It becomes the feature: every session starts clean, cheap, and grounded in the one place the truth actually lives. The amnesia I choose beats the amnesia that gets inflicted.
It scales down
It works on ordinary issues too.
None of this requires a giant port. The same three speeds run a perfectly ordinary issue.
A recent one: a force-refresh gate for BOS — our Booster Operating System, the control plane every truck, route, shift, and gallon runs through. It keeps supervisors mid-shift from getting stranded on a stale cached bundle every time we ship. Not an epic. One feature. But it had been parked for a month: the original PR closed, the branch cold, the context evaporated. The old me would have spent an afternoon reconstructing it from my own memory and gotten half of it wrong. Instead, before writing a line, I gave it the same setup as the port, scaled down: a spec in palimpsest as the recovery anchor — admin-set minimum version → a header → the BOS interceptor → a routine staleness poll — and the Linear issue as the same cold-start README, pointing at it.
Now ground on <linear_issue_link> and continue works for a one-feature issue exactly the way it works for an eighty-three-handler port. The spec is the territory; the issue is the map; the branch is the behavior. Same model, smaller everything. This is the part that should make it interesting to you, whatever you’re building: you don’t have to be doing a giant migration to get the payoff. You just have to be willing to forget things on purpose.
“Why isn’t the spec just a PR we comment on and merge once it’s approved?”
Because a spec isn’t a decision — it’s a recovery anchor, and it moves. A PR wants to be opened, approved, and frozen; the spec wants to be grabbed, trusted, and rewritten by tomorrow’s amnesiac. The thing that should go through review — the durable, this-is-now-true decision — is the ADR or the code itself. Comment on the spec all you like; just don’t make a moving target wait for a merge.
Derive, don’t recall
The day it caught a lie.
Here’s the moment it stopped being a theory.
The first-pass Linear board for the port had five issues marked Todo that were, in fact, Done — ported, oracle-locked, sitting green on the branch. Why? Because that board had been authored from memory. Someone — me — drew the map by recalling the territory instead of looking at it. The restructure only worked the second time because it was derived: read palimpsest, read the branch (CI green means the oracles pass), and only then set the states.
This matters more for an amnesiac than for a human, so let me say it flat out: a map drawn from memory instead of from the territory is a rumor — the most dangerous kind, because it looks exactly like a plan. A human who trusts a wrong board loses an afternoon and grumbles. The next cold agent who trusts a wrong board redoes finished work — or, worse, strolls straight onto a landmine you had carefully written down and then quietly overwrote with a guess. Derive the map from the code and the territory, or don’t draw it.
Form follows function
The filing cabinet should match the engineering.
By now the bookkeeping has a familiar shape, and it’s no accident: it’s the exact shape of the engineering it tracks. Both come down to the same two parts — a contract that can’t lie, and the disposable work it governs:
The contract
what must be true, what must not break
engineering a record/replay oracle, in Git
bookkeeping Linear — the map
The disposable work
fast, rewritten, thrown away
engineering a cheap model doing the grind
bookkeeping palimpsest — the territory
Three surfaces, but only two kinds of thing: the contract you freeze and the work you throw away. (Git quietly plays both — the running code changes every commit; the oracle frozen beside it is the contract that code gets judged against.) The slow-moving ADR is just the contract’s permanent record.
How we build those oracles is a later post. When the filing cabinet ends up with the same architecture as the engineering, both get easier to hold in one head — including the head that resets every session.
When not to do this
The method has a bill, and a blast radius.
I’ve made this sound free. It isn’t. Before you spin up a journal repo and a cold-start README for your next two-hour bug-fix: don’t. The setup is real work — authoring the oracle, writing the spec, pinning the landmines — and it only pays back when the job is big enough, or long-lived enough, to outlast a single session. For a quick fix, the fastest path is still to just fix it.
A few more honest edges:
- The territory rots if you don’t garden it. A palimpsest nobody prunes becomes the exact thing it was built to kill: a stale doc dressed as current. The discipline isn’t the writing — it’s the dating, superseding, and deleting.
- A derived map is only as honest as your gates. “CI green means the oracles pass” is the load-bearing assumption under all of it. If the oracle is thin, a green board is just a rumor with better production values.
- It assumes the work decomposes into resumable units. Some problems are genuinely irreducible — you have to hold the whole thing in one head at once, and those don’t survive a
/clear. (Fewer than you’d think. But not zero, and pretending otherwise just means re-deriving the hard part every session.)
None of these is a reason not to do it. They’re the difference between a system that holds and a cargo cult that performs the rituals and rots anyway.
The world you hand them
The constraint was never the model.
So that’s the model. You thought the job was project management. It was never that — you’re building a prosthetic memory for a brilliant colleague with a perfect five-minute attention span and no yesterday, and the strange dividend is that the thing that orients a cold machine (“what’s next, what’s blocked, what must not break”) is precisely the thing a PM has always wished they had. You don’t need two boards, one for the robots and one for the people. You need one, at the right altitude.
If you want to try it on your own work, the minimum viable version is three things:
- An engineering-journal repo — a separate repo, not a folder in the code tree — with live state in a dated, newest-first
status.md, and one resumable-unit doc per open piece of work. - A Linear epic whose description is a cold-start README (the template above): the one-line goal, a Resume here pointer into
status.md, the frozen contracts and the landmines, and a phase map — scope, never status. - The discipline to
/clearearly and resume with one line —ground on <issue_link> and continue— and to set the board’s state from the code and the territory, never from memory.
Here’s the README we keep at the journal’s root — copy it and start your own:
# <org> engineering journal — "palimpsest"
> A palimpsest: a manuscript scraped and rewritten, earlier drafts still legible
> beneath the latest — an iterative design, layers of thinking overwritten as it evolves.
## What lives here
Temporal docs: in-progress designs, investigations, WIP plans — and the live state of
long-running work, in a dated, newest-first `status.md` per initiative.
## What does NOT live here
- Decisions → a dated ADR in the code repo (immutable).
- Runnable guides → a script or skill in the repo it serves.
- Current state of the system → the code itself.
## Why a separate repo
Temporal docs in a code repo rot the instant the code moves. Worse for an AI agent: a
design next to the code reads as authoritative and current, so it gets hallucinated from.
Keep mutable thinking out of the code tree. Immutable → git (ADRs); temporal → here.
## For agents (and humans skimming)
Everything here is a draft or a point-in-time note — NOT ground truth. Read the date;
verify against the ADRs and the code before acting — derive state, don't recall it.
## Conventions
- Date every entry; check the date before you trust it.
- Logs append, documents reconcile: grow `status.md` newest-first; redraw the
spec in place. A superseded layer stays as history — never deleted, never
"updated to current."
- One fact, one home: live state lives in exactly one place — `status.md`.
The board points at it; it never copies it.
Everything else is detail — except the objection you’ve been holding since the top:
“Won’t this whole apparatus be obsolete in a year? The context windows keep growing; soon the models will just remember.”
Some of it, sure — the edge moves out. But a bigger window is a bigger cliff, not the absence of one: fill it and you’re back to compaction and rumor, just later and at greater expense. The deeper bet doesn’t move at all. The amnesiac didn’t create this problem — it exposed it. Every team already runs on memory it only pretends to have: in three people’s heads, in a wiki nobody trusts, on a board that’s wrong by Tuesday. A colleague who forgets everything between sessions is just the first one honest enough to make you fix it — and the fix doesn’t evaporate when someone quits or a quarter turns. You write the project down so a machine can survive forgetting it, and find you’ve made it survivable for everyone.
That’s the part worth keeping. The agents will keep getting better, and the day their raw ability stops being the constraint is already in sight. What’s left is the world you hand them — how legibly the state is written down, how fast you can drop a cold mind into a hard problem and have it land oriented in five minutes. That isn’t a prompting trick. It’s systems design, and it’s what we’re building Booster’s engineering around, one real migration at a time.
So forget on purpose. Write each thing down once, in the place that moves at its speed; point the map at the territory and never let it copy; then hand the amnesiac a single line — and get out of its way.