Skip to content

brave-orange/ccsave

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ccsave

Game-save your Claude Code sessions. Share them like files.

ccsave (CLI binary: claude-save) exports any Claude Code conversation — messages, tool outputs, the active plan, optionally project files — into a single portable .ccsave archive. Hand it to a teammate or another machine, and they can resume exactly where you left off. Like a game save for your Claude conversations.

中文 README

┌────────────┐    export      ┌─────────────────┐    ship      ┌────────────┐
│  Sender    │ ─────────────▶ │  session.ccsave │ ───────────▶ │  Receiver  │
│ Claude     │                │  (tar.gz)       │              │ Claude     │
│ Code       │                │                 │              │ Code       │
└────────────┘                │  manifest       │              └─────┬──────┘
                              │  session.jsonl  │                    │
                              │  tool-results/  │                    │ /resume
                              │  summary.md     │                    │
                              │  plan.md        │                    ▼
                              │  snapshot/ ⋅⋅⋅   │              continue work
                              └─────────────────┘

Features

  • Single-file portable export — one .ccsave (tar.gz) carries everything needed
  • Auto-redaction of common secrets: Anthropic / OpenAI / GitHub / AWS / Google / Slack keys, JWTs, PEM private keys, .env-style values, generic high-entropy strings
  • Path tokenization — sender's /Users/alice/work/repo becomes {{CWD}} in the archive, gets remapped to the receiver's working directory on import (cross-OS, cross-machine)
  • Three sharing channels
    • Local file you send any way you like
    • LAN HTTP server (claude-save serve) — token auth + same-subnet check + rate limit
    • Push-style receive (claude-save listen) — receiver opens an inbox endpoint
  • Seamless one-shot import — receiver pastes the sender's URL once; CLI lists, picks, streams, and imports in a single command
  • Claude-generated summary baked into each archive — receiver gets a structured digest (goal / decisions / progress / files / how-to-continue) and can resume without reading 200 messages
  • Optional project-file snapshot — content-addressable, gitignore-aware, deduplicated
  • Zero npm dependencies — Node ≥ 18 built-ins and system tar
  • Slash command (/share-session) on top of the CLI for use directly inside Claude Code

Install

Clone into your Claude Code plugins directory:

git clone https://github.com/brave-orange/ccsave.git ~/.claude/plugins/claude-save
chmod +x ~/.claude/plugins/claude-save/bin/claude-save.js

Optionally symlink to your PATH:

ln -s ~/.claude/plugins/claude-save/bin/claude-save.js /usr/local/bin/claude-save

For the slash command, create the skill file:

mkdir -p ~/.claude/skills/share-session
cp ~/.claude/plugins/claude-save/SKILL.md ~/.claude/skills/share-session/SKILL.md

Optional: brew install qrencode (macOS) or apt install qrencode (Linux) to render QR codes in serve mode.

Quick start

Send

# In any Claude Code session, after some real work:
claude-save export

# → ~/Downloads/session-<slug>-<short>.ccsave  (242 KB typical)

# To share it on the LAN:
claude-save serve --port 8765
# → http://192.168.1.42:8765/?token=Xy7Q...kZ8

Receive

# In a fresh Claude Code session, in the directory you want to work from:
cd /path/to/your/work/dir
claude-save import "http://192.168.1.42:8765/?token=Xy7Q...kZ8"
# → Picks newest session, streams archive, detokenizes paths, places JSONL
# → ✓ Imported as session 0817121c-...

# Then restart Claude Code in this directory and /resume to enter the session.

That's it. Three commands across two machines.

Slash-command form (inside Claude Code)

/share-session export                       # in the sender's Claude Code
/share-session serve                        # start LAN server
/share-session import <url>                 # in the receiver's Claude Code

Concepts

Concept What it means
.ccsave tar.gz archive of one Claude session, with manifest + paths tokenized + secrets redacted
sender The machine/user exporting the session
receiver The machine/user importing it
serve mode Sender exposes their archives over HTTP for pull
listen mode Receiver exposes an inbox endpoint over HTTP for push
tokenization {{CWD}} / {{HOME}} / {{CWD_ENCODED}} placeholders, remapped on import
snapshot Optional content-addressable bundle of the sender's project files

CLI reference

claude-save export   [--session <uuid>] [--out <path>] [--include-snapshot]
                     [--no-redact] [--no-tokenize] [--no-summary]
                     [--summary-from <path>] [--gist] [--quiet]

claude-save import   <archive-or-url-or-server-home> [--slug <s>]
                     [--target-cwd <path>] [--apply-snapshot] [--force]
                     [--dry-run] [--token <t>]

claude-save serve    [--port 8765] [--bind 0.0.0.0] [--token auto|<t>]
                     [--dir <path>] [--accept] [--target-cwd <path>]

claude-save listen   [--port 8766] [--target-cwd <path>] [--token auto|<t>]
                     (= serve --accept; receiver-side inbox)

claude-save fetch    <peer-url> [--out <path>] [--token <t>] [--auto-import]
claude-save list     [--limit 20] [--current] [--json]
claude-save inspect  <archive> [--json]

Import URL forms

URL pattern Behavior
http://host:port/?token=xxx Server homepage → list sessions → pick newest → stream + import
http://host:port/?token=xxx + --slug foo Same, but pick the session matching foo
http://host:port/api/sessions/<slug>?token=xxx Direct archive download
~/path/to/file.ccsave Local file

Push to a listen-mode receiver

# Receiver:
claude-save listen --port 8766 --target-cwd $(pwd)
# → POST http://<receiver>:8766/api/import?token=...

# Anyone (sender, automation, browser):
curl -X POST "http://receiver:8766/api/import?token=..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @session.ccsave

# Or have the receiver fetch from the sender's serve URL:
curl -X POST "http://receiver:8766/api/import?token=..." \
  -H "Content-Type: application/json" \
  -d '{"url":"http://sender:8765/api/sessions/foo?token=..."}'

Archive format

session-{slug}-{shortHash}.ccsave         (tar.gz)
├── manifest.json                          metadata, redaction log, token map
├── summary.md                             Claude-generated digest
├── session.jsonl                          tokenized + redacted conversation
├── tool-results/                          tool outputs (tokenized + redacted)
├── subagents/                             child agent JSONL + meta
├── plan.md                                active plan (if any)
└── snapshot/                              optional project files
    ├── files.json                         {relative-path: sha256, size, mode}
    └── blobs/{sha[0:2]}/{sha[2:]}         content-addressable, deduplicated

Inspect any archive without unpacking:

claude-save inspect ~/Downloads/session-foo-a8f2.ccsave
# Version: 1.0
# Session: 8761fe83-...
# Messages: 301 (user 85, assistant 125, tool uses 81)
# Redactions: anthropic-key×8, openai-key×4, github-pat×2, aws-key×2, ...
# One-line: Working on payment retry logic across services X and Y...

Security

  • Auto-redaction is on by default. Every secret is replaced with [REDACTED:type:#hash4] and recorded in manifest.redactions. --no-redact requires explicit flag and prints a warning.
  • HTTP server defaults to LAN-only. Requests from outside the host's subnet (or RFC1918 ranges) return 403, regardless of token.
  • Token auth. 32-byte random token generated at serve start; required as ?token= query or Authorization: Bearer.
  • Rate limited. 5 requests per IP per second.
  • Archive defenses. Path-traversal entries rejected. Unpacked size capped at 500 MB to defeat zip-bombs.
  • Imports are atomic. Everything is staged to a temp directory and only moved into ~/.claude/projects/ after manifest + integrity validation pass.
  • Sender hostname leaks. manifest.source.senderHost records os.hostname(). Inspect before sharing if that's sensitive (flag to disable is on the v1.1 list).

Compatibility

Item Status
Claude Code 2.1.x Tested
Node ≥ 18
Platforms macOS, Linux, Windows (MSYS / Git Bash supported with auto path conversion)
Project-dir encoding (/path-path-) Observed empirically from Claude Code 2.1; falls back to scanning existing dirs on mismatch

How it works

  1. Export reads the session JSONL from ~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl, walks every string field, runs path tokenization and redaction, copies tool-results + active plan, optionally snapshots project files, then tar.gzs the staging dir.

  2. Tokenization uses regex with a [\\/] slash class so the same archive works whether the receiver runs POSIX or Windows. Longest-first replacement avoids {{HOME}} swallowing a {{CWD}} prefix.

  3. Import unpacks into a temp dir, verifies manifest.integrity.contentSha256, runs the inverse path mapping using the receiver's cwd / $HOME / username, generates a fresh sessionId (keeping internal message UUIDs intact so the parent chain stays valid), computes the receiver's encoded project dir, and atomically places the JSONL there.

  4. LAN server binds 0.0.0.0 but performs a same-subnet check on every API call. serve is read-only; listen (a.k.a. serve --accept) exposes POST /api/import that either reads .ccsave bytes from the request body or fetches them from a peer URL given in a JSON body.

Known limitations (v1.0)

  • claude --resume <uuid> is not auto-invoked; restart Claude Code manually after import
  • Memory and tasks state are not yet bundled into the archive
  • cwd → projects/ encoding rule is observed, not from public spec; future Claude Code releases may change it (discovery layer scans existing dirs to mitigate)
  • The HTTP server picks the first non-internal IPv4 interface, which may be a Hyper-V / VMware virtual one — pass the right --bind if needed
  • senderHost and claudeCodeVersion fields in manifest are not yet opt-out

Roadmap

  • v1.1: auto-resume hook · memory + tasks bundling · mDNS / Bonjour discovery for listen · manifest signing · per-field redaction opt-out
  • v2.0: end-to-end encryption (receiver public key) · session diffing / patch archives · cross-session "branch from here"

Testing

node tests/run.js
# 29 passed, 0 failed (29 total)

Covers tokenize edge cases, every redaction rule, CIDR / subnet logic, archive round-trip, full export-import round-trip across simulated cwds, and CLI smoke tests.

Contributing

Issues and PRs welcome. Things especially helpful:

  • Real-world false positives / negatives in the redaction rules
  • Tested values for the cwd → projects/ encoding on Claude Code versions other than 2.1.x
  • Reports on which OS / shell / tar combination broke --force-local path conversion
  • Ideas for the v1.1 / v2.0 items above

License

MIT — see LICENSE.

About

Game-save your Claude Code sessions. Export, share, and resume as portable .ccsave archives.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors