What it does
Scans every supported tool's session store, ranks each session by last activity, and resumes the one you pick — in its original working directory, with its original session ID, via the right CLI.
Each row's subtitle is the last user message in that session, so you see
what you were working on most recently — not how the chat opened. Press n
on any row to add a yellow nickname; nicknamed rows expand to a third line
that keeps the auto-derived title visible (dim) for context, and the
nickname is searched by / too.
┌─ ccr — 211 sessions (2 possibly live) ──────────────────────────────────┐
│ Sessions │ Preview │
│ ▶ [claude] api-service 12m ago │ nick: panic hotfix │
│ panic hotfix │ tool: claude │
│ actually let's also add a regr… │ cwd: ~/projects/api-service │
│ [codex] web-app 1h ● live │ last: 2026-05-23 14:00 (12m) │
│ use exponential backoff capped… │ msgs: 47 │
│ [gemini] cli-tool 3d │ id: a1b2c3d4-5e6f-… │
│ update the migration guide se… │ │
│ [claude] docs-site 1w │ ── recent turns ── │
│ tighten the intro paragraph a… │ ❯ user │
│ │ the panic reproduces only when… │
│ │ ◆ asst │
│ │ Let me add a None check in the… │
└──────────────────────────────────────────────────────────────────────────┘
↑↓/jk · Enter resume · b bookmark · n nickname · / filter · ? help · q
Top row is nicknamed — panic hotfix shows in yellow, the auto-derived
last-message title stays visible underneath in dim gray. Rows without a
nickname are two lines (tags + auto-title), the same as before.
If a selected session is already running elsewhere (detected via pgrep,
matching only processes that carry the id as a resume argument —
--resume <id> / -r <id> / resume <id>), a confirmation modal appears before spawning
a second attachment:
┌─ Confirm resume ──────────────────────────────────────┐
│ ⚠ Session may already be running │
│ │
│ tool: claude │
│ session: a1b2c3d4-5e6f-7890-abcd-… │
│ cwd: ~/projects/web-app │
│ │
│ matching processes: │
│ 42318 claude --resume a1b2c3d4-5e6f-… │
│ │
│ Resuming may interleave writes and corrupt session. │
│ │
│ [y] resume anyway [n] cancel │
└───────────────────────────────────────────────────────┘
Install
Or from source:
Use
| Key | Action |
|---|---|
↑ / k |
up |
↓ / j |
down |
g / Home |
jump to top |
G / End |
jump to bottom |
PgUp/Dn |
page up/down (10 rows) |
/ |
filter: title, cwd, tool, nickname, or full-history content |
Enter |
resume selected session (live-checked) |
v |
open session in agx (timeline viewer) |
b |
toggle bookmark (★ marker, persisted) |
n |
set / edit / clear session nickname (yellow label) |
? / F1 |
help overlay |
q / Esc |
quit |
/ content search covers each session's full history: the conversation
text is indexed by a background thread right after startup (the picker itself
still opens instantly from the tail-window scan), so for the first moments a
content match may cover only recent turns, filling in as the index completes.
On Enter, ccr runs a live-check first: pgrep prefilters processes that
mention the id, then only those carrying it as a resume argument
(--resume <id> / -r <id> / resume <id>, fused --resume=<id> too) count as live — an editor or
tail -f with the session file open does not. If a match is found, a
confirmation modal warns before spawning a second attachment (which would
interleave JSONL writes and corrupt the session). Otherwise it execs the
tool's resume command with the session's original cwd.
CLI subcommands
| Command | Action |
|---|---|
ccr resume <id> |
resume a session directly by id, skipping the picker (--force to override the live-session guard) |
ccr list |
plain-text dump of all sessions (tool id date title) |
ccr path <id> |
absolute path to session file (pipes well) |
ccr show <id> |
raw file contents (same as cat $(ccr path <id>)) |
ccr export <id> |
full-turn markdown dump (or --format json) |
ccr stats |
totals, per-tool, per-project, 30-day activity histogram |
ccr resume <id> runs the same live-check as the TUI: if the session looks
like it is already open elsewhere (a process carries the id as a resume
argument) it refuses, since a second attachment interleaves JSONL writes and
corrupts the session. Pass --force to resume anyway. The id is any id from
ccr list. On success the resumed tool's exit code is propagated; a refusal
or any error exits 1.
ccr never modifies your session files. If you want to delete one, delete
it where its tool stored it (~/.claude/projects/..., ~/.codex/sessions/...,
or ~/.gemini/tmp/...).
Environment variables
| Variable | Purpose |
|---|---|
CCR_CLAUDE_DIR |
Full path to Claude's projects/ dir |
CLAUDE_CONFIG_DIR |
Claude Code's native override; ccr appends projects |
CCR_CODEX_DIR |
Full path to Codex's sessions/ dir |
CCR_GEMINI_DIR |
Full path to Gemini's ~/.gemini root |
CCR_BOOKMARKS_FILE |
Override the ~/.ccr/bookmarks.json location |
CCR_NICKNAMES_FILE |
Override the ~/.ccr/nicknames.json location |
How it works
Each backend knows where its tool stores sessions and how to resume one.
| Tool | Storage | Resume invocation |
|---|---|---|
| Claude Code | ~/.claude/projects/<encoded-cwd>/<uuid>.jsonl |
claude --resume <uuid> (cwd set) |
| Codex | ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl |
codex resume <uuid> (cwd set) |
| Gemini CLI | ~/.gemini/tmp/<project>/chats/session-*.json + projects.json |
gemini --resume <N> — ccr looks up the 1-based index at runtime via gemini --list-sessions |
For each session ccr extracts:
cwd— working directory the session was started in- title — last user message in the session, truncated to 80 chars (so the list shows what you were working on most recently, not how the chat opened)
last_activity— most recent turn timestamp (drives the sort and the● liveflag)message_count— user + assistant turns onlypreview— last 6 turns, rendered in the right pane
Read-only at rest. ccr never touches your session files. The only state it
writes is ~/.ccr/bookmarks.json (when you press b) and
~/.ccr/nicknames.json (when you press n). Both are plain JSON.
Adding a backend
A backend is any type that implements:
Register it in backends::all() and sessions surface in the shared TUI with a
[tool] tag in the left column.
Links
License
MIT