pi-jev-compaction
Pi Coding Agent extension that replaces LLM-summary compaction with TypeSafe Jev keep/drop/truncate decisions.
Package details
Install pi-jev-compaction from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-jev-compaction- Package
pi-jev-compaction- Version
1.0.0- Published
- Sep 18, 2026
- Downloads
- 761/mo · 761/wk
- Author
- each1024
- License
- MIT
- Types
- extension
- Size
- 279.4 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./src/extension.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-jev-compaction
Pi Coding Agent extension that replaces (or augments) Pi’s default LLM-summary compaction with TypeSafe Jev keep / drop / truncate decisions. UI strings and toasts are English only.
Score tool calls and results, drop or truncate stale ones, keep user/assistant text verbatim. Fails soft to Pi’s built-in compaction.
Algorithm and question format adapted from fast-jev-compaction (MIT). That repo’s Claude Code plugin can replace the entire message list; Pi cannot — see Approach below.
Quick start (30 seconds)
pi install npm:pi-jev-compaction- To pin this release, use
pi install npm:pi-jev-compaction@1.0.0(or use@latestfor the latest release). - Get a personal TypeSafe key at https://console.typesafe.ai/settings/keys
- Persist the key (see Key setup), then restart Pi or
/reload - Expect a ready toast, or run
/jev-status
Cost & fallback
Jev calls the TypeSafe API when compacting. Without a key, on network/auth/errors, when history cannot fit, when reduction is too small, or when aborted, the extension falls back to Pi’s built-in summary — no hard failure.
# From a local clone (no publish needed)
git clone <this-repo>
cd pi-jev-compaction
npm install
pi install /absolute/path/to/pi-jev-compaction
# Project-level install from npm (writes .pi/settings.json; shares the extension, not the key)
pi install -l npm:pi-jev-compaction
# Project-level install from a local clone
pi install -l /absolute/path/to/pi-jev-compaction
# Try for this session only
pi -e /absolute/path/to/pi-jev-compaction/src/extension.ts
Registry install note: Pi treats bare package names as local paths; always use the npm: prefix for registry packages (for example, npm:pi-jev-compaction).
On session start the extension toasts once (in-memory flag only; not written to disk; /reload does not repeat it):
TYPESAFE_API_KEYdetected:pi-jev-compaction: ready…- Missing: numbered steps (get key → export or env file → reload →
/jev-status)
Key setup
Each user brings their own TypeSafe key. Do not commit personal TYPESAFE_API_KEY values to the repo, settings files, or share them with colleagues.
| Who | What to do |
|---|---|
| You | Prefer export TYPESAFE_API_KEY in your shell profile, or create ~/.config/pi-jev-compaction/env (see below). |
| Colleagues / OSS contributors | Each person applies for their own TypeSafe key. This extension does not and should not ship or forward someone else’s key. |
| CI | Inject TYPESAFE_API_KEY from a runner secret. Without a key the extension falls back to Pi’s built-in summary. |
Do not put the key in ~/.config/pi-jev-compaction/config.json. That file accepts thresholds only; parsing and /jev-setup strip any apiKey field.
Persist the key
Option A — shell profile (preferred):
# zsh example (~/.zshrc)
echo 'export TYPESAFE_API_KEY="sk-..."' >> ~/.zshrc && source ~/.zshrc
Option B — env file (used only when TYPESAFE_API_KEY is unset in the process environment):
~/.config/pi-jev-compaction/env (or $XDG_CONFIG_HOME/pi-jev-compaction/env)
mkdir -p ~/.config/pi-jev-compaction
printf 'TYPESAFE_API_KEY=sk-...\n' > ~/.config/pi-jev-compaction/env
chmod 600 ~/.config/pi-jev-compaction/env
Comments (# ...) and blank lines are ignored; surrounding quotes are stripped. /jev-setup never writes the key into config.json.
Commands
| Command | What it does |
|---|---|
/jev-status |
Whether a key was detected (shows only detected/missing, never prints the secret), config + env-file paths, effective options, last compact outcome including why it fell back (no_key / jev_error / reduction_too_small / cannot_fit / aborted / …) |
/jev-setup |
Walks through applying for a key + export / env file; writes thresholds to config.json. Interactive confirm, or /jev-setup defaults, or paste JSON (apiKey is stripped) |
/jev-status
/jev-setup
/jev-setup defaults
/jev-setup {"keepThreshold":0.6,"minReductionRatio":0.3}
Options
Defaults match the Claude plugin.
| Option | Default | Description |
|---|---|---|
keepThreshold |
0.5 |
Minimum Jev probability to keep a call / result |
preserveRecentMessages |
6 |
Newest N Jev messages are never changed (the first message is always kept too) |
minReductionRatio |
0.25 |
If character reduction is below this, fall back to Pi’s default summary |
maxStateTokens |
25000 |
Estimated cap for state sent to Jev |
maxRequestTokens |
30000 |
Estimated cap for a single request (state + questions) |
truncateHeadChars |
300 |
Head characters kept when a tool result is truncated |
model |
jev-latest |
Jev model |
baseUrl |
https://api.typesafe.ai/v1/systemone |
System One endpoint |
Optional config file (thresholds only):
~/.config/pi-jev-compaction/config.json (or $XDG_CONFIG_HOME/pi-jev-compaction/config.json)
{
"keepThreshold": 0.5,
"preserveRecentMessages": 6,
"minReductionRatio": 0.25,
"maxStateTokens": 25000,
"maxRequestTokens": 30000,
"truncateHeadChars": 300,
"model": "jev-latest"
}
Environment overrides: PI_JEV_MODEL, PI_JEV_BASE_URL, PI_JEV_KEEP_THRESHOLD, PI_JEV_PRESERVE_RECENT, PI_JEV_MIN_REDUCTION, PI_JEV_MAX_STATE_TOKENS, PI_JEV_MAX_REQUEST_TOKENS, PI_JEV_TRUNCATE_HEAD, PI_JEV_GOAL.
Fallback & toasts
In the cases below the extension does not return compaction, and Pi continues with its built-in LLM summary. Each path has a matching toast (including manual / threshold / overflow):
| Path | Toast |
|---|---|
| No key | Fallback + how to configure (/jev-setup, signup URL, env file) |
| Jev network / auth / malformed response | Reason + fallback |
| History does not fit state budget | Reason + fallback |
reductionRatio < minReductionRatio |
“not worth it” + fallback |
| Very short / no scorable tool calls | Skip Jev, explain, then fallback |
AbortSignal cancelled |
Silent on session_before_compact; short note on session_compact_failed |
| Success | kept / truncated / dropped, approx. reduction %, elapsed time |
/jev-status records the last outcome’s kind (e.g. reduction_too_small) so you can see why Jev did not take over.
session_compact then confirms whether the saved summary is the Jev verbatim encoding or Pi’s built-in summary.
Approach & limitations vs Claude Code
Pi compaction is summary + cut-point, not Claude Code’s full-list replace.
Verified against @earendil-works/pi-coding-agent@0.85.1:
- Event:
session_before_compact, payloadSessionBeforeCompactEvent(preparation,branchEntries,reason:manual|threshold|overflow,signal). - Handler may return
SessionBeforeCompactResult:{ cancel?: boolean; compaction?: CompactionResult }. CompactionResult:{ summary, firstKeptEntryId, tokensBefore, estimatedTokensAfter?, usage?, details? }.SessionManageris append-only:ctx.sessionManageris read-only; history entries cannot be rewritten or deleted. There is no API equivalent to Claude’ssession.compact → { messages }.
So this extension:
- Converts
messagesToSummarize+turnPrefixMessages+ kept messages fromfirstKeptEntryIdinto JevMessage[](plus optionalpreviousSummary). - Runs the same
compact(): asks twonoulquestions per unpinned tool call (keep call / keep full result). - Encodes only the compactable region after prune / truncate into a verbatim structured summary (user/assistant text kept as-is; dropped tool calls omitted; truncated results keep head + note).
- Returns
{ summary, firstKeptEntryId: preparation.firstKeptEntryId, tokensBefore, details }. Pi still sends entries after the cut-point to the model unchanged.
What it cannot do (vs the Claude plugin):
- Cannot rewrite tool results in the “will be kept” region in place. Those messages sit after
firstKeptEntryIdand enter the next context verbatim.preserveRecentMessagespins them; Jev does not truncate them. - Cannot re-insert pruned older messages into the session tree; they only live inside the
summarystring. - No
compactAtPercent/turn.completeauto-trigger — Pi owns when compaction runs (manual/threshold/overflow). Configure Pi’s own compaction thresholds; this extension only handlessession_before_compact. - Therefore this is “lossless for text, lossy for tool bulk” summary encoding, not Claude-style object-level transcript replace.
Upstream parity (algorithm / config)
| Upstream feature | Status |
|---|---|
Options & defaults (keepThreshold 0.5, preserveRecentMessages 6, budgets 25k/30k, truncateHeadChars 300, minReductionRatio 0.25, jev-latest) |
Matched |
| State fitting stages, token estimate, question batching, keep/drop/truncate decisions | Matched (src/jev/) |
| Concurrent batched Jev requests, soft fallback on error / too-small reduction / no key | Matched (adapted toasts + /jev-status) |
Per-call decisions: diagnostic dump |
Matched (in verbatim summary + /jev-status) |
| Config file + env overrides for thresholds | Matched (~/.config/pi-jev-compaction/, PI_JEV_*) |
Full message-list replace via session.compact → { messages } |
Impossible on Pi (append-only SessionManager) |
compactAtPercent turn-complete auto-compact |
Impossible / N/A — Pi triggers compaction itself |
| Claude plugin marketplace / function hooks | N/A (Pi extension + pi install npm:pi-jev-compaction) |
Library API
import {
compactPiSession,
compact,
type JevAsker,
} from "pi-jev-compaction";
const outcome = await compactPiSession({
messagesToSummarize,
turnPrefixMessages,
keptMessages,
firstKeptEntryId: preparation.firstKeptEntryId,
tokensBefore: preparation.tokensBefore,
asker, // fake JevAsker in tests; omit to use TYPESAFE_API_KEY
});
if (outcome.ok) {
return { compaction: outcome.compaction };
}
// else: let Pi compact
compact(messages, asker, options) matches upstream fast-jev-compaction. Tests should inject a JevAsker and not hit the network.
Development
npm install
npm test
npm run typecheck
npm run build
Unit tests use a fake JevAsker and do not call TypeSafe.
License
MIT. Jev core lives under src/jev/ and NOTICE (adapted from fast-jev-compaction).