Night two of this arc was cheap because of a document we wrote in the last ten minutes of night one. The arc spanned two evenings. The first night we shipped one pipeline phase and the second night we shipped the next. That document was the deliverable of the first session, on purpose.
We treat the end-of-session handoff the way we treat the code: as something we owe. If we skip it, we pay to rebuild state every time we sit back down, and that bill compounds.
What the model does not remember
When we pick up a project the next evening, we open a fresh session. The model has no idea what happened last night. The chat that did the work is either gone or buried. Even if we have it, re-reading a 200-prompt transcript to answer “where were we” is the most expensive way to get that answer. The transcript is raw material, and reading it back means re-deriving every decision we already made, including the ones we made and then reversed.
So the next session starts by reconstructing state from whatever is lying around: git log, half-remembered trade-offs, a TODO comment that no longer makes sense out of context. None of that ships anything. If we get it slightly wrong, we relitigate a decision that was already settled, change something that was deliberate, and burn an hour discovering why we did it that way.
The fix is to stop making the next session derive state and hand it state instead.
Six sections, and one of them carries the rest
The handoff doc had six sections:
- What got built. The phases that shipped, in one line each.
- Decisions baked in (don’t relitigate). The settled trade-offs, stated as settled.
- Exact repo state. Each repo, its HEAD SHA, what’s in it, and whether it’s pushed and clean.
- Ready to pick up. The next step, written as something you can actually run.
- Memory updates this session. New rules we learned, named.
- What’s NOT load-bearing yet. The things that look done but aren’t wired in.
Sections 1, 3, 4, 5 and 6 are bookkeeping, useful but mechanical. Section 2 changes the economics.
Decisions baked in
After a long session of making calls, you end up with a stack of trade-offs that felt hard in the moment and are settled by the end. Where the data lives. Why this format and not that one. Why the final synthesis stage gets less tool access than the upstream stages feeding it, because the blast radius of a hijacked tool call is highest closest to where output goes public.
If the next session can’t see that those were decided, it re-decides them. A fresh model will happily re-derive a “better” answer to a question we already closed, and now we’re defending a choice instead of building on it.
So we write them down as closed. The entry reads: “Raw data is cold storage on the box, gitignored; the index is the hot path; they don’t live together. Decided. Move on.” The next session treats that as a foundation. This section is the difference between resuming work and reopening a debate.
It also does something for us specifically. Given an opening, we will redesign the thing we shipped last night. Writing the decision down as baked-in pre-commits our earlier judgment, so we don’t spend a session improving something that was fine.
Exact SHAs turn an investigation into a lookup
The repo-state section is short and boring and saves the most clock time. For each repo: name, HEAD SHA, contents, pushed-and-clean status.
repo-A commit-4600 phase (a)+(b) shipped, pushed, cleanrepo-B commit-27C8 raw + manifest, pushed, cleanWith the SHA written down, we check out exactly the tree the handoff describes and we’re standing where we stood when we wrote it. No git archaeology, no “wait, did we push that branch,” no discovering mid-session that the clone we’re in is two commits behind the one we actually worked in. The SHA is the coordinate.
It matters more the more parallel work we run. On a busy day the same product is checked out in several clones at once, each on a different branch. “Which tree had the work” is a real question, and a SHA answers it with zero ambiguity.
”Ready to pick up” has to run cold
The next-step section fails if it says “continue the pipeline.” That’s a heading. It earns its place only if the next session can execute it with no context.
So the entry for the next phase read like a runbook. Generate the export from Settings. The ZIP arrives by email. The download URL expires in 24 hours, a real gotcha that would have cost the next session an hour if it hadn’t been flagged. Reuse the same paired-output shape from the phase that already shipped. The idempotency key is the conversation id. Output goes to a specific directory. Those are the next session’s first three steps, pre-written, including the trap.
The test: could a different person, or a fresh model with no context, run it without asking a question? If not, it’s a heading wearing a runbook’s clothes.
What’s not load-bearing yet
The last section is the inverse of the decisions section. It catches the things that look finished and aren’t.
The example that earned its spot: the privacy scrubber was wired into one pipeline stage, it worked, and the output was clean. But the wiring is not automatic. Every new stage has to wire the scrubber in explicitly, or it silently ships unredacted data. Had the handoff said “scrubber: done,” the next session would have built the next stage on a false floor and leaked. So the guardrail is a note saying the scrubber works here, is not automatic for other stages, and must be wired per stage.
That note stops “we shipped X” from being read as “X is true everywhere.” A thing demonstrated once is not yet a thing that bears load.
The same move as the shared knowledge store
When we run AI on several fronts at once, every agent has partial context and we spend the day restating ourselves. The fix there was a shared knowledge store: a single place for durable operational state that the agents read instead of asking. That solved context loss across machines and agents.
The handoff doc solves the same problem across time. The next session is functionally a different machine with no shared memory, and the handoff is the entry it reads on startup so it doesn’t have to ask an earlier session anything. One is memory across space and the other is memory across time, and both turn an expensive re-derivation into a cheap lookup.
That is why the handoff is mandatory for us. Once AI makes everything else fast, re-establishing state from scratch every session is the dominant cost. Any state we don’t hand off, we end up paying to rebuild the next evening.
Check whether every session in your AI-assisted work ends with a written handoff covering settled decisions, exact repo state, a runnable next step, and what looks done but isn’t wired in. Without one, the next session pays to rebuild that state and may reopen decisions that were already closed.
Related
- Bootstrapping a New Agent Station, and Giving It a Phone: the station-level state that the handoff doc needs to capture when work spans agents
- When Working Notes Become Operational Infrastructure: how session notes compound into durable infrastructure over time
- My AI agent’s memory was per-folder, so my four clones never learned from each other: the failure mode that a proper handoff doc prevents, state that doesn’t cross context boundaries
- Writing an AI_CONTEXT.md So Your Assistant Stops Rediscovering Your Codebase: the persistent context file that complements the per-session handoff
- When a Manual Workflow Hurts in Seven Small Ways, the Seven Ways Are Your Spec: encoding session-close friction into automation, the next step after the handoff becomes routine