Skip to content

Core concepts

Subspace has a small number of load-bearing ideas. Once they click, every feature is a variation on them. This page is the map; each concept links to its own chapter.

Everything durable, pages, mail, calendar, tasks, agent runs, embeddings, lives in one embedded PostgreSQL database. Postgres schemas (kb, comms, ops, search) namespace the domains, but they share one transaction boundary, one WAL, and one backup stream. A user edit commits atomically with its reindex, its command-log row, and its outbox notice. An agent step’s checkpoint, output nodes, and approval task commit together or not at all.

The knowledge base is an outliner: every page is a tree of nodes (bullets), and every node’s text is the source of truth. A node can also carry an element, a table, a code cell, a terminal, a custom function, or a file, rendered in a node frame but still part of the same tree.

Pages come in kinds: outline pages, directory pages (folders that are themselves pages), and element pages (a page whose body is one element, like a PDF with annotation bullets). Configuration, agents, skills, MCP servers, judges, settings, and plugin data, is also just pages.

Nothing mutates the graph directly. Every change, a keystroke, a rename, an agent’s edit, is a command run through a pure reducer (@subspace/kb-core) shared verbatim by client and server.

  1. Optimistic apply

    The client applies your command locally through the reducer for an instant response, holding it in a pending list.

  2. Authoritative commit

    The server runs the same reducer inside one Postgres transaction: advisory-lock the page, reduce, update nodes / links / labels / deps, stamp the page’s sequence number, append the command log and an outbox row.

  3. Echo and rebase

    The committed command echoes back over the topic bus. The client folds it into the authoritative document and rebases its remaining pending commands. Conflicts resolve last-write-wins in server order.

Because the reducer is total and emits inverses, undo is just issuing the inverse commands, and multiplayer convergence is free.

Every committed transaction can append a row to an outbox. A single dispatcher holds one Postgres LISTEN connection; on NOTIFY it reads new outbox rows and fans them out to two places: WebSocket topics (so open pages update live) and in-process consumers (each advancing its own cursor). This is the one propagation mechanism in the system.

Consumers are how derived state stays current: the search indexer, the OKF exporter, the recompute engine for table formulas, event triage, mail and calendar sync, the agent engine, notifications, and more. Missed notifications are recovered by reading past the cursor, so nothing is lost across a restart.

On top of the outbox sits the ops spine: the layer that turns “something happened” into “something to do”. Every meaningful state change emits an event; a triage layer classifies it by severity (silent / normal / important / ultra) with a deterministic rule fallback; and the results land in an inbox, a task queue, reminders, and a scheduler, with notifications routed by severity.

An agent is a page in agents/ with a prompt, a tool allowlist, an args schema, a model, and an approval policy. It runs on a durable engine (the Workflow DevKit over the self-hosted Postgres World): every step is journaled, waits and approvals are durable hooks, sub-agents are child runs, and the whole thing survives restarts because a pause is a row.

Agents act as a specific user, see only what that user’s page ACLs allow, and pause for approval on every outbound or irreversible tool. A capability broker decides which secrets a run may touch.

The whole graph can mirror to a folder of Markdown files (OKF, one file per page) and back. This is how agents edit pages (they submit Markdown, a codec diffs it to node commands), how GitOps deploys configuration, and how you can keep your knowledge in plain files under version control.

Everything above is extensible through plugins: installable, versioned directories that add page types, sandboxed tools, views, ESM viewers, special-page surfaces, and compiled agent workflows, hot-swappable without a redeploy. MLOps, autoresearch, CRM, and more are built this way.