╭─────────────────────────────────────────────────────────────────────────────────────────╮
│ ● ● ● openrecall — ~/memory ⌘ + T │
├─────────────────────────────────────────────────────────────────────────────────────────┤
██████╗ ██████╗ ███████╗███╗ ██╗██████╗ ███████╗ ██████╗ █████╗ ██╗ ██╗
██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔══██╗██╔════╝██╔════╝██╔══██╗██║ ██║
██║ ██║██████╔╝█████╗ ██╔██╗ ██║██████╔╝█████╗ ██║ ███████║██║ ██║
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██╗██╔══╝ ██║ ██╔══██║██║ ██║
╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║███████╗╚██████╗██║ ██║███████╗███████╗
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚══════╝
one memory for every agent and every session · the host cannot read it
$ openrecall push ./memories user:me
⠿ scan secrets ✓ 0 leaked
⠿ encrypt 12 ✓ aes-256-gcm · key derived locally, never sent
⠿ delta sync → memory.twigpine.com
↑ 3 changed · 9 unchanged ✓ server saw only ciphertext
$ ▮
╰─────────────────────────────────────────────────────────────────────────────────────────╯
One memory for every agent and every session — open-source, self-hostable,zero-knowledge.The memory layer of the agent stack — Claude Code, Zero, OpenClaude, Codex,Cursor, and your SDK agents all read and write the same durable memory, carriedacross sessions and stored where no one but you can read it.
npm i -g @twigpine/openrecall
openrecall init # one passphrase, kept owner-only on this machine
openrecall setup all --write # connect every agent it finds
OpenRecall by Twigpine — the memory layer next toZero andOpenClaude (agents), OpenGateway(inference), and the Twigpine Network (code).
Why
Agents forget everything between sessions, and what one agent learns the nextone never sees. The existing fix — syncing memory to a vendor's cloud — locksthat memory to one tool and means a third party can read everything your agentslearn about you and your code. OpenRecall is the alternative:
- Unified. One memory, every agent. A built-in MCP server gives ClaudeCode, Zero, OpenClaude, Codex, Cursor, Gemini CLI, opencode, and SDK agentsthe same memory tools (
memory_save/recall/search/list/delete) overthe same store, andopenrecall setupwires them up for you. - Works offline, no server needed. Local mode keeps ciphertext in
~/.openrecalland lets every agent on the machine share it safely. Point itat a server when you want the same memory on every machine. - Zero-knowledge. Memory is encrypted on your machine before upload. Theserver stores and serves only ciphertext (AES-256-GCM, key derived from yourpassphrase). We host it but we cannot read it.
- Self-hostable. One server, pluggable storage (filesystem, S3/Tigris/R2,more coming). Run it on our cloud or your own.
- Delta sync. Deterministic encryption means only changed entries upload,even though the server never sees plaintext.
- Secret-aware. A client-side scanner refuses to upload entries that looklike they contain live credentials — before they're ever encrypted or sent.
How it works
agent (Claude Code · Zero · OpenClaude · Codex · Cursor · …)
│ MCP tools: plaintext in, plaintext out
▼ openrecall mcp — runs on your machine, holds the passphrase
│ [ client/crypto.ts — encrypt with a key derived from your passphrase ]
│ ciphertext
▼
local store (~/.openrecall/data) or openrecall server (crypto-blind)
▼
BlobStore: fs | s3 (Tigris/R2/AWS)
Encryption happens in the MCP server process on your machine. Whether memorylives on local disk or on a server, the store only ever holds ciphertext — thekey never leaves the client.
Quick start
npm i -g @twigpine/openrecall # Node 20+; or prefix commands with npx -y @twigpine/openrecall
openrecall init # writes ~/.openrecall/config.json (0600) with a fresh passphrase
openrecall setup # see which agents are on this machine
openrecall setup all --write # register OpenRecall with all of them
openrecall status # check config + store
Restart your agents and they share one memory. setup without --write is adry run that prints every change first; it edits agent configs through theirown mcp add CLIs where they exist and backs up any JSON file it touches. Peragent details — including Zero's sandbox and the Claude Code / OpenClaudeplugin — are in docs/agents.md.
⚠️ Zero-knowledge means no recovery. The passphrase in
~/.openrecall/config.jsonis the only key to your memory — back that fileup. Nobody, including the host, can recover it.
From source (until the first npm release):
bun install && bun run build
node dist/openrecall.js init
node dist/openrecall.js setup all --write # registers absolute paths to this checkout
Use from any agent (MCP)
openrecall setup covers Claude Code, Zero, OpenClaude, Codex, Cursor, GeminiCLI, opencode, Windsurf, Claude Desktop, and VS Code. For anything else thatspeaks MCP, register a stdio server — no env or secrets needed in the agent'sconfig:
{
"mcpServers": {
"openrecall": { "command": "npx", "args": ["-y", "@twigpine/openrecall", "mcp"] }
}
}
Claude Code and OpenClaude can instead install the plugin, which bundles theMCP server and the memory skill:
/plugin install openrecall --marketplace Twigpine/openrecall
| Tool | Purpose |
|---|---|
memory_save(key, content) |
persist a durable fact |
memory_recall(query) |
rank stored memories by relevance (locally) |
memory_search(query) |
literal keyword/substring search |
memory_list() |
list entry keys |
memory_delete(key) |
remove an entry |
Teaching the agent to use memory
Tools alone don't make an agent use memory well — it needs the discipline(recall before answering, save only durable facts, don't duplicate). That livesin one place, skills/openrecall-memory/SKILL.md,and reaches every agent:
- Agents with skills (Claude Code, Zero, OpenClaude, Codex):
setupinstalls it into their skills directory. - Every MCP client: the server exposes the same text as the
memory_guideprompt and a short version in its startupinstructions.
Self-host a server
A server lets several machines share one memory. It needs Bun:
bun install
export STATIC_API_KEYS="me:$(openssl rand -hex 24)" # owner:key — note the key
STORE=fs DATA_DIR=./data bun run src/index.ts
# on each machine — the same passphrase everywhere (copy it from the first)
openrecall init --url https://memory.example.com --api-key <key> --namespace user:me
Each API key owns the user:<owner> namespace subtree. For many users, use theSupabase key table in migrations/ instead of static keys.ALLOW_UNAUTHENTICATED=true skips auth entirely — only for a server bound tolocalhost. What lands on the server is ciphertext — grep its data dir for anyplaintext and you'll find nothing. A Docker image and fly.toml are included.
Use as a library
import { OpenRecallClient } from '@twigpine/openrecall'
const memory = new OpenRecallClient({
url: 'https://memory.twigpine.com',
apiKey: process.env.OPENRECALL_API_KEY,
passphrase: process.env.OPENRECALL_PASSPHRASE, // stays local
})
await memory.push('user:me', { 'MEMORY.md': '# what I know about the user...' })
const { entries } = await memory.pull('user:me')
The library entry points are TypeScript sources — use them from Bun or througha bundler.
API
All bodies are ciphertext; the server validates sizes/hashes without decrypting.
| Method | Route | Purpose |
|---|---|---|
GET |
/health |
liveness + active store |
GET |
/api/memory/:ns |
full data (ciphertext entries + checksums) |
GET |
/api/memory/:ns?view=hashes |
per-key checksums only (for delta) |
PUT |
/api/memory/:ns |
delta upsert { entries, deletions? } |
DELETE |
/api/memory/:ns?key=<entryKey> |
remove one entry |
A namespace (user:me, repo:owner/name, agent:intern) is the unit ofscoping. Entry keys mirror the memdir layout (MEMORY.md, feedback/x.md).
Configuration
- Client (CLI + MCP server):
~/.openrecall/config.json, written byopenrecall init—url(localor a server URL),apiKey,passphrase,namespace,scan(block|warn|off).OPENRECALL_URL,OPENRECALL_API_KEY,OPENRECALL_PASSPHRASE,OPENRECALL_NAMESPACE,OPENRECALL_SCANoverride it;OPENRECALL_HOMEmoves the whole directory. - Server: see
.env.example—STORE(fs|s3),ALLOW_UNAUTHENTICATED,STATIC_API_KEYS/ Supabase auth, and per-namespaceand per-account limits.
Security model
- Encryption: AES-256-GCM; key =
scrypt(passphrase, salt=sha256("openrecall:"+namespace)). - Integrity: the entry key is GCM additional-authenticated-data, so a blobis bound to its key and can't be swapped or replayed.
- Determinism: synthetic-IV nonce enables delta sync; the only leak iswhether two entries are byte-identical.
- Key custody: the passphrase lives only in
~/.openrecall/config.json(mode 0600) or your environment, and only the local MCP/CLI process reads it.Agent configs never contain it. - Defense in depth: a client-side secret scanner runs before encryption and(by default) blocks saves containing live-looking credentials. Override with
OPENRECALL_SCAN=warn|off. - Tenancy: each API key maps to an owner who controls exactly their own
user:<owner>namespace subtree (strict segment match, no substring escapes);per-account quotas and per-owner rate limits are enforced server-side. - Upgrade path: a version byte on every blob allows migrating toXChaCha20-Poly1305 + Argon2id without breaking existing data.
Status
Beta. The crypto-blind server, client crypto, CLI, local mode, MCP server,agent setup, secret scanner, quotas, and rate limiting are implemented andcovered by bun test, including real MCP sessions over stdio under both Bunand Node. Next: the first npm release, the hosted beta atmemory.twigpine.com, and a self-service console for API keys — seeROADMAP.md.
Development
bun install
bun test # run the suite (run `bun run build` first to include the Node bundle)
bun run build # dist/openrecall.js — the single-file Node CLI that npm ships
bun run type-check # tsc --noEmit
bun run check # biome lint + format check
The codebase splits along the trust boundary:
client/ the zero-knowledge client — encrypts here; holds the key
src/ the crypto-blind server — only ever sees ciphertext
src/cli/ client settings, local mode, and `openrecall setup`
src/mcp/ the MCP server (memory tools) over the client
bin/ the CLI (init | setup | status | push | pull | mcp | serve)
skills/ the openrecall-memory skill, shared by every agent
The cardinal rule: plaintext, passphrases, and derived keys never reach theserver. See CONTRIBUTING.md for the full guide.
Contributing
Issues and PRs welcome. Please read CONTRIBUTING.md (devsetup, design principles, Conventional Commits, DCO sign-off) and ourCode of Conduct.
Security
OpenRecall is security software. Please report vulnerabilities privately — do notopen a public issue. See SECURITY.md for the process and thethreat model.
License
Released under the MIT License. Contributions are accepted underthe same license (see CONTRIBUTING.md).