@amaster.ai/pi-memory
Pi extension providing persistent curated memory (MEMORY.md + USER.md) injected into the system prompt as a frozen snapshot.
Package details
Install @amaster.ai/pi-memory from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@amaster.ai/pi-memory- Package
@amaster.ai/pi-memory- Version
0.1.3- Published
- Jun 19, 2026
- Downloads
- 3,598/mo · 1,077/wk
- Author
- qianchuan
- License
- Apache-2.0
- Types
- extension
- Size
- 1.8 MB
- Dependencies
- 2 dependencies · 4 peers
Pi manifest JSON
{
"image": "https://raw.githubusercontent.com/TGYD-helige/pi/master/packages/pi-memory/preview.png",
"extensions": [
"./dist/index.js"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@amaster.ai/pi-memory

Persistent curated memory for pi agents — MEMORY.md (the agent's own notes) and USER.md (what the agent knows about the user). Both are loaded from disk at session start, frozen, and injected into the system prompt for the entire session. Mid-session writes are durable on disk but do not mutate the system prompt — this preserves prefix-cache stability.
Modeled after hermes' default MemoryStore mechanism (no provider/manager abstraction).
Storage
- Location:
<agentDir>/memories/MEMORY.mdand<agentDir>/memories/USER.md - Entries separated by
\n§\n - Atomic writes via temp-file + rename
- Read-modify-write protected by
proper-lockfile - Drift detection: if the on-disk file contains content that wouldn't round-trip through the parser/serializer (or any single entry exceeds the per-store char limit), the mutation is refused and a
.bak.<unix-ts>snapshot is taken for the user to recover from.
Safety
Every write — and every system-prompt snapshot build — runs the content through the bundled threat-patterns scanner at the strict scope. Patterns cover prompt injection, role hijack, C2 framework names, exfiltration, persistence (SSH backdoor, agent-config edits), and invisible unicode.
| Action | On match |
|---|---|
memory_add / memory_replace |
Reject with the matched pattern id; live state and disk unchanged. |
| Snapshot build (load) | Replace the entry with [BLOCKED: <filename> entry contained threat pattern(s): <ids>...]. The poisoned content never enters the system prompt. Live state keeps the original so memory_read / memory_remove can recover. |
Tools
Four LLM-callable tools (separate, not action-multiplexed):
| Tool | Purpose |
|---|---|
memory_add |
Append a new entry. Rejects empty / duplicate / over-limit / threat content. |
memory_replace |
Update an existing entry by short unique substring (oldText). |
memory_remove |
Delete an entry by short unique substring (oldText). |
memory_read |
Return live entries, count, and <percent>% — <chars>/<limit> usage string. |
target is 'memory' (the agent's own notes) or 'user' (user profile facts).
Defaults
| Store | Char limit |
|---|---|
| MEMORY | 2200 |
| USER | 1375 |
These are total chars after §-joining all entries. The limit is enforced at write time, and at load time as a drift signal (single-entry overflow).
Integration Modes
Mode 1: Extension auto-discovery (standalone / CLI)
When installed as a dependency with the pi.extensions field declared in package.json, the runtime auto-discovers and loads the extension. The extension creates its own MemoryStore with file-based storage at <agentDir>/memories/ — fully self-contained.
pi.extensions → session_start → load MEMORY.md/USER.md → freeze snapshot → register tools
→ before_agent_start → append snapshot to systemPrompt
→ session_shutdown → release
- Storage:
<agentDir>/memories/MEMORY.mdand<agentDir>/memories/USER.md - Lifecycle: load on
session_start, snapshot held untilsession_shutdown - Status command:
/pi-memory-statusshows entry counts per file - LLM tools:
memory_add,memory_replace,memory_remove,memory_read
Configure via the pi-memory settings key:
{
"pi-memory": {
"dataDir": "/custom/memory/path",
"memoryCharLimit": 4000,
"userCharLimit": 2000
}
}
Mode 2: Dependency import (host-controlled)
When the host process owns the MemoryStore (e.g. shared across agents, test fixtures, custom storage path), construct the store yourself and register tools directly:
import { MemoryStore, createMemoryTools } from "@amaster.ai/pi-memory";
const store = new MemoryStore({
dir: "/var/lib/pi/agent-42/memories",
memoryCharLimit: 4000,
});
await store.loadFromDisk();
// ToolDefinition[] — wire into your tool registry directly
const tools = createMemoryTools(store);
// System prompt fragment (frozen at loadFromDisk; safe to use repeatedly)
const promptBlock = store.formatAllForSystemPrompt();
You can also pass a pre-built store into the extension via injectedConfig to keep the extension lifecycle but use your own storage:
import memoryExtension from "@amaster.ai/pi-memory";
memoryExtension(pi, { store });
Drift recovery
If memory_add / memory_replace / memory_remove returns success: false with driftBackup: ".../MEMORY.md.bak.<ts>", the on-disk file no longer round-trips through the parser. This usually means a patch tool / shell append / manual edit / concurrent session wrote raw content that broke the §-delimited structure.
To recover:
- Open the
.bak.<ts>snapshot and identify content not yet captured as clean entries. - Add each missing entry via
memory_add. - Either delete the original
MEMORY.md(the next add will recreate it) or rewrite it as a clean§-delimited list.
The drift guard exists to prevent silent data loss — never bypass it by deleting .bak.<ts> snapshots blindly.
Frozen snapshot
loadFromDisk() captures the system-prompt block once; subsequent add / replace / remove calls update live state but not the snapshot. Why:
- The system prompt is the prefix-cache key for every model call. Mutating it mid-session invalidates the entire prefix.
- Tool responses always reflect live state, so the model still sees its own writes — just via tool-result tail, not system-prompt head.
- The snapshot picks up changes on the next
loadFromDisk()(typically the next session start).
Lifecycle reference
| Hook | Behavior |
|---|---|
session_start |
Resolve dataDir, build MemoryStore, loadFromDisk(), capture snapshot, register 4 tools, set status memory: loaded/memory: empty. |
before_agent_start |
Append snapshot to assembled systemPrompt (no-op when empty). |
session_shutdown |
Drop store + snapshot references. |