claude-cellar
Transparent zstd compression for Claude Code session files.
Claude Code stores every session as a plain
JSONL file under ~/.claude/projects/**/. Over time these accumulate — hundreds
of MB of text that compress down to ~18% of their size but can never be
appended to while compressed. claude-cellar keeps the N most recent sessions
uncompressed and zstd-compresses the rest, then transparently re-hydrates them
when you launch Claude so the /resume picker still sees every session.
Verified compression on real sessions: ~82% size reduction (zstd -19). Hydration of 10 sessions takes ~5 ms (parallel, rayon). Round-trip is hash-verified before deleting originals.
Why
- Sessions are plain text;
zstd -19reduces a 4.6 MB session to ~870 KB. - Compression is one-shot at session close; decompression is on the
/resumecritical path, so the codec choice favors fast decoding. - The
/resumepicker only sees.jsonl, so the wrapper hydrates before launching Claude and cleans up on exit — zero change to your workflow.
Install
From crates.io
install auto-detects the real claude binary (canonical locations on
Linux/macOS/Windows), stores the path in ~/.config/claude-cellar/claude-bin.path,
and replaces claude in PATH with a ~75-byte shim that invokes
claude-cellar run -- "$@".
Revert with claude-cellar uninstall.
From source
Usage
Everyday use is transparent. Launch claude as always; the shim hydrates
compressed sessions in parallel (~5 ms for 10 files), Claude sees every
session in /resume, and on exit the wrapper re-compresses any session that
was modified and deletes the unchanged hydrated files.
Manual commands for one-off operations:
# Compress all but the 5 most recent sessions (by mtime) in a directory
# Preview without changes
# Compress/decompress single files
# Resume a specific session by id (auto-decompresses to tmpfs if needed)
# List sessions with size and compression state
# Inspect the persistent log
Architecture
| Component | Purpose |
|---|---|
archive |
Scans a directory recursively for .jsonl sessions, keeps the N most recent uncompressed (--keep), compresses the rest in parallel with zstd level 19, verifies round-trip hash, then deletes originals. |
run |
Hydrates all .jsonl.zst → .jsonl in parallel, spawns the real claude binary with forwarded arguments, waits, then in parallel either re-compresses sessions that were modified or deletes hydrated files whose hash/mtime matches the snapshot. |
install |
Auto-detects the real claude binary, persists its path, and replaces ~/.local/bin/claude with a bash shim (claude.cmd on Windows) that routes every invocation through run. |
resume |
Single-session decompression to a tmpfs scratch ($XDG_RUNTIME_DIR/claude-cellar/scratch/ on Linux, $TMPDIR elsewhere). |
Signal handling: run installs a SIGINT/SIGTERM/SIGHUP forwarder so Ctrl+C
reaches Claude but the wrapper survives to perform cleanup. Without this the
compression state would leak on abnormal exit.
Paths
| Platform | Log | Scratch | Config |
|---|---|---|---|
| Linux | $XDG_STATE_HOME/claude-cellar/cellar.log (default ~/.local/state/...) |
$XDG_RUNTIME_DIR/claude-cellar/scratch/ (tmpfs) |
$XDG_CONFIG_HOME/claude-cellar/ |
| macOS | ~/Library/Application Support/claude-cellar/cellar.log |
$TMPDIR/claude-cellar-scratch/ |
~/Library/Application Support/claude-cellar/ |
| Windows | %LOCALAPPDATA%\claude-cellar\cellar.log |
%TEMP%\claude-cellar-scratch\ |
%APPDATA%\claude-cellar\ |
Compatibility & edge cases
claude-cellar tracks Claude Code's documented session storage. According to
the official docs (code.claude.com/docs/en/settings), there is no documented
override for the ~/.claude/projects/ directory itself, so by default cellar
uses that path. The behavior with related Claude Code settings is:
| Claude Code setting / env / flag | Effect on cellar |
|---|---|
Default install (~/.claude/projects/) |
Works out of the box. |
Filesystem symlink at ~/.claude/projects/<sanitized-cwd> |
Transparent — cellar follows symlinks like any FS-native tool. Useful for shared NFS layouts. |
CLAUDE_CODE_SKIP_PROMPT_HISTORY=1 |
No .jsonl is written by Claude. Cellar finds zero sessions and is a no-op. |
--no-session-persistence (per-run) |
That run does not persist; cellar ignores it. |
cleanupPeriodDays in settings.json |
Claude prunes old .jsonl at startup, but it does not know about .jsonl.zst. Compressed sessions persist past the retention window. |
| Custom path / unusual layout | Override with CLAUDE_CELLAR_PROJECTS_DIR env var or --projects-dir <path> flag on run. |
Overrides
| Variable / flag | Purpose |
|---|---|
CLAUDE_CELLAR_CLAUDE_BIN |
Explicit path to the real Claude binary; skips auto-detection. |
CLAUDE_CELLAR_PROJECTS_DIR |
Override the projects root (where the .jsonl sessions live). |
--projects-dir <path> (on run) |
Same override per-invocation; takes precedence over the env var. |
Benchmarks
Measured on three real Claude Code sessions (NixOS, zstd 1.5.7 CLI, single archive pass):
| Session size | gzip -9 | zstd -3 | zstd -19 | xz -6 |
|---|---|---|---|---|
| 670 KB | 17.3% | 13.6% | 11.6% | 11.1% |
| 1.9 MB | 19.5% | 16.9% | 15.0% | 14.6% |
| 4.6 MB | 23.9% | 20.3% | 18.1% | 17.8% |
zstd -19 lands within 0.3 points of xz -6 on ratio and decompresses ~20× faster
(important on /resume). zstd -3 is close on ratio with near-zero compression
time; the default archive uses -19 because compression is one-shot and
the extra ratio is free.
Status
- v0.1.0 — first public release
- Tested on Linux x86_64 (NixOS) end-to-end: hydrate, resume, exit cleanup, SIGINT survival
- Windows and macOS: code paths are implemented (
dirs,Path,Command::status,cfg(windows)shim) but not yet smoke-tested on those platforms in this release
License
Licensed under either of:
- MIT License (LICENSE-MIT or https://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.