~/sidharth.dev

substrate

v0.2.2 · MIT

Knowledge 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-mcp

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

Paste this into your agent instructions 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 Claude Code session: user asks the agent to open yesterday's substrate handoff and continue the deploy work. The agent calls get_by_date, get_bundle, and log_use, then resumes with full context.

↑ 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,deploy

Your $EDITOR opens with a pre-filled frontmatter template. Write the body, save, quit. Substrate commits it to git automatically.

Terminal showing substrate add, list, search, and ui commands with mocked output.

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,api

Debugging 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,deployment

06 · dashboard

One self-contained HTML file. No server.

substrate ui --open

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

The substrate dashboard in light mode: sidebar with 30-day activity chart, most-referenced leaderboard, and tag chips; main area showing a day-grouped timeline of bundles.
The substrate dashboard in dark mode.

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 main

08 · design invariants

Five non-negotiables.

InvariantWhy
files on disk are truthEvery index, cache, dashboard is disposable. Grep, diff, and edit bundles with any tool.
git is the historyNo custom audit log, no version field. git log is the trail.
boring formatsMarkdown + YAML frontmatter. No proprietary schema, no vendor lock-in.
falsifiable retrievalusage.log records every fetch. Unused bundles surface as deletion candidates.
mcp-native, not mcp-onlyThe CLI works offline, in scripts, in CI. MCP is one optional adapter.