@timmyjl12/pi-context0.1.0
Configurable, cheap smart context management for the Pi coding 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
@timmyjl12/pi-context
A configurable Pi context extension combining pre-compaction shake, pi-vcc-style compaction and recall, and optional JEV relevance decisions.
pi install npm:@timmyjl12/pi-context
Try it for one run without installing: pi -e npm:@timmyjl12/pi-context. Requires pi 1.0 or newer. If you use pi-vcc, read Migrating from pi-vcc first. The extension never activates, uninstalls or replaces other extensions on its own.
How it works
- Shake at 60%, 70%, 80%: each rung once per cycle. Old tool/MCP results become bounded previews with recall references; current/protected turns are retained. Old or superseded skill loads become re-read markers, so skills do not monopolize context.
- Cache-aware timing (default): a rewrite invalidates the provider prompt cache from the earliest edited message onward. While the cache is warm, a due rung rewrites only if it pays back that one-time cost before the next compaction (break-even requests from the model's
costprices, measured prompt growth and the compaction point; model after billion-context-pi's compression-economics write-up). Otherwise it waits and is applied when the next prompt arrives after the model's cache lifetime (promptCache, elseshake.cacheTiming.idleTtlMs, 5 min), when the rewrite costs no extra cache miss. All rungs already reached are applied as one rewrite. After a model switch or on a provider that never reports cache reads, rungs rewrite at the turn boundary.shake.cacheTiming.mode: "boundary"restores immediate rewrites. When the judge narrows a plan, the judged plan is priced again before it is applied: if it removes less or now starts earlier in history and no longer pays back while warm, it waits for a cold prompt like any other deferred rung. - Compact at 95%: structured-free first, optional configured cheap summarizer second, native Pi fallback. Pi's own trigger (
contextWindow − reserveTokens, 16,384 by default) runs first on windows under ~328K tokens unless you raise it, and goes through the samesession_before_compactpath, so pi-context writes the summary either way. Recommended: keep Pi's compaction enabled (compaction.enabled: falsealso turns off Pi's overflow recovery) and make it a backup behind pi-context's 95% by lowering Pi's reserve below 5% of the window, e.g."compaction": { "reserveTokens": 4096 }in~/.pi/agent/settings.json(98% of 200K; usecompaction.modelOverridesfor per-model control). Overflow recovery does not depend on the reserve. pi-context reads Pi's settings (global, trusted project, model overrides) so its shake cost estimates use Pi's actual trigger, and/pi-contextdoctor reports whether Pi's trigger is a backup. A confirmed compaction (Pi'ssession_compact, or pi-context's own boundary compaction once committed) permits a new cycle after usage drops below 55%; if the kept tail stays above 55%, the ladder restarts from the post-compaction usage. A shake-induced dip alone does not replay completed rungs. Boundary compaction keeps at most 30% of the window verbatim. - Compaction builds on shake and JEV: both compaction paths summarize the shaken view, and Pi re-applies shake edits to the kept tail. Every pi-context summary (structured-free or cheap-model) ends its sections with Recoverable Tool Output: up to 24 recall pointers (
pi_context_recall id=…) for tool results leaving context, ranked JEV load-bearing > error > edit > other > shaken, with one-line previews for load-bearing and error results. The list and the read/modified file lists carry forward through each compaction'sdetails(Pi itself does not carry file lists from extension compactions). The section stays insidecompaction.maxSummaryChars. Only when pi-context owns compaction: with pi-vcc owning it (compaction.owner: "auto"while pi-vcc is loaded withoverrideDefaultCompaction), pi-context only shakes and this section is not produced; setcompaction.owner: "pi-context"or remove pi-vcc to enable it. - Recover originals: shake appends context edits rather than overwriting raw entries. Recall reads the current session's original entries, including text omitted from live context by shake or compaction.
- JEV (on when available): hosted TypeSafe JEV is used when a key is available — the environment variable named by
judge.typeSafe.apiKeyEnv(TYPESAFE_API_KEY) first, thenjudge.typeSafe.apiKeyin the owner-restricted config — or through Pi's native TypeSafe classifier (Pi 0.99+). Local Laya via explicit compatibility transport.shake.judge.modeisoff,ambiguousorall;alljudges every eligible result. For each result the judge sees the tool, a head preview, the call's arguments and any later calls on the same file (for example a latereditor re-read, which usually makes the old result stale). Setjudge.typeSafe.enabled: falseto turn it off. No available judge means deterministic reduction, not unverified pair pruning.
Automation thresholds support percentages or absolute token counts and exact provider/model overrides. Overriding a default threshold without specifying extras drops the inherited default ladder for that stage.
Commands and tools
| Surface | Purpose |
|---|---|
/pi-context |
Context controls, status, settings and diagnostics |
/pi-context pause / resume |
Pause/resume automation for this session |
/shake |
Manual shake while idle |
/pi-context-compact |
Request manual/native compaction |
/pi-context-recall <query> [scope:all] |
Display recalled history and supply it as context, without starting a model turn |
pi_context_recall |
Ranked keyword/regex search, pagination, exact id/index expansion, historical file drill-down and touched files |
pi_context_find_skill |
Optional skill discovery |
pi_context_review |
Optional JEV/Laya anti-slop review |
Recall defaults to the active lineage. scope: "all" reaches other branches of the same session, never earlier sessions. Stable #N references are numbered before lineage filtering; Pi's prompt/tool loadout records keep their number but are never listed. expand: [N] and id recover full original text in bounded output pages; #N:path drills into historical tool payloads, not a live file. mode: "touched" lists identifiable file operations with provenance. Regex runs in a terminable worker, with cancellation/deadline and explicit fallback rather than blocking Pi's event loop. In-memory sessions remain supported through the raw session manager.
Configuration
User (optional): <agent-dir>/extensions/timmyjl12/pi-context/config.json (normally ~/.pi/agent/extensions/timmyjl12/pi-context/config.json). No file means built-in defaults; nothing is written on load. Saves from /pi-context store only what differs from the defaults (a stage's threshold and extra rungs together), so the file stays small and later default changes still reach you; it resolves back to exactly what you saved. The folder is created owner-private and an existing file must verify as private before it is used. The verdict cache lives in the same folder (cache/). Older ~/.pi/agent/pi-context/config.json and ~/.pi/agent/pi-context.json are no longer read. Trusted project: <cwd>/.pi/pi-context.json. Model overrides use exact provider/model keys and do not get persisted into user defaults. Prefer environment variables for keys; the one stored secret supported is judge.typeSafe.apiKey (owner-restricted file, never displayed — the settings editor shows a placeholder and keeps the stored key unless you replace it, and doctor names only the source); native Pi provider credentials are used only on the registered classifier's HTTPS origin. A custom judge origin requires an explicit request/environment key. Invalid/inaccessible settings retain the prior valid configuration and report safe guidance; existing unsafe permissions are rejected, not repaired.
{
"version": 1,
"shake": {
"judge": { "mode": "all" },
"elideSkills": true,
"cacheTiming": { "mode": "cold", "idleTtlMs": 300000 }
},
"judge": {
"typeSafe": { "enabled": true, "apiKeyEnv": "TYPESAFE_API_KEY" },
"laya": { "mode": "off" },
"cache": { "persist": true, "maxEntries": 512, "ttlMs": 86400000 }
},
"recall": {
"enabled": true,
"maxSearchResults": 5,
"maxEntryChars": 500,
"maxOutputChars": 20000,
"regexTimeoutMs": 500
}
}
maxEntryChars bounds previews, not stored originals. Recall output limits do not rewrite session history. judge.cache.persist: false disables disk persistence; in-memory verdict reuse remains available. Published schema: schema/pi-context.schema.json.
Two different caches
Judge verdict cache: byte-identical judge-visible inputs reuse relevance verdicts. Entries are session-scoped and expire; resume can reload them when session identity and judge configuration match. Persistence contains hashes, numeric verdicts and counters only—no prompts, raw payloads, free-text choices or credentials. Same configuration does not unnecessarily clear hits. Private storage: owner/mode checks on POSIX and owner-SID/DACL checks on Windows verify directories and existing files before reads, restrict empty temporary files before bytes, and verify the final atomic replacement. Broad or reparse/symlink paths are rejected without repairing existing permissions. If private persistence cannot be verified, use judge.cache.persist: false; numeric in-memory reuse remains available.
Provider prompt cache: status uses actual main-assistant input, cacheRead and cacheWrite usage, separately from judge hits. Capped shake favors newer eligible edit groups and keeps the unchanged prefix verbatim. Reached rungs commit as one batch, and cache-aware timing only rewrites a warm cache when the rewrite pays back before compaction; otherwise it waits for a prompt that already misses the cache. While such a rung waits, pi-context answers Pi's cache_warming_decision with stop when idle, so no money is spent warming a prefix about to be rewritten. Changing historical messages can invalidate the suffix of the provider cache; unchanged hit rate is not guaranteed. The rewrite frontier, real usage and /pi-context's cache misses by cause (pi-context shake, compaction, model switch, idle expiry, Pi loadout change, unexplained; plus the cached share of the first request after the last rewrite) expose that tradeoff. No extra warming/model calls are made.
Safety and coexistence
compaction.owner:auto(default),pi-contextordefer.autodetects pi-vcc's commands/tool and follows pi-vcc's own settings (PI_VCC_CONFIG_PATHor~/.pi/agent/pi-vcc-config.json): withoverrideDefaultCompactionon (pi-vcc's default) pi-vcc compacts and pi-context only shakes; with it off pi-vcc only handles/pi-vcc, so pi-context compacts; for a provider in pi-vcc'sskipForProviders, neither compacts (that provider's own compactor was chosen). Explicit pi-vcc__pi_vcc__compactions are never overridden, and status names the compactor from the committed entry (details.compactor).shake.prunePairrequires a configured judge strongly rejecting every result in the call group and separately judging that nobody needs to know each call happened (both >=strongPruneScore). The call-record question is asked in the same judge request, so it adds no requests. Otherwise calls remain paired with marker results. Signed/thinking assistant blocks are not rewritten.shake.longTextis opt-in. Tool-call blocks and protected current/recent turns remain intact.- Skill filtering is optional and sticky per session; a judge outage reuses the already-filtered list instead of restoring every skill. Tool routing changes only configured namespaces; other extensions' tools remain untouched. With
tools.sticky(default) a selected namespace stays active until the next compaction and an outage keeps the current loadout, because Pi records every loadout change in the transcript. MCP-adapter-managed names are excluded by default;/pi-contextdoctor flags configured tools that are not registered (Pi 0.99.2 renamed MCP tools from-to_). - Supported session identity transitions reset policy, pause, rollback and reports, cancel old work, and suppress stale tool writes. Arbitrary concurrent SDK hosting is not a replacement-readiness claim.
- Laya is off by default: no manager, process or health probes. Even when configured, local setup occurs only if its judge profile is attempted; successful hosted JEV does not require local Laya. Managed shutdown kills the process tree with a bounded wait and host-exit fallback. Setup/install is explicit.
- Boundaries do not invoke the aborting manual compaction API. In-flight guards, cancellation, deadlines and handled asynchronous errors keep operations from overlapping or wedging the terminal.
Migrating from pi-vcc
- Try coexistence with
compaction.owner: "auto"; pi-vcc remains the compactor while pi-context supplies shake. - When satisfied, disable pi-vcc yourself and reload Pi. With no detected pi-vcc,
autolets pi-context own compaction. - Replace
vcc_recall//pi-vcc-recallusage withpi_context_recall//pi-context-recall. Verify resume, recall of shaken/compacted originals and real provider cache usage before making the cutover permanent. - Exercise representative sessions with switches and interrupts and inspect actual provider-cache usage. Automated deadlines/tree tests and synthetic live/terminal evidence are safeguards, not universal guarantees. Laya is optional/off by default; enabling a real managed installation requires its own installation-specific soak.
Trial and rollback
To try only this extension for one invocation, with no change to your package settings:
pi --no-extensions -e npm:@timmyjl12/pi-context
Omit --no-extensions to test coexistence with your configured extensions. Before a permanent switch, record your current package/resource selections with pi list and pi config. If satisfied, run pi install npm:@timmyjl12/pi-context, disable pi-vcc through pi config, and restart Pi. Do not load a second pi-context source alongside this one.
Rollback: exit the trial invocation, or run pi remove npm:@timmyjl12/pi-context and restore your recorded pi-vcc/resource selections. Keep raw sessions and legacy settings; no cache or history deletion is required.
The extension never removes another package or changes global Pi configuration on your behalf.
Development
npm install
npm run check # typecheck, lint, tests, import guard
npm run format:check
The suite runs against the Pi SDK, including a real AgentSession contract for cache-cold shake timing and native classifier compatibility.