Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"name": "Seungwoo Lee"
},
"metadata": {
"description": "Single-plugin marketplace for agent-tree. Navigate any Claude Code session as a numbered tree and resume from any node.",
"version": "0.2.1"
"description": "Single-plugin marketplace for agent-tree. Navigate Claude Code and Codex sessions and generate resume prompts.",
"version": "0.3.0"
},
"plugins": [
{
"name": "agent-tree",
"description": "Visualize a Claude Code session as a numbered tree in your terminal/chat and resume from any node. Terminal-only — no browser.",
"version": "0.2.1",
"description": "Navigate Claude Code and Codex sessions as numbered trees and generate resume prompts. Terminal-only — no browser.",
"version": "0.3.0",
"author": {
"name": "Seungwoo Lee"
},
Expand All @@ -20,7 +20,16 @@
"homepage": "https://github.com/lifrary/agent-tree",
"repository": "https://github.com/lifrary/agent-tree",
"license": "MIT",
"keywords": ["claude", "claude-code", "session", "mindmap", "resume", "fork", "navigation"]
"keywords": [
"claude",
"claude-code",
"codex",
"session",
"mindmap",
"resume",
"fork",
"navigation"
]
}
]
}
15 changes: 12 additions & 3 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
{
"name": "agent-tree",
"version": "0.2.1",
"description": "Visualize a Claude Code session as a numbered tree in your terminal/chat and resume from any node. Terminal-only — no browser.",
"version": "0.3.0",
"description": "Navigate Claude Code and Codex sessions as numbered trees and generate resume prompts. Terminal-only — no browser.",
"author": {
"name": "Seungwoo Lee"
},
"repository": "https://github.com/lifrary/agent-tree",
"homepage": "https://github.com/lifrary/agent-tree",
"license": "MIT",
"keywords": ["claude", "claude-code", "session", "mindmap", "resume", "fork", "navigation"],
"keywords": [
"claude",
"claude-code",
"codex",
"session",
"mindmap",
"resume",
"fork",
"navigation"
],
"skills": "./skills/",
"mcpServers": {
"agent-tree": {
Expand Down
6 changes: 6 additions & 0 deletions .claude/commands/mcp-smoke.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ You are running the agent-tree post-publish MCP smoke test. The goal: prove that

Run this **after `npm publish`** has succeeded. It installs from the registry, not from local source.

The handshake below checks tool presence, not source behavior. Before release,
also run `npm run smoke:release`: its installed-tarball checks cover Claude and
Codex discovery, portable imports, source schemas, and redacted JSON output.
All six tools accept optional `source: "claude" | "codex"`; picks without a
source filter span both.

> **Fixes from Loop 1 + Loop 2 + Loop 3 reviews**:
>
> - **Spec-compliant MCP handshake** (Loop 1): the previous version sent
Expand Down
38 changes: 37 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,43 @@

All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/) and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased] — 0.2.1
## [Unreleased] — 0.3.0

### Added

- A session-source interface separating discovery and log normalization from
analysis, rendering, configuration, and MCP transport.
- Codex rollout support via CLI `--source codex` and MCP `source: "codex"`.
`CODEX_HOME` controls discovery, project filtering uses metadata cwd, and
portable `--file` imports detect Claude Code or Codex automatically.
- Codex message/tool normalization, apply-patch file paths, public reasoning
summaries, compaction markers, duplicate-notification suppression, and
deterministic event identities. Thread IDs remain distinct from root
session IDs. Discovery excludes subagent sessions and symlink entries.
- Source identity in JSON mindmaps and catalogs; source-preserving CLI
snapshot hints and optional source filters for pick history.
- Synthetic adapter, CLI, MCP, and installed-tarball regressions for both
sources. No private rollout fixtures are distributed.

### Fixed

- Tool and file labels redact credentials before truncation, preventing
partial tokens from surviving shorter heuristic labels.
- Interactive picker and discovery fallback messages apply output redaction.

### Breaking

- Pick history is now stored at
`~/.cache/agent-tree/picks/<source>/<session-id>.jsonl`. Flat-directory
history is neither read nor migrated; Claude and Codex UUIDs cannot share
or remove one another's stars.
- Nonempty unrecognized imports require an explicit source instead of
silently producing an empty Claude tree.

This release also includes the previously prepared 0.2.1 changes below.
Publishing is separate from preparing or pushing these versions.

## [0.2.1] — Unreleased preparation

### Toolchain and release verification

Expand Down
28 changes: 23 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ npm test # Vitest 5 — must stay green

Requirements:

- **Node.js ≥22.13.0** for the upcoming 0.2.1 release.
- **Node.js ≥22.13.0**.
- **macOS or Linux** for the full smoke loop. Windows works for the CLI; clipboard / git subprocess paths are platform-shimmed but less exercised.
- CI covers **Node 22, 24, and 26 on Linux and macOS**.
- **ESLint 10** uses flat config; **Vitest 5** runs the tests.
Expand Down Expand Up @@ -57,24 +57,42 @@ If you touch any of these, add a test in `tests/security-hardening.test.ts` (or
- `src/utils/picks.ts` — concurrency / atomicity changes
- `src/utils/safe_path.ts` — path-trust hardening
- `src/mcp/server.ts` — any new tool, session resolution, or analysis cache change
- `src/utils/session_path.ts` / `src/reader/jsonl.ts` — discovery, portable imports, or malformed-input handling
- `src/sources/`, `src/utils/session_path.ts`, and `src/reader/` — discovery, portable imports, or malformed-input handling
- `src/config/loader.ts` / `src/config/schema.ts` — precedence, per-field validation, or security settings
- `src/llm/labeler.ts` / `src/llm/anthropic.ts` — input reservations, token counting, or paid-request handling

The reason: redaction and path-safety bugs are silent failures that bypass every test that doesn't specifically look for them. We learned this the hard way during the v0.1.0 audit (see `CHANGELOG.md` "Post-rebrand audit hardening").

### Routing through canonical helpers

If you add a new code path that analyzes a session, route it through `runPipeline` (MCP uses the analysis/cache helper inside `createServer`). Do **not** call `buildMindMap` directly — it bypasses the pipeline's redaction policy. v0.1.0 had this exact bug for three MCP tools. Catalog discovery is intentionally parse-free, but catalog strings still need redaction before output.
If you add a new code path that analyzes a session, route it through `runPipeline` (MCP uses the analysis/cache helper inside `createServer`). Do **not** call `buildMindMap` directly — it bypasses the pipeline's redaction policy. v0.1.0 had this exact bug for three MCP tools. Claude catalogs are parse-free; Codex catalogs read bounded metadata headers, never analyze the conversation. Catalog strings still need redaction before output.

### Adding a session source

Implement `SessionSource` from `src/sources/types.ts`: `discover`, positive
record identification via `accepts`, and `read` into normalized `RawEvent[]`.
Register it in `src/sources/index.ts`, extend the source ID type and CLI/MCP
choices, and include it in source-isolated pick enumeration. Keep log-format
knowledge inside the adapter/reader, not in tree rendering. Unknown formats
must not silently become empty Claude sessions. Test discovery races, metadata
limits, malformed records, duplicate notifications, and end-to-end exports
using synthetic fixtures. Never commit private rollout logs.

Discovery skips symlink entries and discards detected directory replacements.
These checks are not a filesystem sandbox against another process with write
access to the session directories: portable Node filesystem APIs do not pin
every ancestor during path traversal. Treat imported metadata as untrusted,
retain output redaction, and never execute commands from a transcript.

### Keep the public contracts aligned

- Update CLI validation and MCP schemas together where capabilities overlap.
There are six tools: `agent_tree_sessions`, `agent_tree_list`,
`agent_tree_snapshot`, `agent_tree_picks`, `agent_tree_diff`, and
`agent_tree_unstar`. All per-session tools accept `file` or `sessionId`,
never both; picks takes `{}`. MCP remains heuristic-only.
- Cover portable exports, `CLAUDE_CONFIG_DIR`, UUID-only regular-file
never both. All tools accept optional `source`; picks can filter by source
or list both. MCP remains heuristic-only.
- Cover portable exports, `CLAUDE_CONFIG_DIR`, `CODEX_HOME`, regular-file
discovery (no agent/subagent or symlink entries), strict parse failures,
JSON redaction/no stdout banners, and incompatible CLI flags (exit 2).
JSON is the complete mindmap, not a filtered text view.
Expand Down
70 changes: 56 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# agent-tree

**Navigate any Claude Code session as a numbered tree — and pick up from any point in it.**
**Navigate Claude Code and Codex sessions as numbered trees — and pick up from any point.**

[![npm](https://img.shields.io/npm/v/@seungwoolee/agent-tree.svg?color=cb3837&label=npm)](https://www.npmjs.com/package/@seungwoolee/agent-tree)
[![CI](https://github.com/lifrary/agent-tree/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/lifrary/agent-tree/actions/workflows/ci.yml)
Expand All @@ -21,7 +21,7 @@

A long Claude Code session is hard to look back on. Somewhere in hundreds of messages is the moment right before things went sideways, and scrolling the transcript won't find it for you.

**agent-tree** reads the session log Claude Code already keeps and turns it into a numbered outline: every prompt you typed, with the reads, edits and commands it triggered underneath. Every numbered row is a step. Pick one and you get a ready-to-paste prompt that carries on from that moment in a fresh session — or tries it another way.
**agent-tree** reads the session logs Claude Code and Codex already keep and turns them into numbered outlines: every prompt you typed, with the reads, edits and commands it triggered underneath. Every numbered row is a step. Pick one and you get a ready-to-paste prompt that carries on from that moment in a fresh session — or tries it another way.

<table>
<tr>
Expand Down Expand Up @@ -78,7 +78,7 @@ API keys, tokens and card numbers are stripped before anything is shown, copied
npm install -g @seungwoolee/agent-tree
```

The npm release needs Node.js 20 or later. To use what is on `main` right now, including everything in [What's new in 0.2](#whats-new-in-02), install from source instead. `dist/` is committed, so there is no build step:
The published 0.1.x release needs Node.js 20 or later. Source builds need Node.js 22.13 or later and include [Codex support](#codex-sessions). Until the next npm release, install from source. `dist/` is committed, so there is no build step:

```bash
git clone https://github.com/lifrary/agent-tree
Expand Down Expand Up @@ -113,9 +113,49 @@ agent-tree 3f9c2a71 --list # a specific session, by ID prefix

If `ANTHROPIC_API_KEY` is set, agent-tree also asks Claude for short step labels, which bills your Anthropic account. Add `--no-llm` to skip that. `agent-tree --help` lists every option.

## Codex sessions

Discovery defaults to Claude Code. Select Codex explicitly, or import a file
and let agent-tree detect its format:

```bash
agent-tree --source codex --sessions --limit 10
agent-tree --source codex --cwd ~/Code/api --no-llm --list
agent-tree --source codex 3f9c2a71 --no-llm --snapshot 7 --mode fork
agent-tree --file ./rollout.jsonl --no-llm --strict --json
agent-tree --source codex --picks
```

Codex discovery reads metadata headers from
`<CODEX_HOME or ~/.codex>/sessions/YYYY/MM/DD/rollout-<timestamp>-<uuid>.jsonl`.
It excludes subagent sessions and symlinks; explicit `--file` can inspect a
subagent export. `--cwd` matches the working directory recorded in the header.
Archived sessions are not scanned; open those with `--file`.

Messages, tool calls/results, patch file paths, and public reasoning summaries
are normalized into the same analysis pipeline as Claude logs. Duplicate
`event_msg` message notifications are not counted again. Compaction summaries
are retained as system events; replacement history is not replayed. Encrypted
reasoning is not decoded. A rollout is a chronological log, not a reconstructed
cross-session fork tree.

Continue/fork output is a **copy-paste context prompt**, not a native
`codex resume`/`codex fork` operation, and does not restore files. Claude and
Codex stars are isolated under
`~/.cache/agent-tree/picks/<source>/<session-id>.jsonl`. Old flat-directory
star history is not read or migrated.

JSON mindmaps and catalog entries identify their `source`.
All MCP tools accept optional `source: "claude" | "codex"`. Omit it for
Claude discovery or automatic file detection; `agent_tree_picks({})` lists
both sources. An explicitly selected source that disagrees with a recognized
file header is rejected. For unknown/headerless exports, specify the source.

## What's new in 0.2

0.2.1 (October 2026) is on `main` and ships to npm with the next release; [install from source](#install) to use it today.
The 0.2.1 preparation work (October 2026) is included in the current source
alongside Codex support. npm publication is still pending;
[install from source](#install) to use it today.

- **Browse sessions across projects.** `agent-tree --sessions` lists your recent sessions instantly, without opening them. Claude gets the same view through the new `agent_tree_sessions` tool.
- **Open any session file.** `--file` reads a session log from anywhere, such as one a teammate exported, and `--cwd` points at another project without changing directory.
Expand Down Expand Up @@ -268,7 +308,8 @@ flowchart LR
| `<session-id>` | smart default | UUID or prefix (4+ characters; 8+ is safer) |
| `--latest` | — | the most recent session across all projects |
| `--pick` | — | choose from recent sessions interactively |
| `--file <path>` | — | read a Claude Code JSONL file directly (new in 0.2) |
| `--file <path>` | — | read a Claude Code or Codex JSONL file; auto-detect its source |
| `--source <claude\|codex>` | Claude discovery; automatic file detection | select the session source |
| `--cwd <dir>` | current directory | project for discovery and `.agent-tree.yaml` (new in 0.2) |
| `--sessions` | off | list sessions without analyzing them; all projects unless `--cwd` (new in 0.2) |
| `--limit <n>` | `20` | how many sessions `--sessions` lists (new in 0.2) |
Expand Down Expand Up @@ -349,10 +390,10 @@ If you are an LLM agent who was handed this repository, the notes below give you

```text
package @seungwoolee/agent-tree bins: agent-tree, atree
versions npm 0.1.2 | main 0.2.1 (this README describes main)
versions npm 0.1.2 | main 0.3.0 (this README describes main)
runtime Node.js ≥ 22.13 on main, ≥ 20 for 0.1.x
input <CLAUDE_CONFIG_DIR or ~/.claude>/projects/<encoded-cwd>/<uuid>.jsonl, or --file
output text tree, markdown resume prompts, JSON; MCP tools over stdio
input Claude projects or Codex rollouts; --source selects discovery, --file auto-detects
output text tree, markdown resume prompts, source-tagged JSON; MCP tools over stdio
```

Self-test in an isolated directory:
Expand Down Expand Up @@ -386,8 +427,9 @@ Bare `npx -y @seungwoolee/agent-tree …` works with npm 12, but npm 10 could no
MCP inputs are validated with zod. Success returns `{ "content": [{ "type": "text", "text": "…" }] }`; failure adds `"isError": true`. Catalog results also carry `structuredContent: { sessions: [...] }`, and JSON list results carry `structuredContent: { mindmap: {...} }`. Per-session tools take `sessionId` or `file`, never both, and fall back to the latest session in `cwd`, then the latest overall. `agent_tree_sessions`, `file` and `format` are new in 0.2.

```jsonc
// agent_tree_sessions: list sessions without parsing them, newest first
{ "cwd": "string?", "limit": 20 } // limit: integer 1–1000
// All tools accept optional source: "claude" | "codex".
// agent_tree_sessions: newest first; Codex reads metadata headers only
{ "cwd": "string?", "source": "codex", "limit": 20 } // limit: integer 1–1000

// agent_tree_list: numbered tree; format "json" returns the full redacted mindmap
{ "cwd": "string", "sessionId": "string?", "file": "string?",
Expand All @@ -403,8 +445,8 @@ MCP inputs are validated with zod. Success returns `{ "content": [{ "type": "tex
// agent_tree_unstar: remove a step's star
{ "cwd": "string", "nodeId": "string", "sessionId": "string?", "file": "string?" }

// agent_tree_picks: every star across sessions; takes no arguments
{}
// agent_tree_picks: every star across sources; optional source filter
{ "source": "codex" }
```

`format: "json"` rejects a nonempty `filter` and `phasesOnly: true`. The canonical definitions live in [`src/mcp/server.ts`](./src/mcp/server.ts), and the skill Claude Code loads with the plugin is [`skills/agent-tree/SKILL.md`](./skills/agent-tree/SKILL.md).
Expand All @@ -416,8 +458,8 @@ MCP inputs are validated with zod. Success returns `{ "content": [{ "type": "tex
- [x] **0.1** (April 2026): numbered session tree, continue and fork resume prompts, stars, and a Claude Code plugin with five MCP tools
- [x] **0.2** (October 2026, on `main`): session catalog, portable session files, JSON export, layered configuration, and support for the current Claude Code log format
- [ ] Publish 0.2 to npm
- [ ] A session-source interface, so logs from other coding agents can plug in
- [ ] Codex CLI sessions
- [x] A session-source interface, so logs from other coding agents can plug in
- [x] Codex CLI sessions
- [ ] Gemini CLI sessions

Have an idea or hit a bug? [Open an issue](https://github.com/lifrary/agent-tree/issues).
Expand Down
Loading
Loading