pi-memoria0.4.2
Global working memory, SQLite FTS5 recall, and complete Pi session search
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
pi-memoria
Global memory for Pi: startup rules in MEMORY.md, durable facts in SQLite FTS5, and cited search across every past conversation.
How it works • Installation • Hot memory • Tools • Configuration • Performance • Support
pi-memoria gives Pi one memory shared across every project: instructions that must apply from the first message go in a capped MEMORY.md, everything else in SQLite with FTS5, and past conversations stay searchable through ripgrep. Five tools, local storage only. No embeddings, no network calls, no background model work.
Requirements
- Node.js 22.19+ (uses
node:sqlite; earlier baselines 22.19/24.20, maintained suite 26.10.0). - A Node-based Pi host. The pinned development baseline is 1.0.0, the maintained Pi host. Standalone/Bun builds are not validated with
node:sqlite. - ripgrep (
rg), either on PATH or in Pi's managed<agent-dir>/bin/directory, for session search.
Installation
pi install npm:pi-memoria
This installs the current public npm release. The source version is recorded in package.json; unpublished checkout changes require a local install.
Activate with /reload in an idle session when intended, or a separately approved restart. To uninstall, run pi remove npm:pi-memoria; stored memory remains until you delete its directory.
Install from a local checkout
From the monorepo root:
npm --prefix packages/pi-memoria install --ignore-scripts --legacy-peer-deps --workspaces=false
pi install /absolute/path/to/pi-extensions/packages/pi-memoria
Keep the checkout in place: a local install references it directly. To try it without installing:
pi -e /absolute/path/to/pi-extensions/packages/pi-memoria/index.ts
How it works
| Store | What belongs there | How it is retrieved |
|---|---|---|
MEMORY.md |
Instructions that must apply before any retrieval cue appears | Loaded at startup and refreshed before every user prompt |
| SQLite + FTS5 | Preferences, facts, decisions, names, conventions | memoria_search |
| Original Pi JSONL sessions | What was actually said, including old branches and pre-compaction messages | memoria_sessions, with file and line citations |
"Start every sentence with beep_boop" belongs in hot memory: even a session starting with "Hello" must obey it. "The user likes apples" belongs in SQLite with tags such as fruit and preferences: a fruit recommendation supplies the retrieval cue.
The model decides what to save and when to search; nothing is extracted automatically. Before saving, it searches for related memories, keeps unchanged facts, and edits existing ones when information changes. SQLite rejects repeated identical adds; differently worded paraphrases depend on the model's judgment.
Hot memory
- [h_0123456789abcdef] [p=90] Start every sentence with beep_boop.
Priority is 0–100 (default 50). The entire file, including IDs and newlines, must fit in 5,000 UTF-16 code units, checked before every write. Content is single-line; CR, LF, U+2028, and U+2029 are rejected.
Duplicate adds reuse the existing bullet and consume no capacity. When space is needed, strictly lower-priority bullets are archived to SQLite first (hot-archive), then the file is atomically replaced; if that cannot free enough room, the write fails with the live file unchanged.
[!WARNING] Prefer the tools for edits. External edits can bypass the cap until the next load, and oversized content is never injected.
Recall
Keyword search uses the supplied terms with prefix matching and English stemming, not automatic terminology rewriting. Save personal shorthand as an ordinary fact containing both forms, for example The user's shorthand piem refers to the pi-extensions monorepo. Searching piem then retrieves that fact; use its meaning for a follow-up search when needed. Session search has no recency or project filter. For "remember when" questions, search sessions and cite the original entries; follow next_offset/next_text_offset, and check warnings and exhausted. A partial or failed search is never proof of absence.
Tools
| Tool | Purpose |
|---|---|
memoria_add |
Save a fact to SQLite or a startup rule to hot memory |
memoria_edit |
Change content, tags, priority, or hot text by ID |
memoria_delete |
Remove a memory by ID |
memoria_search |
Search SQLite with keywords, modes, and exact tags |
memoria_sessions |
Search or read original Pi session entries with citations |
Tool replies are compact; oversized results spill to a private pi-memoria-result-* file.
Add a fact:
{"content":"The user likes apples.","tags":["fruit","preferences"]}
Add a hot rule:
{"store":"hot","content":"Start every sentence with beep_boop.","priority":90}
Search memories:
{"query":"kubernetes deploy","mode":"all","tags":["infrastructure"]}
Search sessions:
{"query":"deadline","role":"user","after":"2025-03-04","before":"2025-03-05"}
Read a session entry:
{"action":"read","path":"/absolute/path/to/session.jsonl","line":42}
- Add:
storeislong_term(default) orhot; SQLite acceptstagsandsource. Identical content is reused withcreated: false; edits are the only way to change a fact. SQLite limits: 20,000 characters, 30 tags, 2,000-character source. - Edit/delete: pass an
id(m_for SQLite,h_for hot) and only the fields to change.expected_revisionor hotexpected_contentcatches concurrent writes. Deletion never archives hot bullets or erases sessions. - Search:
memoria_searchsearches SQLite only; hoth_entries are injected fromMEMORY.mdand cannot be searched or read by this tool.modeisany(default),all,phrase, orliteral; a miss falls back to a literal scan and reports the mode used.tagsmatch exactly and case-sensitively. Read an SQLite memory with itsm_ID; long content paginates viatext_offset. - Sessions: decoded JSON is searched, including hidden, ignored, and inactive-branch files. Results carry path/line citations.
exhausted: truemeans every accessible root was scanned without errors; warnings mean partial results, never absence.
Configuration
Environment variables and storage layout
| Variable | Effect |
|---|---|
PI_CODING_AGENT_DIR |
Pi's agent directory; memoria defaults to its memoria/ child and looks for managed ripgrep in its bin/ child |
PI_MEMORIA_DIR |
Override the single global memory directory |
PI_MEMORIA_SESSION_DIRS |
JSON array of additional absolute session roots |
~/.pi/agent/memoria/
├── MEMORY.md
├── memoria.sqlite
└── backups/
Database startup recognizes truly empty stores and the exact shipped memoria v1/v2 schemas, including legacy stores without an application identifier. Current stores receive the MEMO application identifier without a schema-version bump. Foreign, future, customized or unsupported schemas are refused before chmod, journal-mode changes or migration. Supported v1 migration preserves facts, archives, duplicates and FTS indexes.
Database/companion files must be regular single-link files, and existing directory components cannot be symlinks. Unsafe -wal, -shm, -journal aliases and orphan companions are refused. A regular companion observed with zero links during SQLite last-close is rechecked by name, at most 32 times; it is never accepted as an unlinked file. Main-file unlink, nonregular entries and multiple links remain fatal. Ownership inspection uses a private mode-0700 temporary snapshot of the database/WAL/journal, because even SQLite READONLY can alter original SHM read marks. Snapshot files use 0600, copying uses a fixed-size buffer with bounded change retries, and cleanup runs on success/failure. Startup inspection is linear in stored bytes and needs temporary disk capacity; normal queries do not copy the store. Companion disappearance between stat/open or unlink of the same opened companion restarts the bounded snapshot inspection; identity changes and other open errors are not ignored. Concurrent supported startup still re-attests under its migration transaction. WAL-mode selection retries only the driver's numeric SQLITE_BUSY condition, rechecking path safety on every attempt within a five-second deadline; other errors fail immediately. These are focused startup checks, not an OS lease against uncoordinated path/schema mutations by another process.
Session search prefers Pi's managed <agent-dir>/bin/rg (rg.exe on Windows), then inherited PATH if the managed executable is missing (ENOENT). Permission errors or other operational failures are reported, not hidden by fallback. Resolution is retried on each search so a binary provisioned after extension loading is recognized. PI_CODING_AGENT_DIR uses the same absolute/tilde normalization as the memory configuration; PI_MEMORIA_DIR does not move the managed-bin location. Explicit executable overrides for custom callers/tests remain authoritative.
Memoria never downloads binaries or changes PATH. Normal interactive Pi startup can provision missing ripgrep on supported platforms. On an offline first start, after a failed download, or where Pi cannot provision it (such as Android/Termux), install system ripgrep or provision the managed binary separately. Android/Termux users can use pkg install ripgrep. Reading an original entry with action=read does not require ripgrep.
The default session root is <agent-dir>/sessions; roots Pi uses are remembered across projects. Changing PI_MEMORIA_DIR selects a different store without migrating the old one, project cwd is never used to choose it, and no data is sent over the network.
Performance
Benchmark: 10,000 memories and 50,000 session entries (11.9 MB)
| Operation | Median | p95 |
|---|---|---|
| Selective SQLite FTS5 lookup | 0.093 ms | 0.119 ms |
| Exact-tag filtered FTS5 lookup (10,000 matching rows) | 6.308 ms | 7.365 ms |
| Literal SQLite full scan | 4.709 ms | 5.094 ms |
| Hot-file refresh with locking | 0.148 ms | 0.249 ms |
| Session match near the end of the corpus | 26.776 ms | 34.777 ms |
| Absent session term, complete scan | 4.325 ms | 5.172 ms |
npm run bench recreates this synthetic corpus in a temporary directory. Warm-cache medians on Linux, Node 24.20, Ryzen 5 7500F, including rg startup. Indexed lookups stay fast; scans grow with corpus size. Not a performance guarantee.
Development
From the monorepo root:
npm --prefix packages/pi-memoria install --ignore-scripts --legacy-peer-deps --workspaces=false
npm run link-host
npm --prefix packages/pi-memoria run verify
npm --prefix packages/pi-memoria run bench
No package lockfile is currently committed, so npm ci is not a fresh-checkout setup command. The shared host-link helper preserves working dependencies and only repairs missing/broken links.
There is no build step: Pi loads index.ts directly. src/database.ts, src/hot-memory.ts, and src/sessions.ts own the storage layers; index.ts wires them to lifecycle events and the tool schemas. Tests use temporary directories, real SQLite FTS5, real rg, concurrent writers, and Pi's extension loader. See AGENTS.md for architecture and contribution rules.
Support and contact
If pi-memoria is useful to you, you can support its development on Ko-fi.
