When an agent hits its context limit, the built-in fix is a summary, and a summary keeps the conclusions while dropping the decisions, paths, and dead ends behind them. session-continuity is a specified checkpoint file, hooks that catch the compaction you did not see coming, and a linter that checks the file. Optional hooks wire it into Claude Code.
The format and protocols work on any harness that reads files.
Install the linter as a command (not on PyPI; this installs from GitHub):
pipx install git+https://github.com/eliferres/session-continuity
checkpoint-lint CHECKPOINT.mdThe template, docs and hooks live in the repository, so clone it too:
git clone https://github.com/eliferres/session-continuity.git
cd session-continuity
python3 tools/checkpoint_lint.py examples/*.md # zero dependencies, Python 3.9+Copy CHECKPOINT-TEMPLATE.md into your project as CHECKPOINT.md, paste
"The protocols, in one paragraph each" below into CLAUDE.md or your
system prompt, and run the linter before you trust a checkpoint. Hooks
are optional; see docs/hooks.md. To run several
sessions in one project, start each with its own name,
SESSION_CHECKPOINT_NAME=billing claude, and it checkpoints to its own
CHECKPOINT-billing.md.
Depth beats summary. A summary answers "what happened". A resume needs "what is true, what was decided and why, and what not to try again". The worked example is the argument: one paragraph in it records a connection-pool trap that cost two hours, and the next session skips those two hours entirely.
Rewrite in full, never append. An appended checkpoint accumulates contradictions and the reader cannot tell which line is current. Rewriting forces a pass over the whole state, which is where you notice that the thing you called done is actually blocked.
Read it all, then verify, then continue. A partial read reproduces the thin-summary failure the checkpoint exists to prevent. And a checkpoint is a claim, not a fact: anything you are about to act on gets checked against the live source first, because the world moved while you were gone.
Absolute everything. Absolute dates, verbatim paths, real commands, observed output. Every paraphrase is a small compaction, and compaction is the thing that broke.
Compaction optimizes for fitting, and what fits is conclusions. The expensive parts of a session are the parts with no artifact: the alternative you rejected and why, the hour lost to a trap, the number you checked and found wrong. None of it survives a summary, all of it is cheap to write down, and writing it down is what turns a long project into one continuous session rather than a series of confident restarts.
The companion repo agent-memory-vault covers the other half (durable cross-project memory) and ships a minimal checkpoint file as one note in its vault; this repo is the deep version of that one file.
This is the wire format, copied from docs/anatomy.md (that file is the source of truth):
---
type: session-checkpoint
updated: YYYY-MM-DD # absolute, always; the linter rejects anything else
---
# Checkpoint — <one-line arc name>
<Two or three lines telling the reader to read the whole file before
acting, and that everything below is exact rather than remembered.>
## Objective
The outcome the work serves, in one or two lines. Not the current task —
the reason the task is worth doing.
## State
Per workstream: done and verified / in flight / blocked. Exact files,
commands, and observed output. A workstream with no evidence behind it is
"in flight", never "done".
## Decisions and why
Every ruling made, each with the reasoning that produced it, including the
alternatives rejected. The conclusion alone invites relitigation; the
argument is what closes the question.
## Open threads
Next actions in priority order, each concrete enough to act on cold.
Blocked items name the blocker and what clears it.
## Gotchas and dead ends
Approaches tried and rejected with a one-line why each, traps hit and
their fix, and anything that looks wrong but is correct.Five rules make it work:
- Absolute dates, never relative ones. "Fixed yesterday" is
unreadable a week later.
2026-03-11is readable forever. - Verbatim specifics. Paths, commands, identifiers, numbers, and error strings are copied, not paraphrased. Paraphrase is the exact thing compaction already does, and it is what loses the state.
- Written for zero context. Assume the reader has never seen the project. If a sentence only makes sense to someone who was there, it does not belong in a checkpoint.
- Every section survives, even when empty-ish. A missing section reads as forgotten; a section saying "none" reads as answered.
- Depth, not bulk. Write what a fresh session cannot re-derive from the repository and its history. Never paste transcripts.
Required sections: Objective, State, Decisions, Open threads,
Gotchas. The linter matches on prefix, so ## Decisions and why and
## Gotchas and dead ends satisfy the requirement while reading like
prose.
Write at session end, when the context ceiling is close, before any
deliberate compaction, and after each milestone: a checkpoint several
ships behind is worse than none, because it is confidently wrong. Rewrite
the whole file, drop a dated copy in .checkpoints/, and read the file
back rather than trusting the write. End the reply with a fenced pickup
prompt for a fresh session: continue from CHECKPOINT.md, then the
objective's first line and the next open thread, verbatim.
Read the checkpoint in full first, in one read of a known path. Follow its references on demand, verify what you are about to act on, restate a short recap so a human can catch a wrong inheritance early, then continue using the real specifics. Missing or stale checkpoint: say so and fall back to the dated copies, never guess.
Both are spelled out in docs/protocol.md.
Four checks, each guarding a way a checkpoint actually fails. The first three reject the file; the fourth only warns:
- Every required section is present. A missing section is a category of state nobody wrote down.
- No required section is empty. Empty headings are the most common way a checkpoint looks complete and restores nothing.
updated:is an absoluteYYYY-MM-DDdate, and no relative time word ("yesterday", "last week") appears in the prose. Code fences and inline code spans are exempt:git log --since=yesterdayis a command, not a claim.- Length sanity, advisory only: a three-line checkpoint of a long session is a summary wearing a checkpoint's headings.
Exit codes: 0 clean, 1 lint failures, 2 usage or input error (no files given, or a path that is not a file).
CI runs the tests on three Python versions and then lints the shipped example and template, so it can never ship a file its own linter rejects.
- A checkpoint is only as good as the discipline of the agent writing it. Nothing here can make a lazy checkpoint honest, and a confident wrong checkpoint is worse than none.
- The linter checks shape, not substance. "Decisions" full of decisions without their reasoning passes cleanly.
- The hooks are Claude Code specific. Other harnesses need the protocol in the system prompt and a manual checkpoint step.
- The PreCompact hook cannot write the checkpoint, only preserve and stamp what already exists. The judgment is the product, and it comes from the agent.
- Parallel sessions stay apart only when each is started with its own
SESSION_CHECKPOINT_NAME. Two sessions given the same name, or none, still write one shared file.
CHECKPOINT-TEMPLATE.md: the blank, with per-section hints. Copy it into your project.docs/anatomy.md: the file format specification, source of truth for the block above.docs/protocol.md: when and how to write a checkpoint, and how to rehydrate from one.docs/hooks.md: wiring the three optional hooks into Claude Code settings.examples/: one realistic filled checkpoint, mid-migration, that passes the linter.hooks/:precompact-checkpoint.sharchives state and stamps the compaction;sessionstart-resume.shannouncesRESUME AVAILABLEand warns when the checkpoint is behind;context-watch.pyreads the real context size and warns once at a heads-up and once at a wind-down.tools/checkpoint_lint.py: the shape linter, stdlib only.tests/: real fixture files on disk, no mocks.
MIT. See LICENSE.