Lightweight, injectable knowledge bundles for AI agents. Git-versioned markdown, MCP-native, lives in your filesystem.
Project description
substrate
Lightweight, injectable knowledge bundles for AI agents.
Git-versioned · MCP-native · Lives in your filesystem as plain markdown.
Substrate is a local-first knowledge store designed for the agent era. You write a "bundle" — a markdown file with YAML frontmatter — and any MCP-compatible AI tool (Claude Code, Cursor, Zed, Continue, …) can pull it into context on demand. No daemon, no database, no embeddings server. Files on disk are the source of truth; git is the history; an MCP server is the agent-facing API.
~/.substrate/
└── bundles/
└── 2026-05-24/
├── handoff-deploy-staging.md
└── convention-error-handling.md
That's the whole thing. Open them in your editor. Diff them with git. Grep them with ripgrep. Substrate just adds an opinionated CLI and an MCP server on top.
Why substrate
You're using AI agents every day. They forget everything between sessions. The fixes on offer:
- Mem.ai / mem0 / vector DBs — embeddings-heavy, opaque, lossy, lock-in.
- CLAUDE.md / cursor rules — global, mixed with code, no provenance.
- Notion / Obsidian — not designed for programmatic agent access.
Substrate sits in the gap: portable markdown bundles you author deliberately, git-versioned so changes are auditable, and MCP-exposed so any agent can fetch them by id, tag, date, or substring. Nothing magic — and that's the point.
Install
Requires Python 3.10+.
# Standalone CLI tool (recommended)
uv tool install substrate-kb
# Or with pipx
pipx install substrate-kb
# Or editable from source
git clone https://github.com/xlreon/substrate.git
cd substrate && uv tool install --editable .
Initialize the store (one-time):
substrate init # creates ~/.substrate, git-inits it
60-second tour
substrate add "deploy staging landmines" # opens $EDITOR on a new bundle
substrate list --tag handoff # filter by tag
substrate search "asyncpg ssl" # substring across id/tags/body
substrate get 2026-05-24-deploy-staging-landmines | pbcopy
substrate ui --open # static HTML dashboard
Adding bundles non-interactively
substrate add opens $EDITOR by default. For scripted use, four other channels:
substrate add "inline note" --body "the body text" # inline string
substrate add "from a file" --from path/to/note.md # file path
cat note.md | substrate add "piped in" --from - # stdin
substrate add "draft + tweak" --body "starter" --edit # pre-fill, then $EDITOR
--body and --from are mutually exclusive. Both strip leading YAML frontmatter from the source so substrate's own frontmatter is canonical.
Bundles are markdown files under ~/.substrate/bundles/YYYY-MM-DD/. Every add and edit commits to git automatically.
Where your bundles live
Substrate code lives at github.com/xlreon/substrate. You install the binary — you don't fork or clone unless you want to contribute.
Your bundles live in ~/.substrate/bundles/YYYY-MM-DD/<slug>.md. Your data, not ours.
substrate init git-inits ~/.substrate/ locally so you get versioning for free. Want to back it up?
cd ~/.substrate && git remote add origin <your-private-repo> && git push -u origin main
Want to move the store? Set SUBSTRATE_HOME:
export SUBSTRATE_HOME=/opt/team-substrate # shared NFS mount
export SUBSTRATE_HOME=~/Dropbox/substrate # synced folder
export SUBSTRATE_HOME=./project-substrate # project-local
Substrate honors SUBSTRATE_HOME everywhere — CLI, MCP server, dashboard.
For AI agents (MCP)
Substrate ships an MCP server (substrate-mcp) exposing the bundle store to any MCP-compatible client.
Claude Code:
claude mcp add substrate -- substrate-mcp
Cursor / Zed / Continue / other MCP hosts — add to your MCP config:
{
"mcpServers": {
"substrate": { "command": "substrate-mcp" }
}
}
Tools exposed:
| Tool | Purpose |
|---|---|
list_bundles |
Enumerate, optionally filter by tag/date |
get_bundle |
Fetch a bundle by id |
search_bundles |
Substring search across id, tags, body |
get_by_date |
Temporal lookup (2026-05-24 or a range) |
log_use |
Record that an agent used a bundle (optional retrieval metric) |
Now your agent can pull context on demand:
"What did we decide about retry semantics last week?" → agent calls
search_bundles("retry", since="2026-05-17")→ reads top hits → answers with citations to specific bundle ids.
Bundle format
---
id: 2026-05-24-deploy-staging-landmines
created: 2026-05-24T19:30:00+05:30
tags: [deployment, fly, gotcha]
context_refs: []
---
# What broke
asyncpg refused TLS with `?ssl=disable` — needed `?sslmode=disable` instead.
…
The format is deliberately boring: any text editor works, the files survive substrate being uninstalled, and your git log is the history. No proprietary blobs, no opaque indexes.
The dashboard
substrate ui --open generates a single self-contained HTML file with:
- 4-stat overview (total / this week / today / last activity)
- 30-day activity bar chart
- "Most referenced" leaderboard (computed from your AGENTS.md / CLAUDE.md mentions + git commit count)
- Tag filter chips
- Day-grouped timeline with collapsible bodies
- Modal form to draft a new bundle and copy a one-liner shell command to land it
Set SUBSTRATE_ACTIVE_FILE to point at the markdown file where you declare your current "active" bundle (e.g. ~/AGENTS.md, ~/CLAUDE.md, anywhere) and the dashboard will highlight that one at the top:
export SUBSTRATE_ACTIVE_FILE=~/AGENTS.md
In that file, add a line containing ACTIVE BUNDLE and either the bundle id (what substrate list prints) or the path:
## Now
- **ACTIVE BUNDLE:** 2026-05-24-handoff-deploy-staging
Or path-fragment form:
- **ACTIVE BUNDLE:** `~/.substrate/bundles/2026-05-24/handoff-deploy-staging.md`
Marker text is configurable via SUBSTRATE_ACTIVE_MARKER (e.g. export SUBSTRATE_ACTIVE_MARKER=PINNED).
CLI surface
| Command | What it does |
|---|---|
substrate init |
Initialize ~/.substrate as a git-backed store |
substrate add <name> |
New bundle in today's folder. Opens $EDITOR by default; --body TEXT, --from FILE, or --from - (stdin) for scripted input |
substrate list |
List bundles, optionally --tag / --date filtered |
substrate search <query> |
Substring search across id, tags, body |
substrate get <id> |
Print a bundle to stdout (pipe-friendly) |
substrate use <id> |
Copy body to clipboard + log usage |
substrate log |
Show usage log (the falsifiable retrieval metric) |
substrate edit <id> |
Open an existing bundle in $EDITOR |
substrate history <id> |
git log for a specific bundle |
substrate ui |
Generate a static HTML dashboard |
substrate --version |
Print installed version and exit |
Full reference: substrate --help. Design notes: SPEC.md.
Design principles
- Files on disk are source-of-truth. Every index, cache, embedding, dashboard is disposable and rebuildable from the markdown.
- Git is the history. No custom audit log, no "version" frontmatter field.
- Boring formats. Markdown + YAML frontmatter. No JSON-LD, no proprietary schema.
- Falsifiable retrieval.
log_useexists so you can prove (or disprove) that the store earns its keep. - MCP-native, not MCP-only. The CLI works offline, in a script, in a CI job; the MCP layer is an optional adapter.
Contributing
PRs welcome. See CONTRIBUTING.md for dev setup and conventions. Bug reports and feature requests: open an issue.
Support substrate
- ⭐ Star on GitHub if substrate earns its keep in your workflow
- 💬 Share use cases in Discussions
- 🐛 File issues, especially for cross-platform breakage
- 📝 Write up your integration — we'll link it from the docs
License
MIT © Sidharth Satapathy
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file substrate_kb-0.2.2.tar.gz.
File metadata
- Download URL: substrate_kb-0.2.2.tar.gz
- Upload date:
- Size: 156.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f0b874cde75663af233ed11b2e91998353483c10eb84e09c0280ba680b86633
|
|
| MD5 |
7ee82c77844632999a72b1b826267cc4
|
|
| BLAKE2b-256 |
e91623dca31e60b0a89d6cc212bff25cacd34601dc75c41ac13bc2e707b31242
|
Provenance
The following attestation bundles were made for substrate_kb-0.2.2.tar.gz:
Publisher:
release.yml on xlreon/substrate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
substrate_kb-0.2.2.tar.gz -
Subject digest:
0f0b874cde75663af233ed11b2e91998353483c10eb84e09c0280ba680b86633 - Sigstore transparency entry: 1627176766
- Sigstore integration time:
-
Permalink:
xlreon/substrate@772e96f0bf9f41510dc3b625e934b90ff0857c37 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/xlreon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@772e96f0bf9f41510dc3b625e934b90ff0857c37 -
Trigger Event:
push
-
Statement type:
File details
Details for the file substrate_kb-0.2.2-py3-none-any.whl.
File metadata
- Download URL: substrate_kb-0.2.2-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6fa0c3e8998fb66ad774ecc38768dea5f8585c87bd9d19cf3077dee389a45d85
|
|
| MD5 |
eb4741ea08db64648b44baba55ab5283
|
|
| BLAKE2b-256 |
f6d60f15e802c2b1f91f793596edc28c5b6eab42b7f94bc85ca27bea824cb9af
|
Provenance
The following attestation bundles were made for substrate_kb-0.2.2-py3-none-any.whl:
Publisher:
release.yml on xlreon/substrate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
substrate_kb-0.2.2-py3-none-any.whl -
Subject digest:
6fa0c3e8998fb66ad774ecc38768dea5f8585c87bd9d19cf3077dee389a45d85 - Sigstore transparency entry: 1627176880
- Sigstore integration time:
-
Permalink:
xlreon/substrate@772e96f0bf9f41510dc3b625e934b90ff0857c37 -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/xlreon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@772e96f0bf9f41510dc3b625e934b90ff0857c37 -
Trigger Event:
push
-
Statement type: