@aotter/mantle 0.1.2-alpha.6 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +15 -10
  2. package/dist/cli/generate.d.ts +9 -0
  3. package/dist/cli/generate.d.ts.map +1 -1
  4. package/dist/cli/generate.js +40 -1
  5. package/dist/cli/generate.js.map +1 -1
  6. package/dist/cli/main.d.ts +1 -1
  7. package/dist/cli/main.d.ts.map +1 -1
  8. package/dist/cli/main.js +37 -9
  9. package/dist/cli/main.js.map +1 -1
  10. package/docs/adapter-guide.md +6 -1
  11. package/docs/adr/adr-lite-845-frontend-client.md +38 -0
  12. package/docs/agent-prompts.md +91 -0
  13. package/docs/api-mcp-authorization.md +1 -1
  14. package/docs/auth-hosting-model.md +1 -1
  15. package/docs/examples/README.md +22 -0
  16. package/docs/examples/builtin-commerce.md +269 -0
  17. package/docs/examples/builtin-intake.md +143 -0
  18. package/docs/examples/builtin-legal-documents.md +189 -0
  19. package/docs/examples/builtin-procurement.md +241 -0
  20. package/docs/examples/builtin-publication.md +241 -0
  21. package/docs/examples/builtin-reservation.md +149 -0
  22. package/docs/examples/cf-primitives-commerce-inventory.md +809 -0
  23. package/docs/examples/cf-primitives-guarded-api.md +429 -0
  24. package/docs/examples/cf-primitives-intake-hooks.md +319 -0
  25. package/docs/examples/host-chatgpt-sites/.openai/hosting.json +1 -0
  26. package/docs/examples/host-chatgpt-sites/README.md +53 -0
  27. package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +8 -0
  28. package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +294 -0
  29. package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +5 -0
  30. package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +1 -0
  31. package/docs/examples/host-chatgpt-sites/manifests/site.yaml +27 -0
  32. package/docs/examples/host-chatgpt-sites/package.json +1 -0
  33. package/docs/examples/host-chatgpt-sites/public/site.css +1 -0
  34. package/docs/examples/host-chatgpt-sites/scripts/build.mjs +12 -0
  35. package/docs/examples/host-chatgpt-sites/scripts/check.mjs +99 -0
  36. package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +9 -0
  37. package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +63 -0
  38. package/docs/examples/host-chatgpt-sites/src/index.ts +46 -0
  39. package/docs/examples/host-chatgpt-sites/src/mcp.ts +49 -0
  40. package/docs/examples/host-chatgpt-sites/src/media.ts +109 -0
  41. package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +38 -0
  42. package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +1 -0
  43. package/docs/examples/host-chatgpt-sites/src/web.ts +35 -0
  44. package/docs/examples/host-chatgpt-sites/tsconfig.json +1 -0
  45. package/docs/examples/host-chatgpt-sites/wrangler.jsonc +10 -0
  46. package/docs/examples/host-local-admin-otp/.dev.vars.example +3 -0
  47. package/docs/examples/host-local-admin-otp/README.md +70 -0
  48. package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +5 -0
  49. package/docs/examples/host-local-admin-otp/package.json +29 -0
  50. package/docs/examples/host-local-admin-otp/public/.gitkeep +1 -0
  51. package/docs/examples/host-local-admin-otp/smoke.mjs +141 -0
  52. package/docs/examples/host-local-admin-otp/src/index.ts +54 -0
  53. package/docs/examples/host-local-admin-otp/wrangler.jsonc +23 -0
  54. package/docs/examples/{minimal-worker → host-minimal-worker}/README.md +9 -5
  55. package/docs/examples/host-minimal-worker/manifests/site.yaml +25 -0
  56. package/docs/examples/{minimal-worker → host-minimal-worker}/package.json +3 -3
  57. package/docs/examples/host-minimal-worker/tsconfig.json +17 -0
  58. package/docs/handbook/cloudflare/authentication.md +17 -2
  59. package/docs/handbook/cloudflare/bindings.md +9 -7
  60. package/docs/handbook/cloudflare/chatgpt-sites.md +29 -0
  61. package/docs/handbook/cloudflare/conventional-worker.md +3 -3
  62. package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -1
  63. package/docs/handbook/cloudflare/deploy-and-operate.md +14 -20
  64. package/docs/handbook/cloudflare/media-r2.md +2 -2
  65. package/docs/handbook/cloudflare/public-web.md +1 -1
  66. package/docs/handbook/cloudflare/site-chrome.md +75 -0
  67. package/docs/handbook/concepts/authorization.md +2 -2
  68. package/docs/handbook/concepts/four-atoms.md +2 -2
  69. package/docs/handbook/concepts/lifecycle-and-locales.md +1 -1
  70. package/docs/handbook/concepts/mcp-and-agents.md +1 -1
  71. package/docs/handbook/concepts/procedures-and-triggers.md +1 -1
  72. package/docs/handbook/concepts/runtime-and-adapters.md +2 -2
  73. package/docs/handbook/concepts/views.md +2 -2
  74. package/docs/handbook/examples/commerce-transaction.md +4 -806
  75. package/docs/handbook/examples/commerce.md +11 -0
  76. package/docs/handbook/examples/guarded-api.md +3 -420
  77. package/docs/handbook/examples/hub.md +10 -0
  78. package/docs/handbook/examples/intake-form.md +6 -313
  79. package/docs/handbook/examples/intake-hooks.md +11 -0
  80. package/docs/handbook/examples/legal-documents.md +3 -211
  81. package/docs/handbook/examples/procurement-approvals.md +3 -233
  82. package/docs/handbook/examples/publication.md +3 -233
  83. package/docs/handbook/examples/reservation.md +3 -213
  84. package/docs/handbook/navigation.json +17 -2
  85. package/docs/handbook/reference/authorization.md +1 -1
  86. package/docs/handbook/reference/procedure.md +2 -2
  87. package/docs/handbook/reference/schema.md +3 -3
  88. package/docs/handbook/reference/site-config.md +5 -16
  89. package/docs/handbook/reference/surface.md +3 -7
  90. package/docs/handbook/sites/equipment-checkout.md +231 -0
  91. package/docs/handbook/sites/host-reference.md +113 -0
  92. package/docs/handbook/sites/index.md +111 -0
  93. package/docs/handbook/start/project-and-cli.md +22 -14
  94. package/docs/handbook/start/quickstart-admin.md +239 -0
  95. package/docs/handbook/start/quickstart-worker.md +22 -23
  96. package/docs/migration-0.1.2.md +26 -0
  97. package/docs/release-process.md +92 -7
  98. package/docs/sealed-pipeline-ownership.md +2 -2
  99. package/docs/spec-only-host-adoption.md +3 -4
  100. package/docs/transaction-patterns.md +2 -2
  101. package/package.json +15 -15
  102. package/skills/README.md +18 -2
  103. package/skills/develop/SKILL.md +32 -23
  104. package/skills/install/SKILL.md +50 -11
  105. package/skills/provision/SKILL.md +21 -5
  106. /package/docs/examples/{minimal-worker → host-local-admin-otp}/manifests/site.yaml +0 -0
  107. /package/docs/examples/{minimal-worker → host-local-admin-otp}/tsconfig.json +0 -0
  108. /package/docs/examples/{minimal-worker → host-minimal-worker}/smoke.mjs +0 -0
  109. /package/docs/examples/{minimal-worker → host-minimal-worker}/src/index.ts +0 -0
  110. /package/docs/examples/{minimal-worker → host-minimal-worker}/wrangler.jsonc +0 -0
@@ -0,0 +1,239 @@
1
+ ---
2
+ description: "Open local Admin in one shot: generate the prebuilt SPA, bind ASSETS, sign in with email OTP from wrangler logs, land in the Dev UI."
3
+ ---
4
+ # Quickstart: local Admin
5
+
6
+ This page reproduces Core's local Admin OTP reference as a from-scratch walkthrough. Admin is **opt-in**: use it when humans need a Dev UI. A complete Mantle service does not require this surface. Install every `@aotter/mantle*` package from the `latest` dist-tag; see [Versions](../reference/surface.md#versions).
7
+
8
+ The default embed path — Spec + Worker without Admin — is [Quickstart: a minimal Worker](./quickstart-worker.md).
9
+
10
+ ## Prerequisites
11
+
12
+ - Node.js 22 or newer.
13
+ - pnpm 9 or newer. The reference is tested with pnpm.
14
+ - `wrangler` is installed as a project devDependency below. No Cloudflare account, D1 database id or production secret is needed for the local loop.
15
+
16
+ An agent interviews the human for one value before writing files: the bootstrap owner email. The example uses `owner@example.com`.
17
+
18
+ ## 1. `package.json`
19
+
20
+ Install every `@aotter/mantle*` package from the `latest` dist-tag. Admin needs both `@aotter/mantle-admin` and `@aotter/mantle-admin-ui` plus the Cloudflare adapter peers.
21
+
22
+ ```json
23
+ {
24
+ "name": "mantle-local-admin-otp",
25
+ "private": true,
26
+ "type": "module",
27
+ "scripts": {
28
+ "generate": "mantle generate",
29
+ "validate": "mantle validate",
30
+ "typecheck": "tsc --noEmit",
31
+ "predev": "node ensure-dev-vars.mjs",
32
+ "dev": "wrangler dev --local --ip 127.0.0.1 --port 8787"
33
+ },
34
+ "dependencies": {
35
+ "@aotter/mantle": "latest",
36
+ "@aotter/mantle-admin": "latest",
37
+ "@aotter/mantle-admin-ui": "latest",
38
+ "@aotter/mantle-cloudflare": "latest",
39
+ "better-auth": "1.7.2",
40
+ "hono": "^4.13.3",
41
+ "zod": "^4.5.4",
42
+ "aws4fetch": "^1.0.20"
43
+ },
44
+ "devDependencies": {
45
+ "@cloudflare/workers-types": "^5.20260907.1",
46
+ "typescript": "^6.0.3",
47
+ "wrangler": "^4.125.0"
48
+ },
49
+ "packageManager": "pnpm@9.15.0"
50
+ }
51
+ ```
52
+
53
+ Add a `tsconfig.json` that includes the generated module:
54
+
55
+ ```json
56
+ {
57
+ "compilerOptions": {
58
+ "target": "ES2022",
59
+ "module": "ESNext",
60
+ "moduleResolution": "bundler",
61
+ "strict": true,
62
+ "noEmit": true,
63
+ "skipLibCheck": true,
64
+ "types": ["@cloudflare/workers-types"]
65
+ },
66
+ "include": ["src/**/*.ts", ".mantle/generated/**/*.ts"]
67
+ }
68
+ ```
69
+
70
+ `ensure-dev-vars.mjs` copies the example vars on first `pnpm dev`:
71
+
72
+ ```js
73
+ import { copyFileSync, existsSync } from "node:fs";
74
+ if (!existsSync(".dev.vars")) copyFileSync(".dev.vars.example", ".dev.vars");
75
+ ```
76
+
77
+ ## 2. `.dev.vars.example`
78
+
79
+ ```sh
80
+ PUBLIC_ORIGIN=http://127.0.0.1:8787
81
+ BETTER_AUTH_SECRET=local-admin-otp-dev-secret-do-not-use-in-prod
82
+ ADMIN_EMAIL=owner@example.com
83
+ ```
84
+
85
+ Copy it to `.dev.vars` (the `predev` script does this). Never commit `.dev.vars`. `pnpm dev` binds `127.0.0.1:8787` so wrangler's Ready-on origin matches this `PUBLIC_ORIGIN`. A mismatch makes Better Auth reject OTP with `INVALID_ORIGIN`.
86
+
87
+ ## 3. `manifests/site.yaml`
88
+
89
+ One publishing Schema and one public View. `mantle generate` never invents a Schema; this notes model is example business data. `cache` is valid in this snapshot's grammar.
90
+
91
+ ```yaml
92
+ apiVersion: cms.mantle.aotter.net/v1
93
+ kind: Schema
94
+ metadata:
95
+ name: notes
96
+ spec:
97
+ title: Notes
98
+ schema:
99
+ type: object
100
+ required: [title]
101
+ properties:
102
+ title: { type: string }
103
+ lifecycle: publishing
104
+ ---
105
+ apiVersion: cms.mantle.aotter.net/v1
106
+ kind: View
107
+ metadata:
108
+ name: published-notes
109
+ spec:
110
+ surface: public
111
+ from: notes
112
+ cache: { sharedMaxAge: 3600 }
113
+ fields: [id, title]
114
+ filter:
115
+ eq: { field: status, value: published }
116
+ limit: 20
117
+ ```
118
+
119
+ Use the docs that ship with the pinned version. A newer handbook page is not a contract for an older install.
120
+
121
+ ## 4. `src/index.ts`
122
+
123
+ Replace conventional GitHub Auth construction with local email OTP. Core still owns `/admin` and `/api/auth/*`.
124
+
125
+ ```ts
126
+ import {
127
+ ConsoleEmailSender,
128
+ createAuth,
129
+ createMantleWorker,
130
+ type MantleCloudflareEnv,
131
+ } from "@aotter/mantle/cloudflare";
132
+ import { plan } from "../.mantle/generated/mantle.js";
133
+
134
+ export interface Env extends MantleCloudflareEnv {
135
+ readonly ASSETS: Fetcher;
136
+ readonly BETTER_AUTH_SECRET: string;
137
+ readonly ADMIN_EMAIL: string;
138
+ }
139
+
140
+ const sender = new ConsoleEmailSender();
141
+
142
+ export default createMantleWorker<Env>({
143
+ plan,
144
+ cacheScope: "local-admin-otp",
145
+ siteDefaults: (env) => ({
146
+ brand: "Local Admin",
147
+ title: "Local Admin",
148
+ origin: env.PUBLIC_ORIGIN?.replace(/\/+$/, "") ?? "http://127.0.0.1:8787",
149
+ }),
150
+ auth: (env) => {
151
+ const origin = env.PUBLIC_ORIGIN?.replace(/\/+$/, "") ?? "http://127.0.0.1:8787";
152
+ return createAuth({
153
+ database: env.DB,
154
+ baseURL: origin,
155
+ secret: env.BETTER_AUTH_SECRET,
156
+ methods: [{ kind: "email-otp", sender }],
157
+ bootstrapOwner: { match: "email", value: env.ADMIN_EMAIL },
158
+ oauthProvider: {
159
+ loginPage: "/admin/sign-in",
160
+ consentPage: "/oauth/consent",
161
+ scopes: ["mcp"],
162
+ mcpResource: `${origin}/mcp`,
163
+ },
164
+ });
165
+ },
166
+ });
167
+ ```
168
+
169
+ `ConsoleEmailSender` writes the OTP to wrangler logs. It is the local human path. Do not wire it in production.
170
+
171
+ ## 5. `wrangler.jsonc`
172
+
173
+ Admin requires Static Assets. This is not optional.
174
+
175
+ ```jsonc
176
+ {
177
+ "$schema": "node_modules/wrangler/config-schema.json",
178
+ "name": "mantle-local-admin-otp",
179
+ "main": "src/index.ts",
180
+ "compatibility_date": "2026-09-08",
181
+ "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
182
+ "assets": { "directory": "./public", "binding": "ASSETS" },
183
+ "d1_databases": [
184
+ { "binding": "DB", "database_name": "mantle-local-admin-otp" }
185
+ ]
186
+ }
187
+ ```
188
+
189
+ Keep a `public/` directory (empty is fine). `generate` writes `public/_mantle/admin/` into it. Do not put `/_mantle` in `run_worker_first`: those files must be served by the assets layer. A Worker-first catch-all without asset fallthrough is the white-screen class of bug — `/admin` returns SPA HTML `200` while `/_mantle/admin/assets/*` is `404`.
190
+
191
+ ## 6. Install, generate, run
192
+
193
+ ```sh
194
+ pnpm install && pnpm generate && pnpm dev
195
+ ```
196
+
197
+ `mantle generate` writes `.mantle/generated/mantle.ts` and syncs the **prebuilt** Admin SPA from `@aotter/mantle-admin-ui` into `public/_mantle/admin/`. Do not run Vite or otherwise build a frontend unless you are developing `admin-ui` itself.
198
+
199
+ `pnpm dev` binds `127.0.0.1:8787`. Wrangler prints `Ready on http://127.0.0.1:8787`, the same origin as `PUBLIC_ORIGIN`. Open that Ready-on URL. Browsing `http://localhost:8787` still serves HTML, but the OTP Origin header mismatches `PUBLIC_ORIGIN` and Better Auth returns `INVALID_ORIGIN`.
200
+
201
+ ## 7. Sign in
202
+
203
+ ```sh
204
+ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8787/admin/sign-in
205
+ curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8787/_mantle/admin/index.html
206
+ ```
207
+
208
+ Both are `200`. Open `/admin/sign-in`, submit the bootstrap owner email, then read the wrangler log:
209
+
210
+ ```text
211
+ [ConsoleEmailSender] auth.email-otp.sign-in → owner@example.com (en)
212
+ subject: Your Mantle sign-in code: 123456
213
+ ```
214
+
215
+ Enter the code. The first matching sign-in is promoted to `owner` and the Admin shell loads.
216
+
217
+ If the page is blank, fetch an asset URL from the HTML. A `404` there means `ASSETS` is missing or `run_worker_first` swallowed `/_mantle`. That is not a missing `vite build`.
218
+
219
+ ## What `mantle generate` wrote
220
+
221
+ - `.mantle/generated/mantle.ts` — the sealed `plan`, generated types, `createMantle` and `bindMantle`.
222
+ - `public/_mantle/admin/` — the prebuilt Admin SPA. Required for `/admin`.
223
+
224
+ `generate` fails on missing or invalid manifests and never creates a project, a default Schema or a home route. The reference keeps `.mantle/`, `.agents/`, `.claude/` and `public/_mantle/` out of git and regenerates them in `check`; see [Project layout and the CLI loop](./project-and-cli.md).
225
+
226
+ ## Next steps
227
+
228
+ - [Project layout and the CLI loop](./project-and-cli.md) — the files you own, every CLI flag, the daily check loop, ASSETS as a hard Admin requirement.
229
+ - [Authentication](../cloudflare/authentication.md) — production senders, GitHub / hosted modes, roles.
230
+ - [The conventional Worker](../cloudflare/conventional-worker.md) — handlers and extra routes.
231
+ - [Quickstart: a minimal Worker](./quickstart-worker.md) — API-only embed without Admin.
232
+
233
+ ## Source
234
+ - [`docs/examples/host-local-admin-otp/README.md`](../../../docs/examples/host-local-admin-otp/README.md)
235
+ - [`docs/examples/host-local-admin-otp/package.json`](../../../docs/examples/host-local-admin-otp/package.json)
236
+ - [`docs/examples/host-local-admin-otp/src/index.ts`](../../../docs/examples/host-local-admin-otp/src/index.ts)
237
+ - [`docs/examples/host-local-admin-otp/wrangler.jsonc`](../../../docs/examples/host-local-admin-otp/wrangler.jsonc)
238
+ - [`docs/examples/host-local-admin-otp/.dev.vars.example`](../../../docs/examples/host-local-admin-otp/.dev.vars.example)
239
+ - [`docs/examples/host-local-admin-otp/smoke.mjs`](../../../docs/examples/host-local-admin-otp/smoke.mjs)
@@ -3,10 +3,7 @@ description: "Author a minimal Cloudflare Worker from scratch: one Schema, one p
3
3
  ---
4
4
  # Quickstart: a minimal Worker
5
5
 
6
- This page reproduces Core's minimal Worker reference as a from-scratch walkthrough. It is for engineers who want a running Mantle service on their machine in a few minutes, with no visitor frontend and no Cloudflare account.
7
-
8
- > **Version scope**
9
- > The install below uses the published `0.1.0-alpha.17` packages. That release supports this minimal Worker flow, but still includes `mantle create` and `mantle update` and does not contain this handbook. The rest of this handbook describes a later development snapshot; see [Versions](../reference/surface.md#versions) before applying its CLI and migration guidance to a registry installation.
6
+ This page reproduces Core's API-only Worker reference as a from-scratch walkthrough. It is the embed / adapter path: View REST without Admin, Auth or a visitor frontend. Admin is opt-in when humans need a console — [Quickstart: local Admin](./quickstart-admin.md). Install every `@aotter/mantle*` package from the `latest` dist-tag; see [Versions](../reference/surface.md#versions).
10
7
 
11
8
  ## Prerequisites
12
9
 
@@ -16,7 +13,7 @@ This page reproduces Core's minimal Worker reference as a from-scratch walkthrou
16
13
 
17
14
  ## 1. `package.json`
18
15
 
19
- Pin every `@aotter/mantle*` package to the same exact release and add the peers the Cloudflare adapter needs.
16
+ Install every `@aotter/mantle*` package from the `latest` dist-tag and add the peers the Cloudflare adapter needs.
20
17
 
21
18
  ```json
22
19
  {
@@ -27,12 +24,12 @@ Pin every `@aotter/mantle*` package to the same exact release and add the peers
27
24
  "generate": "mantle generate",
28
25
  "validate": "mantle validate",
29
26
  "typecheck": "tsc --noEmit",
30
- "dev": "wrangler dev --local",
27
+ "dev": "wrangler dev --local --ip 127.0.0.1 --port 8787",
31
28
  "check": "mantle generate && mantle generate --check && mantle validate && mantle skills && mantle skills --check && tsc --noEmit"
32
29
  },
33
30
  "dependencies": {
34
- "@aotter/mantle": "0.1.0-alpha.17",
35
- "@aotter/mantle-cloudflare": "0.1.0-alpha.17",
31
+ "@aotter/mantle": "latest",
32
+ "@aotter/mantle-cloudflare": "latest",
36
33
  "better-auth": "1.7.2",
37
34
  "hono": "^4.13.3",
38
35
  "zod": "^4.5.4",
@@ -91,6 +88,7 @@ metadata:
91
88
  spec:
92
89
  surface: public
93
90
  from: notes
91
+ cache: { sharedMaxAge: 3600 }
94
92
  fields: [id, title]
95
93
  filter:
96
94
  eq: { field: status, value: published }
@@ -135,15 +133,15 @@ Both compatibility flags are required by the adapter. `MANTLE_AUTH_MODE` must be
135
133
  pnpm install
136
134
  pnpm exec mantle generate
137
135
  pnpm exec mantle validate
138
- pnpm exec wrangler dev --local
136
+ pnpm exec wrangler dev --local --ip 127.0.0.1 --port 8787
139
137
  ```
140
138
 
141
- `mantle validate` prints `OK no issues (root: manifests, phase: preview)`. Wrangler prints the local origin, normally `http://localhost:8787`; use whatever it prints in the next step.
139
+ `mantle 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.
142
140
 
143
141
  ## 6. Probe the Worker
144
142
 
145
143
  ```sh
146
- curl -s http://localhost:8787/api/views/published-notes
144
+ curl -s http://127.0.0.1:8787/api/views/published-notes
147
145
  ```
148
146
 
149
147
  ```json
@@ -153,13 +151,13 @@ curl -s http://localhost:8787/api/views/published-notes
153
151
  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](../concepts/views.md)).
154
152
 
155
153
  ```sh
156
- curl -i http://localhost:8787/
154
+ curl -i http://127.0.0.1:8787/
157
155
  ```
158
156
 
159
157
  `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](../cloudflare/public-web.md)).
160
158
 
161
159
  ```sh
162
- curl -i http://localhost:8787/mcp/staff
160
+ curl -i http://127.0.0.1:8787/mcp/staff
163
161
  ```
164
162
 
165
163
  `GET /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.
@@ -171,23 +169,24 @@ curl -i http://localhost:8787/mcp/staff
171
169
 
172
170
  `generate` fails on missing or invalid manifests and never creates a project, a default Schema or a home route. `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 the CLI loop](./project-and-cli.md).
173
171
 
174
- > **npm and `ERESOLVE`**
175
- > With npm 11.16.0 a cold Cloudflare install can fail with `ERESOLVE`: Better Auth/Drizzle selects optional `@libsql/client@0.18.0` while this release declares the tested `^0.17.4` peer. If that exact conflict occurs, merge `{ "overrides": { "@libsql/client": "0.17.4" } }` into `package.json` and rerun `npm install`. Do not use `--force` or `--legacy-peer-deps`. Commit the lockfile and use `npm ci` afterwards. Recheck the peer range when upgrading; the workaround is specific to these versions.
172
+ > **npm and optional peers**
173
+ > A cold npm install can fail with `ERESOLVE` when an Auth peer selects a different optional `@libsql/client` than this snapshot declares. If that happens, pin `@libsql/client` in `overrides` to the range in this checkout's `package.json` and rerun `npm install`. Do not use `--force`. Commit the lockfile and use `npm ci` afterwards.
176
174
 
177
175
  ## Next steps
178
176
 
177
+ - [Quickstart: local Admin](./quickstart-admin.md) — opt-in Dev UI: ASSETS, prebuilt Admin, email OTP.
179
178
  - [Project layout and the CLI loop](./project-and-cli.md) — the files you own, every CLI flag, the daily check loop.
180
179
  - [The four atoms](../concepts/four-atoms.md) — add a Procedure and a Trigger to accept writes.
181
- - [Authentication](../cloudflare/authentication.md) — complete `MANTLE_AUTH_MODE` so Admin and `/mcp/staff` open.
180
+ - [Authentication](../cloudflare/authentication.md) — complete Auth so Admin and `/mcp/staff` open.
182
181
  - [Public web, SEO and cache](../cloudflare/public-web.md) — give the service a rendered public surface.
183
182
 
184
183
  ## Source
185
- - [`docs/examples/minimal-worker/README.md`](../../../docs/examples/minimal-worker/README.md)
186
- - [`docs/examples/minimal-worker/package.json`](../../../docs/examples/minimal-worker/package.json)
187
- - [`docs/examples/minimal-worker/tsconfig.json`](../../../docs/examples/minimal-worker/tsconfig.json)
188
- - [`docs/examples/minimal-worker/manifests/site.yaml`](../../../docs/examples/minimal-worker/manifests/site.yaml)
189
- - [`docs/examples/minimal-worker/src/index.ts`](../../../docs/examples/minimal-worker/src/index.ts)
190
- - [`docs/examples/minimal-worker/wrangler.jsonc`](../../../docs/examples/minimal-worker/wrangler.jsonc)
191
- - [`docs/examples/minimal-worker/smoke.mjs`](../../../docs/examples/minimal-worker/smoke.mjs)
184
+ - [`docs/examples/host-minimal-worker/README.md`](../../../docs/examples/host-minimal-worker/README.md)
185
+ - [`docs/examples/host-minimal-worker/package.json`](../../../docs/examples/host-minimal-worker/package.json)
186
+ - [`docs/examples/host-minimal-worker/tsconfig.json`](../../../docs/examples/host-minimal-worker/tsconfig.json)
187
+ - [`docs/examples/host-minimal-worker/manifests/site.yaml`](../../../docs/examples/host-minimal-worker/manifests/site.yaml)
188
+ - [`docs/examples/host-minimal-worker/src/index.ts`](../../../docs/examples/host-minimal-worker/src/index.ts)
189
+ - [`docs/examples/host-minimal-worker/wrangler.jsonc`](../../../docs/examples/host-minimal-worker/wrangler.jsonc)
190
+ - [`docs/examples/host-minimal-worker/smoke.mjs`](../../../docs/examples/host-minimal-worker/smoke.mjs)
192
191
  - [`docs/direct-authoring.md`](../../../docs/direct-authoring.md)
193
192
  - [`packages/mantle-runtime/src/domain/service/Pagination.ts`](../../../packages/mantle-runtime/src/domain/service/Pagination.ts)
@@ -54,6 +54,32 @@ A new project follows [direct authoring](direct-authoring.md). Templates and
54
54
  provider setup are not hidden inside `generate`. Future Builder/landing-next
55
55
  provisioning is a separate decision; this change does not migrate those hosts.
56
56
 
57
+ ## Site chrome: GA4 and Meta Pixel leave siteConfig
58
+
59
+ `SiteConfig.ga4MeasurementId`, `SiteConfig.facebookPixelId`, and their
60
+ `SiteDefaults` seed equivalents are removed. The Admin UI no longer has
61
+ Analytics fields for them, the Runtime site-settings use case no longer
62
+ accepts them, and the Web HTML renderer no longer injects the gtag or Pixel
63
+ base snippet into rendered storefront HTML. This applies to every 0.1.2
64
+ prerelease; it is not staged behind a flag.
65
+
66
+ Core's `siteConfig` remains deployment identity only (locales, brand, title,
67
+ description, origin, icons, media); tracking and verification tags are host
68
+ chrome because frontends are plural and Core cannot assume one `</head>` to
69
+ rewrite. See [Why Core does not inject](handbook/cloudflare/site-chrome.md#why-core-does-not-inject).
70
+
71
+ To keep GA4 or Meta Pixel across the upgrade:
72
+
73
+ 1. Read the existing `ga4MeasurementId` / `facebookPixelId` values from the
74
+ pre-upgrade site settings (Admin API or KV/D1 `SiteConfigRepository`
75
+ directly) before removing the old columns/fields.
76
+ 2. Move the tag injection into host chrome following
77
+ [Cloudflare-first install > Analytics](handbook/cloudflare/site-chrome.md#analytics):
78
+ render the snippet in the host's own document/layout, not through Core.
79
+ 3. Drop the old fields from any locally stored site-settings payloads; the
80
+ Runtime `SiteConfig` type no longer declares them, so a TypeScript build
81
+ against the new types is what surfaces a leftover reference.
82
+
57
83
  ## Earlier alpha.7 compatibility changes
58
84
 
59
85
 
@@ -20,7 +20,7 @@ No task implicitly authorizes publication; no manual package/tag writer exists.
20
20
  | Channels promoted/preserved newer | GitHub release step | Existing release identity or fail |
21
21
 
22
22
  The public-registry gate uses a disposable copy of the directly authored
23
- `docs/examples/minimal-worker` reference, installs the exact candidate, then
23
+ `docs/examples/host-minimal-worker` reference, installs the exact candidate, then
24
24
  checks generation, skill projection, TypeScript and real Worker HTTP behavior.
25
25
  The same reference is gated against exact tarballs before Core tagging. It is
26
26
  a test/example, not a scaffold product or another repository release.
@@ -45,11 +45,25 @@ is introduced. The runnable release-order check guards these transitions.
45
45
 
46
46
  ## Branches and channels
47
47
 
48
- - Alpha releases use the reviewed develop merge. Beta/RC/stable use main after
49
- explicit promotion; first stable acceptance is tracked by #826.
50
- - Alpha/beta/RC GitHub releases are prereleases; their npm tags match suffixes.
48
+ | Version | Source branch | npm dist-tag | GitHub release |
49
+ |---|---|---|---|
50
+ | `X.Y.Z-alpha.N` | `develop` | `alpha` | prerelease |
51
+ | `X.Y.Z-beta.N` | `main` | `beta` | prerelease |
52
+ | `X.Y.Z-rc.N` | `main` | `rc` | prerelease |
53
+ | `X.Y.Z` | `main` | `latest` | release |
54
+
55
+ - The controller derives the source branch from the version: `-alpha` means
56
+ `develop`, anything else means `main`. It refuses a commit that is not that
57
+ branch's tip or not the merge commit of exactly one PR into that branch.
58
+ `scripts/release-tag-order.mjs` rejects any other prerelease identifier.
59
+ - `develop` stays the default integration branch. `main` changes only through
60
+ promotion PRs and hotfix PRs (below); it is never pushed directly, rebased
61
+ or force-updated. Both branches share one ruleset: PR, one approval,
62
+ resolved threads and a current-base `Typecheck + tests` check.
51
63
  - Stable publishes latest. Final 0.1.0 alphas only advance alpha, preserving
52
- existing legacy latest. Historic 0.0 alpha behavior remains recoverable.
64
+ existing legacy latest. No prerelease moves latest; the 0.0 alpha rule that
65
+ also advanced it was removed once 0.0 became unreachable.
66
+ A prerelease channel keeps its last version when a later stable publishes.
53
67
 
54
68
  ## Prepare and run
55
69
 
@@ -57,13 +71,27 @@ is introduced. The runnable release-order check guards these transitions.
57
71
  notes since the previous tag; correct PR metadata and label release-only
58
72
  PRs skip-release-notes. Do not duplicate release entries in CHANGELOG.md.
59
73
  2. Align every workspace package, plugin and marketplace ref to the version.
74
+ The controller checks package.json files and plugin manifests only; docs
75
+ pins and the admin-ui registry dependency are hand-edited, so grep for the
76
+ old version until only lockfiles and registry-pinned examples remain:
77
+
78
+ ```sh
79
+ OLD=<previous version> NEW=<version>
80
+ git grep -l "\"version\": \"$OLD\"" -- '*.json' ':!**/package-lock.json' \
81
+ | xargs perl -pi -e "s/\"version\": \"\Q$OLD\E\"/\"version\": \"$NEW\"/"
82
+ node scripts/sync-plugin-manifests.mjs
83
+ git grep -n "$OLD" -- ':!pnpm-lock.yaml' ':!**/package-lock.json'
84
+ ```
85
+
60
86
  3. Review API compatibility and migration instructions for actual consumers.
61
87
  Frozen legacy consumers stay on alpha.17; do not make them follow new Core.
62
88
  4. Run `pnpm check`, including exact packed Worker, optional products, Bun,
63
89
  Vercel, skills, release invariants, types and tests. Inspect the umbrella
64
90
  docs/skills payload: no workspace dependencies, secrets or local state.
65
- 5. Freeze the PR head for self review; CI must pass before merge. Dispatch
66
- release.yml from that merge with `version` (without v). It refuses an
91
+ 5. Freeze the PR head for self review; CI must pass before merge. Merge into
92
+ `develop` with a merge commit for every version. For an alpha, dispatch
93
+ release.yml from that merge with `version` (without v). For beta, RC and
94
+ stable, continue with the promotion below. The controller refuses an
67
95
  untagged source that is no longer the expected branch tip.
68
96
 
69
97
  The ten public packages remain in dependency order:
@@ -79,6 +107,63 @@ The ten public packages remain in dependency order:
79
107
  9. @aotter/mantle-cloudflare
80
108
  10. @aotter/mantle
81
109
 
110
+ ## Promote to main (beta, RC, stable)
111
+
112
+ Every non-alpha release is the version PR above, one promotion PR and one
113
+ dispatch. The version PR still merges into `develop`, so `develop` always
114
+ contains what `main` publishes and promotions never conflict.
115
+
116
+ 1. Stable only: the release-gate issue (#826 for 0.1.2) records owner
117
+ acceptance. Every gate item passes with linked evidence or is explicitly
118
+ deferred there, and no `release-gate` issue stays open against the version.
119
+ Beta and RC need the gate defined, not passed.
120
+ 2. Merge the version PR into `develop` with a merge commit; note its SHA.
121
+ 3. Pin the promotion head at that SHA so later `develop` merges cannot ride
122
+ along, then open the promotion PR against `main`:
123
+
124
+ ```sh
125
+ git fetch origin
126
+ git push origin <develop merge SHA>:refs/heads/promote/<version>
127
+ gh pr create --base main --head promote/<version> \
128
+ --title "release: promote <version> to main" --label skip-release-notes
129
+ ```
130
+
131
+ The body names the version PR, the pinned SHA and the gate evidence. The
132
+ usual review and checks apply. An organization-admin bypass merge must be
133
+ recorded on the PR (see CONTRIBUTING).
134
+ 4. Merge with a merge commit, never rebase: the controller needs `main`'s tip
135
+ to be the PR's merge commit. `main`'s tree now equals the pinned commit.
136
+ 5. Dispatch from `main` and watch every gate exactly as for an alpha:
137
+
138
+ ```sh
139
+ gh workflow run release.yml --ref main -f version=<version>
140
+ ```
141
+
142
+ 6. RC to stable repeats 2–5 with the next version. `rc` keeps pointing at
143
+ the last RC; stable moves only `latest`.
144
+
145
+ Hotfix on `main` is for a published non-alpha version that cannot wait for
146
+ the next promotion. Branch from `main`, include the version bump, PR into
147
+ `main`, dispatch as in step 5, then immediately PR `main` back into `develop`
148
+ and resolve version files in favour of `develop`. Until that lands, the next
149
+ promotion conflicts on the version files.
150
+
151
+ First stable (0.1.2) specifics: `latest` moves from 0.1.0-alpha.16, the last
152
+ `latest` the frozen legacy consumers saw, to 0.1.2. GitHub generates notes
153
+ from the previous release (v0.1.2-alpha.6); to cover the whole 0.1.2 line,
154
+ regenerate from v0.1.0-alpha.17 and edit the release body after the run. The
155
+ body is not an immutable artifact; the tag and packages are.
156
+
157
+ ```sh
158
+ gh api repos/aotter/mantle/releases/generate-notes \
159
+ -f tag_name=v0.1.2 -f previous_tag_name=v0.1.0-alpha.17 --jq .body > notes.md
160
+ gh release edit v0.1.2 --notes-file notes.md
161
+ ```
162
+
163
+ After publication, move docs/examples that were pinned to a packed checkout
164
+ back to registry installation with an updated lockfile, and close the gate
165
+ issue with the run link and completion evidence.
166
+
82
167
  ## Credentials and verification
83
168
 
84
169
  Core needs NPM_TOKEN for npmjs. Its job-scoped GITHUB_TOKEN creates the Core
@@ -61,7 +61,7 @@ diagnostics.
61
61
 
62
62
  The following pins record the historical sealed-pipeline migration gates.
63
63
  ADR-0021 supersedes the Starter/Landing release coupling: current Core CI and
64
- release use `docs/examples/minimal-worker` from the same reviewed commit.
64
+ release use `docs/examples/host-minimal-worker` from the same reviewed commit.
65
65
  Private consumers can still run the exact-tarball checker in their own repos;
66
66
  public Core PRs receive no cross-repository credentials:
67
67
 
@@ -97,5 +97,5 @@ consumers; they do not duplicate the suite under new names.
97
97
 
98
98
  Issue #674 leaves `CONTRIBUTING.md` plus accepted ADRs as the contributor
99
99
  authority. `AGENTS.md`, `CLAUDE.md`, and the Claude release-skill entry are
100
- small routers; `.agent/skills/mantle-release/SKILL.md` is the only maintainer
100
+ small routers; `.agents/skills/mantle-release/SKILL.md` is the only maintainer
101
101
  release procedure. Shipped `skills/*` remain separate consumer artifacts.
@@ -6,9 +6,8 @@ Runtime. This Spec-only path is allowed by
6
6
  [ADR-0019](adr/0019-sealed-manifest-runtime-pipeline.md), not a new adapter,
7
7
  manifest grammar, or fork of Core.
8
8
 
9
- This recipe targets `0.1.0-alpha.16`. Its public APIs and peer requirements are
10
- prerelease contracts: pin the package, record the tested version, and rerun
11
- compatibility checks when upgrading.
9
+ This recipe targets `0.1.2`. Pin the package, record the tested version, and
10
+ rerun compatibility checks when upgrading.
12
11
 
13
12
  ## What stays with the host
14
13
 
@@ -51,7 +50,7 @@ validation semantics. Do not hand-maintain a second field list for the graph.
51
50
  Install the exact Spec package and its supported peer, without Runtime:
52
51
 
53
52
  ```sh
54
- npm install --save-exact @aotter/mantle-spec@0.1.0-alpha.16 zod@4.5.4
53
+ npm install --save-exact @aotter/mantle-spec zod@4.5.4
55
54
  ```
56
55
 
57
56
  The [synthetic fixture](../packages/mantle-spec/test/fixtures/spec-only-host.yaml)
@@ -1,5 +1,5 @@
1
1
  # Transaction patterns
2
2
 
3
- This guide moved into the handbook: [`docs/handbook/examples/commerce-transaction.md`](handbook/examples/commerce-transaction.md).
3
+ This guide lives in the Examples hub: [`docs/examples/cf-primitives-commerce-inventory.md`](examples/cf-primitives-commerce-inventory.md). The Builder-safe catalog is [`docs/examples/builtin-commerce.md`](examples/builtin-commerce.md).
4
4
 
5
- The handbook ships inside the `@aotter/mantle` package under `node_modules/@aotter/mantle/docs/handbook/` and describes the installed release.
5
+ The handbook and examples hub ship inside the `@aotter/mantle` package under `node_modules/@aotter/mantle/docs/` and describe the installed release.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aotter/mantle",
3
- "version": "0.1.2-alpha.6",
3
+ "version": "0.1.2",
4
4
  "description": "Embeddable Mantle Core umbrella with Spec and Runtime; Web, Admin, Bun, Vercel, Cloudflare, and Admin UI are optional peer packages.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://mantle.tools/",
@@ -79,8 +79,8 @@
79
79
  "README.md"
80
80
  ],
81
81
  "dependencies": {
82
- "@aotter/mantle-runtime": "0.1.2-alpha.6",
83
- "@aotter/mantle-spec": "0.1.2-alpha.6"
82
+ "@aotter/mantle-runtime": "0.1.2",
83
+ "@aotter/mantle-spec": "0.1.2"
84
84
  },
85
85
  "peerDependencies": {
86
86
  "aws4fetch": "^1.0.20",
@@ -88,12 +88,12 @@
88
88
  "hono": "^4.12.0",
89
89
  "@libsql/client": "^0.17.4",
90
90
  "zod": "^4.5.0",
91
- "@aotter/mantle-admin": "0.1.2-alpha.6",
92
- "@aotter/mantle-bun": "0.1.2-alpha.6",
93
- "@aotter/mantle-admin-ui": "0.1.2-alpha.6",
94
- "@aotter/mantle-vercel": "0.1.2-alpha.6",
95
- "@aotter/mantle-cloudflare": "0.1.2-alpha.6",
96
- "@aotter/mantle-web": "0.1.2-alpha.6"
91
+ "@aotter/mantle-admin-ui": "0.1.2",
92
+ "@aotter/mantle-admin": "0.1.2",
93
+ "@aotter/mantle-bun": "0.1.2",
94
+ "@aotter/mantle-cloudflare": "0.1.2",
95
+ "@aotter/mantle-vercel": "0.1.2",
96
+ "@aotter/mantle-web": "0.1.2"
97
97
  },
98
98
  "peerDependenciesMeta": {
99
99
  "@aotter/mantle-admin": {
@@ -136,12 +136,12 @@
136
136
  "typescript": "^6.0.3",
137
137
  "vitest": "^4.1.11",
138
138
  "zod": "^4.5.4",
139
- "@aotter/mantle-admin": "0.1.2-alpha.6",
140
- "@aotter/mantle-admin-ui": "0.1.2-alpha.6",
141
- "@aotter/mantle-bun": "0.1.2-alpha.6",
142
- "@aotter/mantle-cloudflare": "0.1.2-alpha.6",
143
- "@aotter/mantle-vercel": "0.1.2-alpha.6",
144
- "@aotter/mantle-web": "0.1.2-alpha.6"
139
+ "@aotter/mantle-admin": "0.1.2",
140
+ "@aotter/mantle-cloudflare": "0.1.2",
141
+ "@aotter/mantle-admin-ui": "0.1.2",
142
+ "@aotter/mantle-bun": "0.1.2",
143
+ "@aotter/mantle-vercel": "0.1.2",
144
+ "@aotter/mantle-web": "0.1.2"
145
145
  },
146
146
  "engines": {
147
147
  "node": ">=22"
package/skills/README.md CHANGED
@@ -58,8 +58,24 @@ contracts.
58
58
 
59
59
  ## Source-repository marketplace install
60
60
 
61
- The source repository is also an agent plugin bundle. These manifests are not
62
- duplicated into the npm package:
61
+ The source repository is also an agent plugin bundle:
62
+
63
+ ```bash
64
+ # Claude Code — two separate prompts
65
+ /plugin marketplace add aotter/mantle
66
+ /plugin install mantle@mantle
67
+
68
+ # Codex
69
+ codex plugin marketplace add aotter/mantle
70
+ codex plugin add mantle@mantle
71
+ ```
72
+
73
+ These are authoring workflows and do not track a release. Version matching is
74
+ the job of `mantle skills`, which projects the installed package's own skills
75
+ into the project, and `mantle skills --check`, which fails on drift.
76
+
77
+ Cursor and GitHub Copilot read their manifests from the repository directly.
78
+ These manifests are not duplicated into the npm package:
63
79
 
64
80
  - Claude Code: `.claude-plugin/plugin.json` plus `.claude-plugin/marketplace.json`.
65
81
  - Codex: `.codex-plugin/plugin.json` plus `.agents/plugins/marketplace.json`.