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 -f <session-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 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 |
On Enter, ccr runs pgrep -f <session-id> first. If a matching process 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 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 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