A local web app for browsing, searching, and managing the session logs your
coding agents leave behind — Claude Code (~/.claude/projects/), Codex
(~/.codex/sessions/), Gemini CLI (~/.gemini/tmp/), and opencode
(~/.local/share/opencode/opencode.db).
Everything runs on your machine. No data leaves your computer, and no API calls are made. Works on macOS, Linux, and Windows.
The header has four tabs — Claude, Codex, Gemini, opencode — each with the same Projects / Search / Stats pages.
Projects (/) lists every project folder with its real directory path,
resolved by reading the cwd recorded inside each session rather than trusting
the lossy dash-encoded folder name. Two views, toggled by a pill at the top and
remembered in localStorage:
- Table — sortable by path, sessions, size, age, or last activity. Click a header to sort, click again to flip direction.
- Tree — projects nested under their parent directories, with aggregated
session count, size, and most recent activity per folder. Single-child chains
collapse into one row, so
/Users/me/Desktop/GitHubdoesn't cost three lines. Separators follow the logs themselves, so Windows paths keep their backslashes even when viewed from another OS.
Sessions (/p/[projectId]) lists a project's sessions with title (alias →
ai-title → first user prompt), message count, model, git branch, input/output
tokens, file size, and session UUID.
Transcript (/p/[projectId]/s/[sessionId]) renders the JSONL as readable
messages:
- Markdown formatting — bold, italic, lists, fenced and inline code, links.
- Slash commands (
/clear,/model, …) merged with their stdout into one compact terminal-style block. - Tool calls merged with their matching results in a single card. Long results
collapse behind a
▶toggle with a one-line preview. - Collapsible "thinking" blocks.
- Filter pills: messages (default, hides meta and tool-result chatter), tools (anything involving a tool call), all (raw).
- Sticky header and filter bar, plus floating ↑/↓ buttons, so long sessions stay navigable.
Case-insensitive substring scan across every line of every .jsonl. It matches
anywhere — user prompts, assistant replies, tool names, file paths, error
messages, session UUIDs, git branches — and each hit links to its session.
Five summary tiles aggregated across every session log on disk: projects, sessions, total size, total input tokens, total output tokens.
Rename gives any session a custom display name. Click Rename beside a
title to edit inline; an empty name clears the alias and falls back to the
auto-generated title. The name is stored in a sidecar
(~/.claude/projects/_aliases.json, which Claude Code ignores) and mirrored
into the .jsonl as a new ai-title line, so Claude Code's /resume picker
shows the same name. The filename and session UUID are never changed.
Delete removes a session or a whole project after a confirmation dialog
showing the full path. It uses fs.rm with retries, which absorbs the
transient file locks Windows AV and OneDrive sync tend to produce.
Mirrors every feature above for Codex sessions in ~/.codex/sessions/, handling
the format differences transparently:
- Codex writes a flat date tree (
sessions/YYYY/MM/DD/rollout-*.jsonl) rather than per-project folders, so sessions are grouped into projects by their realcwd, read from each rollout'ssession_metaline. - The viewer understands Codex's event stream: user messages, agent replies,
collapsible reasoning, and
function_callcards merged with their output. - Renames live in
~/.codex/sessions/_codex_aliases.json. Codex has no/resumetitle to mirror into, so the rollout.jsonlis never modified.
Same again for Gemini CLI chats under ~/.gemini/tmp/:
- Gemini already stores one folder per project
(
tmp/<project>/chats/session-*.jsonl), and~/.gemini/projects.jsonmaps each to its real working directory, which the app shows as the project path. - Each chat log is an append journal — a header line,
$setpatches, then one object per message. The viewer reconstructs the conversation from it: prompts, replies, collapsible thoughts, andtoolCallsmerged with their results. - Context tokens are shown instead of input tokens. Gemini records cumulative context size per turn, so the app reports the peak rather than a meaningless sum. Output tokens are summed normally.
- Renames live in
~/.gemini/_gemini_aliases.json; the chat log is untouched.
opencode keeps no log files at all — everything lives in one SQLite database at
~/.local/share/opencode/opencode.db, read here through Node's built-in
node:sqlite (no extra dependency):
- Recent opencode versions file every session under a single
globalproject whose worktree is/, so that table is useless for grouping. Projects are grouped by each session's recordeddirectoryinstead, which is the real working directory. - A session is a
sessionrow, a turn is amessagerow, and every text / reasoning / tool block is apartrow holding JSON. The viewer replays them in order: prompts, replies, collapsible reasoning, and tool calls merged with their output. - Size is the stored JSON weight of a session's messages and parts, since there is no file to measure. Token counts come from the session row.
- opencode auto-titles sessions and its own
/renameoverwrites that same field, so Rename writes straight tosession.title— the change shows up in the opencode TUI too. Deleting a session or project deletes those rows; messages and parts cascade with them.
- Node.js 20+ (
node -v). - At least one agent's storage —
~/.claude/projects/,~/.codex/sessions/,~/.gemini/tmp/, or~/.local/share/opencode/opencode.db. Each appears the first time you run that agent. Tabs whose storage is missing simply render empty. The opencode tab needs Node.js 22.5+ fornode:sqlite.
git clone https://github.com/POSTTTT/claude-code-sessions
cd claude-code-sessions
npm installOneDrive caveat (Windows only). If you cloned into a OneDrive-synced path like
C:\Users\<you>\OneDrive\Documents\GitHub\…,npm installmay hang silently — file-on-demand sync intercepts every small write npm makes. Either pause syncing for two hours from the tray icon and retry, or move the repo somewhere unsynced such asC:\dev\claude-code-sessions.
npm linkThis installs a global claude-sessions command pointing at this copy of the
project. npm install -g . from the project folder does the same thing.
claude-sessionsNo cd, no npm run. The server defaults to http://localhost:3000 and your
browser opens automatically once it's ready. Ctrl+C stops it.
| Command | What it does |
|---|---|
claude-sessions |
Start the dev server + auto-open browser (default) |
claude-sessions --prod |
Start the production server (requires a prior build) |
claude-sessions --build |
Run next build, then start the production server |
claude-sessions --no-open |
Don't open the browser |
claude-sessions --help |
Show the help and the project path |
By default the app reads ~/.claude/projects/, ~/.codex/sessions/,
~/.gemini/tmp/, and ~/.local/share/opencode/. Point it elsewhere with
CLAUDE_HOME, CODEX_HOME, GEMINI_HOME, and/or OPENCODE_DATA_DIR:
# macOS / Linux
CLAUDE_HOME=/Volumes/backups/.claude claude-sessions# Windows
$env:CLAUDE_HOME = "D:\backups\.claude"
claude-sessions- Next.js 15 (App Router) + React 19
- TypeScript, Tailwind CSS
- Server-side filesystem access via server components and Server Actions
- No database, no auth — runs on
localhostonly
The path-to-folder-tree logic has a standalone check:
node src/lib/pathtree.test.mjs- Delete is permanent.
fs.rmremoves the.jsonlfile or the whole project folder. The confirmation dialog shows the full path first. - Rename never rewrites existing content — it appends a single
ai-titleline and leaves every other entry intact. - No auth, single user. The app expects to be reached on
localhost. Don't expose it on a network.
See LICENSE.