pi-compact
不依赖 LLM 的 Pi 自动压缩、精确历史召回与上下文增强扩展
Package details
Install pi-compact from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-compact- Package
pi-compact- Version
0.8.0- Published
- Nov 2, 2026
- Downloads
- 1,345/mo · 119/wk
- Author
- davideasden
- License
- MIT
- Types
- extension
- Size
- 254.1 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-compact
中文版:README.zh-CN.md
A long-term memory, deterministic session-compaction, and exact-history-recall extension for Pi.
The core of pi-compact is long-term memory. Compaction manages window capacity: history remains recoverable, and durable memory can be reconstructed after compactions, restarts, and context-window switches, then queried through tools on demand. The extension calls no LLM; the deterministic checkpoint still contains only pointers and audit metadata, while a separate session-scoped, rule-based work summary is extracted from original text with entry IDs. That summary can restore context but is not a semantic conclusion. Original session entries remain the source of truth and can be re-read through the recall tool or command.
Features
- Stores an append-only memory event log under
.pi/pi-compact/; current memory is rebuilt by a pure projector, and older events cannot silently overwrite newer state. - Users write authoritative memory with
/remember,/memories, and/forget. Model proposals stay provisional and never become active or pinned by themselves. - Models query history through tools on demand. After a successful compaction, the extension builds a session-scoped structured work summary from the primary records involved in that compaction, keeping excerpts, files, and entry IDs; the summary accumulates only along the current branch's compaction chain, can be injected on
before_agent_startfor the current session, and can be searched through the recall tool. It is an index of original text, not semantic inference or a verified conclusion. The extension registers nocontexthook. Authoritative long-term memory still injects only pinned/active records the user wrote with/remember. - Takes over Pi's native
/compactcommand and normalmanual,threshold, andoverflowcompactions. - Reuses Pi's own boundary calculation, token accounting, persistence, and recovery flow. The checkpoint is a deterministic pointer/audit extract, not primary memory.
- Records a WindowManifest (
windowId, parent window, retained boundary,sourceCount,sourceHash,previousHash). - Verifies that tool calls and tool results are fully paired before compacting; on unsafe boundaries it falls back to an earlier safe boundary first and only cancels when no safe boundary exists, to avoid breaking context.
- Produces a deterministic event ledger and never infers work completion or semantic conclusions. Rule-derived records extract files, commands, exit codes, and test counts, plus user sentences carrying explicit durability markers, and stay provisional with provenance. They are session-scoped and never shared across sessions.
- History records distinguish
primaryvsderived:compactionandbranch_summaryare derived and can be filtered withsourceClass; thinking remains inrawbut not in default search text. - Provides the
pi_compact_recalltool with list/search/read, entry-ID lookup, keyword search, file-path and kind filters, pagination, and raw-entry replay. Long raw entries supportoffset/rawLimit. - Provides the
/pi-compact-recallcommand, which displays results through the UI without triggering a model turn. - Provides
pi_memory_search,pi_memory_read,pi_memory_propose,pi_memory_update, andpi_compact_new_context. - Automatically creates a project-level
.pi/pi-compact.jsonconfig without overwriting existing project or global configs.
Installation
The current source requires Pi >=0.87.1; development and integration tests pin 1.4.0, which requires Node.js >=22.19.0. The instructions below assume this repository lives at github.com/DavidEasden/pi-compact. The published v0.8.0 matches the current source.
Pi packages execute extension code, so review the source before installing.
Install from GitHub
Pin to a release tag (recommended — pinned refs are not moved by pi update --extensions or pi update --all):
pi install git:github.com/DavidEasden/pi-compact@v0.8.0
Or track the default branch without pinning:
pi install git:github.com/DavidEasden/pi-compact
SSH shorthand and raw HTTPS URLs work too:
pi install git:git@github.com:DavidEasden/pi-compact@v0.8.0
pi install https://github.com/DavidEasden/pi-compact@v0.8.0
Notes:
- The
git:prefix enableshost/user/repoandgit@host:user/reposhorthands; without it, only protocol URLs (https://,http://,ssh://,git://) are accepted. v0.8.0must be an existing tag or commit (create and push it once withgit tag v0.8.0 && git push origin v0.8.0). To move to a newer tag later, re-runpi install git:github.com/DavidEasden/pi-compact@<new-tag>.- Global installs are cloned to
~/.pi/agent/git/github.com/DavidEasden/pi-compact; with-l(project settings), the clone lives at.pi/git/github.com/DavidEasden/pi-compactand the project auto-installs any missing packages on startup after being trusted. - Try the package without installing it:
pi -e git:github.com/DavidEasden/pi-compact
Install from npm
The same code is published to npm as pi-compact:
pi install npm:pi-compact@0.8.0
Or track the latest published version:
pi install npm:pi-compact
Try it without installing it:
pi -e npm:pi-compact
Notes:
- A versioned spec such as
npm:pi-compact@0.8.0is pinned, sopi update --extensionsandpi update --allskip it. - Global installs go under
~/.pi/agent/npm/; with-l(project settings) they go under.pi/npm/.
Try locally
Run from the project root:
npm ci
pi -e /absolute/path/to/pi-compact
You can also point directly at the entry file:
pi -e /absolute/path/to/pi-compact/index.ts
Install the local package
pi install /absolute/path/to/pi-compact
This writes to the global Pi settings by default. Use -l to write to the current project's .pi/settings.json:
pi install -l /absolute/path/to/pi-compact
The extension uses Pi's @earendil-works/pi-coding-agent API, verified against Pi 1.4.0 for context_edit, post-compaction projections, and the current extension lifecycle. Pi and typebox are peer dependencies provided by the Pi environment; the development dependency pins Pi 1.4.0 for reproducible host integration tests.
Configuration
On first startup, if there is no project config and no global config in the user directory, the extension creates:
.pi/pi-compact.json
Config lookup order:
- Current project
.pi/pi-compact.json - Global
~/.pi/agent/pi-compact.json - Built-in defaults
The extension uses the first existing config file and fills in missing fields with defaults; project and global configs are not merged field-by-field. If the project config exists but cannot be parsed as JSON, the extension falls back to the default config and does not read the global one.
Default config:
{
"enabled": true,
"overrideDefaultCompaction": true,
"summaryMaxChars": 12000,
"autoRecall": true,
"autoRecallMode": "full",
"autoRecallMaxChars": 5000,
"recallMaxResults": 8,
"recallMaxChars": 16000,
"debug": false,
"memory": {
"enabled": true,
"pinnedInjection": true,
"proposalsProvisionalOnly": true,
"hintMaxChars": 4000,
"deriveOnCompact": true
},
"history": {
"autoRecallPrimaryOnly": true,
"excludeInContext": true
},
"window": {
"manifest": true
},
"sessionSummary": {
"enabled": true,
"inject": true,
"maxChars": 6000,
"maxEvidence": 80
}
}
Config fields:
| Field | Default | Description |
|---|---|---|
enabled |
true |
Enables compaction takeover; recall tools remain available and memory is controlled by memory.enabled |
overrideDefaultCompaction |
true |
Whether to take over Pi's normal compaction; when disabled, the default compaction is kept |
summaryMaxChars |
12000 |
Maximum character count of the deterministic checkpoint text |
autoRecall |
true |
Legacy compatibility field; does not enable automatic recall |
autoRecallMode |
full |
Parses legacy full/hint/off modes; none inject history at runtime |
autoRecallMaxChars |
5000 |
Legacy auto-recall budget; no current runtime effect |
recallMaxResults |
8 |
Legacy auto-recall count; no current runtime effect. Manual queries use limit |
recallMaxChars |
16000 |
Recall output budget, always enforced for model tools. Only the UI command can explicitly request an oversized complete single raw entry |
debug |
false |
Whether to print extension debug logs (counts and character totals only; never original text) |
memory.enabled |
true |
Enables durable memory commands, tool reads/writes, and rule derivation |
memory.pinnedInjection |
true |
Append user-authored pinned/active authoritative memories to the system prompt on before_agent_start. Provisional, rule-derived, and model-proposed records are never injected. Requires memory.enabled |
memory.proposalsProvisionalOnly |
true |
Model proposals can only be written as provisional; even false does not auto-promote them to active/pinned |
memory.hintMaxChars |
4000 |
Character budget for the authoritative-memory hint injected on before_agent_start |
memory.deriveOnCompact |
true |
Write rule-derived provisional records into the current session after a successful compaction (files, commands, exit codes, test counts, and user sentences with durability markers); never shared across sessions |
history.autoRecallPrimaryOnly |
true |
Legacy automatic recall source filter; no current runtime effect |
history.excludeInContext |
true |
Legacy automatic recall deduplication flag; no current runtime effect |
window.manifest |
true |
Write WindowManifest and the window event log after successful compaction; cancellation writes neither |
sessionSummary.enabled |
true |
Whether to generate a deterministic work summary for the current session after a successful compaction and expose it to the summary tool |
sessionSummary.inject |
true |
Whether to inject already-committed summaries for the current branch into the current session's system prompt; never injected across sessions |
sessionSummary.maxChars |
6000 |
Maximum characters of the auto-injected summary; trimmed at whole JSON evidence items |
sessionSummary.maxEvidence |
80 |
Maximum original-text evidence items kept per session summary, minimum 2, preserving the initial user request and recent evidence |
Flat aliases such as memoryEnabled, memoryHintMaxChars, historyAutoRecallPrimaryOnly, and windowManifest are also accepted; nested objects win. Numeric fields must be positive safe integers; sessionSummary.maxEvidence is at least 2. The caps for summaryMaxChars, autoRecallMaxChars, recallMaxResults, recallMaxChars, memory.hintMaxChars, sessionSummary.maxChars, and sessionSummary.maxEvidence are 100000, 50000, 30, 100000, 50000, 30000, and 500 respectively; legal values above a cap are clamped, invalid values fall back to defaults, and unknown fields are ignored. Char budgets are not token budgets. Defaults enable memory and keep model proposals provisional; history and summaries are queried through tools on demand, and automatic injection is limited to a budgeted session excerpt index plus user-confirmed pinned/active memories. Legacy injection settings still cannot restore the removed context hook.
The automatic compaction threshold and retained-tail size are still controlled by Pi's own compaction settings; this extension does not set its own trigger threshold.
Usage
Compact now
Run Pi's native command:
/compact
Pi's native /compact command calls its normal compaction flow. When enabled and overrideDefaultCompaction are both true, this extension receives the session_before_compact event and replaces Pi's default LLM summary with its deterministic checkpoint. The extension does not register a separate compaction command. When enabled or overrideDefaultCompaction is false, /compact keeps Pi's default summary behavior.
Authoritative long-term memory
Durable memory lives in .pi/pi-compact/memory.jsonl under Pi's ctx.cwd workspace directory. Sessions started with the same cwd share workspace memories; a different cwd gets a separate store, even when the session IDs match. The extension does not infer a Git root. session memories are visible only in the session that created them. The public scopes are workspace and session; old project and user event scopes are projected as workspace without rewriting the append-only log. User writes are authoritative; model proposals are always provisional and become active/pinned only after the user confirms them with /remember. The extension cannot guarantee that the model will obey these memories.
Appends to memory.jsonl (and windows.jsonl) are guarded by a per-log synchronous file lock (.pi/pi-compact/memory.jsonl.lock, windows.jsonl.lock) so concurrent Pi processes cannot interleave the read-last → compute-seq → append sequence and lose events. PI_COMPACT_LOCK_TIMEOUT_MS is only a bounded wait timeout (mainly for tests), not a live-lock lease: a lock whose owner PID is still alive is never reclaimed because of age. Crash recovery deletes a lock only when the owner PID is known dead, when stored start time and the live process start time are both readable and differ (PID reuse), or when this process can prove from start time that it left the lock behind and does not currently hold it. Linux reads /proc/<pid>/stat; macOS and other available Unix platforms try synchronous ps with TZ=UTC; Windows tries standard OS facilities such as PowerShell Get-Process StartTime. Start-time identity is best-effort — not every platform can read it, and any failure is treated as unverified. Unparsable, empty, or otherwise invalid lock metadata is not deleted within a grace period (it may be a concurrent create/write window); after the grace period (PI_COMPACT_STALE_LOCK_GRACE_MS, default 1000 ms, mainly for tests) it is reclaimed as a crash leftover so an empty lock file cannot deadlock writes forever. Within the grace period, unverified identity waits until the timeout and throws a clear error that owner metadata could not be verified or the lock is still held, and that the write did not complete. Manual deletion of the .lock file remains the explicit recovery path. The lock is reentrant within a process and is always released when the transaction ends. Release and reclaim require the lock file's owner token to match, and also the pid/startTime when those fields are present; missing expected metadata or a mismatch never deletes another owner's lock. Write failures throw explicit errors that surface to the user or model — a write is never reported as successful after a failure.
When reading either log, events must form an unbroken chain: seq starts at 1 and increases by exactly one, prevHash must equal the previous accepted event's hash, and each event's own hash must be correct. Reading stops at the first invalid, duplicated, skipped, or tampered event and only replays the trusted prefix. Once such an event exists, further appends to that log are rejected with an explicit error: the user must repair the log by hand before writing again, and the extension never truncates or rewrites the log to hide the problem. An unparsable half-line at EOF is still tolerated — it is skipped on read and the next append seals it, so a crash mid-write remains recoverable.
/remember use pnpm instead of npm
/remember pin kind:constraint do not change the production database
/remember supersede:mem_abc the new authoritative statement
/memories
/memories status:pinned token
/forget mem_abc
/remember accepts pin, kind:, scope:, priority:, and supersede:<id>. /memories can filter by status:, kind:, and keywords. /forget marks a memory as resolved so it leaves default memory queries. These commands only perform deterministic local writes and UI notifications; they do not trigger a model turn.
Memory tools:
| Tool | Description |
|---|---|
pi_memory_search |
Search memories; with no query, lists pinned/active/provisional |
pi_memory_read |
Read by ID; long content can be sliced with offset/limit |
pi_memory_propose |
Propose a provisional memory; it never becomes active/pinned automatically |
pi_memory_update |
Can only edit/resolve the model's own provisional proposals |
pi_compact_new_context |
Requests compaction after all tools in the batch finish, then resumes the task on success; if unsupported, suggests /compact |
Rule-derived memories have author=rule and provenance, stay provisional, and are not user-confirmed facts. They use scope=session and are visible only in the session that produced them. Beyond files, commands, and test counts, the extractor only picks short user sentences carrying durability markers such as “prefer”, “by default”, “always”, or “in this project”, classifying them as preference, constraint, or decision. It does not analyze assistant narration, does not infer long-term preferences from ordinary requests, and skips suspected credential content. Without a valid session ID nothing is derived. Records stay provisional until the user confirms them and are never injected as authoritative memory; legacy rule-derived workspace provisional records are marked resolved on the next successful compaction, while user-written records are untouched.
Durable-memory writes are bounded. A memory body over 8000 characters is rejected rather than truncated. sourceEntryIds are deduplicated and capped at 64 entries / 4096 characters, with truncation reported in the tool result. Model proposals with identical content in the same scope (and session, for scope:session) are written once. Provisional records authored by the model or rules leave default lists and search after 30 days; explicit status:provisional queries still return them, and user-authored records never expire this way. Memory search and read output is capped at 16000 characters including JSON metadata and escaping; search excerpts are limited to 600 characters per body, and omitted content can be read by ID.
With debug=true, the extension logs summary/derivation candidate counts, characters and token estimates, elapsed time, failure categories, and — at Pi's before_provider_request boundary — payload and stable-prefix hashes and lengths; assistant usage records the provider-reported input/output/cacheRead/cacheWrite. Logs never contain prompt or memory body text. Hash/prefix stability only verifies the provider payload the extension actually observes; cacheRead/cacheWrite are provider-reported values, and whether they yield real cost savings still depends on the provider and server implementation, which the extension does not guarantee.
Inspect status
/pi-compact-status is a read-only diagnostic command. It reports the effective switches (enabled, memory, summary, debug), memory and window log event counts, row counts and file sizes, the current session's summary event and evidence counts, and process-local injection and compaction statistics (cache hits/misses, last injected characters and tokens, last compaction reason, duration, record count, checkpoint characters, and derived-record count). It notifies through the UI, sends nothing to the model, and triggers no model turn.
Manual recall
Run inside Pi:
/pi-compact-recall token refresh
Supported argument forms:
/pi-compact-recall file:src/auth/session.ts
/pi-compact-recall kind:tool_result timeout
/pi-compact-recall ids:entry-123,entry-456 raw
/pi-compact-recall scope:all old config page:2 limit:5
/pi-compact-recall raw:true file:src/auth.ts
Arguments:
| Argument | Description |
|---|---|
| Plain text | Searches original session records by keyword |
ids:id1,id2 |
Selects records exactly by entry ID |
file:path |
Matches file paths extracted from records |
kind:type |
Filters by user, assistant, tool_call, tool_result, bash, or custom |
scope:active-lineage |
Searches only the current branch; the default |
scope:all |
Searches the whole session, including other branches |
page:N |
Result pagination, starting at 1 |
limit:N |
Results per page, default 8, range 1 to 30; not affected by recallMaxResults |
raw or raw:true |
Outputs the raw session entry JSON |
summary or action:summary |
Reads the most recent committed structured summary for the current session and branch |
summary_search or action:summary_search |
Searches the current branch's summary evidence by keyword, returning excerpts and source entry IDs |
list or action:list |
Bounded listing of recent records; no keyword required |
offset:N |
Character offset for sliced raw reads |
rawLimit:N |
Character length for sliced raw reads |
| `sourceClass:primary\ | derived\ |
Entry IDs in the examples are placeholders; use the real IDs shown by recall output.
Summaries are extracted by rules from the current session's primary original records and contain only excerpts, categories, files, and source entry IDs; they do not infer completion status, test-result meaning, or user preferences. Summaries accumulate along the current branch's parent compaction events; different sessions use separate hash-named logs. When the full content is needed, read the original by the entry IDs the summary cites.
When ids is given, records are selected by ID and scope and limit apply, while the keyword, file, kind, and page are ignored; results are returned in original session order. Without ids, a keyword or file is required unless action is list — an empty query or a kind-only query does not list the full history.
Keyword search is tokenized text matching; it does not support regular expressions or semantic search. File filtering only matches already-extracted paths and never reads files from disk. Paths mainly come from tool arguments and simple bash commands; paths inside message bodies are not necessarily indexed. The command splits arguments on whitespace and does not parse quoted paths with spaces; pass such paths via the tool's file field instead.
The command displays recall content through UI notifications without sending it to the model or appending session messages. The UI command supports scope:all for other branches; the model tool always stays on the current branch.
pi_compact_recall tool
The model can call it directly:
{
"query": "token refresh",
"file": "src/auth/session.ts",
"kind": "tool_call",
"scope": "active-lineage",
"page": 1,
"limit": 8,
"raw": false
}
Available fields mirror the /pi-compact-recall arguments: query, entryIds, file, kind, scope, page, limit, raw, action, offset, rawLimit, and sourceClass. action:summary reads the session summary, and action:summary_search searches summary evidence and returns source IDs.
action is list/search/read/summary/summary_search. Summary actions read only committed summaries matching the current session ID and the current branch's compaction entries; search results carry entryId, so the original entry can be read with entryIds. Summary excerpts are untrusted historical data and must not be treated as verified conclusions or instructions. All model-tool output, including a single raw entry ID, obeys the recallMaxChars hard budget. An oversized single raw entry returns valid JSON containing entryId, offset, limit, totalChars, truncated, and body; use offset/rawLimit to continue reading. Only the UI command, with one explicit ID and raw and no slicing parameters, can return the complete original JSON without that budget.
Multiple raw hits include only complete entries that fit and list omitted IDs; JSON is never cut in the middle. Pretty output is clipped at complete result blocks. Pagination divides records; offset/rawLimit divides an individual raw entry. Raw data preserves stored tool arguments, outputs, timestamps, and parent links. Thinking stays out of default search text. compaction and branch_summary are derived and can be filtered with sourceClass.
Query history and memory on demand
The current version registers no context hook and does not auto-inject full history body text. On before_agent_start it can append a static compaction pointer, the current branch's structured work summary for the current session, and — when memory.pinnedInjection is enabled — pinned/active authoritative memories written by the user. The summary contains only rule-extracted excerpts of primary records, file lists, and entry IDs, is marked as untrusted JSON data, and is bounded by sessionSummary.maxChars. Provisional, rule-derived, and model-proposed long-term memories are never injected as authoritative memory. Historical detail stays reachable through pi_compact_recall.
The model's pi_compact_recall searches only the current branch. If the active lineage is unavailable, it does not expand to the whole session. Users can explicitly select scope:all in the /pi-compact-recall UI command. Tool results enter ordinary model context; UI command results only appear in the interface.
Stored originals remain available for exact retrieval. On-demand queries do not guarantee that the model recalls every relevant detail or follows every memory.
Compaction and data boundaries
pi-compact takes over only normal compactions and does not yet take over Pi's session_before_tree branch summaries.
During compaction:
- Uses Pi's
firstKeptEntryId, including context-invisible metadata and entries omitted bycontext_edit. - Converts the entries before the boundary from Pi's pre-compaction context projection into ID-bearing audit records.
context_editomissions affect the checkpoint's source count and hash; replacements affect the projected record content used for derived-memory inputs. The original raw entry remains available for explicit replay. - Generates a deterministic checkpoint with only
compactor,sourceCount, andsourceHash. It copies no history body and is not primary memory. - Stores
sourceEntryIds,sourceHash,sourceRecordCount,keptEntryId,omittedRecordCount,checkpointChars,summaryMaxChars,isSplitTurn, andestimatedTokensAfter(character count / 4, rounded up; not provider usage). Pi computes its own context-wide post-compaction estimate; the extension does not invent billed usage. - Previews each candidate compaction with Pi 1.4.0's
buildSessionProjection(), checking the retained tail after omissions and replacements. Results must follow their calls, and ordinary calls must have results; the replaced prefix does not block compaction. Unsafe boundaries fall back only to earlier candidates in the current compaction window, after previewing each candidate. No safe boundary, failed projection, or an aborted request cancels compaction without falling back to LLM summarization. Pi'serror/abortedassistant states may have calls without results. Once validation passes, checkpoint generation errors degrade to pointer JSON; a changed boundary gets a recomputedisSplitTurn. - Only after Pi commits compaction and emits success does the extension generate and append a window manifest under the log lock. Window IDs bind the session and actual compaction entry, so repeated events do not append duplicates. Rule-derived memories are also written after success, along with a session-scoped deterministic work summary that accumulates along the current branch's compaction chain and keeps excerpts, files, and entry IDs under
.pi/pi-compact/sessions/in a hash-named per-session log. Cancellation and failure leave no window, derived records, or summary. Legacydetails.windowremains readable; new manifests live in.pi/pi-compact/windows.jsonl.
Original session entries are the source of historical truth; a structured session summary is a deterministic excerpt index generated from primary records, carrying source entry IDs and the source hash — it makes no semantic inferences and does not verify statements. The user-written memory log is the sole source of authoritative durable memory. The checkpoint stores only counts and a hash; it is not a backup of raw text. Non-text content such as images shows only placeholder information in the text extraction.
The extension does not delete original session entries and does not create a separate backup; the raw text still relies on Pi's session storage. A finite context cannot display all history at once.
Development
Install dependencies:
npm ci
Run tests:
npm test
npm test runs unit and Pi SDK integration tests; npm run test:integration runs only the host lifecycle tests. Integration tests use a local Faux provider without API keys or online model requests, and write sessions and logs only to temporary directories.
Run the TypeScript type check:
npm run typecheck
Run the manual performance benchmark:
npm run bench
Inspect published contents:
npm pack --dry-run
The published allowlist is index.ts and src/; npm also automatically includes package.json and README files. Test files and tsconfig.json are not part of the package.
Project structure
index.ts Pi extension entry
src/config.ts Config loading, normalization, and scaffolding
src/hooks.ts Compaction projection validation and session hooks
src/recall.ts Recall tool and /pi-compact-recall command
src/memory.ts Memory commands and memory/new-window tools
src/status.ts Read-only /pi-compact-status diagnostics
src/core/content.ts Message text, files, thinking separation, and snippet boundaries
src/core/auto-recall.ts Legacy gate pure functions, not connected at runtime
src/core/lock.ts Synchronous log lock, owner-token reclaim, portable start-time identity
src/core/ledger.ts Deterministic checkpoint and details
src/core/session.ts Session entry conversion, sourceClass, search, and raw replay
src/core/jsonl.ts Corruption-safe JSONL I/O
src/core/projector.ts Pure-function memory event projection
src/core/store.ts `.pi/pi-compact/` event logs
src/core/window.ts WindowManifest and hash chain
src/core/summary.ts Deterministic session-summary extraction, isolated storage, accumulation, and search
src/core/working.ts Authoritative-memory hint rendering
src/core/memory-policy.ts Memory write limits, proposal deduplication, and provisional TTL
src/core/runtime-stats.ts Process-local injection and compaction counters
src/core/derive.ts Non-semantic rule derivation
src/types.ts Shared types
scripts/bench.mjs Manual performance benchmark
tests/ Unit tests
Verification scope
Verified so far:
Deterministic record extraction, keyword and file search, raw record preservation, and hashing.
Thinking stays out of default search; primary/derived filtering and current-branch enforcement for the model tool.
Deterministic memory-event replay, supersede/pin, EOF half-line tolerance, and rejected appends after a chain break.
Window hash chain, memory command/tool entry points, and sliced long-raw reads.
Compaction boundary checks for tool calls and tool results.
Config scaffolding and normalization of invalid configs, including memory/history/window.
manual,threshold, andoverflowcompaction reasons plus aborted requests, via simulated hook events.Empty active lineage does not widen the search; no
contexthook is registered, and only bounded session excerpts with source IDs are injected according to configuration.before_agent_startcompaction-pointer, session-summary, and authority-memory injection, including exclusion of provisional/rule/model records and thepinnedInjection/sessionSummary.injectoff switches.Deterministic session-summary extraction, session isolation, hash-named per-session logs, branch accumulation,
summary/summary_searchrecall, and rejection of untrusted prefixes in corrupted logs.Legacy auto-recall gates retain unit tests but are not connected at runtime;
working.tsremains in use only to render the authoritative-memory hint, not the oldpi-compact-memory-hintmessage.Log locks refuse token/metadata mismatches and do not reclaim live owners by age. Invalid metadata can be reclaimed after the grace period. Portable start-time identity (Linux
/proc, Unixps, WindowsGet-Process) and conservative unverified fallback are unit-tested without changingprocess.platformor recycling real PIDs.Clean dependency installation, TypeScript type checking, and real Pi CLI extension loading.
Pi 1.4.0 SDK metadata boundaries, full overflow retry,
context_editomissions/replacements and candidate projections, cancellation of orphan tool results, parallel/sequential tool-batch continuation, user abort, cancellation without side effects, success-event deduplication, and session persistence/restoration.Memory-tool disablement, session isolation, explicit historical status queries, long-content/JSON budgets, and search/read pagination.
Online model API responses and billing, manual TUI interactions, and long-running behavior remain outside these tests.
License
MIT