A session todo list evaporates
Todo lists native to the agent runtime are per-session. When the context resets, so does everything the agent knew about where the work stood.
Substrate is a local-first work tracker that lives in your repo and is driven by your coding agents over MCP. The process is defined once, as data — so every agent, this session or the next, reads the same durable state and hits the same gates at write time.
v0.7.0 is pre-release: not on npm yet, so install from source until it ships.
CLAUDE.md, or GitHub Issues?Two things those can’t do — which are the whole reason Substrate exists.
Todo lists native to the agent runtime are per-session. When the context resets, so does everything the agent knew about where the work stood.
A CLAUDE.md is durable but unstructured, and it’s advisory: as context fills, agents drift away from it — and nothing tells them at the moment they break it.
GitHub Issues is durable and structured, but it sits outside the working tree — a round trip the agent has to remember to make — and it doesn’t model your gates.
Substrate’s state lives in .substrate/, next to the code. A new session — or a second agent — reads exactly where work stands and which gates are unmet, without re-deriving it from git log.
One binary in your project. Two processes, one directory, everything local.
.substrate/boards/*.json defines boards, groups, your own field_schema, and policies. They’re committed with your code and read fresh on every call — edit the JSON and the change takes effect immediately. No migration, no cascade.
Tasks, comments and an append-only event log live in a local SQLite database (libsql, WAL mode — safe for concurrent agents). It’s gitignored: runtime state stays on your machine.
substrate serve hosts a localhost-only inspector: a live kanban that auto-refreshes, so a task an agent moves shows up within seconds. It only observes — it never writes, and there’s no drag-and-drop.
.substrate/
config.json # project id + name
boards/*.json # boards, groups, field_schema, policies, team (committed)
members/*.json # optional team registry (committed)
data.sqlite # tasks, comments, event log (gitignored)
attachments/ # (gitignored)
logs/substrate.log # warnings + errors from mcp/serve (gitignored) The JSON is committed. The database and attachments are gitignored by default.
Two policy classes. That’s the whole model.
transition_guard — blocksBlocks a move between groups when a required field isn’t set, and returns transition_blocked to the agent at the instant of the write, naming the field that’s missing.
agent_responsibility — suggestsAttaches non-blocking suggestions to matching writes. Every write returns an envelope listing the policies that fired.
Mark a field human_only and an agent’s write tools refuse to set it — only a person can, from the CLI. A guard that requires one is a sign-off an unattended agent structurally cannot give itself.
{
"ok": false,
"error": {
"code": "transition_blocked",
"message": "Policy 'tests-before-review' blocks moving from 'Build & Test' to 'Review'.",
"details": {
"policy_id": "pol_01HX…",
"from_group": "Build & Test",
"to_group": "Review"
}
}
} The field a gate checks is self-attested — the agent sets tests_passing: true itself; nothing runs your tests. A gate is a confession step, not a control: it records the claim and blocks until the claim is made, but it does not verify the claim is true. A perfectly-timed hard rail still beats advisory prose an agent has drifted from — but it’s worth being precise about.
human_only fieldsMark a field human_only and an agent’s write tools refuse to set it — and update_board refuses to un-protect it. Only a person can set it, from the CLI: substrate approve <task_id> <field>. A guard that requires a human_only field is a sign-off an unattended agent structurally cannot clear on its own. substrate pending-approval lists everything waiting on a human.
Node 20 or newer, and a few minutes.
Substrate isn’t on npm yet. Clone the repo, build it, and link the binary once — after that, substrate works the same everywhere.
git clone https://github.com/42pe/substrate.git
cd substrate && pnpm install && pnpm build && pnpm link --global
substrate install-skill # installs the agent skill into ~/.claude/skills/
cd /path/to/your-project && substrate init
substrate serve # inspect at http://localhost:7475 Add the stdio MCP server to your agent runtime’s config. From there the agent calls whoami and takes it from there — 32 tools, one documented set of conventions.
{
"mcpServers": {
"substrate": {
"command": "substrate",
"args": ["mcp"]
}
}
} What you’re getting into, before you spend an afternoon on it.
What isn’t ready yet, and what changes when it is. Each of these disappears from this list the day it ships.
Today Substrate is installed from source. When the package is published, the install becomes one npx command and the MCP config stops pointing at a local path.
Installation, concepts, gates, the agent workflow and the CLI reference are written and waiting on a deploy.
The deck from the f13 talk, posted as it was given.
No marketing, just news about how Substrate is coming along.
The tool itself. Substrate collects nothing and sends nothing. There is no telemetry, and the CLI never makes a network call — your boards, tasks and logs stay on your machine.