Lossless structural codec for Claude Code session JSONLs — portable conversation snapshots that move between devices.
Project description
claude-snap
Portable, lossless snapshots of Claude Code sessions.
--fork-session is a Claude Code primitive that already works locally: pick up
where you left off in a new shell, with full context. claude-snap is the same
primitive when the destination is a different device.
Pack a session JSONL on your laptop. Drop the artifact into a Claude chat on your phone. Keep the chain of ideas going. Read-only on a device that can't execute (the phone); read-write when reloaded into Claude Code on a device that has the repo.
This is not a memory layer. Not a search tool. Not a history browser. Not a summarizer. Not a markdown renderer. It's a codec.
What's in the box
claude-snap pack session.jsonl → session.snap.jsonl # compress
claude-snap unpack session.snap.jsonl → session.jsonl # restore (byte-identical events)
claude-snap stats session.snap.jsonl # how much did we save
Zero runtime deps. Pure stdlib Python 3.9+. MIT.
Install
pip install claude-snap
End-to-end UX
Today (manual, but works on day one):
- On your laptop, after a Claude Code session:
claude-snap pack ~/.claude/projects/<encoded-path>/<uuid>.jsonl # → <uuid>.snap.jsonl
- Move the
.snap.jsonlto your phone — AirDrop, iCloud Drive, email-to-self, gist, whatever moves a text file. - On your phone, open Claude (mobile app or claude.ai), upload/paste the file, and tell Claude "this is a packed prior session — use it as context." Phone-Claude now has the full conversational chain, every file state laptop-Claude saw, every edit it made.
Reattaching to laptop:
claude-snap unpack session.snap.jsonl # → session.jsonl, byte-identical events
Drop the unpacked JSONL back into ~/.claude/projects/<...>/ and Claude Code
resumes against it.
Asymmetry: phone vs laptop
When you load a snapshot into a Claude chat on a device that doesn't hold the repo:
- Can: ideate, discuss, suggest code, draft the next edits, plan, review what was done.
- Can't: actually
Edit/Write/Bashagainst the laptop's files.
Two reasons, the second is load-bearing:
- No executor connected to the laptop's filesystem.
- The snapshot itself has no execution surface. It's inert text. There's no protocol where phone-Claude could reach back through it to your laptop.
That's not a discipline imposed by the codec; it's what the medium is. The right architecture for cross-device mobility: by construction, the snapshot moves without dragging side-effect capability with it.
What "lossless" means here
Roundtrip property: unpack(pack(events)) produces the original event
payloads byte-for-byte (modulo header/footer metadata).
The codec only ever replaces redundant events with refs. It never:
- summarizes
- truncates conversational turns
- drops reasoning
- collapses Edit/Write payloads
- approximates anything
The redundancy it exploits is structural:
- Re-reading an unchanged file. If Claude does
Read(foo.py)twice and nothing has Edit'dfoo.pybetween them, the second read becomes a ref. Content preserved exactly once. - Repeated identical tool output. If
pytest -qreturns the same bytes twice, the second result becomes a ref. - Mutation invalidates dedup. If
foo.pywas Edit'd between two Reads, the second Read is not ref'd — its content has genuinely changed.
Conversational turns (you and Claude talking) are never dedup'd. That's the chain of ideas; you keep all of it.
What compression to expect
The codec only removes structural redundancy: repeat reads of unchanged files, repeat tool calls with identical output. If your session re-reads or re-runs a lot, expect a meaningful ratio. If every Read and every Bash is unique (common in modern Claude Code sessions, where Claude tends to retain what it has already seen), expect close to 1.0× — and that's correct, not a bug. The artifact is still portable and lossless, which is the point. Compression is incidental.
Why this exists
The space around Claude Code history has two kinds of tools:
- Dumpers (
claude-conversation-extractor,cctrace,claude-code-history-mcp) give you the full firehose. Hit context window limits the moment a session has nontrivial Read/Bash bloat. - AI summarizers (
claude-mem) give you a summary. Lossy by design. Throws away the chain-of-changes that's the whole point.
Neither lets you "transplant the session into a fresh chat on another device and pick up where you left off." That requires the real conversation, just without the redundant payload bytes.
Roadmap
- v0.1.0 (you are here): the codec.
- A Claude Code skill / configurable script that finds the active session, packs it, and drops the artifact at a configurable location (iCloud Drive folder, S3 bucket, etc.). Removes step 1 of the manual flow.
- Schema adapters for other agentic CLIs (Cursor, Aider, Codex, Gemini CLI). The Event format is intentionally tool-agnostic.
The phone-side step (upload into a chat) remains an unsolvable workaround
until Claude clients natively understand fork-session payloads. See the
linked anthropics/claude-code issue.
Status
v0.1.0. Codec is correct on the roundtrip property and on the dedup
heuristics tested in tests/test_codec.py. Schema normalization handles the
dominant Claude Code JSONL shape; edge cases in unusual tool invocations
(custom MCP tools, Task subagents) currently fall through to the generic
META bucket and pass through unchanged — safe but uncompressed.
Contributing
Issues and PRs welcome. Particularly interested in:
- Dedup heuristics for tools we don't currently special-case
- Schema adapters for other agentic CLIs
- A laptop-side packing skill / hook for Claude Code
License
MIT.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_snap-0.1.0.tar.gz.
File metadata
- Download URL: claude_snap-0.1.0.tar.gz
- Upload date:
- Size: 15.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92878461c4a30c2bf56635f31eab54d95fba71089f357a30a68a583f1f38208c
|
|
| MD5 |
1018a7d97efcea3a7e24fc73818799b3
|
|
| BLAKE2b-256 |
e5d13b5b775426109966b3ba2ec1e8eb9f9b58e1c86ace7bc1e84e0117d71d15
|
File details
Details for the file claude_snap-0.1.0-py3-none-any.whl.
File metadata
- Download URL: claude_snap-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa69121d66c44d1f798f58f289154fc766c19f90cff7ddb1e45299eaf5a7dcd3
|
|
| MD5 |
610964500ab873d7793fbc9f418e4c16
|
|
| BLAKE2b-256 |
10b86d0f687f94187b21b4bb426176734dce6e089b99836b399a1578cac6fade
|