Nulldown turns Markdown into deterministic structure.
Markdown is the shared language of people and agents. Nulldown makes it addressable, replayable, queryable, attributable, composable, and renderable, so one source can power documents, shared state, agent memory, targeted retrieval, workflows, and interfaces.
flowchart LR
Markdown["Markdown"] --> Nulldown["Nulldown"]
Nulldown --> State["Deterministic structure"]
State --> Memory["Agent memory"]
State --> Retrieval["Targeted retrieval"]
State --> UI["Document-native UI"]
State --> Trust["Explicit trust modes"]
Most systems repeatedly translate the same work between documents, prompts, databases, memory, and component state. Nulldown keeps those uses connected to readable Markdown and inspectable state.
The canonical documentation lives in Nulldown:
- Documentation index
- Why Nulldown: deterministic structure for Markdown
- State model
- Agents, retrieval, and memory
- Documents as interfaces
- Privacy and trust boundaries
- Build with Nulldown
- Status and direction
| Area | Current capability |
|---|---|
| Deterministic state | Ordered branch diff events, parent-linked snapshots, checkpoints, replay, and promotion. |
| Retrieval and memory | Structural document/runtime queries, source references, priority overlays, and optional NullMem facts, procedures, capabilities, and freshness signals. |
| Interfaces | Native Nulldown composition, nullplug runtime contracts, runtime facts, and policy-controlled proposed mutations. |
| Trust | Public plaintext, client-sealed, provider-assisted, and self-hosted workflows with different explicit trust properties. |
| Deployment | Cloudflare Pages/R2/D1 plus a self-hostable Bun API backend using filesystem blobs and SQLite metadata. |
Install the CLI:
bun install -g @thenullnode/nulldown
nd --helpCreate a document, edit its branch, and retrieve the changed structure:
nd create README.md --json
nd branch resolve <rootId> --json
nd diff apply <rootId> --branch <branchId> --insert '0:# Updated title\n\n' --json
nd branch query <rootId> <branchId> --query "updated title" --top 1 --jsonRun against a local or preview API:
nd --base=http://127.0.0.1:8788 get <id> --jsonUse the separate MCP package to let agents retrieve structure, manage branch diffs, and work with NullMem without shelling out:
bun install -g @thenullnode/nulldown-mcp
nulldown-mcpConfigure ND_BASE_URL, ND_TOKEN, ND_ACCOUNT_ID, and ND_CLIENT_ID in the MCP client environment as needed. Read/query tools support bounded compact responses; expand exact branch content only when a decision needs it. See the MCP package README.
Run the API locally with filesystem blob storage and SQLite metadata:
nd serve --host 127.0.0.1 --port 8788 --data-dir .nulldown-dataRun the same API in Docker with /data as the persistent volume:
docker build -t nulldown .
docker run --rm -p 8788:8788 -v nulldown-data:/data nulldownThe local server supports core drop, branch, diff, resolved-query, priority, and NullMem routes. It is a self-hostable API backend, not a full packaged replacement for every hosted route or the web application.
Install dependencies:
bun installRun the Vite development server:
bun run devRun Cloudflare Pages development with Functions:
bun run pages:devRun focused verification:
bun run test
bun run build
bun run cli:build
bun run package:check-cli
bun run package:check-mcpRepository rules live in AGENTS.md. Nulldown-hosted plans, documentation, and agent memory are updated with branch diffs and verified through resolved queries. The local docs/ directory retains source-coupled references and migration material; the hosted documentation graph is the public conceptual source of truth.
MIT