> ## Documentation Index
> Fetch the complete documentation index at: https://docs.substrate.42.pe/llms.txt
> Use this file to discover all available pages before exploring further.

# How Substrate Works: Local-First Architecture Overview

> Learn how Substrate stores boards as code, keeps runtime state in SQLite, and exposes two surfaces: an MCP server for agents and a read-only web UI.

Substrate splits its state into two deliberate tiers: board definitions live as JSON files in your repo — reviewable in pull requests, versioned with your code — while tasks and their history live in a local SQLite database that changes constantly and stays gitignored. Understanding that split explains almost every design decision you'll encounter.

## Substrate-as-code

Each board is a single JSON file at `.substrate/boards/<id>.json`. It holds the board's groups, field schema, policies, and optional team binding. Substrate reads each file fresh on every call, so an edit — whether through a text editor, a git merge, or an MCP tool — is live on the next request. There is no migration step, no cascade, and no rebuild.

```json .substrate/boards/delivery.json theme={null}
{
  "id": "delivery",
  "name": "Delivery",
  "description": "How work ships.",
  "field_schema": {
    "task": {
      "spec_approved": { "type": "boolean" },
      "priority": { "type": "enum", "values": ["low", "med", "high"] }
    },
    "comments": {}
  },
  "groups": [
    { "id": "spec", "name": "Spec", "description": "", "position": 0,
      "color": null, "version": 1, "archived_at": null }
  ],
  "policies": [],
  "team": [{ "member": "builder", "groups": ["spec"] }],
  "version": 1,
  "created_at": "2026-01-01T00:00:00.000Z",
  "updated_at": "2026-01-01T00:00:00.000Z",
  "archived_at": null
}
```

<Warning>
  A board file that doesn't match the expected shape fails the entire substrate load with `substrate_corrupt` — the error names the file and how to fix it. Run `substrate validate` to check without starting a server.
</Warning>

## Runtime state in SQLite

Tasks, comments, and the append-only event log live in `.substrate/data.sqlite` — a libsql database running in WAL mode, safe for concurrent agents. This data is deliberately *not* substrate-as-code: tasks change constantly, are per-checkout, and would turn every board file into a merge conflict if stored there.

## What gets committed and what doesn't

`substrate init` writes the correct gitignore block for you, and the command is idempotent — run it again and nothing breaks.

| Path                             | Contents                                      | Git        |
| -------------------------------- | --------------------------------------------- | ---------- |
| `config.json`                    | Project id, name, description, schema version | committed  |
| `boards/*.json`                  | Boards, groups, field schema, policies, team  | committed  |
| `members/*.json`                 | The persona registry                          | committed  |
| `data.sqlite` (+ `-wal`, `-shm`) | Tasks, comments, event log                    | gitignored |
| `attachments/`                   | Task attachments                              | gitignored |
| `logs/substrate.log`             | Warnings and errors from long-lived processes | gitignored |
| `substrate.pid`                  | Single-owner lock held by a live serve        | gitignored |
| `serve.json`                     | The port serve actually bound                 | gitignored |

<Warning>
  Because the database is gitignored, a git worktree or fresh clone checks out your boards but **not** the database. Substrate warns on startup when it detects this condition. See [Worktrees and Clones](/agents/worktrees-and-clones) for how to handle this.
</Warning>

## Two surfaces

Substrate exposes exactly two surfaces, with a clear separation of intent.

<CardGroup cols={2}>
  <Card title="MCP Server" icon="server" href="/mcp/overview">
    `substrate mcp` — the read/write surface. Agent runtimes spawn it over stdio. Provides 32 tools covering reads, task and comment writes, and workflow edits.
  </Card>

  <Card title="Web UI" icon="browser" href="/concepts/web-ui">
    `substrate serve` — a localhost-only, read-only inspector. Boards render as a live kanban that auto-refreshes. The UI never writes — no drag-and-drop.
  </Card>
</CardGroup>

<Note>
  `substrate approve` is a write channel deliberately reserved for people. That asymmetry is what makes a `human_only` gate real: an agent's MCP tools structurally cannot set those fields.
</Note>
