Skip to content
 
 

Repository files navigation

pi-context-tree — git-style /branch, /merge, /crop plus a context panel for pi

pi-context-tree

Git for your agent's context.
Branch off for side-quests, squash the conclusion back as a human-confirmed decision record, and surgically crop bloated tool output — all inside pi.

CI MIT License Node >= 22.19 pi 0.84.3

Why · Features · Demo · Status · Install · Quickstart · Usage · Panel · FAQ · Development · Docs


pi-context-tree is a pi package that turns the session tree into a git-style workflow with a rich context panel. It keeps the working context small, fresh, and relevant, folds side-work back as clean reviewed commits, and never lets lossy auto-summaries touch your source material.

Never mutates your session JSONL — every change is append-only and recoverable, verified by byte-for-byte golden tests against real pi.

Why

As the context window fills, retrieval degrades measurably and non-uniformly — attention is a fixed budget and every token competes for a slice:

  • Context rot (Chroma 2025, cited in Anthropic's context-engineering guidance) — answer quality drops with input length, even on trivial tasks.
  • NoLiMa (ICML 2025) — of 13 models claiming ≥128k windows, 11 fall below half their short-context score by 32k tokens.

So pruning is a quality feature, not just a cost one. pi-context-tree treats the session like a git repo: a small trunk (master), side-work on branches, and master only ever receives clean, human-reviewed commits — never a lossy auto-summary. (Heuristic: keep the trunk in a 5–15% band.)

Why not pi's built-in /fork, /tree, and /compact?

You can already split and navigate context natively — but the moves that keep the trunk clean aren't there. That's the gap this fills:

You want to… Native pi pi-context-tree
explore a side-quest, then bring back only the answer /fork + /tree split and navigate; leaving a branch auto-summarizes (lossy, unconfirmed) /branch + /merge --squash fold back a human-confirmed decision record — the noisy turns stay on the branch, recoverable
reclaim part of the active context /compact rewrites a broad context prefix into an automatic summary /compress replaces one reviewed message range; /crop removes one fat result or whole Q&A turn — both are append-only and recoverable
see what's filling the window and act on it /tree switches branches /panel adds per-node token costs, a top-consumers view, decision cards, and one-key crop/branch/merge

Features

/branch <name> [model] Label the current point and fork off — optionally onto a cheaper model for the side-quest. The trunk model is restored on merge.
/merge Close a branch — bare /merge squashes to a human-confirmed ◆ decision record (--pick for the mode selector); also discard and tournament (winner record + epitaphs for the losers).
/compress [instructions] Select one continuous range through two native Pi Session Tree screens, draft a summary with the current model, and review it before it replaces that range. The continuation stays unchanged and the source stays recoverable.
/crop Stub fat tool/MCP results, or drop a whole Q&A turn — append-only, always recoverable. --top crops the biggest result inline; or review in the panel; or headless --auto --apply.
/undo One-key revert of the last mutation — re-open a squashed/discarded branch, restore a compression or crop, or undo a /branch. Append-only: nothing is deleted.
/panel (Ctrl+Q) Full-screen TUI: the tree with per-node token costs, branch status colors, top context consumers, all decision records (/decisions --export to markdown), and an entry inspector.
Ambient health gauge A green→red bar above your prompt with a trend + jump attributionctx 38% ▲ +24% (chrome.snapshot) tells you what to crop. Honest while estimating (band + ~est, never a fake-precise %). Plus a hashed title and a 40% nudge.
pitree A standalone, read-only forest CLI across all your pi projects, with dangling-branch detection.

Demo

pi-context-tree demo — branch a side-quest, squash it back as a decision record, then crop a fat tool result from the panel

The full-screen context panel — the tree with token costs, branch status colors, the health gauge, and one-keystroke actions:

The pi-context-tree context panel (a real terminal capture): the session tree with per-node token costs, branch status colors, a squashed branch and its decision record, the health gauge, and the key-hint footer

Prefer to click around? Open the interactive TUI mockup in a browser — the keybindings match the implementation.

Requirements

  • pi (the coding agent) — built and tested against @earendil-works/*@0.84.3 (newer pi usually works too; see Status).
  • Node.js ≥ 22.19.

pi install handles everything else; pi provides its core packages to the extension at runtime.

Status & compatibility

Maturity: v0.1.0 — the first public release. Every command and panel view works against pi 0.84.3, covered by golden and real-TUI tests (see Development). Bug reports and feedback are very welcome.

pi version: built and tested against @earendil-works/*@0.84.3. The extension declares a permissive peer dependency on pi, so it also loads against newer pi — a new pi release doesn't require an update, and most just keep working. A non-blocking CI lane runs the full integration suite against pi@latest on every push as an early warning for breaking changes; if it (or your own session) breaks on a newer pi, please open an issue.

Install

# from npm (recommended — versioned releases):
pi install npm:pi-context-tree

# …or straight from GitHub (tracks the default branch):
pi install git:github.com/navbytes/pi-context-tree

# update: re-run the install  ·  uninstall:
pi remove npm:pi-context-tree

Pin a version for reproducibility: pi install npm:pi-context-tree@0.1.0 (or git:…@v0.1.0 from GitHub). The bare forms track the latest release / the default branch. See Status & compatibility.

Development tree & standalone CLI
# load packages/extension from source (don't combine with the installed package — duplicate commands):
pi remove git:github.com/navbytes/pi-context-tree   # if previously installed
pi -e /path/to/pi-context-tree

# standalone forest CLI (read-only, never writes) — install globally from npm:
npm install -g @pi-context-tree/pitree
pitree [dir] [--dangling] [--json]
pitree ui                                            # session picker → read-only panel

Quickstart

The core loop, end to end:

# 1. install into pi (survives restarts; re-run to update)
pi install npm:pi-context-tree

# 2. inside a pi session, fork off for a side-quest
/branch fix-flaky-test               # add a model id (e.g. haiku-4.5) to run the branch on a cheaper one

#    …do the noisy exploration…

# 3. fold just the conclusion back to the trunk as a reviewed decision record
/merge            # bare /merge = squash → opens $EDITOR; save to confirm, quit empty to abort

# 4. see and prune what's in context any time
/panel            # browse the tree;  /crop --top to stub the biggest tool dump

# summarize one older range but keep everything after it unchanged
/compress preserve exact commands and validation results

# changed your mind? one-key, append-only revert of the last branch/merge/crop/compress
/undo

New to the workflow? The hands-on USAGE guide walks the full loop with worked examples.

Usage

/branch <name> [model]

Labels the current point (mirrored into pi's native labels — it doubles as a checkpoint) and opens a branch, optionally switching to a cheaper model for the side-quest. The trunk model is recorded and restored on merge.

/branch fix-flaky-test               # branch at the current leaf
/branch fix-flaky-test haiku-4.5     # …and run the branch on haiku (bare id or provider/id; Tab completes)

/merge [--pick | --no-llm | --discard | --tournament] [note…]

Closes the nearest open branch at or above the leaf. Bare /merge squashes — the 99% path, straight to the editor draft. --pick opens a selector with every mode; or pass a mode directly:

  • squash (the default) — the branch model drafts a decision record from the branch transcript; it opens in your editor. Nothing lands until you save — closing the editor empty aborts everything. The confirmed record becomes one ◆ decision record at the branch label; the noisy turns stay on the branch (history is append-only, never deleted).
  • squash --no-llm — same flow, but you write the record into the template yourself (no LLM call).
  • --discard [note] — back to the label, nothing injected, branch marked rejected. The note lands on the close marker.
  • --tournament — needs open sibling branches forked from the same point. The current branch wins: ONE combined record (winner + one-line drafted epitaphs for each loser), per-sibling close markers. Epitaphs keep the trunk model from re-proposing rejected approaches.

Merging never triggers pi's lossy summarize-on-leave — you never end up with both a summary and a decision record.

/compress [instructions]

Opens Pi's native Session Tree twice without moving the current leaf:

  1. The first tree opens at the current leaf. Move with Pi's native tree keys and press Enter to select the range start.
  2. The second tree opens at the normalized start boundary. Move to the range end and press Enter again.

Both screens use Pi's native branch connectors, active-path marker, folding, filtering, scrolling, labels, theme, and keybindings. Cancel either selector to write nothing. Off-path or structural entries, decision records, an incomplete current user turn, and incomplete tool-call groups are invalid. An invalid selection shows a notice and reopens the same native selector.

Tool calls are atomic groups: selecting an assistant tool-call member or one of its results expands that endpoint to the complete call/result group. After both selections, Pi's standard confirmation shows the normalized start and end labels, selected entry count, and estimated token total. Declining it stops before drafting.

The current model sees only the selected serialized source. Optional command text becomes extra summary instructions. The draft then opens in the editor. Saving a non-empty review is required. Cancel or save an empty value to write nothing.

Apply writes a visible ctree/range-tail message with the approved summary and the unchanged continuation, then a ctree/range-compact marker. It navigates with summarize:false; Pi's summarize-on-leave flow is not used. Original JSONL entries stay unchanged on the previous branch, and /undo restores the original source leaf.

Command Use it for
/compress A reviewed summary of one continuous active-context range.
/crop Exact removal of large tool output or a whole Q&A turn.
/merge A reviewed decision record that brings a branch conclusion back to its fork.
Pi /compact Pi's automatic broad-prefix compaction. It is not range-selected or append-only recovery managed by this extension.

/crop [--top] [--auto] [--apply] [--dry-run] [--min-tokens N] [--older-than N] [--keep glob]

Surgically stubs out fat tool/MCP results. Interactive by default: opens the panel's crop view with rule-based pre-marking when --auto is given. --auto --apply skips the panel entirely (scriptable; the only mode available where pi has no TUI). --dry-run always wins — it reports and writes nothing.

/crop --top is the one-shot path: it names the single biggest unprotected result and asks ✂ chrome.snapshot ~61k → crop? [y/N] — one trusted decision instead of the blind rules sweep.

Auto rules: ≥ --min-tokens (default 10k), older than --older-than assistant turns (default 2), never the latest result per tool (cropping those needs an explicit double-mark in the panel), never --keep matches.

Two granularities, one mechanism. The crop panel has a t toggle:

  • result mode (default) — stub individual fat tool/MCP results, replaced by [cropped: tool arg, ~tokens, sha8].
  • turn mode — remove a whole Q&A turn (a user question + every answer/tool entry it spawned) together. Removing only the answer would orphan tool_call/tool_result pairs and break user/assistant alternation, so turns drop as a unit. A removed turn collapses to one label-free [dropped turn — N entries, ~tokens, recoverable: sha8] note. The current/leaf turn is protected; ◆ decision records can never be swept up. Turn removal is panel-only.

Both branch at an anchor and leave the originals untouched on the previous branch — recoverable forever, nothing is ever deleted.

/undo

One-key revert of the last pi-context-tree mutation — append-only, nothing is deleted. It navigates the leaf back to the anchor the mutation recorded, and a confirm names exactly what reverts:

  • after a squash / discard → re-opens the branch at its tip (the decision record stays in history, off-path);
  • after a crop → restores the original fat result or Q&A turn;
  • after a range compression → restores the original sourceLeafId; the reviewed summary stays off-path;
  • after a /branch → drops back to where you branched.

It reverts the last active mutation (the most recent still on your path) — run it again to peel back further. This is the safety net for merging, compressing, and cropping.

/panel (also Ctrl+Q) and /decisions [--export path]

The full-screen context panel (an overlay over Pi). /decisions opens it on the decisions view; /decisions --export [path] writes trunk records to markdown. The panel stays open across actions: jump, branch, merge, or crop apply runs in command context after session revalidation, then the panel opens again with fresh state. Ctrl+Q stays view-only when Pi does not provide command context; use /panel for mutations.

The context panel

A full-screen overlay with five keyboard-driven views — tree (every entry with its token cost and branch status), consumers (what is using the window), decisions (◆ records as cards), crop, and inspect. You act from where you see the problem: b branch, m merge, c crop, and jump/fold. /compress uses Pi's native Session Tree outside this custom panel. The screenshot above is the tree view.

Full keymap, glyph legend, and reading guide → USAGE §5 — The context panel.

Ambient UI (outside the panel)

A context-health gauge bar pinned above the prompt (CONTEXT ▓▓░ … N% band, green→red, band ticks at 5/15/40%). It carries a trend when context is filling fast and attributes jumpsctx 38% ▲ +24% (chrome.snapshot) names what just bloated the window. While Pi is still estimating, it shows the band word and a coarse ~est, never a fake-precise percent. The red-band nudge and the /compact warning include /compress as the reviewed range-summary option.

pitree — the standalone forest CLI

pitree [dir] [--dangling] [--json]   # scan ~/.pi/agent/sessions across all projects (read-only)
pitree ui                            # session picker → the read-only panel

Flags dangling branches (open forks with no close marker) across every project. It never writes — enforced by a test.

How it works

  • Append-only, always. Every mutation (/merge, /crop, /compress) writes new ctree/* entries; existing session JSONL lines are never edited or deleted, so originals are recoverable forever.
  • Human-confirmed merges. The only summarization is branch→decision-record, and it always passes through your editor before entering the trunk. /merge integrates with (never fights) pi's native summarize-on-leave and never double-writes a summary and a decision record.
  • Layered, pi-light core. core imports nothing of pi (pure parsing/tree/estimation/planning); tui builds the panel on pi-tui; only the extension adapter touches pi's API. See the architecture doc for the verified pi APIs (with file:line references) and the load-bearing design decisions.

FAQ

Ctrl+Q doesn't open the panel. It's view-only in pi 0.84.3 (shortcuts get no command context) — use /panel to mutate. If even view-only won't open, a terminal multiplexer may be intercepting the key; run /panel directly.

My commands appear twice. You have both the installed package and a -e dev tree loaded. Remove one — pi remove git:github.com/navbytes/pi-context-tree, or stop passing -e.

The gauge says "est" or shows a ~. pi reports zero context usage right after a session loads, so until your first fresh turn the gauge shows the band word + a coarse ~Nk est (no fake-precise percent on a guess); it switches to pi's exact number once a turn lands.

Where did /undo put me? /undo returns to the source recorded by the latest active branch, merge, crop, or range-compression marker. Nothing is deleted. A decision, crop tail, or range summary remains in off-path history.

Does this ever rewrite or delete my session? No. /merge, /crop, and /compress append new entries. The originals stay recoverable on the previous branch, with byte-preservation coverage against real Pi sessions.

How do I pin a version? pi install npm:pi-context-tree@0.1.0 installs a specific release from npm (or git:…@v0.1.0 from GitHub). The bare npm: / git: forms track the latest published release / the default branch and update whenever you reinstall.

Development

npm install
npm test            # builds core/tui/pitree dist, then vitest in all workspaces
npm run check       # tsc --noEmit ×4 packages + biome
npm run fixtures    # regenerate committed fixtures (deterministic, byte-identical)

Layout: core (parser, tree, estimator, crop and range planners, panel view-model — zero Pi deps) · tui (ContextPanel on pi-tui) · extension (the Pi-facing surface, loaded from source via jiti) · pitree (standalone CLI/panel).

Testing. TDD throughout; packages/core/src/testkit.ts exports the deterministic SessionBuilder used by tests and fixtures. Golden integration tests (packages/extension/test/golden/) run the real pinned pi in --mode rpc against a mock OpenAI endpoint and pin the resulting session JSONL byte-for-byte. A real-TUI test boots pi in a pseudo-terminal via expect(1) and walks the panel keymap. Both self-skip when pi/expect are missing; re-record intended golden changes with UPDATE_GOLDENS=1 npm test -w @pi-context-tree/extension.

CI (.github/workflows/ci.yml): lint+types+unit per push · integration against the pinned pi (keyless) · a non-blocking pi@latest drift lane.

See CONTRIBUTING.md for the full conventions and the dev loop.

Roadmap

  • Upstream a branchWithFilteredHistory API to pi (replaces the crop reconstruction-block compromise with true per-entry filtered history).
  • Mutating actions from Ctrl+Q once pi exposes a command-invoke API (view-only today).
  • v2 (out of v1 scope): web dashboard, RPC-attach mutation for the standalone panel, scope-selector export, global zoom-out view.

Documentation

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for the TDD / append-only / conventional-commit conventions, and see CHANGELOG.md for release notes. Bug reports and feature requests use the issue templates.

License

MIT © Naveen (navbytes).

Acknowledgements

Built for pi by earendil-works. The git-style context model and the "context is the new code" framing come from the Context Engineering deck that originated this project; the design philosophy is grounded in the context-rot and NoLiMa research cited above.

About

Git for your agent's context: /branch, /merge, /crop + a context panel for pi sessions — keep context small, fresh, and recoverable.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages