substrate
v0.2.2 · MITKnowledge bundles for AI agents. Markdown on disk, git for history, MCP for retrieval. The minimum layer that solves cross-session amnesia.
no daemon · no database · no embeddings
01 · what it is
A directory of markdown. A CLI. An MCP server.
That's substrate. You author bundles deliberately — handoffs, playbooks, conventions, debugging notes — and any MCP-compatible agent (Claude Code, Cursor, Zed, Codex, Continue) reads them on demand by id, tag, or date.
Each bundle is a markdown file with YAML frontmatter. Bundles live under ~/.substrate/bundles/YYYY-MM-DD/. Git tracks every change automatically.
---
id: 2026-05-24-handoff-deploy-staging
created: 2026-05-24T19:30:00+05:30
tags: [handoff, deploy, fly]
---
# Where we left off
asyncpg SSL fix landed on staging. Prod deploy half-wired —
need to set REDIS_URL secret and add the release_command.02 · install
Three commands.
# install the CLI + MCP server
uv tool install substrate-kb
# initialize the bundle store at ~/.substrate/
substrate init
# register the MCP server with Claude Code
claude mcp add substrate -- substrate-mcpSame idea for Cursor, Zed, Codex CLI, and Continue — host-specific one-liners below.
03 · wire your agent
One paragraph. Pasted into the right file.
Adding the MCP server gives your agent the capability. Telling it when to use that capability is one paragraph in your CLAUDE.md, AGENTS.md, or .cursorrules file.
## substrate
You have access to a substrate knowledge store via MCP. Use it when:
- The user mentions "my notes," "yesterday's handoff," or a date
→ call `get_by_date` with that date.
- The user mentions a "playbook," "runbook," "rubric," or "template"
→ call `search_bundles` with the keywords. If a bundle tagged
`prompt` or `playbook` matches, read it with `get_bundle`
and follow it verbatim.
- The user references a specific bundle id (e.g. 2026-05-24-foo)
→ call `get_bundle(id="2026-05-24-foo")` directly.
- You are about to make a decision that benefits from prior context
→ search substrate for relevant tags before deciding.
After using a bundle, call `log_use(id=..., note=...)` so we can
measure which bundles earn their keep.That's the entire integration. From now on the agent reaches for substrate without prompting — you just speak naturally about your notes, playbooks, or past sessions and the right MCP call happens.
what it looks like

↑ a session resuming yesterday's work via the substrate MCP tools
04 · first bundle
The 60-second tour.
substrate add "handoff deploy staging" --tag handoff,deployYour $EDITOR opens with a pre-filled frontmatter template. Write the body, save, quit. Substrate commits it to git automatically.

Adding bundles non-interactively
$EDITOR is the default, but not the only path. Four channels, all of them pipe-friendly:
# inline body
substrate add "inline note" --body "the body text"
# from a file
substrate add "from file" --from path/to/note.md
# from stdin (pipe-friendly)
cat note.md | substrate add "piped in" --from -
# pre-fill from --body or --from, THEN open the editor
substrate add "draft + tweak" --body "starter" --edit--body and --from are mutually exclusive. Both strip leading YAML frontmatter from the source so substrate's own frontmatter stays canonical.
05 · patterns
Four patterns that pay off.
If your workflow doesn't hit at least one of these a few times a week, a folder of markdown files is enough — you don't need this tool.
Cross-session handoffs
Write what was decided and what's half-done before stopping. Next session resumes without re-explaining.
substrate add "handoff fly decision" --tag handoff
# next morning:
# You: "Open my handoff from yesterday and continue the deploy work."
# Agent: [calls get_by_date(date="2026-05-23", tag="handoff")]Pre-authored prompts
Author a playbook once when you're calm. The agent picks it up later when you're rushed and follows it verbatim.
substrate add "prompt run migration" --tag prompt,playbook,migration
# days later:
# You: "Run the migration playbook on the new index addition."
# Agent: [searches substrate, fetches the playbook, follows step-by-step]Shared conventions across parallel agents
Three agents on three branches all read the same convention bundle and stay consistent.
substrate add "convention api error envelope" --tag convention,apiDebugging breadcrumbs
Write the root cause when you fix a gnarly bug. Six days later a related issue surfaces and the agent finds the bundle in 80ms instead of re-spelunking.
substrate add "gotcha asyncpg ssl disable" --tag gotcha,asyncpg,deployment06 · dashboard
One self-contained HTML file. No server.
substrate ui --openStats overview · 30-day activity chart · most-referenced leaderboard · tag filter chips · day-grouped timeline · modal to draft new bundles from the browser. All static. Drop it on any host if you want to share it.


07 · where bundles live
On your filesystem. In your home directory.
~/.substrate/
├── .git/ # auto-committed history
├── bundles/
│ ├── 2026-05-23/
│ │ └── convention-error-handling.md
│ └── 2026-05-24/
│ ├── handoff-deploy-staging.md
│ └── prompt-bug-triage-template.md
└── usage.log # append-only TSV (gitignored)Set SUBSTRATE_HOME to move the store anywhere — a Dropbox folder for cross-machine sync, a project subdirectory for per-repo bundles, a mounted shared volume for a team. To version-control your bundles, push the auto-initialized git repo to any remote.
cd ~/.substrate
git remote add origin git@github.com:you/my-substrate.git
git push -u origin main08 · design invariants
Five non-negotiables.
| Invariant | Why |
|---|---|
| files on disk are truth | Every index, cache, dashboard is disposable. Grep, diff, and edit bundles with any tool. |
| git is the history | No custom audit log, no version field. git log is the trail. |
| boring formats | Markdown + YAML frontmatter. No proprietary schema, no vendor lock-in. |
| falsifiable retrieval | usage.log records every fetch. Unused bundles surface as deletion candidates. |
| mcp-native, not mcp-only | The CLI works offline, in scripts, in CI. MCP is one optional adapter. |