pi-precompact0.4.0
Precompute Pi compaction summaries without interrupting the agent.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-precompact
An experimental Pi extension that prepares compaction summaries while the agent continues its work. Pi still decides when to compact. The extension supplies a valid prepared summary at that boundary, or leaves the request to Pi.
Inspired by OpenCode background compaction. This is an independent implementation, not an OpenCode port.
Status
- Supports Pi 1.2.0 up to 1.5.x. CI tests every release in that range, and the newest Pi every day.
- Uses Pi's native context projection, preparation, and summary generator.
- Does not abort the agent or inject a
continuemessage. - Does not install itself, change settings, or run a background process.
- Has deterministic unit tests and SDK integration tests with Pi's local Faux provider.
- Has no live-provider endurance or latency benchmark yet.
Install
pi install npm:pi-precompact
New sessions load the extension. Run /reload in a session that is already open.
To try it for one invocation without changing settings:
pi -e npm:pi-precompact
Do not combine it with another extension that replaces compaction.
Commands:
/precompact status
/precompact off
/precompact on
/precompact reset
These commands affect only the current session. reset cancels the prepared job and clears the failure counter.
/precompact and /precompact status open a status card in the TUI, in place of the editor.
The card appears only on this explicit request. It shows the state and last event, a context bar with the plugin's start and Pi's threshold,
the expected result of a held summary, the request usage, and the failure count. It updates every second.
Press r to reset, o to switch off or on, and Escape or Enter to close. RPC, JSON, and print modes keep the one-line answer.
When Pi adopts a background summary, the TUI and RPC clients receive one notice, for example:
✓ Background summary applied · no wait · 249k → ~38k tokens · prepared in 48s
waited 12s replaces no wait when Pi had to wait for a running request. The token value after → is Pi's estimate.
Native fallback compactions produce no notice.

The plugin sets one footer status from session start, precompact: <state>:
| State | Meaning |
|---|---|
idle |
Enabled; no summary is in progress. |
running |
Preparing a summary while the agent continues. |
ready |
Holding a summary until Pi requests threshold compaction. |
paused |
Two background requests failed; native compaction remains available. |
off |
Disabled for this session, or native auto-compaction is disabled. |
unavailable |
Unsupported Pi installation, virtual model, or no model selected. |
In Pi's built-in TUI footer, the plugin moves this status from the status row into the statistics line. Pi's own context segment stays exactly as Pi renders it. From 100 columns, a context bar comes before it:
━━━━━━━━━━━━━━━━━━━│━━━─│─ 91.6%/272k (auto) → ~14%
- The accent mark is where background preparation starts. The error mark is where Pi compacts.
- The fill uses the state colour:
runningaccent,readysuccess,pausedwarning, the others muted or dim. → ~14%follows while a summary is ready: the estimated context after Pi adopts it.✓ prefollows directly after an adopted summary, until the next change.pre running,pre ready(without an estimate),pre paused,pre off, andpre unavailablename the other states.

From top to bottom: idle, running, ready with the expected context, an adopted summary, and off.
After a compaction Pi shows ? until it has measured the next response.
Below 100 columns the line shows 91.6%/272k (auto) pre: ready instead. When even that does not fit,
or the footer has an unknown layout, Pi's status row keeps precompact: <state>.
Before the first response with token usage, Pi shows only its context value and no usage numbers.
The plugin then shows nothing either: no bar, no pre text, and no status row entry.
With the first measured response, the bar fades in once:
- Pi's numbers appear at once; the bar reserves its columns in the same frame.
- Each glyph fades from the terminal background to its colour in 120 ms, 5 ms after its left neighbour.
- The fill grows from 80 to 240 ms. A frame follows every 40 ms; the easing is
cubic-bezier(0.23, 1, 0.32, 1). - A new width or state during the animation shows the final bar at once. A new context value, such as a tool result right after the first response, updates Pi's number and lets the fill grow towards it.
- Sessions with earlier responses, for example after
/resumeor/reload, show the bar without animation.


The plugin asks the terminal for its background colour once, as Pi's theme does.
Without an answer or without truecolor, each glyph appears directly in its colour as the wave reaches it.
Set PI_PRECOMPACT_MOTION=off before starting Pi to show the bar without animation.
Use /precompact status for the last event and failure count.
Pi's (auto) context indicator refers to native automatic compaction, not this plugin.
Pi has no public API to place text inside its footer. A zero-row widget below the editor finds the one mounted
built-in FooterComponent and wraps the render method of that instance; the prototype stays untouched.
The plugin reads the instance's status provider read-only and never modifies shared statuses.
Other footer decorators can wrap the same instance before or after it; each keeps the other's lines.
Custom footers are left alone. Shutdown and reload restore Pi's method and clear this plugin's status only.
JSON, print, and RPC modes receive no terminal status or footer decoration.
To remove it, run pi remove npm:pi-precompact.
Scheduling
- After a completed turn, resolve Pi's effective compaction settings for the current model.
- Start one summary when context reaches 85% of the native compaction ceiling.
- Require at least 64,000 measured input and cache tokens from the latest valid assistant response.
- Keep the result in memory while the agent continues.
- At native threshold compaction, validate the snapshot and await its result if necessary.
- Return the prepared summary to Pi, or let Pi perform normal compaction.
The ceiling is contextWindow - reserveTokens. With Pi's default reserve of 16,384 tokens and a 272,000-token model,
the ceiling is 255,616 tokens: background work starts at 217,274 tokens (80%), and Pi compacts above 255,616 tokens (94%).
The extension reads Pi's effective compaction settings, so a changed reserve or a model override moves both marks.
The extension does not start speculative work after the ceiling is already reached.
A job has a two-minute deadline from its start. Foreground waiting uses the remaining time, not a new two-minute timeout. Two background failures pause speculative work until compaction or an explicit reset. Manual compaction, custom instructions, and overflow recovery always use Pi's foreground path.
Context safety
The summary uses the canonical prepareCompaction() and compact() functions from the running Pi installation.
There is no copied cut-point or projection algorithm.
The extension hashes the original branch and checks it again before applying a result. It rejects changed models, settings, branch prefixes, context edits, and intervening compactions. It also checks after a foreground wait, because session changes can race the request. Session replacement, tree navigation, reload, model selection, and cancellation discard pending work.
Pi keeps the retained history as native messages. The extension does not convert recent tool output or attachments into truncated text. New messages after the snapshot remain in that retained history. No catch-up summary call is necessary. Pi can still make two native summary calls for a split turn.
Before acceptance, an in-memory SessionManager previews the real compaction entry, including replayed system state.
The estimated result must reduce context and fit below the native ceiling with a 15% estimate margin.
New history after the snapshot must also fit within min(max(2 × keepRecentTokens, 30,000), ceiling / 4).
These checks use Pi's token estimates, not an exact provider tokenizer. Native overflow recovery remains the final safeguard.
Pi 1.2 to 1.5 skip inherited file metadata from all extension-generated compactions. A narrow adapter preserves this extension's marked file lists in both background preparation and foreground fallback. It leaves other extensions' details alone.
Compatibility and limits
prepareCompaction() is not a public root export in Pi.
The adapter loads the installed distribution module after it checks that the runtime is Pi 1.2.0 up to 1.5.x and matches its package.
Other versions, mismatched installations, and binary installations without distribution modules leave the extension inactive.
Pi's normal compaction remains available.
To try an untested Pi release at your own risk, start Pi with PI_PRECOMPACT_ALLOW_UNTESTED_PI=1. The extension then shows a warning.
Virtual routing models use native compaction only. This avoids speculative work against unresolved model limits.
Physical models use ctx.modelRegistry.streamSimple(), with the configured provider and request-time authentication.
The extension does not read credential files or resolve secrets itself.
Background requests do not use custom SDK agent.streamFunction overrides or request-transform hooks.
Background summaries consume provider quota, even when discarded. Requests can overlap with ordinary agent requests.
Accepted summaries carry their native usage into the compaction entry.
The extension records known discarded-result usage as a non-context precompact.discarded custom entry.
Pi does not include those custom entries in its built-in cost totals.
Partial failures and cancelled or late requests can incur costs without returning usage. A provider that ignores abort can continue remote work after the local wait ends.
This extension follows Pi's summary prompt and cache policy. It does not implement OpenCode's prompt-cache optimization.
It reads persisted context, not temporary context or context_with_system hook transformations.
Persistent omissions and replacements must use Pi's context_edit entries.
Development
See CONTRIBUTING.md for setup, Changesets, the commit hook, and the separate release procedure. See CHANGELOG.md for release notes.
Prerequisites: Node.js 22.19+, Python 3.11+, Git, npm, Make, and tar.
From the repository root, install the locked development dependencies:
npm ci --ignore-scripts
Install the changeset hook once per clone:
make hooks-install
Run the same checks as CI:
npm run check
This checks formatting, lint, types, runtime tests, the actual npm tarball, and the Changesets flow. CI runs these checks on Linux and macOS with Node.js 22 and 24, and the tests against every supported Pi release. A daily workflow runs the tests against the newest Pi.
Tests use temporary directories, in-memory credentials, in-memory sessions, and a local scripted provider. They do not load personal extensions, read real credential files, or call a remote model. The integration tests inject deterministic token usage through Pi's finalized-message hook. They exercise real extension loading, provider streaming, tool-driven turns, threshold compaction, fallback, and shutdown.
Source:
src/index.ts: lifecycle hooks and commands.src/controller.ts: job scheduling and cancellation.src/native.ts: version-guarded native adapter.src/validation.ts: branch validation and context preview.src/files.ts: file-metadata inheritance for Pi 1.2 to 1.5.src/card.ts: the status card for/precompact status.src/footer.ts: the context bar in Pi's built-in footer.src/format.ts: token, duration, and share formatting.
