trusty-memory
Memory palace MCP server (HTTP/SSE + Unix domain socket) backed by usearch
vector store, SQLite metadata, and fastembed embeddings. Stores and retrieves
natural-language memories organized into named "palaces" (namespaces), with an
optional knowledge-graph layer for structured triples.
Claude Code integration uses the companion trusty-memory-mcp-bridge binary
which speaks stdio MCP and pipes it over the daemon's Unix domain socket.
The legacy in-process serve --stdio flag was removed in issue #150 because
it deadlocked on redb's exclusive write lock whenever a long-lived daemon
was already running.
Integrates with Claude Code and any other MCP-aware client as a first-class long-term memory backend.
System Requirements
- RAM: 512 MB minimum; 1 GB+ recommended (ONNX embedding model loads ~22 MB, usearch index scales with corpus size)
- Disk: ~100 MB for the model cache on first run
(
~/Library/Application Support/trusty-memory/on macOS,~/.local/share/trusty-memory/on Linux) - Rust: 1.88+ (if building from source)
Installation
The installed binary is named trusty-memory.
Quick Start
Start the daemon
By default, serve self-spawns a detached background daemon (alias for
trusty-memory start) and returns control to the shell so you keep your
prompt. The daemon binds HTTP/SSE on a dynamic port in the 7070..=7079
range (with OS fallback) and writes the resolved address to its
discovery file. Pass --foreground to keep the daemon inline (used by
launchd / systemd / Docker), or --http <ADDR> to pin a specific address.
Browser dashboard + REST API
The same trusty-memory serve daemon serves the embedded Svelte admin UI
at the bound address (printed by trusty-memory monitor web once the
daemon is running) and a REST API under /api/v1/.
Bind to a named palace
When all tool calls should default to one palace namespace, use --palace:
With a default set, the palace argument becomes optional in every MCP tool
call.
Claude Code Integration
Run trusty-memory setup once — it installs the launchd LaunchAgent
(macOS), pre-warms the embedder cache, and patches every Claude settings
file it finds with the canonical MCP server entry. The MCP entry points
at trusty-memory-mcp-bridge, a thin stdio-to-UDS pipe (PR #149) that
Claude Code spawns as a child process. The bridge then connects to the
long-lived daemon over the Unix domain socket the daemon owns.
If you prefer to edit .mcp.json (or ~/.claude/mcp.json) by hand:
Claude Code auto-discovers .mcp.json on project open. The
trusty-memory-mcp-bridge binary must be on PATH and the daemon must be
running (started either by trusty-memory setup's LaunchAgent or by
trusty-memory start / trusty-memory serve).
Available MCP Tools
All 12 tools are exposed via both the MCP protocol (over the
trusty-memory-mcp-bridge → UDS path) and the HTTP API (/api/v1/). The
palace argument is required unless the server was started with
--palace <name>.
Memory tools
| Tool | Arguments | Description |
|---|---|---|
memory_remember |
palace, text, room?, tags? |
Store a memory. Returns the drawer_id. |
memory_recall |
palace, query, top_k? |
Hybrid BM25+vector recall (L0/L1/L2 layers). |
memory_recall_deep |
palace, query, top_k? |
Deep recall (L3 — slower, higher recall). |
memory_list |
palace, room?, tag?, limit? |
List stored memories, optionally filtered. |
memory_forget |
palace, drawer_id |
Delete a specific memory by ID. |
Palace management tools
| Tool | Arguments | Description |
|---|---|---|
palace_create |
name, description? |
Create a new palace namespace. |
palace_list |
— | List all palaces and their IDs. |
palace_info |
palace |
Palace metadata and statistics. |
Knowledge graph tools
| Tool | Arguments | Description |
|---|---|---|
kg_assert |
palace, subject, predicate, object, confidence?, provenance? |
Assert a knowledge triple. |
kg_query |
palace, subject |
Query triples by subject. |
Dream and status tools
| Tool | Arguments | Description |
|---|---|---|
memory_dream |
palace? |
Run a consolidation cycle (merge near-duplicates, prune, compact). |
memory_status |
— | Global statistics (total drawers, vectors, KG triples). |
Inter-project messaging (issue #99)
| Tool | Arguments | Description |
|---|---|---|
memory_send_message |
to_palace, purpose, content, from_palace? |
Deliver a message to another palace's inbox. |
Plus two CLI subcommands:
trusty-memory send-message --to <palace> --purpose <p> --content <text> [--from <palace>]— non-MCP entry point. Posts to the daemon'sPOST /api/v1/messages.trusty-memory inbox-check [--palace <id>]— installed as a Claude CodeSessionStarthook bysetup. Reads unread messages from the cwd-derived palace, prints them to stdout (Claude Code injects stdout as session context), and atomically marks them read.
Design
A message is a drawer in the recipient's palace carrying a namespaced tag envelope. No new schema, no new database — just convention:
| Tag | Example | Meaning |
|---|---|---|
msg:v1 |
(literal) | Marker tag for the v1 envelope. |
msg:from=<palace> |
msg:from=trusty-tools |
Sender palace id. |
msg:to=<palace> |
msg:to=claude-mpm |
Recipient palace id (audit). |
msg:purpose=<text> |
msg:purpose=task |
Free-text purpose / category. |
msg:sent_at=<rfc3339> |
msg:sent_at=2026-05-25T12:34:56+00:00 |
UTC send timestamp. |
msg:read=<bool> |
msg:read=false |
Receiver-flipped read flag. |
Addressing
Sender and recipient palaces are addressed by repo slug. The slug is derived from the working directory by:
- Take the basename of
git rev-parse --show-toplevel(or cwd, when not in a git checkout). - Strip a trailing
.gitsuffix if present. - Lowercase.
- Replace every run of whitespace or
_with a single-. - Strip every character outside
[a-z0-9-]. - Collapse consecutive
-and trim leading/trailing-.
Examples (all resolve to trusty-tools):
/Users/bob/Projects/trusty-tools,
/Users/bob/Projects/Trusty_Tools,
/Users/bob/Projects/trusty tools,
/Users/bob/Projects/.trusty-tools.git.
No central registry; sender and receiver agree on the slug out of band.
Delivery
The receiver's trusty-memory setup installs trusty-memory inbox-check as
a SessionStart hook in every Claude Code settings file it finds (alongside
the existing UserPromptSubmit prompt-context hook). On every new Claude
Code session, the hook:
- Resolves the receiver palace slug from cwd.
- Fetches unread messages from
GET /api/v1/messages?palace=<slug>&unread_only=true. - Prints each as a Markdown block to stdout — Claude Code injects stdout as session context.
- Atomically marks each delivered message read via
POST /api/v1/messages/mark_read.
The mark-read step uses an in-memory compare-and-swap on the palace's
drawer table so two concurrent sessions opening at once cannot
double-deliver: exactly one observes read=false and flips the flag, the
other returns false and emits nothing.
Every failure path in inbox-check degrades to exit 0 with empty stdout
so a missing or slow daemon never blocks Claude Code session start.
Migration from claude-mpm /mpm-message
This primitive replaces the Python /mpm-message skill in claude-mpm
(which wrote to ~/.claude-mpm/messaging.db via a process-local SQLite
file). The companion ticket in claude-mpm is #557; data migration is
out of scope here.
Web UI
When running in HTTP mode, the embedded Svelte admin dashboard is available at:
http://127.0.0.1:<port>/
The dashboard provides:
- Real-time palace overview (drawer counts, vector counts, KG triple counts)
- Live event stream (palace created, drawer added/deleted, dream completed)
- Manual dream (consolidation) trigger
- Palace-scoped memory browsing
Configuration
Environment variables
| Variable | Default | Description |
|---|---|---|
RUST_LOG |
warn |
Tracing filter. E.g. RUST_LOG=info or RUST_LOG=trusty_memory=debug. |
OPENROUTER_API_KEY |
— | Enables chat completions via OpenRouter (/api/v1/chat). |
TRUSTY_DATA_DIR_OVERRIDE |
— | Override the data directory (intended for tests). |
Config file
~/.trusty-memory/config.toml (created on first run if absent):
[]
= ""
= "anthropic/claude-3.5-sonnet"
[]
= false
= "http://127.0.0.1:11434"
= "llama3"
Data directory
Memories and vector indexes persist under the OS-standard data directory:
- macOS:
~/Library/Application Support/trusty-memory/<palace-id>/ - Linux:
~/.local/share/trusty-memory/<palace-id>/
Each palace directory contains:
drawers.db— SQLite metadata storevectors.usearch— usearch vector indexkg.db— knowledge-graph triples (SQLite)chat_sessions.db— chat session history
Architecture
trusty-memory (this crate) trusty-memory-core
axum HTTP/SSE server ──────► PalaceRegistry
Unix domain socket ──────► usearch vector index
embedded Svelte UI SQLite metadata + KG
12 MCP tools fastembed (AllMiniLML6V2Q)
trusty-memory-mcp-bridge (separate binary, PR #149)
Claude Code stdio ◄──pipe──► trusty-memory UDS
trusty-memory-core owns the storage engine: usearch for approximate
nearest-neighbor search, SQLite for metadata and knowledge-graph triples, and
fastembed for 384-dim text embeddings. The MCP server (trusty-memory) is a
thin protocol layer on top.
The embedded Svelte UI is compiled at build time and served via rust-embed —
no separate web server or Node.js installation is needed at runtime.
Feature Flags
| Flag | Default | Description |
|---|---|---|
axum-server |
enabled | Compiles the HTTP server, SSE endpoint, and axum-based REST API. Disable with default-features = false when embedding only the in-process MCP tools (e.g. from open-mpm). |
# Full daemon build — no change needed (axum-server is on by default)
= { = true }
# rlib consumer — omit the HTTP stack
= { = true, = false }
Migration
From kuzu-memory (MCP config, issue #278)
If you're switching from the legacy kuzu-memory Python MCP server, rewrite
every Claude mcpServers config entry in one command:
# Dry-run: see what would change
# Apply: rewrite all Claude settings files atomically
Knowledge-graph hygiene (issue #278)
Auto-KG extraction skips drawers tagged cross-project-qa, test, or
fixture so synthetic content never pollutes the graph. Drawers deleted via
memory_forget cascade-delete their derived triples automatically.
The REST endpoint DELETE /api/v1/palaces/{id}/kg/triples/{triple_id} lets
you surgically remove a single active triple; triple_id is the base64url
encoding of subject + "\0" + predicate.
From kuzu-memory data (issue #277)
Import entities and relations from a kuzu-memory store.redb into a
trusty-memory palace:
# Dry-run: see what would be imported
# Apply the import (idempotent — safe to re-run)
# Cap at 100 entities
Each kuzu-memory entity becomes one drawer; each relation becomes one KG triple. Re-running is idempotent: entity IDs are SHA-256-derived UUIDs so duplicate imports produce the same drawer ID and are silently skipped.
Development
# Build and run (background daemon, dynamic port)
# Run inline on a specific address (foreground, useful for debuggers)
# Tests
# Check only (faster)
License
Licensed under the MIT License.