Navigate any Claude Code session as a numbered file-tree in your terminal — and resume from any node.
A finished Claude Code session can run thousands of turns across hours of work. Linear /wrap summaries flatten that into prose and lose the branches, dead-ends, and good-but-discarded ideas. agent-tree parses the session JSONL into a tree-style hierarchy you read directly in your terminal: each user-prompt is a phase, each segment underneath is a sub-action, and any node you've previously resumed from is marked with ⭐. Pick a number, and the resume markdown lands on your clipboard ready to paste into a fresh claude session.
Built for Claude Code today. Designed to extend to Codex / Gemini sessions tomorrow — hence the agent-neutral name.
If an LLM agent landed on this README from a bare repo URL, jump to For agents (LLMs handed this URL) for an identity block, self-test sequence, MCP tool schemas, and common task recipes.
agent-tree · session fd8b7e83 · 8602 events · 1916 turns · 210 nodes · 2707 min
1. 🎯 Build agent-tree per SPEC.md v0.3 (root)
2. ├─ "Read SPEC.md — self-contained spec v0.3 …" (23 actions · 21 files · 19min) T0 events 0–40
3. ├─ "Implement milestones M1 through M5 end-to-end" (24 actions · 19 files · 14min) T+1h 8m events 1362–1494
4. ├─ ⭐ "Must run strictly inside the terminal" (15 actions · 15 files · 12min) T+23h 43m events 5885–5918
5. ├─ "Layout is secondary — think file-tree hierarchy" (1 action · 1 file · 3min) T+24h 44m events 6583–6587
6. └─ ⭐ "Polish the output carefully" (9 actions · 9 files · 4min) T+43h 17m events 7077–7144
Pick a number to copy that node's resume context.
N → continue mode (preserve decisions, change direction)
N fork → fork mode (discard subsequent turns)
N c / N f → shorthand
Phase headers are cyan on TTY, ⭐ marks are yellow, T+1h 8m / events 0–40 are dimmed. --phases-only collapses sub-actions for fast navigation; default view expands them.
npx -y @seungwoolee/agent-tree --listUseful for a quick check without committing to a global install. The first run fetches the package; subsequent runs use the npm cache.
npm install -g @seungwoolee/agent-treeTwo bins are exposed: agent-tree (primary) and atree (alias).
The plugin manifest ships an MCP server so the tools surface natively in every Claude Code session — no subprocess spawn, no --no-llm juggling.
~/.claude/plugins/local/ is not auto-scanned, so a plain git clone there will not register the plugin. The canonical registration path uses Claude Code's plugin CLI:
# Option A — directly from GitHub (recommended)
claude plugin marketplace add github:lifrary/agent-tree
claude plugin install agent-tree@agent-tree
# Option B — from a local clone (contributors / live dev)
git clone https://github.com/lifrary/agent-tree
cd agent-tree
npm install && npm run build # dist/*.js ships in git too — optional for Option A
claude plugin marketplace add "$PWD"
claude plugin install agent-tree@agent-treeRestart Claude Code. The plugin loader only spawns MCP servers at session start, so changes to installed_plugins.json need a restart to take effect.
After restart, /mcp should list agent-tree with status connected and 5 tools beneath it. Or invoke the tool directly in chat:
> Use agent_tree_list with cwd="/path/to/any/project"
Claude Code calls the tool and returns a numbered file-tree of that project's most-recent session.
If the tools don't surface:
- Confirm the plugin is CLI-registered and enabled:
claude plugin list | grep agent-tree # → should show "Status: ✔ enabled"
- Confirm the cache has the MCP server file (version-agnostic glob):
ls ~/.claude/plugins/cache/agent-tree/agent-tree/*/dist/mcp-server.js
- Restart Claude Code (the plugin loader only spawns MCP servers at startup).
- After a version bump, refresh the cache.
claude plugin installis idempotent — re-running it on an already-registered plugin is a silent no-op, so uninstall first:claude plugin uninstall agent-tree@agent-tree claude plugin install agent-tree@agent-tree
- Smoke-test the published tarball end-to-end. If you cloned this repo, the bundled slash command
/mcp-smokeruns a clean/tmpinstall + spec-compliant MCPinitialize+tools/list+ 5-tool assertion. Otherwise seeRELEASING.mdStep 7 for the manual JSON-RPC sequence.
# Smart default — interactive picker for the latest session of the current project
agent-tree
# Print the file-tree to stdout (skill / pipe friendly)
agent-tree --list
# Use a specific session by UUID prefix
agent-tree 69c2f35e --list
# Phase-only view for fast navigation
agent-tree --list --phases-only
# Resume from a node by display number — markdown to stdout, clipboard on TTY
agent-tree 69c2f35e --snapshot 7 --mode continue
agent-tree 69c2f35e --snapshot 12 --mode fork
# Filter long sessions
agent-tree 69c2f35e --list --filter "auth"
# Pick history across every session
agent-tree --picks
# Compare two nodes
agent-tree 69c2f35e --diff 7 12
# Remove a star you regret
agent-tree 69c2f35e --unstar 7Default routing:
- TTY stdout (you in your terminal) → interactive picker (
--tui) - non-TTY (piped, redirected, or invoked from a skill) → list mode (
--list)
Snapshots auto-copy to your system clipboard on TTY (pbcopy / xclip / clip); paste into a fresh claude session as the first message and resume.
| Mode | When to use |
|---|---|
| Continue | Decisions up to this point were good — keep going from here, skipping whatever the session did next. |
| Fork | Re-try this moment with the subsequent turns erased, exploring a different direction entirely. |
The pick is recorded either way; ⭐ is GitHub-style binary (no per-mode bookkeeping).
| Flag | Default | Notes |
|---|---|---|
<session-id> |
smart default | UUID or short prefix; positional |
--latest |
— | force globally most-recent session |
--pick |
— | interactive picker over recent sessions |
--list |
(auto on non-TTY) | print file-tree to stdout |
--snapshot <id> |
— | print one node's resume markdown to stdout |
--mode <continue|fork> |
continue |
snapshot mode |
--tui |
(auto on TTY) | interactive readline picker |
--phases-only |
off | hide sub-actions, show only user-prompt headers |
--filter <kw> |
— | case-insensitive label/time/range match |
--no-group |
grouped | disable consecutive same-file collapsing |
--no-color |
colored on TTY | force-disable ANSI |
--picks |
— | list every pick across every session |
--unstar <id> |
— | remove ⭐ from a previously picked node |
--diff <a> <b> |
— | summarise event range / files / tools between two nodes |
--no-llm |
LLM on if key set | skip Anthropic call, heuristic labels only |
--model <name> |
claude-sonnet-4-6 |
Anthropic model for LLM labeling |
--max-llm-tokens <n> |
50000 |
input token budget ceiling |
--redact-strict |
off | add PII patterns (email/phone/card/SSN/RRN) |
--redact-dryrun |
off | print redaction hit counts to stderr |
--include-sidechains / --flatten-sidechains / --drop-sidechains |
include | subagent (Task-tool) handling |
--dry-run |
off | run pipeline, emit no output |
--dump-json <dir> |
— | dump intermediate artifacts (raw / graph / segments / tree) |
-v, --verbose / --trace |
— | log levels |
Run agent-tree --help for the canonical list. The flag definitions live in src/cli/options.ts.
When this plugin is installed, five tools surface natively in every Claude Code session:
| Tool | Purpose |
|---|---|
agent_tree_list |
numbered file-tree of a session (with phase grouping, filter, ⭐) |
agent_tree_snapshot |
resume markdown for one node (continue/fork) + git context, records pick |
agent_tree_picks |
every recorded pick across every session |
agent_tree_diff |
event range / files / tools between two nodes |
agent_tree_unstar |
remove ⭐ from a previously picked node |
Example invocation from chat:
> Use agent_tree_list with cwd="/Users/alice/Code/myproject", phasesOnly: true
The tools are zod-validated. Full schemas + agent-friendly recipes live in For agents below; canonical definitions live in src/mcp/server.ts.
The bundled skill (skills/agent-tree/SKILL.md) tells Claude Code to prefer MCP tools and fall back to the CLI when the server isn't connected.
This section is for LLM agents who've been pointed at this repo with little other context. Top-down: identity → self-test → tool schemas → recipes → constraints. Everything below is intentionally machine-friendly (literal commands, fenced JSON shapes, table-driven recipes).
package @seungwoolee/agent-tree
repo https://github.com/lifrary/agent-tree
version 0.1.2 (as of 2026-04)
bins agent-tree, atree
runtime Node.js ≥ 20
mode terminal-only — no browser, no HTML, all output is text/markdown
data reads ~/.claude/projects/<encoded-cwd>/*.jsonl
license MIT
The encoded-cwd rule: a session's JSONL lives at ~/.claude/projects/<cwd-with-slashes-replaced-by-dashes>/<session-uuid>.jsonl. Example: cwd /Users/alice/Code/myproject → ~/.claude/projects/-Users-alice-Code-myproject/. The CLI's smart-default uses the caller's cwd to find the right encoded directory automatically.
If you have shell access, run this sequence to confirm install + spot-check capability. Uses an isolated /tmp dir (no global pollution) — the same pattern the bundled /mcp-smoke slash command uses, so this path is regression-tested every release:
mkdir -p /tmp/atree-probe && cd /tmp/atree-probe
npm init -y >/dev/null && npm install @seungwoolee/agent-tree
# 1) Identity — package version.
./node_modules/.bin/agent-tree --version
# → 0.1.2 (or newer)
# 2) Bin runs (no JSONL data required).
./node_modules/.bin/agent-tree --help | head -20
# → Usage / Options / commands (commander-style)
# 3) Data probe — does any session JSONL exist on this machine?
./node_modules/.bin/agent-tree --list 2>&1 | head -5
# → tree header, or "(no session in this project — falling back to globally
# latest: <uuid>...)" if the cwd lacks data, or "No agent-tree session JSONL
# files found..." on a totally fresh machine.npx -y @seungwoolee/agent-tree --version does not work as you'd expect: the package ships two bins (agent-tree and atree) so npx 10+ can't auto-resolve from the unscoped package name alone, and --version falls through to npx's own version output (returning the npm version 10.9.4, not 0.1.2). The form npx -y @seungwoolee/agent-tree agent-tree --version works for --version and --help (because commander short-circuits on those flags before parsing positionals), but breaks --list because npx passes the bin name through as an arg and commander reads it as the [session-id] positional. The isolated-install form above sidesteps all of that.
For users who insist on a one-shot global install: npm install -g @seungwoolee/agent-tree && agent-tree --version is the simple form.
Three ways an LLM can invoke agent-tree:
- CLI — when you have shell access. Smart-default picks the latest session in
cwd's project. Pipe tohead/grepfor filtering. - MCP tools — when you ARE Claude Code with this plugin installed. Five
agent_tree_*tools, zod-validated, no subprocess spawn. - Skill — auto-loaded by Claude Code when this plugin is installed. The skill prompt at
skills/agent-tree/SKILL.mddefines when to invoke and how to format output.
If you're a non-Claude-Code agent (Codex, Gemini, custom): only the CLI path is available today. v0.2 will add direct adapters for non-Claude session formats — see Roadmap.
All five tools are stdio-only (the plugin loader spawns a child process). Inputs are zod-validated; pass JSON. Responses follow the MCP envelope:
Render a numbered ASCII tree of a session. Phase headers (user prompts) at depth 1, sub-actions at depth 2.
{
"cwd": "string", // required — caller cwd, used for smart-default session pick
"sessionId": "string?", // optional — UUID prefix (≥8 chars). Omit for cwd's latest.
"phasesOnly": "boolean?", // optional — show only phase headers, hide sub-actions
"filter": "string?" // optional — case-insensitive keyword on labels / time / range
}Returns a tree like:
Session 69c2f35e (-Users-alice-Code-myproject)
agent-tree · session 69c2f35e · 230 turns · 26 nodes · 62 min
1. 🎯 Setup auth flow (root)
2. ├─ "Wire up Auth0 redirect URLs" (15 actions · 12 files · 8 min) T0 events 0–48
...
(⭐ = previously picked — 3 starred, 7 total picks)
Get the resume markdown for a specific node. Records the pick (⭐) for future display.
{
"cwd": "string", // required
"nodeId": "string", // "7" (display number) or "n_007" (raw id)
"mode": "continue|fork", // continue = preserve decisions; fork = discard subsequent turns
"sessionId": "string?"
}Returns markdown that pastes directly into a new claude session as the first message. Show it to the user verbatim inside a fenced code block — any reformatting (line break tweaks, prose around it) breaks tool-use blocks.
List every pick across every session. Shows session id × node × mode × timestamp.
{
"cwd": "string?" // optional — currently unused, kept for shape symmetry
}Summarize what happened between two nodes (event range, files touched, tools used).
{
"cwd": "string",
"from": "string", // "7" or "n_007"
"to": "string", // "12" or "n_012"
"sessionId": "string?"
}Remove the ⭐ marker from a previously picked node (deletes its pick history entries).
{
"cwd": "string",
"nodeId": "string",
"sessionId": "string?"
}| User says | What to call |
|---|---|
| "show me what we worked on yesterday in " | agent_tree_list({ cwd: "<repo>", phasesOnly: true }) |
| "go back to where we set up auth" | agent_tree_list({ cwd, filter: "auth" }) then agent_tree_snapshot |
| "I want to try a different direction at step 7" | agent_tree_snapshot({ cwd, nodeId: "7", mode: "fork" }) |
| "what changed between steps 3 and 11?" | agent_tree_diff({ cwd, from: "3", to: "11" }) |
| "remove the star from node 4" | agent_tree_unstar({ cwd, nodeId: "4" }) |
| "show me all my saved bookmarks" | agent_tree_picks({}) |
After agent_tree_list, show the tree verbatim in a fenced code block — wide-char alignment + ⭐ + ANSI-stripped output is meant to be displayed, not paraphrased. Same for agent_tree_snapshot markdown — the user pastes it into a new session, and reformatting breaks it.
- No
~/.claude/projects/data → no output. agent-tree reads from there. A fresh machine (no prior Claude Code sessions) gets a friendly "no JSONL found" message; there's no fallback data source. - In-progress sessions are lossy. The tool needs a finalized JSONL. Don't run it against a session that's still being written — the parse will be incomplete or fail.
- Ambiguous session prefix → error. If
sessionId: "fd"matches multiple sessions, the tool returns an error asking for a longer prefix. Use ≥8 chars for stability. - LLM labeling costs money. Default skill mode is
--no-llm(heuristic labels). Don't enable--llmwithout warning the user about cost (~$0.10–0.20 per typical 200-turn session with Sonnet). - Snapshots contain redacted but verbatim user text. 16 default redaction patterns strip secrets;
--redact-strictadds 5 PII patterns (email/phone/card/SSN/RRN). Always show a share warning if the snapshot is going somewhere external. - MCP path resolution. When this plugin is installed via
claude plugin marketplace add github:...,${CLAUDE_PLUGIN_ROOT}resolves to the cache path under~/.claude/plugins/cache/agent-tree/agent-tree/<version>/. When installed from a directory marketplace (claude plugin marketplace add "$PWD"), it resolves to the absolute source path frozen at registration time. A folder rename does not auto-update the directory marketplace registration — re-runclaude plugin marketplace addafter a rename or hand-edit~/.claude/settings.json.
CHANGELOG.md— what changed and why; every pivot has a paper trailskills/agent-tree/SKILL.md— the prompt Claude Code auto-loads when this plugin is installedsrc/mcp/server.ts— canonical MCP tool definitions (zod schemas live here)src/cli/options.ts— canonical CLI flag definitionsRELEASING.md— release sequence + post-publish smokeCONTRIBUTING.md— dev loop + check chain + test guarantees
When ANTHROPIC_API_KEY is set, each segment can carry an LLM-derived label, summary, and suggested next steps. Prompt caching amortizes the system block across every segment so a typical 200-turn session costs ~$0.10–0.20.
--no-llmfor offline / zero-egress.--max-llm-tokens 30000to cap spend.--model claude-haiku-4-5-20251001for ~90% cost reduction.
The heuristic phase labels (taken verbatim from user prompts) are usable on their own — the LLM adds polish, not core functionality.
Snapshot markdown contains the redacted session context, including the verbatim last user-turn of the chosen segment. Defaults strip 16 patterns:
- Anthropic / OpenAI (incl. project keys) / GitHub PAT (classic + fine-grained) / Slack / AWS (access key + temp key) / GCP (API key + OAuth token) / HuggingFace / Stripe / npm API tokens (length-gated, class-boundary-anchored via negative lookahead so trailing
-/_doesn't slip the seam) - Bearer tokens, JWTs (3-part dot-separated, base64url-aware)
- PEM private key blocks
--redact-strict adds 5 PII patterns: email, phone (E.164 + free-form with required separators — split into two regexes to dodge ReDoS), card (Luhn-validated), SSN, and Korean RRN. --redact-dryrun prints hit count per pattern to stderr so you can verify what would be stripped without running for real.
Redaction is applied before truncation — earlier sessions had a regression where 60-char truncation sliced an API key below the 20-char regex floor. Tests in tests/security-hardening.test.ts enforce zero-leak across the pipeline (39 tests including ReDoS fuzz guards and class-boundary anchoring per pattern).
Cache directory (~/.cache/agent-tree/) is created with mode 0700. The pick history at ~/.cache/agent-tree/picks/<sid>.jsonl is per-session and append-only.
Flags can be set via YAML config or environment variables. Precedence:
CLI flags > env vars > ~/.config/agent-tree/config.yaml > <project>/.agent-tree.yaml > defaults
Default schema lives in src/config/schema.ts.
JSONL (session)
│
▼
[1] Reader streaming parse + DAG via parentUuid;
│ indirect-cycle guard (iterative DFS)
│ → RawEvent[] + SessionGraph
▼
[2] Analyzer 6 boundary signals (gap / file-Jaccard / topic-shift /
│ slash-cmd / sidechain transition / turn-cap)
│ → TopicSegment[]
▼
[3] Tree builder group segments into phases (user-prompt headers);
│ heuristic labels; LLM overlay (optional);
│ redactor applied here, before truncation
│ → MindMap with continue/fork ContextSnapshot per node
▼
[4] Renderer numbered file-tree (text.ts) — wide-char-aware,
│ consecutive-file grouping, ANSI on TTY, ⭐ for picks,
│ phase metadata (N actions · M files · T min)
▼
Output: stdout (markdown for snapshot, file-tree for list/tui)
clipboard (TTY auto-copy via pbcopy / xclip / clip)
MCP tools (when running as Claude Code plugin; 3-entry LRU cache
keyed on jsonl mtime so in-progress sessions invalidate)
Source layout is documented inline in src/ module headers; CHANGELOG.md explains why the current shape exists (every pivot left a paper trail).
- v0.1 — agent-tree on Claude Code sessions: file-tree, ⭐ picks, MCP plugin, snapshot resume, audit-hardened (v0.1.0–v0.1.2 shipped)
- v0.2 — Codex JSONL adapter (
~/.codex/sessions/shape) +SessionSourceinterface so the reader stops being Claude-specific - v0.3 — Gemini session adapter (assuming a stable on-disk format emerges)
- v1.0 —
--share-safemode that strips raw user-text from snapshots for external sharing
The agent-tree name is the long-term commitment; multi-agent support is the reason it isn't claude-tree.
git clone https://github.com/lifrary/agent-tree
cd agent-tree
npm install
npm test # vitest, 134 tests / 12 files at last green
npm run typecheck # tsc --noEmit, strict
npm run lint # eslint
npm run build # esbuild → dist/cli.js + dist/mcp-server.js
./dist/cli.js --helpTwo maintainer slash commands ship in .claude/commands/ (tracked, version-controlled, runnable by anyone with the repo cloned):
/pre-publish-audit— version sync (6 fields), exact tarball file-set vs frozen baseline, dist freshness vs source mtime, MCP manifest sanity, prepublishOnly chain/mcp-smoke— clean/tmpinstall of the published tarball + spec-compliant MCPinitialize+tools/list+ 5-tool assertion
Contributor workflow: CONTRIBUTING.md. Release procedure: RELEASING.md. Decision history: CHANGELOG.md.
MIT © 2026 Seungwoo Lee