I run Claude Code across a lot of projects — plugins, little web apps, infra scripts. Two things kept tripping me up. claude -r resumes a session, but only if you’re already standing in the right directory. And once you’ve got three terminal tabs open, they all look identical, so you lose track of which project each one is actually in.
So I wrote cc. Type it, and you get a fuzzy-searchable list of every Claude project you’ve touched, newest first. Pick one — it jumps to that directory, paints the terminal a colour that’s unique to that project, and resumes the session. Close Claude and the colour resets. No plugin, no agent, no background daemon. About fifty lines of zsh.
The two tricks
The first is finding the projects. Claude stores each session under ~/.claude/projects/, but the folder names are flattened and ambiguous. The real working directory is sitting inside the session log, so I read it straight out of the newest .jsonl file and sort by modified time:
for d in ~/.claude/projects/*/; do
local -a files=("$d"*.jsonl(N.om)) # newest .jsonl first
local f=$files[1]; [ -z "$f" ] && continue
cwd=$(grep -o '"cwd":"[^"]*"' "$f" | head -1 | sed 's/.*"cwd":"//;s/"$//')
ts=$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' "$f")
printf '%s %s\t%s\n' "$ts" "$cwd" "$cwd"
done | sort -r
That feeds straight into fzf. Type cc plug and if only one project matches it jumps right in; otherwise you get a filtered list.
The second trick is the colour. Apple Terminal can be driven with AppleScript, so I find the tab whose tty matches the current shell and set its background. The colour isn’t random — it’s a hash of the project name, so the same project always gets the same shade. After a while you stop reading the title bar and just recognise the project by its tint:
local h=$(printf '%s' "$name" | cksum | cut -d' ' -f1)
local idx=$(( h % ${#palette} + 1 ))
Before tinting it stashes the original background, so when Claude exits everything goes back exactly how it was.
Resume, or start fresh
Resuming is what I want most of the time, so it’s the default — hit Enter and you’re back in the last thread. But every so often I want a clean session in a project, not the conversation I left half-finished. So after you pick the project, cc asks one more thing: resume, or start new? Enter takes the default; one key down starts fresh.
mode=$(printf '%s\n' 'Resume session' 'New session' | fzf --height=20% --reverse)
if [[ $mode == 'New session' ]]; then claude; else claude -r; fi
Two lines glued onto the end. That’s the whole feature.
Why so small
I could have reached for a session manager, or a TUI, or some MCP thing. But this is the whole problem: list my sessions, let me pick one, make the window obvious, resume. zsh and fzf already do the heavy lifting — I just glued them together. It’s been the most-used fifty-odd lines on my machine for weeks.
The idea isn’t mine. I’ve leaned on zoxide — the z command — for years to jump straight to a directory by frecency instead of typing out paths. cc is that same instinct pointed at Claude sessions instead of folders. If z isn’t in your shell yet, start there; it’s the thing I’d miss most.
The full function lives in my dotfiles. If you want it, the shape above is basically all of it.
Leave a Reply