pi-anthropic-compat
Native Anthropic compaction compatibility for Pi
Package details
Install pi-anthropic-compat from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-anthropic-compat- Package
pi-anthropic-compat- Version
0.0.10- Published
- Oct 8, 2026
- Downloads
- 1,883/mo · 668/wk
- Author
- kaanozdokmeci
- License
- MIT
- Types
- extension
- Size
- 108.9 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./extensions/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-anthropic-compat
Native Anthropic compatibility for Pi, starting with signed on-demand compaction.
Requires Pi >=1.1.0 <1.2.0 and Node.js 22.19 or newer. Releases are
validated against Pi 1.1.0. The extension refuses to load on a Pi older than
1.1.0, because Pi does not enforce the package's peer range when it installs
packages.
Install
pi install npm:pi-anthropic-compat
Native compaction starts off. Open /anthropic-settings, enable it, and
press Ctrl+S to save and apply.
Use your existing Anthropic API key or Claude subscription login in Pi.
The extension does not manage a separate credential store.
Compaction
With native compaction enabled, /compact and Pi's automatic compaction request
a signed summary from Anthropic using compact-2026-09-04.
The extension:
- uses Pi's Anthropic serializer and authentication;
- checks the selected model's live compaction capability before summarizing;
- preserves the complete signed block, including opaque fields;
- summarizes the full active conversation or an older range with recent messages retained;
- sends the signed block first on later Anthropic requests;
- preserves original messages in Pi's append-only session tree;
- persists the checkpoint for resume, reload, and branch navigation;
- includes summary generation in Pi's token and cost totals; and
- cancels native compaction on failure without silently switching algorithms.
Run at least one ordinary Anthropic turn before the first native compaction. This captures the final system instructions and tool definitions after other extensions have transformed them. The capture persists in the session, so a resumed session does not need another turn.
Full-history compaction is the default. Set Native tail tokens in
/anthropic-settings to retain recent messages verbatim, including their signed
thinking. This extension's keepRecentTokens setting controls retention.
Pi's separate setting with the same name does not control the native boundary.
Retaining recent messages
Set keepRecentTokens to a positive integer, such as 16000.
The extension selects an actual earlier Anthropic request as the older range.
It sends only that range for summarization, then replays the signed summary
followed by the unchanged recent messages.
The target uses Pi's approximate message token counts. Opaque thinking is not accurately measurable with that estimate. Retention rounds up to a safe request boundary and can exceed the target. A retained range can start with an assistant response rather than a complete user/assistant exchange.
If no recorded boundary satisfies the target, compaction cancels without a summary request. Run more Anthropic turns or reduce Native tail tokens. Existing sessions need an ordinary turn with this extension version to record a boundary. The extension never silently substitutes full-history compaction.
Retained history requires unchanged model, system instructions, tools, and earlier messages. Incompatible changes stop replay before transmission. Cache-marker movement and equivalent JSON formatting are allowed. Pending tool calls must finish before compaction. Arbitrary messages cannot be removed from the middle of retained history.
When thinking is enabled, keep-tail mode explicitly requests
prefix_mismatch_behavior: "error" instead of silently dropping invalid
thinking. Turning retention off does not discard a previously retained range.
To change system instructions or tools, first compact the whole conversation
with keepRecentTokens: 0, then make the change.
Do this before upgrading Pi if the last compaction kept recent messages.
Runtime upgrades can change prompt text and tool declarations, which can
invalidate retained history even when thinking is off.
Pi records the current prompt and tool declarations on every compaction entry and leads the compacted context with that snapshot. Models that accept prompt updates in place, such as Fable 5.1 and Opus 5, keep the original leading prompt in earlier requests, so a prompt or tool update anywhere in the active conversation makes the snapshot differ from the request that bound the recent thinking. Keep-tail compaction then cancels before any summary request. Models that receive a collapsed prompt can still retain turns made after the update. Full-history compaction is unaffected.
Pi codemode's only mode hides direct tools from turn requests, but the
transcript still declares them. Summary requests leave out every current
transcript tool that the last turn request did not send, as its saved request
template records, so they declare the tools the turns sent. The retained-tail
check uses the tools Pi will send after compaction, so a tool change still
cancels keep-tail compaction before any summary request.
Pi synthesizes effort-control messages around Fable responses. The extension removes only a verified duplicate boundary instruction that was already summarized. It preserves every instruction inside the retained range.
Pi lifecycle
Pi still owns automatic-compaction timing, cancellation, and retry behavior.
Pi also decides whether a session is large enough to compact before invoking
extensions. Very short sessions can return “Nothing to compact.”
The extension does not change Pi's global compaction settings or intercept
/tree branch summarization.
Turning native compaction off prevents new native summaries. Existing signed summaries still replay until another Pi compaction replaces them.
Models and endpoints
This version supports the direct Claude API and these documented model IDs:
claude-haiku-5-5claude-sonnet-5-5,claude-sonnet-5,claude-sonnet-4-6claude-opus-5-5,claude-opus-5,claude-opus-4-8,claude-opus-4-7,claude-opus-4-6claude-fable-5-1,claude-fable-5claude-mythos-5-1,claude-mythos-5,claude-mythos-preview
The live Models API must also report support. Haiku 4.5 does not support native on-demand compaction. Unsupported models, other providers, and proxies retain Pi's ordinary compaction behavior.
Pi's virtual models are not supported. Native compaction checks the
selected model, not the model that answers a request. Pi's experimental virtual models, registered with
pi.registerVirtualModel(), stay selected while Pi routes each request to a
physical model. With a virtual model selected, /compact and automatic
compaction use Pi's ordinary compaction. This holds even when the router sends
every request to a supported Anthropic model. Select that model directly to use
native compaction.
When switching to an unsupported model or provider, Pi's readable summary remains available as ordinary context. Returning to a supported Anthropic model restores native replay if that checkpoint is still on the active branch.
Bedrock, Google Cloud, threshold compaction, context editing, and background compaction are not implemented.
Failure and cost
The summary input must fit the model's context window. Compact before the window is exhausted. An already oversized conversation may require selecting an earlier branch rather than attempting native overflow recovery.
Pending tool calls must have results before compaction. Empty or unsigned summaries, refusals, timeouts, aborted requests, unsupported responses, and concurrent session changes leave the original conversation intact. The extension does not retry billed summary requests automatically.
Compaction is billed separately. Accounting uses usage.iterations, not the
top-level usage fields, which can be zero on a successful summary request.
Failed summary requests can still incur charges.
The extension stores final request templates, compact request-boundary hashes, signed summaries, and retained native messages in Pi's existing session file. It records a template and a boundary hash on every direct Anthropic turn, even while native compaction is off, so that enabling it later can retain turns that already happened. It does not store a complete transcript copy for every request. It never stores authentication headers or logs raw provider error bodies. Treat session files as private conversation data.
Settings
/anthropic-settings provides a searchable settings list:
- Enter changes the selected value or opens its editor. It never implicitly saves.
- Space activates a result or inserts a space when search has focus.
- Tab / Shift+Tab move between search, results, and action controls.
- F1 opens scrollable details, full errors, and the exact save target.
- Edits remain drafts until explicitly applied or saved.
- Apply to session applies drafts without writing configuration files and stays open.
- Ctrl+S saves and applies changes without closing.
- Save and close saves and applies changes, then closes on success.
- Escape cancels a field editor or discards unapplied drafts and closes the main menu. It does not undo settings already applied to the session.
Search matches labels, configuration keys, and descriptions. Numeric editors offer presets and custom values across the complete supported range. Use inherited value removes the selected override rather than copying its current default into the file. Rows show their configuration source. Pi's remapped selection and cancel keys are respected.
Settings are stored in ~/.pi/agent/pi-anthropic-compat.json.
PI_CODING_AGENT_DIR changes that directory.
{
"enabled": false,
"keepRecentTokens": 0,
"maxSummaryTokens": 4096,
"timeoutSeconds": 120
}
| Setting | Accepted values |
|---|---|
enabled |
true or false |
keepRecentTokens |
Integer from 0 to 200000 |
maxSummaryTokens |
Integer from 1024 to 32768 |
timeoutSeconds |
Integer from 10 to 600 |
A trusted project's .pi/pi-anthropic-compat.json overrides global values.
The menu saves to that file when it already exists. Otherwise it saves globally.
Untrusted project configuration is ignored. Invalid configuration produces an
error instead of silently enabling native compaction.
Saving changes only edited overrides and preserves unknown keys and inherited
values. The save target stays fixed while the menu is open. Non-conflicting
external edits are preserved; conflicting edits are rejected for review.
Opening or closing without changes does not create a configuration file.
Reopening shows active session values, not freshly read file values. * marks
an unapplied draft. ~ marks an active session override or a value that differs
from the saved configuration. Details shows the saved value when it differs.
Ctrl+S also persists changes previously applied only to the session.
Session settings are stored as extension state entries in the Pi session,
outside model context. They survive menu closure, tree navigation, extension
reload, process restart, and switching away and back. Resuming the same session
restores its settings before provider operations. A new session, fork, or clone
has a separate identity and starts from configuration files.
Pi's --no-session mode cannot be resumed after exit. Pi also defers creating a
new session file until its first assistant message.
Applying and saving wait for Pi to become idle. Escape cancels a pending operation
without discarding the draft. Failures leave the menu open. If a save reaches disk
but cannot be applied to the session, the menu reports that distinction and
Ctrl+S retries application. Cooperating writers use a .settings-lock file.
An interrupted writer can leave a lock that requires review; locks are not
automatically deleted. External editors do not participate in that lock.
Session overrides retain their original conflict checks across menu reopenings.
Conflicting external edits remain protected after reload or restart.
The menu requires TUI mode. File configuration also works in print and RPC
modes. /compact <instructions> supplies additional summary guidance.
Development
mise trust
mise install
mise run init
mise run check
pi -e .
Keep extension loading enabled when using Anthropic. In particular, do not
disable an installed system-prompt patcher. Final provider-payload transforms
run before this extension captures system instructions and replays summaries.
Avoid another extension replacing the anthropic provider's stream function.
Tests use synthetic responses and real Pi session machinery without network inference. They cover protocol validation, token accounting, configuration, the settings menu, automatic/manual compaction, repeated summaries, durable replay, forks, branch navigation, cancellation, and concurrent session changes. Retained-history tests cover safe-boundary selection, token targets, thinking, effort instructions, changed system/tools/content, and cold session resume.
npm test and npm run test:live remove an inherited PI_PACKAGE_DIR from
their test processes, so in-process tests read the repository Pi's own metadata.
Ordinary pi launches are unaffected.
Live tests make billed Fable 5.1, Opus 5.5, Sonnet 5.5, and Haiku 5.5 requests at low effort:
npm run test:live
They use your existing Pi Anthropic login, global context instructions, and
global prompt-patcher rules. The patcher itself is the pinned
pi-system-prompt-patcher development dependency. The conversations contain
synthetic facts. The SDK tests refuse to run when an inherited
PI_PACKAGE_DIR selects another Pi, so run them through npm run test:live.
The SDK tests require actual signed thinking for each model, then verify native keep-tail compaction, unchanged replay, usage, and fact recovery. Two negative controls must return thinking-prefix errors after deliberate system and history changes. Low effort can omit thinking on simple tasks, so the fixture includes a multi-step arithmetic problem. A response without thinking fails the test. A Sonnet 5.5 test adds a tool mid-conversation, which Pi sends as an inline tool definition, compacts the full history, and requires a call to the added tool afterwards.
The CLI tests use PI_PACKAGE_ARCHIVE when supplied and otherwise pack the
extension locally. Each loads the archive through the shipped Pi executable in
RPC mode with an isolated agent directory and runs a turn that
reads the facts with Pi's built-in read tool, a native compaction, a
continuation, a restart, and a resumed continuation. Tool declarations and the
tool-call/result pair therefore pass through the summary request and replay.
Fact recall after compaction proves the signed block replayed, because the
extension withholds Pi's summary message once a checkpoint exists. The test
requires the selected Pi to match the repository's Pi development dependency.
PI_ANTHROPIC_CLI_PATH selects another cli.js to test; the default is the
repository's Pi dependency.
Fable tests retain recent messages. Opus 5.5, Sonnet 5.5, and Haiku 5.5 tests cover both
full-history and retained-message compaction. The default test suite and CI skip live tests.
Anthropic live runs keep normal tools, extensions, capabilities, and resource
loading enabled. Test state and prompt-patcher rules are isolated without
restricting the available tools.
Each CLI subprocess resolves its own package directory, and the SDK tests use
the repository Pi. Both test suites resolve the
global prompt-patcher rules the way the patcher does: the model-specific file
for the model under test wins over the provider file, and relative, absolute,
and ~/ references are all accepted. They copy those rules unchanged into the
isolated agent directory and write isolated patcher settings that point at the
copy. Global configuration remains unchanged.
Rules that rewrite Pi's package directory must use the patcher's
{piPackageDir} placeholder rather than a fixed installation path. The
placeholder resolves to the Pi under test, so the same rule matches both your
installed Pi and the repository's Pi dependency. A rule that names a fixed
installation path does not match the repository Pi, and the patcher aborts the
turn.
npm run test:live is the complete release validation. scripts/test-live.ts
runs the packaged settings tests offline, then the SDK and CLI tests against
the Pi development dependency. Live test files run sequentially to limit
concurrent requests against the same account.
Set PI_PACKAGE_ARCHIVE to test a prepared archive instead of packing the
working directory. A relative path resolves from the current working
directory, which is the repository root under npm run test:live. All CLI runs
use that archive. An empty value, a missing path, a non-file path, or malformed
archive contents fail rather than falling back to a newly packed package.
Release
The shared release tooling records a package digest in a signed release commit.
The tag workflow verifies that digest, attests the archive, stages it on npm,
and creates the immutable GitHub release for the tag from the same archive and
the version's CHANGELOG.md section (Unreleased for prereleases).
The npm trusted publisher permits staging only and is restricted to this
repository's publish.yml workflow and npm-publish environment. Every
release after 0.0.1 stages through that workflow with npm provenance and
requires maintainer approval on npm.
Prepare and push a release:
mise exec -- npm run release -- X.Y.Z
git push --atomic origin main vX.Y.Z
Before signing, the release command runs npm run test:live against the exact
archive built from the staged files. Missing live-test prerequisites or a failed
test stop the release before the commit and tag. The post-commit reproducibility
rebuild does not repeat the live tests.
If live validation fails, the generated version changes in package.json and
package-lock.json remain staged. No release commit or tag is created by that
failed validation. A version-update failure can leave unstaged changes, and a
signing failure leaves the staged version changes without a release commit.
The release command requires a clean worktree, so inspect the remaining changes
before retrying:
git status --short
git diff -- package.json package-lock.json
git diff --cached -- package.json package-lock.json
Undo only the version changes generated by the failed attempt, then stage only
those corrections. Preserve unrelated edits. Verify that git status --short
is empty before rerunning the release command. If unrelated work remains,
finish it separately rather than discarding it to retry the release.
After the signed release commit exists, the command still verifies the commit
signature, subject, and digest trailer, rebuilds the package from the committed
tree, and creates and checks the tag. A failure at any of those steps leaves
the local release commit on main and, if the tag was already created, the
local tag. Nothing has been pushed. Do not rerun the release command: it
rejects a HEAD that differs from origin/main and cannot repair the state.
Do not push the commit or tag while signature verification, the reproducibility
check, or tag verification is incomplete.
Inspect read-only first:
git status --short
git log -1 --show-signature
git tag --points-at HEAD
git diff origin/main..HEAD -- package.json package-lock.json
Removing the local release commit or tag changes local refs. Obtain explicit approval after reviewing the exact refs, the failure, and a recovery path. Never replace a published tag. Do not automate recovery in the release command.
The .github/npm-package-files allowlist defines the complete public package.
Do not publish credentials, test fixtures, session data, or development notes.
Stable versions use latest. Prereleases use their prerelease identifier.