
Declarative, declarative + code, or pure code — plus a private registry. Features are added, not rebuilt from scratch.
WebAuthn login. No password to leak or to forget. It's sz.ws's technical statement, not an option.
Next.js + OpenNext on Cloudflare Workers, D1 / R2 for data, responding close to everyone.
Three kinds of extension, from a single manifest file to a full package of code. Install one and it shows up in the admin — the core doesn't change.
One manifest.json is one feature: content types, admin pages and public routes, all described as data — the contact form on the right is a real example from the registry.
A manifest that also ships its own admin components and SQL, published and versioned together in the registry.
A whole package living in extensions/<id>/ — its own admin, public pages, API and kit, compiled into the core.
{ "kind": "declarative", "id": "contact", "coreApi": "^1.3.0", "contentTypes": [{ "name": "submission", "fields": [ { "key": "name", "type": "text", "required": true }, { "key": "email", "type": "text", "required": true }, { "key": "message", "type": "text", "required": true } ] }], "adminPages": [{ "view": "collection", "layout": "table" }], "publicRoutes": [{ "pattern": "/contact", "view": "form" }] }
Excerpt from the contact extension's manifest in the registry — a declarative form whose anonymous submissions land straight in shared content.
cms add fetches from the registry, materialises extensions/<id>/ and patches registry.ts. Private registries work over a token, and re-running is idempotent — no duplicate lines.
~/cms $ npx @sz.ws/cms add contact
registry — fetched manifest.json
materialised extensions/contact/
patched extensions/registry.ts
--dry-run shows what it would do; private registries use SZWS_REGISTRY_TOKEN.
A chat panel built into the admin, wired to your content, orders and settings. It can answer questions, draft changes and run real calculations — but every write comes back as a proposal. Nothing changes until you say yes.
A new post, a status change, a refund — every write is held up as a proposal first. There is no setting that skips this.
Ask how many orders came in this month and it renders the same chart components the dashboard uses — real numbers pulled from your data, not a guess dressed up as one.
A QuickJS sandbox running in a Web Worker does the arithmetic — the model runs real code instead of doing math in its head.
None of this is a screenshot — these are the same components that ship in the admin. Select the text, hover the rows. They play one shared timeline on a loop: a ⌘K search, the numbers filling in, the save bar rising and dropping away.
Writing your first extension