MCPcopy Index your code
hub / github.com/angelnicolasc/graymatter

github.com/angelnicolasc/graymatter @v0.6.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.6.0 ↗ · + Follow
979 symbols 2,976 edges 97 files 532 documented · 54%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

graymatter-banner

GrayMatter

CI Go Reference Latest Release Coverage 73.5% Platforms Go Report Card License

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"]

Why

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.

GrayMatter-Chart1

~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.


Observability

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.

GrayMatter-TUI

What you get at a glance:

  • Facts — total stored, distributed across agents
  • Memory cost — KB on disk (text + embeddings), not tokens
  • Recalls — cumulative access count across all sessions
  • Health — percentage of facts above relevance threshold (weight > 0.5)
  • Token cost (30d) — real spend breakdown by model, with cache hit rate
  • Agent activity — facts vs recalls per agent, side by side
  • Weight distribution — how consolidated your memory is over time
  • Activity timeline — facts created per day, last 30 days

The dashboard auto-refreshes every 5 seconds. Press 1–4 to switch tabs, r to force refresh, q to quit.


Install

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

MCP clients (drop-in)

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_reflect uses agent, the other four use agent_id).

Any other MCP-compatible client

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.

Global install (all projects)

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.

Troubleshooting — "MCP is connected but nothing gets stored"

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:

  1. No instructions. An MCP connection only makes tools available — nothing tells the model to call them. If 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).
  2. Orphaned manual server. MCP clients spawn 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.

How memories get stored

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.


Library usage

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")

Full agent pattern

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_reflect MCP tool to self-curate. See Claude Code / Cursor (MCP) below.

Config

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,
})

CLI

```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

Extension points exported contracts — how you extend this code

Provider (Interface)
Provider generates float32 vector embeddings from text. A nil return from Embed signals keyword-only mode to the caller. [6 …
pkg/embedding/provider.go
ExtractConfig (Interface)
ExtractConfig is the subset of configuration needed for fact extraction. Satisfied by graymatter.Config via the same met [3 …
pkg/memory/extract.go
EntityExtractor (Interface)
EntityExtractor pulls entities from a text string, returning Nodes and Edges to upsert into the knowledge graph. [3 implementers]
cmd/graymatter/internal/kg/extractor.go
AdvancedStore (Interface)
AdvancedStore is the narrow interface exposed to advanced callers (CLI, MCP, TUI) that need direct access to CRUD, listi [1 …
graymatter.go
ConsolidateConfig (Interface)
ConsolidateConfig is the subset of configuration used by consolidation. Defined as an interface to avoid a circular impo [3 …
pkg/memory/consolidate.go
Exporter (Interface)
Exporter writes a slice of facts to an output directory. [3 implementers]
cmd/graymatter/internal/export/exporter.go
VectorStore (Interface)
VectorStore is the pluggable vector search backend. The default implementation wraps chromem-go (zero-infra, pure-Go, pe [2 …
pkg/memory/vectorstore.go
Store (Interface)
Store is the persistence surface Run needs. It is deliberately the subset of operations a run performs, so the runner ha [2 …
cmd/graymatter/internal/harness/store.go

Core symbols most depended-on inside this repo

Close
called by 48
pkg/memory/vectorstore.go
Put
called by 47
pkg/memory/rpc/server.go
toolError
called by 27
cmd/graymatter/internal/mcp/server.go
Open
called by 26
pkg/memory/store.go
Close
called by 26
cmd/graymatter/store_handle.go
Close
called by 25
cmd/graymatter/internal/harness/store.go
List
called by 24
graymatter.go
DB
called by 24
graymatter.go

Shape

Function 422
Method 375
Struct 163
Interface 14
TypeAlias 5

Languages

Go100%

Modules by API surface

cmd/graymatter/store_handle.go58 symbols
cmd/graymatter/internal/daemon/host.go52 symbols
cmd/graymatter/cmd_tui.go47 symbols
pkg/memory/rpc/server.go39 symbols
pkg/memory/store.go35 symbols
pkg/memory/store_test.go31 symbols
graymatter.go31 symbols
cmd/graymatter/internal/mcp/server.go31 symbols
cmd/graymatter/internal/server/server.go27 symbols
pkg/memory/rpc/wire.go26 symbols
cmd/graymatter/internal/daemon/client.go25 symbols
pkg/memory/rpc/client.go20 symbols

For agents

$ claude mcp add graymatter \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page