Layered, path-scoped memory for coding agents. One master memory inherited everywhere, an independent memory and persona for every project directory, and controlled cross-agent handoff — all kept in central storage, with zero files written into your project folders.
Every working directory becomes its own agent. Enter a new folder and a fresh persona grows on top of your shared master memory; return to it later and the same agent — its identity, long-term facts, and decisions — comes back. Different directories can collaborate across a controlled boundary without ever reading each other's private memory.
Ships today as a native extension for the Pi coding agent (v0.84.1) and as a Claude Code plugin (hooks + MCP server + statusline, Claude Code 2.1.x). Both hosts resolve the same central store, so the same directory is the same agent with the same memory no matter which host you enter from. The core is host-neutral by design — Codex and MCP adapters are next and reuse the same registry, memory, and handoff schema unchanged.
Effective Memory
= Master Core (shared, inherited read-only)
+ Workspace Identity (this directory's persona & role)
+ Workspace Long-term (this directory's verified facts & decisions)
+ Retrieved Memory (fetched for the current task)
+ Current Session (the host's native session)
- Master holds only what is stable across every project: who you are, cross-project preferences, principles, and safety boundaries. It is inherited live — update it once and every agent sees the new version at its next safe checkpoint. No per-directory snapshots to drift.
- Workspace holds everything specific to one directory: the agent's name and role, project facts, architecture decisions, and a daily log. Local writes stay local — they never leak into master or into a sibling directory.
- Promotion is the only path from workspace to master, and it always requires explicit user confirmation with a visible diff.
flowchart TD
U[User in a directory] --> PI[Host session -- Pi today]
PI --> AD[Host adapter]
AD --> CORE[Host-neutral memory core]
CORE --> RES[Workspace resolver]
RES --> REG[Central UUID registry]
CORE --> COMP[Context composer]
COMP --> MM[Master memory]
COMP --> WS[Workspace overlay]
COMP --> AD
AD --> INJ[Bounded memory injected before each turn]
PI --> TOOL[workspace_memory tool + slash commands]
TOOL --> POL[Policy & confirmation engine]
POL --> AUD[Audit log]
AD --> HB[Handoff broker]
HB --> CHILD[Target directory child process]
CHILD --> HB
CC[Claude Code adapter: hooks + MCP + statusline] --> CORE
FUTURE[Future Codex / MCP adapter] -. same core contracts .-> CORE
Path resolution is deterministic: canonicalize the cwd, match the nearest registered ancestor, then filesystem identity (device+inode, survives same-volume renames), then git root, then the cwd itself. A copied or re-cloned directory is treated as a new agent — private memory is never silently inherited across a copy.
- Central storage, zero project intrusion. Everything lives in one host-neutral store under your home directory (
~/.path-memoryon fresh installs; an existing~/.pi/agent/workspace-memory/is reused as-is). No.memoryfolder, marker, or database is ever written into a business project. - Default isolation. A directory's private memory can only be loaded by its own workspace. Cross-agent access is limited to a public profile (name, role, availability) plus whatever a handoff explicitly carries.
- Prompt-injection resistant. A project README, web page, or attachment cannot trigger a durable write. Long-term writes require an explicit user memory intent, a confirmed proposal, or a trusted, verified system event — nothing else.
- Secrets never persist. A content scanner hard-rejects API keys, tokens, and private-key blocks before they can reach memory.
- Evidence-backed completion. Every write is followed by a read-back and hash check; every handoff ends with an exit code and result verification. Failures are surfaced, never silently swallowed.
- Crash- and concurrency-safe. Atomic temp-file + fsync + rename writes, revision compare-and-swap, and a single-authority cross-process lock (SQLite lease/fencing, with an mkdir-lock fallback) keep concurrent host processes from losing updates or corrupting the registry.
An agent can discover other agents' public profiles and send a structured task package to one of them. The broker starts an isolated child process in the target directory, which naturally loads the target's own master + workspace memory plus the handoff — and nothing of the source's private memory. A three-layer data boundary (tool-layer path rejection, realpath-validated references, a reportBack result schema), depth/cycle limits, idempotency keys, and SIGTERM→SIGKILL cancellation keep collaboration bounded and auditable.
Requires Node.js 22+ and the Pi coding agent v0.84.x. Get the code:
git clone https://github.com/aezizhu/path-memory
cd path-memory
npm install
npm run check && npm test # optional: confirm the suites are greenPi runs the TypeScript entry point directly — there is no build step. The
package declares its extension under the pi key in package.json, so Pi
picks it up from the repo path as-is.
Try it for one session (no config change, fully reversible):
cd <any project directory>
pi -e /absolute/path/to/path-memory-e loads the extension for the current run only. On first use it creates
central storage (~/.path-memory, or your existing
~/.pi/agent/workspace-memory/ if you already have one); it writes nothing
into your project folder and does not touch any pre-existing memory.
Enable it permanently:
pi install /absolute/path/to/path-memory # writes to ~/.pi/agent/settings.json
pi list # confirm it is installed
pi remove path-memory # undo at any timeMigrating memory from an older setup is a separate, deliberate step — always dry-run first, backed up, and verified per file before anything is switched over. Do not point it at real data casually; follow the rollout runbook.
The same repo doubles as a Claude Code plugin: four lifecycle hooks
(SessionStart / UserPromptSubmit / PreToolUse / SessionEnd), the
workspace_memory MCP tool (the Pi 15 actions plus adapter-gated
rebind/accept), the same 11 /memory-* slash commands as prompt
templates, and a statusline that renders the exact Pi footer. High-risk
actions (master writes, promote, forget, restore, export, rebind, accept) go
through Claude Code's permission prompt with the same diff text Pi shows,
backed by a single-use gate token — non-interactive runs fail closed.
Requires Node.js 22+ and Claude Code 2.1.x:
git clone https://github.com/aezizhu/path-memory
cd path-memory
npm install
npm run build # hooks / MCP server / statusline run from dist/ as plain node
# try it for one session:
claude --plugin-dir "$PWD"
# or install persistently:
claude plugin marketplace add "$PWD"
claude plugin install path-memory@path-memoryPlugins cannot register a statusline themselves; wire it once in
~/.claude/settings.json:
"statusLine": { "type": "command", "command": "node \"/absolute/path/to/path-memory/bin/cc-statusline.js\"" }It renders the same footer as the Pi host:
Agent: <name> · memory <layers> · rev <n> · <health>.
Both hosts resolve the central store through one shared resolver, in priority order:
PATH_MEMORY_ROOTenv override (also the test sandbox knob)PI_CODING_AGENT_DIRset →<dir>/workspace-memory(a Claude Code process inside a Pi sandbox automatically joins that sandbox)- An existing Pi store at
~/.pi/agent/workspace-memory/→ reused as-is: existing Pi users get cross-host sharing with zero migration - Fresh installs → the neutral
~/.path-memory
Memory is never stored under $CLAUDE_CONFIG_DIR — that would split the same
directory into two different agents. /memory-doctor on either host reports
the storage root and which branch decided it. Concurrent Pi and Claude Code
sessions on the same store are the storage layer's normal operating mode:
cross-process locking, atomic writes, and revision compare-and-swap already
guard every write.
Once loaded, the extension takes over the host lifecycle automatically — you do not configure it per turn:
- Enter a directory → it resolves (or creates) that directory's agent and shows the agent name and health in the TUI footer.
- Every turn → it injects a bounded
Master + this-workspacememory before the model runs, labelled with source layer and revision. - Say "remember X" in plain language → it writes to the current workspace's long-term memory (never to master, never to a sibling), then reads back and reports the verified path and revision.
- Promote to master only ever happens through
/memory-promotewith a visible diff and your explicit confirmation.
Everything else is driven through the slash commands below (or the model
calling the workspace_memory tool on your behalf).
/memory-status · /memory-init · /memory-agents · /memory-promote · /memory-forget · /memory-restore · /memory-handoff · /memory-inbox · /memory-rebind · /memory-doctor · /memory-preview-context
A single tool exposes fifteen actions to the model: status, initialize, read, list, search, write, propose, promote, forget, restore, agents, handoff, inbox, export, doctor. Every result reports the workspace ID, the layer written, the revision, whether the write-back verified, and whether user confirmation is required.
src/
├── core/ host-neutral, zero host-SDK imports (enforced by test)
│ ├── domain/ workspace / master / proposal / handoff types
│ ├── ports/ HostContext, ContextInjector, Confirmation, Status, AgentExecutor, MemoryBackend
│ ├── policy/ write-intent, policy engine, scanner gate, config guard
│ └── services/ resolver, stores, composer, retrieval, governance
├── storage/
│ ├── registry/ UUID registry, canonical paths, identity projection
│ ├── markdown/ Markdown source-of-truth, mutation lock, content scanner
│ ├── sqlite/ derived FTS5 index (rebuildable from Markdown)
│ ├── locks/ cross-process lock coordinator + lock-mode authority
│ └── migration/ importer framework (zhafron / hermes / generic)
├── collaboration/ handoff broker, protocol, data boundary, report-back
└── adapters/
├── shared/ host-neutral adapter layer: runtime, actions, doctor, storage resolver
├── pi/ the Pi host adapter (thin shims over shared/)
└── claude-code/ the Claude Code adapter: hooks, MCP server, statusline, gate tokens
The core/, storage/, and adapters/shared/ layers import no host SDK — a guard test asserts it — so a new host is an adapter, not a rewrite.
Verified end-to-end on Pi v0.84.1 (macOS, Node v22.23.2):
| Suite | Result |
|---|---|
| Unit | 320 passing |
| Integration | 41 passing |
| Concurrency | 6 passing (10-process registry race, orphan reclaim, projection-crash recovery) |
| Security | 47 passing (secret/injection/traversal/fail-closed) |
| End-to-end | 16 passing (A/B isolation, promote gating, handoff minimality) |
| Migration | 18 passing (dry-run zero-write, idempotent, resumable, quarantine) |
| Claude Code adapter | 12 test files passing (hook binaries via synthetic stdin, MCP stdio, confirmation matrix, gate tokens, cross-host shared-store E2E) + opt-in live claude -p smoke |
| Performance | cold P95 ≈ 29 ms, warm ≈ 22 ms (budget 150 ms) |
All acceptance criteria pass; a fresh adversarial audit found and fixed three high/critical issues before release.
- ✅ Pi adapter (v0.84.1)
- ✅ Claude Code adapter (plugin: hooks + MCP server + statusline, CC 2.1.x)
- ⏳ Codex adapter
- ⏳ MCP memory-backend adapter
The registry, master/workspace, and handoff schemas are host-neutral and stay stable across adapters.
Built on the excellent pi-hermes-memory by Chandra Teja (MIT). Its atomic lock coordinator, Markdown mutation lock, content scanner, FTS5 query layer, and SQLite store are vendored at a pinned commit — see UPSTREAM.md and THIRD_PARTY_NOTICES.md for the exact provenance and every local change.
MIT © 2026 aezizhu