npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

context-fold

v0.3.0

Published

Deterministic, reversible in-session context compaction for the Pi coding agent — folds stale tool output out of the model's view, never out of the session.

Readme

context-fold

Deterministic, reversible context compaction for the Pi coding agent. Long agentic sessions stay under budget by folding stale content — mostly long chains of tool calls — out of the model's view. Every fold is reversible, indexed, and computed without a model call. The core is written to be harness-agnostic and can be adapted to other coding harnesses with some work.

Requirements: Node ≥ 22.19.0 and Pi ≥ 0.80.4.

pi install npm:context-fold

The idea

Context management is annoying, and I know plenty of people who are too lazy to summarize and hand off to a new session. They let context grow unmanaged right up until they smash /compact. This system came out of iterative research over various compaction methods, and it is an attempt at economically optimizing context over a long session — eating as few cache-read hits as possible until you decide to end the session or the work is done.

Why deterministic

The published evidence points the same way from several directions.

Deterministic masking of stale tool output matches or beats LLM summarization on agentic coding tasks, at equal or lower cost (The Complexity Trap, SWE-agent, Anthropic's context editing).

LLM summaries lose exactly what matters. File and identifier trails are the weakest-preserved category even in good production summarizers (Factory.ai). In one fixed-interval math experiment, 40.4 % of post-summary answer-state transitions went from correct to wrong — even though summarization was net positive overall (Self-Compacting Agents). A summary can also fabricate instructions that then become post-compaction "ground truth" (claude-code #46602).

For precise recall, retrieval over raw stored history beats an in-context summary by a wide margin (MemGPT, LongMemEval). But grep only finds what lexically matches (NoLiMa) — which is why every fold emits a deterministic index of exact tokens rather than a paraphrase.

The system in short

1. Per-turn: the fold ladder. Once usage crosses ~45 % of the context window, a fold event masks stale tool_result and thinking blocks. User intent, assistant conclusions, and the record of every action are never touched. Fresh tool results are always delivered in full at least once.

2. The floor. Eventually no more tool calls can be masked. At that point context-fold says so rather than churning. What remains is the irreducible floor, and it cannot compress past it.

3. Hard compaction. Pi decides when this fires. By default (CONTEXTFOLD_COMPACT=det) context-fold intercepts it and hands Pi a summary rendered verbatim from the session's seed index, so Pi's LLM summarization never runs. CONTEXTFOLD_COMPACT=native opts back into Pi's stock behavior.

At this stage the raw messages do leave live context — that is what compaction is. What survives is the index, the spool, and Pi's session file, all on disk and all reachable through recall. The loss is bounded and reversible rather than lossy and final. There is no paraphrase step and nothing that can hallucinate. The extension warns you after a second forced compaction; it is worth running a handoff well before that, at a definable task finish line.

4. Handoff. (manual, /fold-handoff) Writes a seed file for starting a fresh session: the same verbatim index plus the goal you state.

On the thresholds. Every percentage above is a default, not a tuned constant. The right first-fold point trades the initial cache write against how many times you compact over a session, and I have not settled it. All of them are environment variables (see Configuration) and all of them may move in a future minor release.

What it does

Discrete fold events

Between fold events the context is append-only. Rewriting history invalidates the provider's prompt-cache suffix, so mutations are batched at points where that cost is paid once:

  • First fold when usage crosses ~45 % of the context window (25 % when telemetry shows the session has never had a live cache read, since there is no warm prefix worth protecting).
  • A fold event masks stale tool_result/thinking blocks outside the protected tail to their deterministic digests, keeping detected risk lines verbatim, and commits them as a frozen layer whose bytes never change again. The context head stays byte-identical turn over turn, which is what keeps prefix caches warm.
  • Each further event needs at least a ladder step (~12 % of the window) of maskable mass. Crossing the absolute budget cap (min(200k, 0.75 × window)) folds immediately.

Spool-backed recovery

Every committed ladder fold writes the exact masked block to a versioned, sha256-verified spool envelope before the raw message can leave live history. The model sees a deterministic {#code FOLDED} digest and can retrieve the original through recall or restore it through unfold. This happens only when context pressure folds stale material; context-fold never hides a fresh result before its first delivery.

The seed index

Every fold event appends one deterministic record to seed-index.jsonl in the session spool directory (spec: docs/SEED_INDEX_SPEC.md): files touched, commands run, error lines in every spelling the lexicon knows (lowercase failed, npm ERR!, …), exact identifiers and numbers harvested from the masked output, first lines of user messages, and byte-extent spans into the spool. Extraction is pure regex — same input, byte-identical output.

Getting detail back

  • recall search=<term> — one sweep over every folded block, with matching lines grouped by code. A detail lost somewhere behind N pointers costs one call, not N.
  • recall <code>, with optional grep=<term> or lines=<a-b> — whole or partial retrieval, token-capped so a recall can never re-flood what folding saved.
  • unfold <code> — sticky re-expansion. The block stays expanded and is never re-masked.

Recall works live, after resume, and after hard compaction: masked content resolves from the spool even once the raw message has left history.

Status and advisories

Measured prompt-cache telemetry (per-message cacheRead/cacheWrite) drives the advisories below, in price-agnostic input-token equivalents — fee ratios are near-constant across vendors, with cache read ≈ 0.1× input.

  • Cold detection — an expected-warm turn that read zero cached tokens gets one stderr notice with the re-billed size and a /new suggestion.
  • /context-fold status — fold position (usage %, the next-fold gauge), cache hit ratios, and flags: folds committed but not observed on the wire, a second forced compaction, irreducible context past half the window, cold with a large carry, and recall churn. Advisory only; nothing blocks.
  • Footer status line (TUI) — a persistent one-line summary in Pi's footer (⧉ context-fold ×3 · ~41k tok masked · next fold: 3.1k/9.6k maskable · cache avg 66%), updated as fold events fire. Purely visual: nothing is added to the transcript or the model's context, and headless modes are unaffected. The middle segment is the ladder's trigger gauge, showing whichever fold condition is actually binding — below the entry threshold it names it (next fold at 45% ctx); once usage is past the threshold, which is permanent from then on, it tracks maskable mass toward the next fold step (next fold: 3.1k/9.6k maskable, counting up from 0 right after a fold as new observations land). ⚠ no more folds possible (over budget) appears only in the terminal state where the irreducible tail and roots exceed the budget. cache avg is the whole-session cache hit ratio, unlike Pi's CH, which is the last turn only.
  • Fold cost accounting — once a fold event has fired, the status reports both sides: tokens masked per turn against tokens the provider re-prefilled because the fold moved the prefix, plus the running net. A fold rewrites history from the earliest masked block forward, so that re-prefill is a real cost this extension causes, and reporting only the savings would be dishonest accounting. It is charged to the single turn carrying the new bytes, because every later turn reads them back from cache. The cost side needs a provider that reports cache writes: Anthropic and Bedrock Converse do, while the Codex route reports cached reads only and Pi hardcodes Google's write to zero. Where writes are unreported the line says so instead of showing a zero — "nothing was rewritten" and "this provider never says" are different facts.

Guarantees

  • History is never mutated. Folding exists only in the per-call outgoing copy; the session file keeps every raw payload.
  • Nothing is destroyed. Ground truth lives in the session file and the spool. Every {#code} handle resolves through recall/unfold until spool GC ages it out (default 14 days).
  • Tool pairs cannot orphan. Folding is in-place content substitution and never changes the message count, so a tool_call can never lose its tool_result. Structural, not policed.
  • Failure signals survive compression at every fidelity level — the error lexicon is deliberately broad and any-case.
  • No model is ever called. Folding, digests, compaction, and the handoff seed are all deterministic. Nothing this extension produces is a paraphrase.
  • Fail-open, bounded blast radius. A defect costs one result's folding, one block's fidelity, or one turn's folding — never the turn itself. CONTEXTFOLD=0 disables everything per session.
  • Deterministic core. The pure core has no clock, no randomness, and no I/O; all disk I/O lives in the adapter.

Limitations

  • Token counts are estimates. The estimator is a uniform ~4-characters-per-token heuristic, not a per-model tokenizer, so every threshold in this document is approximate. It drives budget decisions well enough; do not read it as billing truth.
  • Images are invisible to the budget math. A tool result carrying non-text parts (screenshots, rendered pages) is never folded, so nothing is ever lost — but its real token cost is not counted either. Image-heavy sessions read as further from the fold threshold than they are, so folding starts later than it should.
  • The tool names are generic. The extension registers recall and unfold as global tools. If another extension registers the same names, one will shadow the other.
  • Spool GC judges other sessions by file age. The sweep at session start deletes sibling spool directories whose newest file is older than the retention window. Live sessions refresh a heartbeat file each turn, so an idle-but-running session is safe; a session whose process is suspended for longer than the window can still lose its spool to a freshly started sibling. CONTEXTFOLD_SPOOL_RETAIN_DAYS=0 disables the sweep.
  • Primarily exercised against one model family. Development and testing have mostly used gpt-5.6-sol via the openai-codex provider. Folding only reads Pi's usage numbers and message shapes, so other providers should work; fold cost accounting is the one feature with a known provider dependency, since it needs reported cache writes. The figures quoted above come from individual runs rather than a repeatable harness.
  • Folding changes what the model sees. A pointer is not the payload. Agents handle this well in practice, since the teaching text explains the contract, but if you see an agent confused by a {#code FOLDED} marker, CONTEXTFOLD=0 turns everything off for a session.
  • Pre-1.0. The on-disk formats are versioned but not frozen. While the major version is 0, a change to fold timing or to the seed-index record shape is a minor bump, documented in CHANGELOG.md.

Known integrations

Findings from running context-fold beside other Pi extensions. The common theme: a fold can be committed and correct locally yet still be discarded or deferred downstream, which is why the extension watches provider usage for exactly that.

  • @howaboua/pi-codex-conversion defers folds to user-turn boundaries. Its cached WebSocket continuation answers a mid-chain prefix change by sending only the pending tool output as a delta against the server-held previous response, so a fold's rewrite of older history stays local for the rest of that tool chain. At the next user message there is no pending tool output, the changed prefix forces a full resend, and provider-reported input drops all at once. Folding still works — recall, the spool, and compaction are unaffected — but a long autonomous tool chain can approach the provider's context limit before any fold takes effect on the wire.
  • codex-lite does not rewrite context. Its dialect mode replaces Pi's stock tools and appends prompt guidance. There is no fold bypass in that pairing; fresh shell output reaches the model before it can age into a ladder fold. Focused shell commands still reduce context growth.
  • Current Pi chains context transforms as middleware. Pi 0.83.0 and 0.84.1 are verified. On older builds that predate transform chaining, context-fold must load after another context rewriter. session_before_compact still selects one compaction result. Full versioned collision table in docs/pi-api-surface.md.
  • Do not load the package twice. pi install npm:context-fold plus a -e npm:context-fold flag registers recall/unfold twice and fails loudly at load with a tool-name conflict. Installed or -e, pick one.

The wire watchdog. Because every one of these failure modes is invisible in the extension's own output, the telemetry checks the outcome instead: a fold that masked tokens strictly shrinks the outgoing prompt, so if the next turn's provider usage reads the whole pre-fold prompt back from cache, the rewrite provably never reached the wire. When that happens the extension warns once per session on stderr and raises a flag in /context-fold and the footer status line.

Install

# Try it for one session, without installing:
pi -e npm:context-fold

# Install persistently:
pi install npm:context-fold

From a clone, point Pi at the checkout instead: pi -e /path/to/context-fold.

Configuration

| Var | Default | Meaning | |---|---|---| | CONTEXTFOLD | (on) | Master kill switch: 0/off = the extension registers nothing this session. | | CONTEXTFOLD_FOLD_AT | 0.45 | First fold when usage ≥ this fraction of the context window. | | CONTEXTFOLD_FOLD_STEP | 0.12 | A fold event must save at least this fraction of the window (spaces events). | | CONTEXTFOLD_COLD_FOLD_AT | 0.25 | First-fold threshold when no live cache read has ever been observed. | | CONTEXTFOLD_BUDGET_FRACTION | 0.75 | Budget = this fraction of the context window… | | CONTEXTFOLD_BUDGET_CAP | 200000 | …capped at this absolute ceiling (attention degrades at absolute depth). 0/off disables. | | CONTEXTFOLD_TAIL | 20000 | Protected-tail target — the newest ~N tokens never fold (clamped to half the budget). | | CONTEXTFOLD_COMPACT | det | Hard-compaction answer: det = deterministic seed-index summary; native = Pi stock. | | CONTEXTFOLD_RECON_TOKENS | 18000 | Reconstruction estimate used by the reset flag (input-token equivalents). | | CONTEXTFOLD_SPOOL_RETAIN_DAYS | 14 | Spool GC window at session start. 0/off = never delete. | | CONTEXTFOLD_DEBUG | (off) | One-line fold/cache summary to stderr each turn. | | CONTEXTFOLD_DUMP | (unset) | Debug/e2e seam: write each turn's outgoing (folded) view to this JSON path. |

Verification

npm install && npm run typecheck && npm test   # unit + integration suite
scripts/e2e-ladder.sh   # live: fold event fires, index emitted, head byte-stable, buried value recalled
scripts/e2e-resume.sh   # live: folds survive a session restart

The live scripts drive real Pi sessions against a real provider, so they cost money and need provider auth plus python3. They load the working copy explicitly, so they test the checkout rather than an installed build. Override the model with E2E_PROVIDER / E2E_MODEL. These are liveness checks, not benchmarks — they assert that folding happens and survives, not how much it saves.

Develop

npm install
npm run typecheck
npm test

The core (src/core/*) has zero harness dependencies; the Pi adapter (src/adapters/pi/*) owns all I/O and hook wiring. Architecture notes are in DESIGN.md, the index format in docs/SEED_INDEX_SPEC.md, and the Pi APIs this leans on in docs/pi-api-surface.md.

There is no build step: Pi loads the TypeScript source directly through jiti, so the package ships src/ as-is and installs no dependencies of its own.

typebox and @earendil-works/pi-coding-agent are declared as optional peer dependencies. Pi injects them at runtime — never bundle a copy.

Provenance & license

MIT. The pure core is ported from Accordion (pinned commit 0c22434), stripped of UI coupling and hardened since; the discrete fold ladder, seed index, spool-backed recovery, and advisor layers are original to this project.

Much of this documentation was drafted with an LLM and edited by hand. The design decisions, thresholds, and measurements are mine.