AI-operable, data-defined, headless
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.
// 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
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
01
Mount createCMS() under /api and run void deploy. The engine creates its own tables in D1 on the first request.
02
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
The agent proposes collections, writes drafts, and builds pages, then requests review. You approve and publish from /admin.
Overview
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.
Reference
Getting started
Deploy