omp packages

@ian-pascoe/pi-context-management0.8.2

Session-native Notes, History, and agent-owned Context Windows for Pi.

GitHub Actions Published 12 hours ago MIT ~1.7K downloads/mo

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.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

Pi Context Management

@ian-pascoe/pi-context-management lets a Pi agent continue work across native Context Windows using its own Notes, an explicit Handoff, a bounded recent Tail, and retrievable original History.

Requires Node >=22.19.0, Pi >=1.1.0, and a Pi runtime exposing the required checkpoint capabilities. The adapter checks runtime methods, writable hooks, and native append ownership rather than requiring an exact Pi version. Missing or lost capabilities fail closed before checkpoint mutation.

Development dependencies and the native compaction scheduling regression baseline are pinned to Pi 1.0.0. Runtime checks validate interface shape, not persistence ordering or compatibility with every future Pi release. Pi still lacks arbitrary-time checkpoint mutation through its public extension API.

Install

pi install npm:@ian-pascoe/pi-context-management
# or from this checkout
pi -e ./packages/pi-context-management/src/index.ts

Tools and commands

Surface Purpose
context_notes List, read, write, append, delete, copy, or literally search named Markdown Notes.
context_history Browse Context Windows and entries, read exact recorded entry JSON, or perform case-sensitive literal search.
context_rollover Save an explicit agent-written Handoff and request an immediate native Context Checkpoint after the complete tool batch.
/context Inspect Pi's native context usage and compaction settings, Notes, and recent Context Windows.
/compact Ask the agent to update Notes, write a fresh Handoff, roll over, and then wait for the next user input.
/rollover Request the same pausing preparation directly, including when native compaction has no history to compact.

context_rollover registers with Pi's model-only exposure: it stays declared to the model while active, including under codemode.mode: "only", but Pi never offers it to codemode scripts or other tools' ctx.executeTool() calls, so a script sees tools.context_rollover as nonexistent. It must also be the only direct call in its tool batch; batched calls are rejected before checkpoint mutation, which also keeps nested calls out on Pi runtimes that predate exposure. context_notes and context_history keep Pi's default exposure.

context_notes and context_history declare an outputSchema and return matching structuredContent, so a Pi codemode script receives an object rather than JSON text. Script fields are snake_case, like Pi's bash and pi-termctrl; the model still reads the same camelCase JSON text, and session details keep their camelCase shape. Fields present depend on the action:

Tool / action Script value
context_notes list { notes: [{ name, updated_at, ref, characters, agent?, session? }], total, next_offset }
context_notes read { name, ref, content, offset, total_characters, next_offset, agent?, session? }
context_notes write/append/delete/copy { action, name, saved: true }
context_notes / context_history search { matches: [{ ref, name?, agent?, session?, offset, preview }], next_offset }
context_history windows { windows: [{ ref, items }], total, next_offset }
context_history list { items: [{ ref, type, timestamp, preview }], total, next_offset }
context_history read { ref, resolved_in_session, format, content, offset, total_characters, next_offset, availability }

Failures still throw. context_rollover has no schema because it cannot run inside a script.

Notes use labels rather than filesystem paths. A session branch may hold up to 128 Notes; a Note name is 1–64 characters and content is at most 64,000 characters. Append inserts one newline before the appended text when the existing Note is non-empty and does not already end with a newline; the limit applies to the joined content, separator included. Appending empty text leaves the Note unchanged. Lists and search return at most 20 results per page. A Note read returns the whole Note unless offset/limit select a character range; a History read returns at most 2,000 characters of entry JSON per call, from a zero-based offset. Stable references have the form context:<source-session>:<entry>.

context_history list previews describe each entry instead of its JSON envelope: user: <text…>, assistant: <text…> or assistant → bash(<command…>), toolResult(read): <text…>, custom(<customType>), thinking_level_change(<level>). Previews are one line of at most 120 characters. list and search accept optional type (recorded entry type such as message, custom, or compaction) and role (message role such as user, assistant, or toolResult, which implies message) filters; both default to no filter, so every entry is returned, and total/next_offset count the filtered entries. Search previews show the decoded text around a match, while offset still addresses the serialized entry JSON that read returns. A direct search call skips its own assistant tool-call block, so its query does not match itself; a search run from a codemode script has no such block, so the script's text can match.

Lineage scope

context_notes list and search, and context_history search, accept scope: "branch" (the default) covers this session's selected branch, as before; "lineage" adds the sessions of the agents that spawned this agent and that it spawned, at any depth, but not its siblings. Scoped results carry agent (the owning agent's ID, or root) and session. Other sessions are read from their files as their latest branch, live and read-only: they are never written, never opened through Pi's session manager (which can rewrite a file), and a half-written final line from a running session is skipped. A ref from a scoped result works with context_notes read (the current version of that Note) and copy (an unlinked snapshot saved under the same name, or name; it fails rather than overwrite an existing Note), and with context_history read. History windows and list browse this session only.

Lineage comes from the Agent Lineage Record that @ian-pascoe/pi-utils/agent-lineage defines and a subagent extension such as @ian-pascoe/pi-minimal-subagents writes into each child session; children live in their root agent's session folder, which the lineage scope reads. Without such an extension, or for children created before it wrote records, the lineage scope covers only this session. The Note Index lists only this session's own Notes.

History is read-only and limited to recorded entries on the selected branch, unless a scope says otherwise. Forks inherit entries on their selected path and then diverge; abandoned siblings are excluded, and other sessions are covered only by a scope. Context-only Child Agent inheritance does not copy the source Notes/History store, so an inherited reference may be unavailable locally. Foreign references resolve only when a persisted owned record proves the issuer had that entry; otherwise browse the current branch for a fresh reference. Reads do not open arbitrary external spill paths or reconstruct unavailable originals.

Tool annotations (MCP semantics, reported by pi.getAllTools() and never sent to model providers) are all closed-world. context_history is read-only. context_notes and context_rollover are not read-only, but are non-destructive and not idempotent: Notes and Handoffs append to the session journal and earlier values stay readable through History.

Transcript previews

Note writes/appends and Rollover Handoffs display their text as tool arguments stream in. Collapsed previews use at most eight rendered lines, including the heading and any omission notice, and follow the newest text. Expand the tool output to read the full text. Completed writes and Rollover requests retain the preview; a saved Handoff still indicates a request, not a completed checkpoint. Other operations keep their compact summaries.

Context Windows

A normal Rollover carries standing instructions, the agent-written Handoff, a Note Index of at most 4,000 characters, and a Tail sized by contextManagement.tailTokens (default 0). With the default, the Tail is only Pi's newest cut point: the context_rollover call and its result. The Handoff, Notes, and History carry continuity instead of a raw transcript, as in Codex's experimental context management. Pi's cut points still decide where the Tail may start, so tool calls stay with their results; omitted History remains retrievable. An Emergency Rollover keeps Pi's native keepRecentTokens retention, because its saved Handoff may be stale.

When Pi requests normal automatic or manual compaction, Context Management asks the agent to refresh useful Notes and call context_rollover alone with a fresh Handoff. This applies equally to TUI /compact, SDK, and remote compaction. Automatic threshold preparation continues the current task after the checkpoint. Manual preparation stops with the checkpoint and waits for the user's next input without another model request; its custom instructions shape the Handoff but cannot resume work. A direct agent-initiated context_rollover outside manual preparation continues normally. The native summarizer is replaced, not called in addition. Preparation uses ordinary agent turns and can therefore make model requests. While preparation is pending, repeated threshold checks do not inject more reminders.

/rollover [instructions] requests pausing preparation directly, even when Pi's native compaction preparation has no history to compact. Its instructions are limited to 2,000 characters. Pi owns /compact, including its model/auth and history checks. A redirected SDK compact() call rejects with Compaction cancelled while asynchronous fresh preparation proceeds; it does not return an immediate checkpoint result. The TUI may likewise display cancellation before the preparation notice. That cancellation is not a completed checkpoint. If preparation is cancelled, fails, or ends without Rollover, the extension reports noncompletion, leaves the existing conversation intact, and does not silently use a stale Handoff or repeatedly nudge the agent. Already acknowledged Notes remain saved; request /rollover explicitly to try again.

Actual native overflow is the exception: an Emergency Rollover immediately uses the last saved Handoff, marked stale or absent, rather than attempting another oversized preparation request. Native overflow includes Pi's recoverable truncated-response case. Recover recent work through History. All paths use the same native checkpoint representation. Resume, fork, tree navigation, and Pi's existing native inheritance consume that checkpoint directly. Running Child Agents are not replaced or patched.

Manual and threshold compaction are claimed before other session_before_compact hooks run, as if Context Management cancelled first. Other hooks therefore cannot veto or delay Rollover preparation, and summarizer overrides such as pi-claude-bridge never spend a request on a discarded summary. During native overflow, other hooks may still observe or cancel recovery. If one supplies compaction content, the Emergency Rollover replaces it regardless of load order, and a warning names that extension. Empty observer results cannot trigger Pi's native summarizer fallback. Every Context Checkpoint, including one committed directly by context_rollover, emits Pi's session_compact event so provider session caches and other listeners observe the new Context Window.

Pi alone owns context accounting, automatic compaction timing, and Emergency Rollover retention. The extension owns only the normal Rollover Tail size and the Idle Rollover below. There are no extension-owned 80%/90% thresholds or fit checks. Pi owns overflow retry and permits at most one rebuilt request. User cancellation does not trigger recovery, and completed tools are not replayed.

Idle Rollover

A large Context Window left idle loses its provider prompt cache, so the next message would resend all of it uncached. Idle Rollover, modelled on Claude Code's idle compaction, prepares a pausing Rollover just before the cache expires, while the preparation request can still read the cached prefix cheaply. The next message then starts from the small new Context Window.

  • When: after an agent run settles (not on Escape) in an interactive frontend (tui or rpc; never in print-mode runs or Child Agents), when Pi's native context usage is at least minTokens (default 200,000), and nothing has happened since: no input, new turn, model or thinking-level change, tree navigation, or Context Checkpoint.
  • Timing: Pi's cache-warming refresh point, 90% of the model's prompt cache lifetime (at least ten seconds early), plus two seconds so Pi's own decision lands first. The lifetime comes from the model's promptCache tier that PI_CACHE_RETENTION selects: the short tier by default (five minutes on Anthropic, so about 4.5 idle minutes) and the long tier with PI_CACHE_RETENTION=long (one hour, about 54 minutes). Models without a lifetime never Idle Rollover.
  • Pi cache warming: while Pi's cacheWarming: "idle" mode keeps refreshing the cache, Idle Rollover follows each refresh and waits. It runs only once warming stops, at its 30-minute idle limit or because Pi judges another refresh uneconomic, at the refresh point after Pi's last warm.
  • Expired caches: if the check runs past Pi's late-refresh cutoff (halfway from the refresh point to expiry), for example after the machine slept, it does nothing.
  • Preparation: it is a Manual Rollover started by a displayed pi-context-idle-prepare message: the agent refreshes Notes, writes a Handoff, calls context_rollover, and stops. Input typed meanwhile is queued as a follow-up and runs after the checkpoint, in the new Context Window. An Idle Rollover that is cancelled or ends without a checkpoint reports noncompletion, is not retried until the user starts another run, and does not suppress later threshold preparation.

Settings

Use Pi's native compaction settings in global ~/.pi/agent/settings.json or trusted project .pi/settings.json:

{
  "compaction": {
    "enabled": true,
    "reserveTokens": 16384,
    "keepRecentTokens": 20000
  }
}

These are Pi's defaults: enabled controls automatic compaction, reserveTokens controls its headroom, and keepRecentTokens controls recent-history retention for native compaction and Emergency Rollover. Disabling automatic compaction leaves manual compaction and explicit Rollover available. /context reports native usage and settings, not a separate estimate.

The normal Rollover Tail and Idle Rollover are configured under contextManagement in the same files; a trusted project overrides global settings key by key:

{
  "contextManagement": {
    "tailTokens": 0,
    "idleRollover": { "enabled": true, "minTokens": 200000 }
  }
}

All keys are optional and default to the values shown. tailTokens is a nonnegative integer budget for recent History kept after a normal Rollover, measured with Pi's own estimate, which also counts thinking text that providers may not replay. contextManagement is this extension's namespace, not a Pi setting. An invalid tailTokens or idleRollover value is ignored for that file, with one warning per session load.

The other, obsolete contextManagement keys are ignored: warningThreshold, emergencyThreshold, safetyMarginTokens, and outputReserveTokens. A block holding anything but tailTokens and idleRollover (or one that is not an object) in global or trusted-project settings produces one warning per session load pointing to native compaction settings. The extension neither edits configuration nor blocks continuation, even if the obsolete block is malformed. Remove it when convenient; there is no one-to-one migration of percentage thresholds.

Pi's usage is not an exact outgoing-request measurement. Initial oversized input or later growth in standing instructions, tool declarations, or other extensions' projections can still reach the provider limit. Native overflow recovery is the backstop; the extension does not intercept provider payloads, add a sizing margin, or promise that a fresh Handoff will fit.

Failure behavior

Notes are persisted independently, so an acknowledged Note survives a later failed or cancelled Rollover. A checkpoint append failure leaves the prior Context Window selected, stops Context Management, and requires fixing the storage failure and reopening the persisted session (/reload alone is insufficient); rollback of Pi's speculative in-memory journal entries is not transactional. A post-append refresh failure preserves the committed checkpoint; reopening restores its Context Window.

Pi defers initial journal flush until an assistant response exists. If the first request is already too large, shorten it before retrying—the extension cannot safely create a durable checkpoint before the first assistant turn.

The extension uses Pi session entries only. It does not edit session files directly, add repository memory files, run a database or daemon, call a background model (Idle Rollover is an ordinary agent turn), use embeddings, replace the subagent framework, or manage tool exposure.

This is privileged extension code: review it before installing it into an agent that can access local files, tools, or credentials.