Quickstart: a minimal Worker
This page reproduces the API-only Worker reference as a direct-authoring walkthrough: View REST without Admin, Auth or a visitor frontend. For a new project, mantle generate --host cf --features spec,api assembles that smaller composition. Omit --features to include Admin, MCP and a blank home. The local Admin tutorial covers an authored Worker entry. Pin every selected @aotter/mantle* package to one exact version; see Versions.
Prerequisites
- Node.js 22 or newer.
- pnpm 9 or newer. The reference is tested with pnpm; see the npm note at the end of this page.
wrangleris installed as a project devDependency below. No Cloudflare account, D1 database or secret is needed for the local loop.
1. package.json
Step 5 adds the two Mantle packages at one exact version. For a prerelease evaluation, select its exact version explicitly rather than mixing channels. The entries below are the peers and tools used by this direct-authored reference.
{
"name": "mantle-minimal-consumer",
"private": true,
"type": "module",
"scripts": {
"generate": "mantle generate",
"validate": "mantle validate",
"typecheck": "tsc --noEmit",
"dev": "wrangler dev --local --ip 127.0.0.1 --port 8787",
"check": "mantle generate && mantle generate --check && mantle validate && mantle skills && mantle skills --check && tsc --noEmit"
},
"dependencies": {
"better-auth": "1.7.2",
"hono": "^4.13.3",
"zod": "^4.5.4",
"aws4fetch": "^1.0.20"
},
"devDependencies": {
"@cloudflare/workers-types": "^5.20260907.1",
"typescript": "^6.0.3",
"wrangler": "^4.125.0"
},
"packageManager": "pnpm@9.15.0"
}The reference's own check script ends with && node smoke.mjs, a test that starts the Worker and asserts the three probes in step 6. This walkthrough runs those probes by hand instead.
Add a tsconfig.json that includes the generated module:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"types": ["@cloudflare/workers-types"]
},
"include": ["src/**/*.ts", ".mantle/generated/**/*.ts"]
}2. manifests/site.yaml
One publishing Schema and one public View. mantle generate never invents a Schema; this notes model is example business data.
apiVersion: cms.mantle.aotter.net/v1
kind: Schema
metadata:
name: notes
spec:
title: Notes
schema:
type: object
required: [title]
properties:
title: { type: string }
lifecycle: publishing
---
apiVersion: cms.mantle.aotter.net/v1
kind: View
metadata:
name: published-notes
spec:
surface: public
from: notes
cache: { sharedMaxAge: 3600 }
fields: [id, title]
filter:
eq: { field: status, value: published }
limit: 203. src/index.ts
The conventional Worker entry hands the sealed plan to the Cloudflare adapter.
import { createMantleWorker } from "@aotter/mantle/cloudflare";
import { plan } from "../.mantle/generated/mantle.js";
export default createMantleWorker({ plan });createMantleWorker owns the D1 and assets bindings, Auth, Admin, View REST, HTTP Triggers, OAuth, MCP and cache policy. Application handlers and extra routes go through its extend option; see the conventional Worker.
4. wrangler.jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "mantle-reference",
"main": "src/index.ts",
"compatibility_date": "2026-09-08",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"observability": { "enabled": true },
"vars": { "MANTLE_AUTH_MODE": "self-managed" },
"d1_databases": [
{ "binding": "DB", "database_name": "mantle-reference-local" }
]
}Both compatibility flags are required by the adapter. MANTLE_AUTH_MODE must be explicit; self-managed without GitHub credentials is a deliberate partial configuration for this local reference, so Auth-owned routes fail closed while public routes work. Local wrangler dev creates the D1 database on demand; configure a real database_id and the full auth matrix before any remote deploy (Authentication).
5. Install, generate, validate, run
# Resolve once; for a requested prerelease, set its exact version instead.
MANTLE_VERSION=$(pnpm view @aotter/mantle@latest version)
pnpm add --save-exact "@aotter/mantle@$MANTLE_VERSION" "@aotter/mantle-cloudflare@$MANTLE_VERSION"
pnpm exec mantle generate
pnpm exec mantle validate
pnpm exec wrangler dev --local --ip 127.0.0.1 --port 8787mantle validate prints OK no issues (root: manifests, phase: preview). Wrangler prints Ready on http://127.0.0.1:8787. Use that origin in the next step. The Admin OTP path uses the same pin; PUBLIC_ORIGIN must match wrangler's printed origin there.
6. Probe the Worker
curl -s http://127.0.0.1:8787/api/views/published-notes{ "ok": true, "data": { "rows": [], "page": 1, "show": 20, "hasMore": false } }The View is served with no data because the local D1 is fresh. show follows the View's limit when the request carries no ?show=; ?page= and ?show= are the reserved pagination params (Reads: Views, REST and MCP).
curl -i http://127.0.0.1:8787/GET / returns 404. No visitor frontend is installed or rendered; mantle-web is optional composition and never owns an implicit home route. Add your own routes or templates when the product needs them (Public web, SEO and cache).
curl -i http://127.0.0.1:8787/mcp/staffGET /mcp/staff returns 503 with the error code setup_incomplete until MANTLE_AUTH_MODE is backed by a complete configuration. This is the expected fail-closed state; a working public endpoint is not evidence of a working Admin or MCP login.
What mantle generate wrote
.mantle/generated/mantle.ts— one module with the sealedplan, generated types (MantleHandlers<Env>),createMantleandbindMantle. The Worker entry above imports onlyplan.public/_mantle/admin/— the Admin SPA, synced only when@aotter/mantle-admin-uiis installed. This project did not install it, so nothing is written there and/adminhas no assets.
This walkthrough uses the existing direct-authored Worker entry; in that legacy compile mode, generate expects the supplied manifests and does not add a home route. New applications can instead use mantle generate --host cf with --features spec,api for a smaller assembled Worker. The CLI never invents a Schema. mantle generate --check reports stale output without writing. The reference keeps .mantle/, .agents/ and .claude/ out of git and regenerates them in check; see Project layout and CLI.
Next steps
- Quickstart: local Admin — opt-in Dev UI: ASSETS, prebuilt Admin, email OTP.
- Project layout and the CLI loop — the files you own, every CLI flag, the daily check loop.
- The four atoms — add a Procedure and a Trigger to accept writes.
- Authentication — complete Auth so Admin and
/mcp/staffopen. - Public web, SEO and cache — give the service a rendered public surface.
Source
docs/examples/host-minimal-worker/README.mddocs/examples/host-minimal-worker/package.jsondocs/examples/host-minimal-worker/tsconfig.jsondocs/examples/host-minimal-worker/manifests/site.yamldocs/examples/host-minimal-worker/src/index.tsdocs/examples/host-minimal-worker/wrangler.jsoncdocs/examples/host-minimal-worker/smoke.mjsdocs/direct-authoring.mdpackages/mantle-runtime/src/domain/service/Pagination.ts