AI-operable, data-defined, headless

A CMS an AI can run from day one

Collections, fields, and pages live in D1 as data, so the structure changes without migrations. Connect an agent over MCP: it drafts content, proposes schema changes, and builds json-render pages while admins approve. Runs on Void and Cloudflare Workers + D1 + R2.

build-app.ts
// Mount the CMS in a Void app
const cms = createCMS({
  db,
  bucket: storage,
  site: { specValidator: validateSiteSpec, specGuide, themeSchema },
  mcp: false, // MCP is served at the site root
})

app.route("/api", cms.router) // REST
app.route("/mcp", cms.mcp) // MCP, behind OAuth sign-in

// Then hand the site to Claude: add https://<host>/mcp
// as a connector and sign in on your site.

Capabilities

Batteries included

One engine sits behind REST, MCP, and your own loaders, with the same access checks everywhere. Each capability is built in, not a plugin you wire up yourself.

MCP from day one

An MCP server at /mcp with 31 tools and a built-in guide. Add the URL to Claude, sign in on your site, and it can run the whole site.

Structure as data

Collections, fields, and documents live in D1 as JSON. Add a field or a whole collection without a migration or a deploy.

Proposals & approval

Schema changes are saved as proposals with their impact on stored documents measured. Nothing changes until an admin approves.

Pages as json-render specs

Pages, layouts with an Outlet, and menus are documents too. Data queries fill the state; the path resolves to one merged spec.

Your component catalog

Specs use only the components you define in code. Style goes through props and theme tokens that become CSS variables.

Drafts, review, revisions

Working and live copies per document. Editors and AI request review, admins publish, schedule, or restore any revision.

Full-text search

An FTS5 trigram index over text and rich text, with separate live and working rows for public and admin search.

Localization

One document per language, grouped by a translation key. Lists, pages, and search filter by locale.

Webhooks & API keys

Every change lands in a durable outbox and drains to signed webhooks. Bearer keys carry a role and the same access checks.

How it works

From deploy to a running site

01

Deploy with Void

Mount createCMS() under /api and run void deploy. The engine creates its own tables in D1 on the first request.

02

Connect an agent

Issue an editor API key in the admin and add the MCP server with claude mcp add. The agent reads the guide and your component catalog.

03

Approve and publish

The agent proposes collections, writes drafts, and builds pages, then requests review. You approve and publish from /admin.

Overview

What it is

Code fixes the kinds of things that exist: field types, hooks, access rules, MCP tools, and your page components. D1 holds how they are combined and what they contain. The REST API, the MCP server, and your own loaders all go through one engine with the same access checks. This documentation site is itself a set of CMS pages.