
Three lines of code to give your AI agents persistent memory and cut token usage by 90%.
One binary. Drop it in. Run it. No Docker, no databases, no config files, no cloud accounts, no bullshit.
General-purpose MCP server. Zero vendor lock-in.
Works with Claude Code, Cursor, Codex, OpenCode, Antigravity — and any MCP-compatible client.
Also a plain Go library if you don't use MCP.
Free. Offline. No account required.
ctx := context.Background()
mem := graymatter.New(".graymatter")
mem.Remember(ctx, "agent", "user prefers bullet points, hates long intros")
facts, _ := mem.Recall(ctx, "agent", "how should I format this response?")
// ["user prefers bullet points, hates long intros"]
Every AI agent is stateless by default. Each run re-injects the full conversation history — and that history grows linearly. Two prompts in and you've already burned half of your daily quota.
That's not just a memory problem. That's a money and performance problem.
Mem0, Zep, Supermemory solve this — but they're Python/TypeScript-only and require a running server. The Go ecosystem has no production-ready, embeddable, zero-dependency memory layer for agents.
That gap is GrayMatter.

~97% reduction in context tokens — versus full-history injection.
Context quality improves over time as consolidation surfaces only what matters.
No Docker. No Redis. No API key required for storage.
Drop it in once. It auto-connects to Claude Code, Cursor, Codex, OpenCode, Antigravity — any MCP-compatible client picks it up automatically.
You can't improve what you can't see.
graymatter tui opens a live terminal dashboard with everything your
agent memory is doing — no extra setup required.

What you get at a glance:
The dashboard auto-refreshes every 5 seconds. Press 1–4 to switch tabs,
r to force refresh, q to quit.
Binary (recommended):
# Linux (x86_64)
curl -sSL -o graymatter.tar.gz https://github.com/angelnicolasc/graymatter/releases/download/v0.6.0/graymatter_0.6.0_linux_amd64.tar.gz
tar -xzf graymatter.tar.gz
sudo mv graymatter /usr/local/bin/
# Linux (ARM64)
curl -sSL -o graymatter.tar.gz https://github.com/angelnicolasc/graymatter/releases/download/v0.6.0/graymatter_0.6.0_linux_arm64.tar.gz
tar -xzf graymatter.tar.gz
sudo mv graymatter /usr/local/bin/
# macOS (Apple Silicon)
curl -sSL -o graymatter.tar.gz https://github.com/angelnicolasc/graymatter/releases/download/v0.6.0/graymatter_0.6.0_darwin_arm64.tar.gz
tar -xzf graymatter.tar.gz
sudo mv graymatter /usr/local/bin/
# Windows (PowerShell)
iwr https://github.com/angelnicolasc/graymatter/releases/download/v0.6.0/graymatter_0.6.0_windows_amd64.zip -OutFile graymatter.zip
Expand-Archive graymatter.zip -DestinationPath .\graymatter_cli
Go install:
go install github.com/angelnicolasc/graymatter/cmd/graymatter@latest
Library:
go get github.com/angelnicolasc/graymatter
graymatter init
One command auto-wires GrayMatter into every supported client at once. Existing entries from other MCP servers are merged, not overwritten — safe to run in any repo.
init also drops a managed memory block into CLAUDE.md and
AGENTS.md so the model is actually told to call the tools (skip with
--skip-instructions). Your own content in those files is preserved; only
the marked block is managed.
| Client | Config file auto-wired | Scope |
|---|---|---|
| Claude Code | .mcp.json |
project |
| Cursor | .cursor/mcp.json |
project |
| Codex (OpenAI) | ~/.codex/config.toml |
home |
| OpenCode | opencode.jsonc |
project |
| Antigravity (Google) | mcp_config.json |
project (opt-in: --with-antigravity) |
Narrow down what gets wired:
graymatter init --only claudecode,cursor # whitelist
graymatter init --skip-codex --skip-opencode # blacklist
graymatter init --with-antigravity # include opt-in clients
Then restart your editor (or toggle the MCP server off/on in its settings). Five tools become available:
| Tool | What it does |
|---|---|
memory_search |
Recall facts for a query |
memory_add |
Store a new fact |
checkpoint_save |
Snapshot current session |
checkpoint_resume |
Restore last checkpoint |
memory_reflect |
Add / update / forget / link memories (agent self-edit) |
Agents using these tools should read docs/AGENTS.md — when to store vs. checkpoint, query patterns, anti-patterns, and the exact per-tool parameter names (heads-up:
memory_reflectusesagent, the other four useagent_id).
GrayMatter speaks plain MCP. If your client isn't on the table above, point it at the binary:
graymatter mcp serve # stdio transport
graymatter mcp serve --http :8080 # HTTP transport
The schema is identical to every other MCP server — command +
args: ["mcp", "serve"]. No proprietary glue.
If you'd rather not run graymatter init in every repo, drop the same
JSON into the editor's global config — ~/.cursor/mcp.json for Cursor,
~/.claude/mcp.json for Claude Code:
{
"mcpServers": {
"graymatter": {
"command": "graymatter",
"args": ["mcp", "serve"]
}
}
}
graymatter must be on PATH. The init command handles this
automatically on Windows via the User PATH registry; on macOS / Linux
the recommended install path /usr/local/bin is already on PATH.
Run the built-in diagnosis first:
graymatter doctor # human-readable
graymatter doctor --json # scriptable
It checks the full chain: binary on PATH → data dir writable → store
health and lock state → MCP wiring per client → agent instructions present.
The two most common failure modes it catches:
CLAUDE.md / AGENTS.md
don't mention the memory tools, the agent will happily chat for an hour
and never write a fact. Fix: graymatter init (writes the block for you).graymatter mcp serve
themselves. If you also started one manually in a terminal, it holds
the single-writer bbolt lock and the client's own instance can't open
the store. Fix: kill the manual process.There are four ways a fact ends up in the store. You don't have to pick one — they compose:
| Path | Who calls it | When to use |
|---|---|---|
mem.Remember(ctx, agent, text) |
Your code, explicitly | You already know the exact string worth keeping. |
mem.RememberExtracted(ctx, agent, llmResponse) |
Your code, on raw LLM output | You want GrayMatter to pull atomic facts out of a full response for you (LLM-assisted; falls back to storing the raw text if no API key is set). |
memory_reflect (MCP tool) |
The LLM itself, mid-session | Claude Code / Cursor agents self-curate: add, update, forget, or link memories when they notice a contradiction, finish a task, or learn a preference. |
Consolidate (async, on by default) |
Background goroutine | Summarises, decays, and prunes over time. Runs automatically after writes once ConsolidateThreshold is hit. |
Forgetting a single Remember call is not fatal. memory_reflect lets the
agent fix its own memory as it works, and Consolidate curates the store
over time. That's why long interactive sessions in Claude Code Desktop
and Cursor are a sweet spot for GrayMatter — not only 24/7 autonomous
agents. The LLM maintains its own memory through MCP.
Three functions cover 95% of use cases. All methods accept context.Context as the first argument so timeouts and cancellation propagate end-to-end — no wrappers needed.
import "github.com/angelnicolasc/graymatter"
ctx := context.Background()
// Open (or create) a memory store in the given directory.
mem := graymatter.New(".graymatter")
defer mem.Close()
// Always check health in production — New() never panics, but it may degrade
// to no-op mode if the data dir is unwritable or bbolt fails to open.
if !mem.Healthy() {
log.Fatalf("graymatter: %v", mem.Status().InitError)
}
// Store an observation.
mem.Remember(ctx, "sales-closer", "Maria didn't reply Wednesday. Third touchpoint due Friday.")
// Retrieve relevant context for a query.
facts, _ := mem.Recall(ctx, "sales-closer", "follow up Maria")
// ["Maria didn't reply Wednesday. Third touchpoint due Friday."]
Context propagates everywhere — timeouts and traces work as expected:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := mem.Remember(ctx, "agent", "observation"); err != nil { ... }
results, err := mem.Recall(ctx, "agent", "query")
ctx := context.Background()
mem := graymatter.New(project.Root + "/.graymatter")
defer mem.Close()
if !mem.Healthy() {
log.Fatalf("graymatter: %v", mem.Status().InitError)
}
// 1. Recall before calling the LLM.
memCtx, _ := mem.Recall(ctx, skill.Name, task.Description)
messages := []anthropic.MessageParam{
{Role: "system", Content: skill.Identity + "\n\n## Memory\n" + strings.Join(memCtx, "\n")},
{Role: "user", Content: task.Description},
}
// 2. Call your LLM.
response, _ := client.Messages.New(ctx, anthropic.MessageNewParams{...})
// 3a. If you already have a clean string worth keeping, store it directly.
mem.Remember(ctx, skill.Name, "Maria prefers Slack over email; replies within 2h.")
// 3b. Or let GrayMatter pull atomic facts out of the raw response for you.
// Uses ANTHROPIC_API_KEY if set; otherwise stores the raw text as a single fact.
mem.RememberExtracted(ctx, skill.Name, responseText)
Inside Claude Code / Cursor you don't need either call — the LLM uses the
memory_reflectMCP tool to self-curate. See Claude Code / Cursor (MCP) below.
mem, err := graymatter.NewWithConfig(graymatter.Config{
DataDir: ".graymatter",
TopK: 8,
EmbeddingMode: graymatter.EmbeddingAuto, // Ollama → OpenAI → Anthropic → keyword
OllamaURL: "http://localhost:11434",
OllamaModel: "nomic-embed-text",
AnthropicAPIKey: os.Getenv("ANTHROPIC_API_KEY"),
OpenAIAPIKey: os.Getenv("OPENAI_API_KEY"),
DecayHalfLife: 30 * 24 * time.Hour, // 30 days
AsyncConsolidate: true,
})
```bash graymatter init # create .graymatter/ + .mcp.json graymatter remember "agent" "text to remember" # store a fact graymatter remember --shared "text" # store in shared namespace (all agents) graymatter recall "agent" "query" # print context graymatter recall --all "agent" "query" # merge agent + shared memory graymatter checkpoint list "agent" # show saved checkpoints graymatter checkpoint resume "agent" # print latest checkpoint as JSON graymatter mcp serve # start MCP server (Claude Code / Cursor) graymatter mcp serve --http :8080 # HTTP transport graymatter export --format obsidian --out ~/vault # dump to Obsidian vault graymatter tui # 4-view terminal UI graymatter run agent.md [--background] # run a SKILL.md agent file graymatter sessions list # list managed agent sessions graymatter plugin install manifest.json # install a plugin graymatter serve
$ claude mcp add graymatter \
-- python -m otcore.mcp_server <graph>