I run 15+ Claude Code sessions at a time. When my terminal crashes I lose track of all of them, and the built-in claude --resume picker only surfaces a fraction of my history. These three scripts fix both problems.
Shell wrapper. Every time you type claude, it asks for a name. Hit enter to skip and let Claude auto-name.
# Add to ~/.zshrc or ~/.bashrc
source claude-session-namer.sh$ claude
Session name (enter to auto-name): protein-analysis
Doesn't interfere with --resume, -c, -p, --help, or -n.
claude-checkpoint writes all live, named sessions to ~/.claude/session-checkpoint.json every 5 minutes (via launchd). Dead PIDs get pruned. Each tick also copies the prior checkpoint to .prev as a one-cycle backup, and (if ~/.claude is a git repo) commits the file when the named-session set changes.
claude-restore reads the checkpoint and reopens everything. Uses cmux workspaces if you have it installed (preserving sidebar grouping), otherwise falls back to Terminal.app tabs.
claude-restore --list # see what's saved
claude-restore # reopen everything (asks first)
claude-restore --yes # skip confirmation
claude-restore --prev # read .prev backup instead of live checkpoint
# (use when a checkpoint tick wiped real state)
claude-restore --from-commit <sha> # read a historical checkpoint from the
# ~/.claude git repo. Find one with:
# cd ~/.claude && git log --oneline session-checkpoint.jsonSessions are resumed by their UUID (the checkpoint records sessionId per entry), so each tab resumes the real conversation directly — not the picker pre-filtered by name, which was a real failure mode of an earlier version of this script. The --from-commit flag is the recovery hatch for when both the live checkpoint and .prev have been overwritten with stale state: if ~/.claude is git-tracked, the checkpoint is committed on every named-session-set change, so any prior state is recoverable from history. Already-running sessions (matched by UUID against the current live checkpoint) are skipped on restore to avoid opening duplicates.
Separate from claude-restore. Reads ~/.claude/projects/*/*.jsonl and prints every Claude Code session that has ever existed — name, cwd, last-touched timestamp, message count, first-prompt preview, session UUID. Useful when the built-in picker can't find the session you remember having three weeks ago.
claude-sessions # all sessions, newest last
claude-sessions --named # only sessions you named
claude-sessions --cwd ~/projects/foo # filter by cwd
claude-sessions --since 2026-04-01 # recent only
claude-sessions --resume aperture # print copy-pasteable resume command
claude-sessions --search "specific text" # deep-grep transcript bodies (uses ripgrep)
claude-sessions --json | jq ... # machine-readable outputThe --resume flag emits (cd <cwd> && claude --resume <uuid>) so you sidestep the picker entirely. --search uses ripgrep to find sessions by content when you don't remember the name.
cp claude-checkpoint.sh ~/.local/bin/claude-checkpoint
cp claude-restore.sh ~/.local/bin/claude-restore
cp claude-sessions.py ~/.local/bin/claude-sessions
chmod +x ~/.local/bin/claude-checkpoint ~/.local/bin/claude-restore ~/.local/bin/claude-sessions
# Checkpoint every 5 minutes
cat > ~/Library/LaunchAgents/com.claude.session-checkpoint.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.claude.session-checkpoint</string>
<key>ProgramArguments</key>
<array>
<string>/Users/YOUR_USER/.local/bin/claude-checkpoint</string>
</array>
<key>StartInterval</key>
<integer>300</integer>
</dict>
</plist>
EOF
launchctl load ~/Library/LaunchAgents/com.claude.session-checkpoint.plist{
"timestamp": 1775882363,
"named": [
{ "name": "protein-analysis", "cwd": "/Users/me/projects/biolab", "workspace": "Biolab" },
{ "name": "api-refactor", "cwd": "/Users/me/projects/backend", "workspace": "" }
],
"unnamed_count": 2,
"total": 6
}If cmux is running, each named session is matched to its workspace by tab name — exact match first, then case-insensitive substring fallback.
checkpoint — Claude Code keeps live session metadata in ~/.claude/sessions/{PID}.json. The checkpoint script iterates those files, checks PID liveness with kill -0, captures cmux workspace layout if available, and writes the named ones to a single JSON file. Atomic write (tmp + mv). The prior checkpoint is kept as .prev so one bad cycle (e.g., a tick right after a restart) doesn't wipe the only record.
restore — Reads the checkpoint. With cmux: creates each workspace if missing, opens a new surface (vertical tab) per session, sends the resume command, renames the tab. Without cmux: uses osascript to open Terminal.app tabs.
sessions — Iterates every transcript JSONL once, extracting customTitle, cwd, timestamps, and the first user prompt. Total scan time is ~1s for 1,000+ sessions on local SSD. The catalog is built fresh each run; no cache.
- macOS for launchd. Linux works too — substitute
cronand pick a multiplexer. - Python 3 (stdlib only)
- Claude Code CLI
- cmux (optional, for workspace-aware restore)
- ripgrep (optional, only for
claude-sessions --search)