Share, browse, and resume Claude Code sessions — without leaking your paths or API keys.
ccshare turns a Claude Code session (~/.claude/projects/<hash>/<uuid>.jsonl)
into a portable .ccsession bundle that's safe to send. Recipients can preview
it in a browser (read-only) or import it and run claude --resume to pick up
where you left off.
It also ships a local 3-pane web dashboard for browsing every session you've ever had, with markdown rendering and one-click export.
┌──────────────────┐ .ccsession ┌──────────────────┐
│ ~/.claude/... │ ─ scrubbed ─► │ teammate's box │
│ session.jsonl │ ─ normalized ─► │ • view in browser│
│ (paths, secrets) │ │ • or claude │
│ │ │ --resume │
└──────────────────┘ └──────────────────┘
Status: v0.1.0. Single-file Python script, zero dependencies beyond stdlib.
All 6 acceptance gates pass on every change (./verify.sh).
A Claude Code session lives at ~/.claude/projects/<cwd-hash>/<uuid>.jsonl.
You can't just send the file:
- Paths are absolute and machine-specific. Your
/Users/wq/Projects/foomeans nothing on someone else's box, andclaude --resumepicks the project by hashingcwd. - Secrets leak. Tool results often contain API keys, tokens, env dumps that ended up there mid-debug.
- Resume needs a real cwd. The recipient's filesystem won't have the same files in the same place.
- Skills and MCP servers differ. A session that called
/my-skillwon't resume cleanly if the recipient doesn't have it.
ccshare handles all of this: redacts secrets (with a mandatory preview),
normalizes paths into placeholders, packages the bundle, and remaps everything
on import. The viewer never writes to the recipient's ~/.claude.
git clone https://github.com/Equality-Machine/ccshare.git
cd ccshare
chmod +x src/ccshare
# optional: symlink onto your PATH
ln -s "$(pwd)/src/ccshare" ~/.local/bin/ccshareRequires Python 3.10+. No pip install, no node modules.
# 1. See your recent sessions
ccshare list
# 2. Preview what would be redacted (always do this first)
ccshare scan ~/.claude/projects/<hash>/<uuid>.jsonl
# 3. Package it
ccshare export-from-file ~/.claude/projects/<hash>/<uuid>.jsonl \
--out share.ccsession --no-interactive
# Or by index from `list`:
ccshare export 1 --out latest.ccsession --no-interactiveThe output .ccsession is a zip containing the rewritten transcript and a
manifest with redaction summary + path mappings — typically <1MB for a normal
session.
# View only — opens a browser, NEVER touches ~/.claude
ccshare view share.ccsession --port 7321
# Or import + register so claude --resume works
ccshare import share.ccsession --target ./imported --register --no-interactive
# → prints: cd ./imported && claude --resume <session-id>ccshare view-all --port 7321 --limit 100A 3-pane dashboard in the browser:
- Left: session cards (title, project, turn count, tool count)
- Middle: rendered conversation with markdown, syntax-aware code blocks, expandable tool calls
- Right: session metadata, files touched, tools used, skills, MCP servers, one-click Export .ccsession button (auto-redacts before download)
Filter sessions live with the search box. Useful for finding "that session where I figured out the OAuth bug last week".
Redacted (replaced with [REDACTED:type]):
| Type | Pattern |
|---|---|
| Anthropic, OpenAI, OpenRouter API keys | sk-ant-…, sk-…, sk-or-v1-…, sk-proj-… |
| GitHub tokens | ghp_, gho_, ghu_, ghs_, ghr_ |
| AWS access / secret keys | AKIA…, AWS_SECRET_ACCESS_KEY=… |
| Slack tokens | xoxb-, xoxp-, xoxa-, xoxr-, xoxs- |
| Email addresses | *@*.tld |
| Private IPs in tool output | 10.*, 192.168.*, 172.16-31.* |
Normalized (placeholders preserved in manifest for reversibility):
| What | Placeholder |
|---|---|
/Users/<you>/... |
{{HOME}}/... |
| Original cwd | {{CWD}} |
| Git branch | {{BRANCH}} |
The manifest.json records every mapping, so import rewrites placeholders
back to the recipient's environment.
./verify.sh is the dev loop. Every code change must keep all six gates green:
| Gate | What it proves |
|---|---|
| A | Round-trip: export then import produces an equivalent transcript (3 fixtures: tiny / medium / complex) |
| B | Resume works: imported session is registered to ~/.claude/projects/... so claude --resume finds it |
| C | Viewer renders correctly (HTML structure check + screenshot evidence) |
| D | Redaction recall = 100% on the adversarial fixture (20 needle secrets/PII items must all be caught) |
| E | No /Users/<you>/* paths leak through; mappings are reversible |
| F | 10-step end-to-end UX walkthrough |
./verify.sh # all gates
./verify.sh A # single gate
SKIP_PEEKABOO=1 ./verify.sh # skip the screenshot stepDay-0 setup pulls real sessions as test fixtures (gitignored — they contain your data) and runs the suite:
./tests/fixtures/bootstrap.sh
./verify.shThe adversarial fixture (tests/fixtures/adversarial.jsonl + its
expectations.json) is committed and serves as ground truth for redaction
recall. If you find a leak, add a needle to the fixture and a counter-line to
the expectations.
Everything is in one ~1900-line Python file (src/ccshare), organized by
section:
src/ccshare single-file CLI
├─ Redaction patterns regex bank + redactor
├─ Normalizer path / cwd / branch placeholders
├─ Loader stream-parse jsonl events
├─ Packer write .ccsession (zip)
├─ Importer unpack + remap + register session
├─ Viewer (cmd_view) single-session browser preview
└─ Dashboard (cmd_view-all) 3-pane multi-session HTTP server
tests/
├─ fixtures/
│ ├─ tiny / medium / complex .jsonl (gitignored, regenerated locally)
│ └─ adversarial.jsonl + expectations (committed; ground truth for Gate D)
├─ diff_session.py Gate A — round-trip equivalence
├─ check_resume.py Gate B — registration check
├─ check_viewer_html.py Gate C — viewer DOM
├─ check_redactions.py Gate D — recall
├─ check_normalize.py Gate E — leak detection
└─ gate_f_walkthrough.sh Gate F — 10-step UX
docs/
├─ RUBRIC.md every gate's pass criteria
└─ peekaboo-probe.md browser screenshot helpers
Single file is a deliberate choice: easy to drop into a teammate's ~/.local/bin/
and run with no install. If a module gets big enough to warrant splitting, it
will earn its own file.
- ✅ v0.1 —
export-from-file,import,scan,view,view-all,list,export N,--register. Markdown rendering. In-page export from the dashboard. All 6 gates automated. - v0.2 —
--with-filesto package referenced files alongside the transcript. Interactive TUI for redaction preview. - v0.3 — visual baseline diff against committed PNG.
- Maybe — Linear / Slack share targets, search across all sessions.
- ❌ No cloud upload or "publish to cloud" service. Bundles are files; share them however you'd share any file (Lark, Signal, Drive, scp).
- ❌ No encryption. Bundles are zip files. If the channel is sensitive, encrypt the channel.
- ❌ No real-time collab.
- ❌ No automatic file-snapshot resume restoration (
--with-filesis opt-in and packages copies, not snapshots).
Pull requests welcome. The contract is simple:
- Don't break the gates.
./verify.shmust stay green. New behavior gets a new gate or extends an existing one. - Adversarial fixture is ground truth for redaction. If you teach the
redactor a new pattern, add a needle to
adversarial.jsonland a counter toexpectations.jsonin the same PR. - Single file unless there's a real reason. Modularity for its own sake is rejected; modularity that makes the code easier to test or reason about is welcome.
MIT. See LICENSE.
Built at Efflora by the AI Agent infrastructure team. We use this internally to share interesting Claude Code sessions among the team and to dig through our own session history.
If you find a leak the redactor missed, please file an issue with a minimal fixture — no real secrets, just the pattern.