Keep a durable work-in-progress checkpoint live in your project so any session can be paused and resumed cold without losing detail. Runs in two modes. Ambient (default): the moment a session crosses the significance line (a decision is made, a file is created or substantially edited, a multi-step task is underway, or analysis has accumulated that isn't yet saved), initialize a checkpoint and refresh it each round the resumable state changes, without being asked. Explicit: also fire on "check...
Scanned 7/1/2026
Install via CLI
openskills install jasonfrasca/claude-checkpoint-skill---
name: checkpoint
description: >
Keep a durable work-in-progress checkpoint live in your project so any session can be paused and resumed
cold without losing detail. Runs in two modes. Ambient (default): the moment a session crosses the
significance line (a decision is made, a file is created or substantially edited, a multi-step task is
underway, or analysis has accumulated that isn't yet saved), initialize a checkpoint and refresh it each
round the resumable state changes, without being asked. Explicit: also fire on "checkpoint this", "pause
here", "I need to stop", "save where we are", "I'm rebooting", and on reset signals ("reset this chat",
"compress the context", "clear the mud") which refresh the file and then emit a paste-back block that
clears a bloated live session. Writes one file per workstream at .checkpoints/<topic>-checkpoint.md
holding the full in-progress state, not a summary. This is the repo-backed lifeline; claude --resume is
only a convenience on top of it.
---
# Checkpoint Skill
## What this skill does
Keeps a complete work-in-progress checkpoint live in your project so the current task survives a pause, a
reboot, a new machine, or a cancelled `claude --resume`. The checkpoint is a file in your project's
version-controlled or synced directory, never in `~/.claude/` (local, unsynced, prunes after 30 days) and
never in a scratch or download folder.
A checkpoint is not a summary of what happened. It is everything the next session needs to continue the
work cold.
The checkpoint runs on its own. It does not wait for you to ask. Once a session is significant, the
checkpoint initializes and then stays current round over round, so at any moment the project holds enough to
resume from a dead stop.
**Why a standing instruction and not a hook.** Claude Code has no hook that writes a *contextual*
checkpoint on a timer. Hooks run shell commands, not reasoning, so a hook can name the file but can't fill
it with the session's actual state. Ambient mode is therefore a standing instruction Claude follows,
loaded every session via this skill's description. This is deliberate; don't "upgrade" it to a hook
expecting the same output. A `Stop`-hook reminder ("did you refresh the checkpoint?") is a valid
reinforcement if reliability ever proves weak, but it supplements the instruction, it doesn't replace it.
## Where the checkpoint lives
Default path: `.checkpoints/<topic>-checkpoint.md` at the project root.
The only hard requirement is that the location is **durable**: a directory that is version-controlled
(committed to git) or synced (Dropbox, iCloud, OneDrive, a network share). That is what makes the
checkpoint survive a dead session, a power loss, or a new machine. Pick whatever fits your project:
`.checkpoints/`, `docs/checkpoints/`, or any folder you already back up. Avoid `~/.claude/` and avoid
scratch folders. Set your preferred location once and use it consistently.
## Two modes
**Ambient (default).** Claude maintains the checkpoint proactively across the whole session. No prompt
needed. This is the normal state for any session doing real work. It announces once on init (see Noise
control); that announcement is a feature, so you should know the lifeline kicked in.
**Explicit.** You name a pause: "checkpoint this", "pause here", "I need to stop", "I'm rebooting", "save
where we are". Force an immediate full refresh on the spot, even if the round didn't change much.
Both modes write the same file in the same shape. Ambient mode is the same act, done continuously instead
of on command.
## Ambient mode: the trigger and the cadence
**The significance line (when to initialize).** Run this test silently: *if the session ended right now
and all I had was the saved files, would I lose anything worth keeping?* The first time the answer is yes,
create the checkpoint. That moment is any of:
- A decision gets made that later work rests on.
- A file is created, or substantially edited.
- A multi-step task is underway and more than the first step is done.
- Research, analysis, or source material has accumulated in the session that isn't saved yet.
What does **not** cross the line: a single quick question, a one-line lookup, a trivial one-off edit, or a
clarifying back-and-forth that hasn't produced anything yet. Don't checkpoint noise.
**The refresh cadence (when to update).** After each round of work, run a second silent test: *has the
resumable state changed since the last write?* New decision, new or edited artifact, a step completed, or a
new open item or blocker. If any moved, refresh before yielding the turn. If the round was pure discussion
that changed no state, skip the write. The checkpoint tracks state, not chatter.
**Incremental, not a rewrite.** On refresh, touch only the sections that changed. Don't regenerate the
whole file every round. The Status and Next action lines change most; Mission and settled Decisions change
rarely.
**Noise control and the refresh marker.** Announce the checkpoint once, when it first initializes, and give
the path so you know it exists. After that, every round the checkpoint file is actually written, surface a
single compact marker so you can see the lifeline fired without asking for it. Fold the marker into the
reply Claude is already giving that turn; it is part of normal output, not a separate message:
`checkpoint ✅`
Marker rules:
- **Format.** One line, written as inline code so the terminal renders it with color contrast, on its own
line. In a session juggling more than one workstream, name the file: `checkpoint ✅ <topic>`.
- **Never an extra step.** The marker rides on a reply already being sent. It is never its own message,
never a separate tool round-trip, never a prose "checkpoint updated" report. The compact token is the
whole signal.
- **Only on a real write.** It appears only on rounds the file was actually refreshed. A pure-discussion
round that changed no state writes nothing and shows no marker. If a round wrote the file but no prose is
sent, the marker rides the next reply.
- **It replaces silent refresh, not the init announcement.** Mention the checkpoint in full only if asked,
if a blocker is newly surfaced, or at session close.
## Status-line backstop (optional, model-proof)
The inline marker is model-driven, so a missed turn could read as a false "nothing saved." A status line
closes that gap, and it is scoped to the session asking, not to the newest file on disk. Every checkpoint
file carries its owning session's id as its first line, `<!-- ckpt-session: <id> -->`, stamped on each
write. The status line reads the current render's `session_id` (the harness passes it on stdin), finds the
newest checkpoint stamped with that id, and renders `✓ ckpt <topic> <YYYYMMDD-HH:MM:SS>` (the file's
modified time), green when one exists, dim `• no checkpoint` when none.
This is why a fresh or `/clear`-ed session shows nothing instead of a stale checkpoint from another
session: `/clear` rotates the `session_id`, so the new id matches no file until this session writes one.
`claude --resume` and `/compact` preserve the id, so a resumed workstream keeps showing. Parallel sessions
each show only their own.
This package ships three scripts for it: `statusline.sh` (reads `session_id`, matches stamped checkpoints,
prints the timestamp); `session-id.sh` (a `SessionStart` hook that injects this session's id into context
so the stamp can be written, since the model has no other way to learn its own id); and `checkpoint-stamp.sh` (a
`PostToolUse` hook that writes the stamp onto line 1 after every checkpoint write, so stamping doesn't
depend on the model remembering). The README shows how to wire all three. A status-line or hook config
change loads on the next Claude Code start. The inline marker is the in-flow signal; the status line is the
always-on backstop.
## Stamping the session id
If you wired up the optional status line, the `checkpoint-stamp.sh` `PostToolUse` hook handles this for
you. After every Write/Edit to a checkpoint file, line 1 becomes `<!-- ckpt-session: <session_id> -->` for
the acting session, replacing a stale stamp or prepending a missing one. You don't write the stamp yourself
and you don't read the file back to check it; the hook runs after your write regardless.
The convention it enforces, for reference: the file's **first line** is exactly
`<!-- ckpt-session: <session_id> -->`, the heading follows on the next line, and any prior `ckpt-session`
line is overwritten so the stamp names whoever last worked the file. If you didn't install the hook but
still want the status line, you can write the stamp yourself (take `<session_id>` from the `SessionStart`
hook's injected line); leaving stamping to the model is unreliable, which is exactly why the hook exists.
With no stamp at all, the status line honestly shows `• no checkpoint`.
## Checkpoint contents
One file per workstream at `.checkpoints/<topic>-checkpoint.md`, where `<topic>` is a short kebab-case name
(e.g. `auth-refactor`, `data-migration`). If a session spans more than one workstream, keep one file each
and refresh whichever is active. If the file already exists, refresh in place; never spawn a duplicate.
Pull inputs into the project: if the work depends on a file dropped outside the project, read it once and
copy it (or its extracted text) in, so the checkpoint is self-contained.
Sections:
- **Mission.** What this workstream is trying to produce, in one short paragraph.
- **Decisions made so far.** The settled choices the work rests on. Convert relative dates to absolute.
- **Live artifacts and paths.** Every file produced or in flight, with exact paths.
- **Status.** What is done, what is open, what is blocked and on what.
- **Open items.** Anything needing a decision or input before the work can finish.
- **Next action.** The precise next step to take on resume, specific enough to execute without rereading the chat.
## How to resume
Launch Claude from the project directory, then say "resume `<topic>`" or "read the `<topic>` checkpoint and
pick up." Claude opens `.checkpoints/<topic>-checkpoint.md` and continues from the Next action line. This
does not require `claude --resume` to work, because the checkpoint is a file, not a chat.
A fresh chat picking up the work is the same act: point it at the checkpoint file. There is no separate
briefing document to write. The full-state checkpoint is the briefing. A compressed summary is exactly what
fails, dropping the one detail the resume needed.
## Reset mode (explicit)
A reset clears a live session that has grown long, muddy, or expensive, without starting a new chat. It is
a use of the same checkpoint state, not a separate system: the durable file is the single source of truth,
and the paste-back block below is a compressed render of it, never a parallel store.
**Triggers.** "reset this chat", "compress the context", "clear the mud", "reset and continue." Distinct
from "checkpoint this" (refresh the file, keep working) and "I'm rebooting" (refresh the file, resume
later). Propose a reset unprompted when the signs are clear: outputs getting noisier or more hedged,
earlier constraints slipping, settled facts being re-explained, or the thread re-litigating a locked
decision.
**Action.** Two steps, in order:
1. Refresh the durable checkpoint at `.checkpoints/<topic>-checkpoint.md` to full current state, exactly as
a normal refresh. Nothing about the ambient or explicit behavior above changes.
2. Emit a compressed paste-back block, rendered from that checkpoint. You paste it as your next message to
replace the accumulated history; treat it as ground truth from that point and continue from the Next
action with no re-summarizing.
**The paste-back block.** Render it from the checkpoint, under ~400 words, every line load-bearing:
- **Checkpoint path.** The exact path to the durable file (`.checkpoints/<topic>-checkpoint.md`). This line
is mandatory. It is the completeness guarantee: anything the block compresses out is still in the file,
one read away. The block is the fast path; the file is the complete record.
- **Mission.** One to three sentences, the current goal.
- **State.** `✓ done` / `→ in progress` / `✗ open`, surgical, no narration.
- **Locked decisions.** Settled choices the reset must honor, one line each.
- **Active thread.** The specific angle being worked in the last few exchanges.
- **Constraints active this session.** Rules established here that a cleared context would otherwise lose.
- **Next action.** The exact first move to make after the reset.
Compression test on every line: if removing it changes nothing the work does next, cut it. The block is
the fast path, never the sole record. Completeness lives in the checkpoint file it names, which the resumed
session reads in full whenever the block isn't enough.
## Rules
- Durable storage only. Never write the checkpoint to `~/.claude/` or to a scratch folder.
- One file per workstream. Refresh in place; do not spawn duplicates.
- Full state, not a summary. If a path, decision, or blocker is missing, the checkpoint failed its job.
- Ambient by default. Don't wait to be told. Initialize at the significance line, refresh each round state changes.
- After the first announce, each real write rides out a one-line `checkpoint ✅` marker folded into that turn's reply. Never a verbose report, never a separate step. An optional status line (see above) is the always-on backstop.
- Plain markdown, real headings and paragraph breaks.
No comments yet. Be the first to comment!