Rolling JSONL snapshots for Claude Code sessions with automatic restore after context overload.
When a Claude Code session hits context limits, the session crashes and all conversation context is lost. You have to start from scratch.
session-snapshot does two things:
-
Saves snapshots — a Claude Code hook that periodically copies the session JSONL file (every ~80KB of growth, once the session exceeds ~200KB). One rolling snapshot per session, always up to date.
-
Auto-restores — a wrapper (
cclaude) that detects context overload when Claude exits and automatically restores the session from the last snapshot, resuming where you left off.
The tool has 4 parts: a hook, a wrapper, a path resolver, and a CLI.
A Claude Code hook that runs on every PostToolUse event. After each tool call, it checks whether the session JSONL has grown enough to warrant a new snapshot.
How it decides to snapshot:
- Ignores sessions under 200KB (~50K tokens) — too small to worry about
- After reaching 200KB, snapshots every ~80KB of growth (~20K tokens worth)
- Rolling strategy: one snapshot per session, each new one overwrites the previous
What it produces:
~/.config/session-snapshot/snapshots/{sessionId}.jsonl— byte-perfect copy of the session JSONL~/.config/session-snapshot/snapshots/{sessionId}.state.json— tracks snapshot count and last size~/.config/session-snapshot/snapshots/latest.json— pointer to the most recent snapshot (session ID, paths, timestamp) used by the wrapper
Hook interface: Exports a default object with name, version, and run(input). Claude Code calls run() with { session_id, hook_event_name } — the hook only acts on PostToolUse.
A bash wrapper around claude that adds crash recovery. You run cclaude instead of claude — all arguments are passed through.
How auto-restore works:
- Runs
claudewith your arguments - When
claudeexits, checkslatest.jsonfor a recent snapshot - Detects context overload if both conditions are met:
- Snapshot is less than 10 minutes old
- Session JSONL grew more than 100KB beyond the snapshot (sign of compaction/overflow)
- If overload detected: replaces the crashed JSONL with the snapshot copy
- Restarts
claude --resume {sessionId}with a prompt telling the model that context was restored - Loops back to step 2
Flag preservation: Remembers flags like --dangerously-skip-permissions, --verbose, --debug across restarts by saving them to ~/.config/session-snapshot/pending-flags.txt.
Claude Code stores session JSONLs in ~/.claude/projects/{project-hash}/{sessionId}.jsonl, but the hook only receives a session ID — not the full path. This module finds the JSONL by scanning all project directories.
- Scans
~/.claude/projects/subdirectories for a matching{sessionId}.jsonl - Caches successful lookups in
~/.config/session-snapshot/path-cache.json(up to 50 entries) - Cache is checked first; if the file no longer exists, the entry is evicted and a fresh scan runs
Management commands:
| Command | What it does |
|---|---|
install |
Registers the hook + installs the cclaude wrapper |
uninstall |
Removes the hook registration + wrapper |
status |
Shows whether the hook is active, wrapper is in PATH, lists snapshots |
clean |
Deletes all snapshot files |
test |
Runs self-checks (plugin loads, modules import, paths resolve) |
Install modes: If claude-hooks plugin directory exists (~/.config/claude-hooks/plugins/), the hook is symlinked there. Otherwise, it registers directly in ~/.claude/settings.json under hooks.PostToolUse.
┌─────────────┐ PostToolUse hook ┌──────────────────┐
│ Claude Code │ ──────────────────────► │ snapshot.ts │
│ (session) │ │ copies JSONL │
└──────┬──────┘ │ every ~80KB │
│ └────────┬─────────┘
│ exits │
▼ ▼
┌─────────────┐ detects overload ┌──────────────────┐
│ cclaude.sh │ ◄────────────────────── │ snapshots/ │
│ (wrapper) │ restores JSONL │ latest.json │
└─────────────┘ └──────────────────┘
Requires Node.js 22+.
git clone https://github.com/Chill-AI-Space/session-snapshot.git
cd session-snapshot
./bin/cli.sh installThis will:
- Register
snapshot.tsas aPostToolUsehook (via claude-hooks plugin dir or directly in~/.claude/settings.json) - Install the
cclaudewrapper to~/.local/bin/
Launch Claude through the wrapper instead of directly:
cclaude # all your usual claude arguments work
cclaude -p "hi" # flags are passed through to claudeThat's it. Snapshots happen automatically in the background. If context overload occurs, the wrapper detects it and restores the session.
session-snapshot install # Install plugin + wrapper
session-snapshot uninstall # Remove plugin + wrapper
session-snapshot status # Show snapshot info
session-snapshot clean # Remove all snapshots
session-snapshot test # Run self-testsession-snapshot/
src/
snapshot.ts # Hook plugin — creates rolling JSONL snapshots
claude-paths.ts # Finds session JSONL files across project dirs
bin/
cclaude.sh # Wrapper — auto-restore loop around claude
cli.sh # CLI for install/uninstall/status/clean/test
~/.config/session-snapshot/
snapshots/
{sessionId}.jsonl # Snapshot copy of session JSONL
{sessionId}.state.json # Rolling state (count, last size)
latest.json # Pointer for wrapper auto-restore
path-cache.json # Cached session ID -> JSONL path mappings
logs/
snapshot.log # Debug log (when enabled)
Environment variables:
SESSION_SNAPSHOT_DEBUG=1— enable debug logging to~/.config/session-snapshot/logs/snapshot.log
Tunable constants in src/snapshot.ts:
SNAPSHOT_INTERVAL(default: 80,000 bytes) — JSONL growth between snapshotsSNAPSHOT_MIN_SIZE(default: 200,000 bytes) — minimum session size before snapshotting starts
session-snapshot uninstall
# To remove snapshots too:
rm -rf ~/.config/session-snapshotMIT