carn
A terminal UI for browsing, searching, and managing your local Claude and
Codex session archives.
What it does
You accumulate hundreds of AI coding sessions across different projects.
They live as raw JSONL files scattered under ~/.claude/projects/ and
~/.codex/sessions/. carn indexes them into a local SQLite store and
gives you a fast, searchable TUI to browse conversations, read
transcripts, and resume sessions — without leaving the terminal.


Features
Browsing
- Conversation list with model, token count, duration, tool usage, and
git branch
- filter by provider, project, model, version, git branch, plan
status, or multi-part conversations — with regex support
- Automatic grouping of related sessions into multi-part conversations
- Subagent detection and display
- Split and fullscreen layout modes with
tab to switch focus
Search
- Search (
/) — debounced full-text search across all message content
via the SQLite FTS index; an empty query returns to the full
conversation list
- Structured filters (
f) handle provider, project, model, version,
git branch, plan, and multi-part narrowing
- Search preview snippets in results
Transcript viewer
- Markdown rendering with syntax highlighting
- Toggleable sections: thinking blocks, Tool calls, tool
Results, sidechain messages, system messages, plans
- Diff display with colored additions and removals
- Search within transcript (
/) with next / N previous match
navigation
Actions
- resume a session in the original provider with correct working
directory — works for both Claude and Codex sessions
- Copy to clipboard — pick a target: conversation, plan,
or raw source files
- export conversation as Markdown
- open conversation, plan, or raw files in
$EDITOR
- Resync from source directories without restarting
Stats
- Fullscreen analytics dashboard (
S from the browser)
- Six tabs: Overview, Activity, Sessions, Tools, Cache, Performance —
switch with
ctrl+f / ctrl+b
- Time range selector (
r): 7d, 30d, 90d, all
- Filter overlay (
f) narrows by provider, project, model, version, and
more — with a Split by row that re-renders supported charts as
stacked series grouped by Provider, Version, Model, or Project
- Tokens by model, project, and (provider, version) charts, plus a
heaviest session table — press
enter on the selected row to open it
- Daily activity line chart and weekday × hour heatmap
- Session duration and message-count histograms, prompt growth and
billed-tokens-per-turn lanes with cyclable
avg / p50 / p95 /
p99 / max modes
- Tool call shares, error and rejection rates
- Cache lanes: daily rate, main vs subagent, reuse and hit rate by
duration, first-turn cold cache by Claude version
- Performance scorecard with outcome, discipline, efficiency, and
robustness lanes
- Pinned Metric detail lane below the charts that explains the
selected lane; move focus with
h / l, cycle the lane metric with
m where supported
First launch
On first run, carn shows an import overview with source and archive paths,
configuration status, and file counts. Press enter to import, or
configure settings before proceeding.
Installation
Homebrew (macOS and Linux)
brew install rkuska/carn/carn
The Homebrew tap installs a source formula and builds carn locally with Go.
Binary download
Download a pre-built binary from
Releases and place it in your
$PATH.
From source
Requires Go 1.25.2 or later. SQLite is bundled — no external dependencies.
go install github.com/rkuska/carn@latest
Or build manually:
git clone https://github.com/rkuska/carn
cd carn
go build -o carn .
On first launch, carn scans source directories and builds its canonical
store at ~/.local/share/carn/. Subsequent launches detect changes and
rebuild incrementally.
Configuration
Configuration is optional. All settings have sensible defaults.
Create a config file at ~/.config/carn/config.toml
(or $XDG_CONFIG_HOME/carn/config.toml):
# Source and archive directory paths.
[paths]
# archive_dir = "~/.local/share/carn"
# claude_source_dir = "~/.claude/projects"
# codex_source_dir = "~/.codex/sessions"
# log_file = "~/.local/state/carn/carn.log"
# Display preferences.
[display]
# Go time format for timestamps shown in headers and metadata.
# timestamp_format = "2006-01-02 15:04"
# Number of loaded transcripts to keep in the browser cache.
# browser_cache_size = 20
# Search behavior.
[search]
# Milliseconds to wait before triggering a deep search query.
# deep_search_debounce_ms = 200
# Logging behavior.
[logging]
# Log verbosity: debug, info, warn, error.
# level = "info"
# Maximum log file size in megabytes before rotation.
# max_size_mb = 10
# Number of rotated log files to keep.
# max_backups = 3
Set DEBUG=1 to force debug-level logging.
Keybindings
Press ? at any time to open the help overlay.
Browser
| Key |
Action |
j / k |
Move up / down |
gg / G |
Jump to top / bottom |
ctrl+f / ctrl+b |
Page down / up |
enter |
Open conversation |
/ |
Search conversations |
ctrl+l |
Clear active search |
f |
filter dialog |
O |
Toggle fullscreen / split layout |
tab |
Toggle focus between list and transcript |
r |
resume session in provider |
S |
Stats dashboard |
R |
Resync conversations from source |
o |
open session in editor |
? |
Help |
q / ctrl+c |
Quit |
Transcript viewer
| Key |
Action |
j / k |
Scroll up / down |
gg / G |
Jump to top / bottom |
ctrl+f / ctrl+b |
Page down / up |
/ |
Search transcript |
n / N |
next / previous match |
t |
Toggle thinking blocks |
T |
Toggle Tool calls |
R |
Toggle tool Results |
p |
Toggle plans |
s |
Toggle sidechain messages |
m |
Toggle system messages |
v |
Toggle selection mode — hide borders for clean mouse copy |
y |
Copy — choose target: conversation, plan, or raw |
o |
open — choose target: conversation, plan, or raw |
e |
export as Markdown |
r |
resume session |
q / esc |
Back to browser |
Copying text from the transcript
y copies the visible conversation, a selected plan, or the raw source
files to the clipboard.
v toggles selection mode — hides pane borders and line padding so you
can drag with the mouse to select clean text. Press v again to restore
the framed view.
- Native terminal selection is also available as a fallback: hold Option
while dragging on macOS Terminal and iTerm2, or Shift while dragging
on most Linux terminals, to bypass the TUI and select directly.
Stats view
| Key |
Action |
ctrl+f / ctrl+b |
Next / previous tab |
j / k |
Scroll content up / down |
g / G |
Jump to top / bottom |
h / l |
Move between metric-detail lanes |
r |
Time range selector |
f |
filter and split-by overlay |
m |
Cycle metric on the focused lane |
enter |
Open focused token-heavy session (overview tab) |
? |
Help |
q / esc |
Back to browser |
Import overview
| Key |
Action |
enter |
Import / continue |
c |
configure settings in $EDITOR |
? |
Help |
q / ctrl+c |
Quit |
How it works
Raw sessions (~/.claude/projects/, ~/.codex/sessions/)
-> Scan and group by project + slug
-> Parse metadata and messages
-> Canonical SQLite store (~/.local/share/carn/)
|- Conversation catalog
|- Transcript blobs
|- Full-text search index
-> TUI browser, viewer, deep search
Source directories are never modified. All processed data lives in the
archive directory and can be rebuilt from source at any time.
Development
Run the canonical test suite with coverage gating:
go run ./cmd/testsuite
Refresh the committed coverage baseline after an intentional increase:
go run ./cmd/testsuite -update
Enable the repo pre-commit hook once per clone:
git config core.hooksPath .githooks
The hook runs:
go fix ./...
golangci-lint run ./...
GOPLS_LINT (gopls info-level diagnostics)
go run ./cmd/testsuite
The hook requires a clean working tree before commit because go fix ./...
may rewrite tracked files. When it does, the hook stages those go fix
changes before running lint and coverage.
License
GPL-3.0. See LICENSE.