Switching AI Agents Without Starting Over
A note the last session leaves in your repo, so the next one — any vendor — knows where the work stood
We build Origin, an MIT-licensed CLI that runs alongside AI coding agents and records each session into the repository itself. This is how one part of it works.
The note the last session left
AI coding agents — Claude Code, Cursor, Codex and the rest — work in sessions. You open one, you work, you close it, and everything it understood about the task is gone. The next session starts blank. If you switch to a different agent it starts blanker still, because none of them can read each other’s history.
Here is the exception. This was sitting in an agent’s context window one morning, before anyone typed anything:
Previous session context (claude-code, 18h ago): Summary: Diagnosis is solid. It's not Origin's code — it's CPU starvation from the host. Last prompt: "Origin is slow again, debug what's the issue" Changes: +6774 -308 lines
Nobody pasted that in. Nobody asked for it. The session that produced it had ended eighteen hours earlier and wrote it to a file on the way out. When the next session started, that file was read and rendered into its prompt before the first instruction arrived.
So the agent opened already knowing where things stood — which branch, which files were unfinished, what the last instruction had actually been. That is the entire feature. The rest of this article is about why the block is that short.
What it is like without one
You spent Friday afternoon on something nasty. Three files half-rewritten, a branch you named in a hurry, a fix that worked but needed one more case handled. You closed the laptop.
Monday you open your agent and type “ok let’s finish this.”
It has no idea what “this” is. So the first ten minutes go to reconstruction: which branch, which files are dirty, what the goal was as opposed to the last thing you typed, what you already tried and rejected. You are briefing a new hire who was in the room on Friday and remembers none of it.
Then make it worse in the way that is now normal — on Monday you open a different agent. Friday was Claude Code; today you want Cursor, or Codex, or whatever shipped a better model last week. Each keeps its history in its own directory in its own format, and none of them read each other’s. There is no shared storage even in principle.
This is not an edge case. People pick an agent per task, not per project, and the switching cost is paid in re-explanation every single time.
Seeing it
The note lives at .git/origin-handoff.json. You can read exactly what is stored and exactly what the next agent will be given:
$ origin handoff show
Cross-Agent Handoff Context
Agent: claude-code Model: claude-opus-5 Session: 7f3776c8 Ended: 18h ago Branch: fix/prompt-capture-window
Last prompt: "the turn count is still wrong on merge commits"
Files in progress (3): packages/cli/src/git-capture.ts packages/cli/src/session-state.ts packages/cli/src/commands/hooks.ts
Changes: +212 -47 lines
Open TODOs: - handle the squash-merge case in the same pass
Context that will be injected into next agent session: ────────────────────────────────────────────────── ... ──────────────────────────────────────────────────
origin handoff clear throws it away if you would rather start clean.
What gets carried
Every field earns its place by answering a question you would otherwise have to answer yourself:
Field Saves you from branch “which branch were we on?” filesChanged “what’s half-done right now?” lastPrompt “what were you actually trying to do?” openTodos remembering the thing you said three sessions ago agentSlug, model not knowing whether to trust the previous session’s approach Two properties matter more than the schema.
It is written at the end of every turn, not at session end — so an agent that crashes, is killed, or is closed without ceremony still leaves a current note behind.
And agentSlug is written by one agent and read by another. That is what makes it cross-vendor: a Cursor session’s note is read by a Claude Code session, and says plainly that it came from Cursor.
The hard part is what it refuses to carry
This is where a feature like this is won or lost. Each rule below exists to prevent a specific bad experience, and each costs the feature something on purpose.
Not the transcript. There is a permanent temptation to make the note bigger — the whole conversation, every file read, all the reasoning. Every version of that makes it worse. The value is that the next agent reads it completely before starting work. A 40,000-token history does not get read, it gets skimmed, and skimmed context is how an agent confidently resumes the wrong task.
Not a session where you only talked. Ask your agent a question — “what’s in this repo’s history?” — and it answers. No files changed, nothing written. If that session overwrote the note, Friday’s real work-in-progress would be replaced by Monday’s idle question, and the next agent would open oriented around nothing. So a session that touched no files and changed no lines never replaces one that did.
Not its own output, fed back. Origin already injects context at session start. Ask an agent about that context and its answer is a recap of the injection. Store the recap as the session summary and the next session injects it, the agent after that recaps the recap, and within days the note is a description of a description of something that was once actual work. So the feature recognises text that is its own prior output and refuses it — on read as well as on write, which means a repo that already picked one up heals itself the next time it is read.
Not everything you say, as a commitment. Open TODOs are the highest-leverage field and the most dangerous, because a TODO is injected into every future session until it is resolved.
“We should refactor the retry logic” is a commitment. “We need to switch the gh user, but switch it back after” is an instruction for right now. If the extractor cannot tell those apart, you get an agent that keeps trying to switch your GitHub user next week, for reasons nobody remembers. So extraction is anchored to actual development verbs (fix, add, refactor, migrate, handle…) and rejects hedged phrasing (I think, maybe, for now, never mind). Both rules deliberately match less.
That inversion is the most transferable idea here. In an ordinary data pipeline you tune an extractor toward recall, because a false positive is just a bad row somebody filters later. When the consumer is a language model, a false positive is an instruction that a capable system will act on, repeatedly, until a human notices. The cost is unbounded and nearly undetectable, because a plausible-looking TODO is indistinguishable from a real one.
Not stale state. A note older than 24 hours is not injected at all. In-progress state decays fast: a day-old list of “files in flight” probably describes files since committed, reverted, or rewritten by someone else. Confidently wrong context is worse than none, because the agent has no way to know it should distrust what it was handed.
It lives in .git, and that is a decision about you
.git/origin-handoff.json is not a committed file. It never appears in a diff, never shows up in a pull request, never lands in a teammate’s clone. It is scoped to your checkout, the way .git/HEAD is. Three consequences worth knowing before turning it on:
Nothing leaks into review. Your last prompt — however you phrased it at 7pm on a Friday — is not going in front of your team. It does not sync. A colleague pulling your branch gets your code, not your note. Origin has a separate mechanism for metadata meant to travel between machines; this deliberately is not it. You can inspect and delete it with ordinary tools. It is JSON on disk. cat it, rm it, or use origin handoff show and origin handoff clear. 7. What it cannot do
It cannot arbitrate between simultaneous sessions. It records the last one to finish, so in a checkout where three agents run at once the note reflects whichever stopped most recently. The honest fix there is a worktree per session, not a smarter merge.
It cannot reconstruct reasoning it was never given. If a session’s approach lived entirely in the model’s head and never touched a file, a note about files will not recover it.
And it is only as good as the last session’s summary. It is a bookmark, not a substitute for writing things down.
Why it belongs next to the code
Agents are becoming interchangeable faster than anyone expected. Which one is best for a given task changes month to month, and people switch accordingly, often mid-task.
The thing that should not be interchangeable is your place in the work. That state does not belong in a vendor’s session store, because you will not be in that vendor’s session tomorrow. It belongs next to the code — in a format anything can read, small enough that the next agent, whatever it turns out to be, can absorb it in one pass before touching anything.
The whole feature is a JSON file in .git. Most of the engineering went into deciding what to leave out of it.
Implemented in the Origin CLI (MIT, getorigin.io): handoff.ts holds the payload, the carry-forward rules and TODO extraction; context-injection.ts assembles and deduplicates the blocks injected at session start. origin handoff show prints the current note and exactly what the next agent will receive.

