@aotter/mantle 0.1.2 → 0.1.3-alpha.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 (43) hide show
  1. package/README.md +36 -13
  2. package/dist/auth.d.ts +2 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +2 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/cli/generate.d.ts.map +1 -1
  7. package/dist/cli/generate.js +3 -0
  8. package/dist/cli/generate.js.map +1 -1
  9. package/dist/cli/main.d.ts +1 -1
  10. package/dist/cli/main.d.ts.map +1 -1
  11. package/dist/cli/main.js +5 -0
  12. package/dist/cli/main.js.map +1 -1
  13. package/dist/cli/skills.d.ts.map +1 -1
  14. package/dist/cli/skills.js +3 -0
  15. package/dist/cli/skills.js.map +1 -1
  16. package/dist/codegen/emitMantleModule.d.ts.map +1 -1
  17. package/dist/codegen/emitMantleModule.js +38 -2
  18. package/dist/codegen/emitMantleModule.js.map +1 -1
  19. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +109 -2
  20. package/docs/agent-prompts.md +38 -29
  21. package/docs/auth-hosting-model.md +1 -1
  22. package/docs/examples/host-local-admin-otp/README.md +10 -0
  23. package/docs/handbook/cloudflare/authentication.md +44 -3
  24. package/docs/handbook/concepts/mcp-and-agents.md +10 -5
  25. package/docs/handbook/navigation.json +8 -2
  26. package/docs/handbook/reference/diagnostics.md +5 -1
  27. package/docs/handbook/reference/manifest.md +1 -1
  28. package/docs/handbook/reference/procedure.md +1 -0
  29. package/docs/handbook/reference/surface.md +6 -4
  30. package/docs/handbook/reference/trigger.md +1 -1
  31. package/docs/handbook/releases/index.md +75 -0
  32. package/docs/handbook/start/project-and-cli.md +15 -4
  33. package/docs/handbook/start/quickstart-admin.md +20 -209
  34. package/docs/labels.md +3 -3
  35. package/docs/migration-0.1.2.md +10 -126
  36. package/docs/release-process.md +80 -39
  37. package/docs/spec-only-host-adoption.md +1 -1
  38. package/package.json +25 -16
  39. package/skills/README.md +21 -15
  40. package/skills/install/SKILL.md +5 -5
  41. package/skills/plugin/SKILL.md +6 -6
  42. package/skills/provision/SKILL.md +27 -17
  43. package/skills/update/SKILL.md +4 -3
@@ -1,227 +1,38 @@
1
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."
2
+ description: "Open local Admin in one shot: follow the official OTP example, bind ASSETS, sign in with email OTP from wrangler logs, land in the Dev UI."
3
3
  ---
4
4
  # Quickstart: local Admin
5
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).
6
+ Admin is **opt-in**: use it when humans need a Dev UI. A complete Mantle
7
+ service does not require this surface. The default embed path — Spec + Worker
8
+ without Admin — is [Quickstart: a minimal Worker](./quickstart-worker.md).
7
9
 
8
- The default embed path — Spec + Worker without Admin — is [Quickstart: a minimal Worker](./quickstart-worker.md).
10
+ The procedural source of truth is the official example:
9
11
 
10
- ## Prerequisites
12
+ **[`docs/examples/host-local-admin-otp/README.md`](../../examples/host-local-admin-otp/README.md)**
11
13
 
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
14
+ Copy that directory outside the SDK checkout (or author the same files from
15
+ it). Interview the human for one value before writing files: the bootstrap
16
+ owner email. The example uses `owner@example.com`. Then:
192
17
 
193
18
  ```sh
194
19
  pnpm install && pnpm generate && pnpm dev
195
20
  ```
196
21
 
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`.
22
+ Open the wrangler Ready-on URL (`http://127.0.0.1:8787/admin/sign-in`), submit
23
+ the owner email, and read the OTP from wrangler logs. `mantle generate` syncs
24
+ the prebuilt Admin SPA; do not Vite-build Admin.
218
25
 
219
- ## What `mantle generate` wrote
26
+ Traps (documented on the example):
220
27
 
221
- - `.mantle/generated/mantle.ts` — the sealed `plan`, generated types, `createMantle` and `bindMantle`.
222
- - `public/_mantle/admin/` — the prebuilt Admin SPA. Required for `/admin`.
28
+ - Prefer `127.0.0.1` over `localhost` (`INVALID_ORIGIN`).
29
+ - `pnpm check` / smoke rewrites `.dev.vars` to a smoke-only port — restore it
30
+ from `.dev.vars.example` before `pnpm dev`.
223
31
 
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).
32
+ Install every `@aotter/mantle*` package from the `latest` dist-tag; see
33
+ [Versions](../reference/surface.md#versions). Admin needs both
34
+ `@aotter/mantle-admin` and `@aotter/mantle-admin-ui`, wrangler `ASSETS` on
35
+ `./public`, and `createAuth` email-otp + `ConsoleEmailSender`.
225
36
 
226
37
  ## Next steps
227
38
 
package/docs/labels.md CHANGED
@@ -29,12 +29,12 @@ For package README or package-local docs changes, prefer the package area label
29
29
  | `area:runtime` | `packages/mantle-runtime` behavior, ports, use cases, dispatcher, and MCP runtime. |
30
30
  | `area:spec` | `packages/mantle-spec`, manifest parsing, validation, diagnostics, CLI, spec types. |
31
31
  | `area:cf` | `packages/adapters/cloudflare`, Workers adapter, D1/KV/ASSETS wiring, Cloudflare deploy behavior. |
32
- | `area:starters` | Legacy `aotter/mantle-starters` source and retirement migration. |
33
32
  | `area:skills` | `skills/*` agent briefs and install/extend/provision workflows. |
34
33
  | `area:admin-ui` | `packages/mantle-admin-ui` React admin SPA. |
35
34
  | `area:docs` | Repo-wide human docs, governance docs, ADR text, release docs, root README content, and cross-cutting documentation work. |
36
35
  | `area:adapter` | Adapter boundary work spanning Cloudflare or future adapters. |
37
36
  | `area:ci` | GitHub Actions, dependency automation, and repository checks. |
37
+ | `area:starters` | **Legacy only.** Retired `aotter/mantle-starters` source and migration notes. Do not use for new Core work. |
38
38
 
39
39
  ## Release and review gates
40
40
 
@@ -45,7 +45,7 @@ For package README or package-local docs changes, prefer the package area label
45
45
  | `breaking-change` | Semver-relevant breaking change. | Generated release notes must call it out. | The change is redesigned to be non-breaking. |
46
46
  | `skip-release-notes` | Release bookkeeping with no user-facing change. | Excluded from generated GitHub Release notes. | The PR contains a user-facing change. |
47
47
  | `needs-adr` | Architecture, trust boundary, package boundary, or long-lived decision needs an ADR or ADR-lite proposal. | Do not merge implementation until the decision is captured. | ADR/proposal lands or maintainer confirms an existing ADR covers it. |
48
- | `needs-grammar-revise` | Manifest grammar or closed-enum change. | Requires grammar-revise round before code/types/starters change. | Grammar decision lands or the change no longer affects grammar. |
48
+ | `needs-grammar-revise` | Manifest grammar or closed-enum change. | Requires grammar-revise round before code/types change. | Grammar decision lands or the change no longer affects grammar. |
49
49
  | `needs-discussion` | Not converged enough for implementation. | Do not start coding from this issue. | Closing criteria are met and scope is concrete. |
50
50
 
51
51
  ## Creating missing labels
@@ -56,12 +56,12 @@ Use these commands from a checked-out repo:
56
56
  gh label create "area:runtime" --description "Runtime package, ports, use cases, dispatcher, render, MCP runtime" --color "1d76db"
57
57
  gh label create "area:spec" --description "Spec package, manifest parsing, validation, diagnostics, CLI, types" --color "1d76db"
58
58
  gh label create "area:cf" --description "Cloudflare Workers adapter and bindings" --color "1d76db"
59
- gh label create "area:starters" --description "Starter templates and starter validation" --color "1d76db"
60
59
  gh label create "area:skills" --description "Agent Skills and install/extend/provision workflows" --color "1d76db"
61
60
  gh label create "area:admin-ui" --description "React admin UI" --color "1d76db"
62
61
  gh label create "area:docs" --description "Documentation and governance" --color "1d76db"
63
62
  gh label create "area:adapter" --description "Adapter boundary and future adapter work" --color "1d76db"
64
63
  gh label create "area:ci" --description "CI, dependency automation, and repository checks" --color "1d76db"
64
+ gh label create "area:starters" --description "Legacy only: retired mantle-starters source and migration" --color "cfd3d7"
65
65
  gh label create "breaking-change" --description "Semver-relevant breaking change" --color "b60205"
66
66
  gh label create "skip-release-notes" --description "Release bookkeeping only; omit from generated GitHub notes" --color "ededed"
67
67
  gh label create "needs-adr" --description "Requires an ADR or ADR-lite decision before merge" --color "d93f0b"
@@ -1,129 +1,13 @@
1
- # Leaving the legacy alpha.17 launch line
1
+ # Upgrading to 0.1.2
2
2
 
3
- 0.1.0-alpha.17 remains immutable and is the final version for existing Landing
4
- and Starters. Those repositories/tags/bundle URLs remain available. Staying on
5
- that version requires no migration. No stable 0.1.0 release is planned.
3
+ 0.1.2 is the first stable release and the first public one. There is no earlier
4
+ stable to upgrade from and no migration to perform.
6
5
 
7
- The new line removes `mantle create`, the Starter bundle `mantle update`
8
- command, and `@aotter/mantle/provision`. There are no aliases or replacement
9
- scaffold commands. `generate`, `validate`, `emit-openapi` and `skills` remain.
10
- Generation and runtime Web rendering retain their existing responsibilities.
6
+ What it contains, what it requires and what it does not yet cover is in
7
+ [Releases](handbook/releases/index.md).
11
8
 
12
- To upgrade an existing application:
13
-
14
- 1. Read its installed version, lockfile, entry, scripts and provider bindings;
15
- keep unrelated work safe in the normal git workflow.
16
- 2. Pin the selected SDK packages to the intended exact new release and update
17
- the lockfile through the package manager. Review required peer upgrades.
18
- 3. Remove scripts invoking the retired scaffolder/bundle updater. If application
19
- code imports the provision renderer, remain on alpha.17 until that host's
20
- provisioning design is migrated explicitly; do not replace it with a
21
- handwritten remote-code loader.
22
- 4. Retain application source and all Worker/D1/KV identity, origins, auth mode,
23
- secrets and legacy `.mantle` metadata. Those files are not templates to
24
- replace or evidence that new Starter tags must exist.
25
- 5. Run the installed `mantle generate`, `generate --check`, `skills`,
26
- `skills --check`, `validate`, and the project's TypeScript/tests. Test local
27
- routes and configured authorization before considering deployment.
28
-
29
- ## Native Schema-table storage reset
30
-
31
- The 0.1.2 pre-beta line replaces the generic `entries` JSON table with one
32
- native SQLite/D1 table per Manifest Schema. Mantle's row envelope uses
33
- `_mantle_id`, `_mantle_status`, `_mantle_version`, `_mantle_author_id`,
34
- `_mantle_created_at`, and `_mantle_updated_at`; authored fields keep their exact
35
- names as native columns. The old generated columns, projection views and
36
- compatibility repository were removed.
37
-
38
- This is intentionally a storage-format break before beta. Reset and
39
- re-bootstrap development or internal-alpha content databases that contain the
40
- old `entries` layout. Move required data manually outside Mantle and Control;
41
- there is no product migration workflow for this unreleased format. Automatic
42
- artifacts cover initial and additive changes only. Removed columns and tables
43
- remain physically present so the previous Worker can still run. Renames, type
44
- changes, data transforms, and any `uniqueIndexes` tuple change require the same
45
- manual rebuild. The pre-beta Cloud
46
- path does not accept or execute destructive SQL.
47
-
48
- Row APIs are now Schema-qualified. `EntryRepository.get` and
49
- `EntryReader.readById` accept `{ collection, id }`; Admin entry detail and
50
- mutation routes require `?collection=<schema>`, and generic MCP entry tools
51
- require `collection`. Generated `entries.<schema>` bindings supply it for you.
52
-
53
- A new project follows [direct authoring](direct-authoring.md). Templates and
54
- provider setup are not hidden inside `generate`. Future Builder/landing-next
55
- provisioning is a separate decision; this change does not migrate those hosts.
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
-
83
- ## Earlier alpha.7 compatibility changes
84
-
85
-
86
- 0.1.2 removes the temporary full-site compatibility stack. Mantle Core is now
87
- an embeddable parse → link → compile → prepare → bind pipeline; Web, Admin,
88
- Admin UI, Bun, Vercel, and Cloudflare are selected separately.
89
-
90
- | alpha.7 | 0.1.2 |
91
- |---|---|
92
- | `parseManifests*` | `parseManifestSources({ sources })` |
93
- | raw `Manifest[]` validation/runtime input | `ParsedManifestSet` → `LinkedManifestSet` → `RuntimePlan` |
94
- | `createCmsRuntime({ manifests, db })` | `bootMantleRuntime({ plan, storage })`, or explicit prepare then `createMantleRuntime({ prepared })` |
95
- | `CmsRuntime.db` / `entryReader` | keep the application DB handle; use `runtime.entries` for Mantle reads |
96
- | generated `manifest`, `site.ts`, `types.d.ts` | generated `plan`, `createMantle`, `bindMantle`, and types in `mantle.ts` |
97
- | `mantle introspect` | install `@aotter/mantle-spec` directly and run `mantle-spec introspect` |
98
- | `mantle emit-types` | use `mantle generate`; for raw declarations, run `mantle-spec emit-types` |
99
- | generated `.agent/skills/` | generated `.agents/skills/`; legacy user files are left untouched |
100
- | `bindMantleSite` / string-keyed Views | `bindMantle(runtime)` and generated lower-camel properties |
101
- | `createCmsRef` / `CmsConfig` | `createMantleRuntimeRef` / `MantleCloudflareConfig` |
102
- | `mountServerEndpoints` | explicitly compose `mountRuntimeEndpoints` and optional `mountAdmin` |
103
-
104
- Delete stale generated `site.ts` and `types.d.ts` files once, then run
105
- `mantle generate`. Install only the optional package used by the host;
106
- installing the umbrella alone now pulls only Spec and Runtime.
107
-
108
- Intentional behavior changes:
109
-
110
- - Generated-plan fingerprint or version mismatches fail immediately and ask
111
- the developer to regenerate.
112
- - Runtime HTTP trigger JSON bodies must be objects. Arrays and primitives are
113
- rejected at the request boundary.
114
- - Malformed percent-encoded paths are routing misses (`404`), not claimed
115
- Mantle routes.
116
- - Better Auth and every `@better-auth/*` package move together to 1.7.
117
- `oauthProvider.validAudiences` becomes protected `resources`; MCP uses one
118
- canonical `${PUBLIC_ORIGIN}/mcp` resource and CIMD client discovery.
119
- - The Cloudflare adapter no longer requires `OAUTH_KV` or
120
- `@cloudflare/workers-oauth-provider`. Old opaque tokens and KV registrations
121
- cannot be migrated safely and must reconnect.
122
- - Canonical plan ordering may change stable field/export order (including
123
- Admin CSV columns) without changing field values.
124
-
125
- This alpha changes the Better Auth D1 schema, including required account
126
- issuer identity and OAuth resource/client tables. Reset and re-bootstrap a
127
- pre-1.7 alpha auth database; do not guess an issuer backfill. Reset old generic
128
- content storage as described above and move required data manually outside
129
- Mantle.
9
+ Every version before 0.1.2 was an internal prerelease. If you are holding a
10
+ database created by one of those, `LEGACY_STORAGE_RESET_REQUIRED` means it
11
+ predates native Schema tables: rebuild it rather than migrating it. Move any
12
+ data you need out of Mantle by hand first — there is no product migration for
13
+ that unreleased storage format.
@@ -1,9 +1,9 @@
1
1
  # Release process
2
2
 
3
- First stable targets 0.1.2 (#826). The last legacy Landing/Starter release is
4
- 0.1.0-alpha.17. Its immutable artifacts and repositories remain available;
5
- recover that version with its tagged controller/docs. New releases have no
6
- Starter/Landing checkout, tag, dispatch, credential or deployment dependency.
3
+ How a version reaches npm. What each shipped stable contains is
4
+ [Releases](handbook/releases/index.md); this document is the procedure only.
5
+ A release has no Starter/Landing checkout, tag, dispatch, credential or
6
+ deployment dependency.
7
7
 
8
8
  ## Authority and state transitions
9
9
 
@@ -15,9 +15,9 @@ No task implicitly authorizes publication; no manual package/tag writer exists.
15
15
  |---|---|---|
16
16
  | Reviewed source; unused version | Core source/packed-consumer gates, then immutable Core tag | Exact canonical merged PR SHA and version required |
17
17
  | Tag exists; registry candidates partial | Existing npm/GPR publication steps | Verify existing artifact identity; publish missing versions only |
18
- | Registry candidates verified | Public-registry reference consumer gate | No mutation; failure leaves public channels unchanged |
19
- | Consumer passes | Monotonic npm/GPR channel promotion | Same version is a no-op; older runs cannot move a channel backward |
20
- | Channels promoted/preserved newer | GitHub release step | Existing release identity or fail |
18
+ | Registry candidates verified | Public-registry reference consumer gate | No mutation; failure leaves public channels and `mantle-release` unchanged |
19
+ | Consumer passes | That registry's promote step: monotonic channel add, then `dist-tag rm` of `mantle-release` only | Same version is a no-op; older runs cannot move a channel backward. Removal runs only after that package's promote loop, and only when `mantle-release` points at this version. A missing tag is a no-op. A tag pointing at another version is left for that version's promote step. `alpha` / `beta` / `rc` / `latest` are never removed |
20
+ | Channels promoted or preserved, and the temp tag cleared or left | 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
23
  `docs/examples/host-minimal-worker` reference, installs the exact candidate, then
@@ -39,9 +39,41 @@ foundational blocker returns to the state table and the user for a scope
39
39
  decision instead of starting another local redesign loop.
40
40
 
41
41
  Invariants: immutable versions/tags retain their identity; registry integrity
42
- and the published-consumer gate precede public channel promotion; retries
43
- cannot move channels backward. No downstream mutation, unpublish or rollback
44
- is introduced. The runnable release-order check guards these transitions.
42
+ and the published-consumer gate precede public channel promotion and any
43
+ removal of `mantle-release` by the release controller; retries cannot move
44
+ channels backward. No downstream mutation, unpublish or rollback is
45
+ introduced. The runnable release-order check guards these transitions.
46
+
47
+ Mutation boundaries during a release: `Publish to npmjs` and `Mirror to
48
+ GitHub Packages` may attach `mantle-release` while publishing a version.
49
+ `Promote npmjs channel tags` is the only release step that moves npmjs
50
+ channels or removes that tag for the version being released. `Promote
51
+ GitHub Packages channel tags` is the only release step that does the same
52
+ for GitHub Packages. Recovery of a partial release reruns that same
53
+ controller and version. It does not call the cleanup workflow.
54
+
55
+ The cleanup workflow is a separate writer for one case the controller
56
+ cannot cover: a release commit that predates temp-tag removal still leaves
57
+ `mantle-release` behind, and a personal npm token that is `read-write` on
58
+ `npm access` can still receive 403 on dist-tag DELETE.
59
+ `.github/workflows/remove-mantle-release-dist-tag.yml` uses the Actions
60
+ `NPM_TOKEN` and `GITHUB_TOKEN`. It is not a release controller and not a
61
+ recovery path.
62
+
63
+ | State | Sole next writer | Retry / invariant |
64
+ |---|---|---|
65
+ | Leftover `mantle-release` after `alpha`, `beta`, `rc`, or `latest` already points at that version | `remove-mantle-release-dist-tag`, only when `confirm` is `remove-mantle-release` | Missing tag is a no-op. Only `mantle-release` is removed. Before and after dist-tags are printed and compared; every other tag is unchanged |
66
+ | `mantle-release` points at a version no consumer channel has | No deletion | The job fails and leaves the tag. Channel moves stay on the release promote step |
67
+ | Confirm string is anything else | No registry call | The job fails before reading or editing tags |
68
+
69
+ It shares the `release-controller` concurrency group with
70
+ `cancel-in-progress: false`, so it waits out an in-progress release instead
71
+ of deleting `mantle-release` between publish and channel promotion. After
72
+ this file is on `develop`:
73
+
74
+ ```sh
75
+ gh workflow run remove-mantle-release-dist-tag --ref develop -f confirm=remove-mantle-release
76
+ ```
45
77
 
46
78
  ## Branches and channels
47
79
 
@@ -56,14 +88,17 @@ is introduced. The runnable release-order check guards these transitions.
56
88
  `develop`, anything else means `main`. It refuses a commit that is not that
57
89
  branch's tip or not the merge commit of exactly one PR into that branch.
58
90
  `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.
63
- - Stable publishes latest. Final 0.1.0 alphas only advance alpha, preserving
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.
91
+ - `develop` is where every change integrates first, so it is the base for all
92
+ work despite `main` being the repository's default branch on GitHub. `main`
93
+ changes only through promotion PRs and hotfix PRs (below); it is never pushed
94
+ directly, rebased or force-updated. Both branches share one ruleset: PR, one
95
+ approval, resolved threads and a current-base `Typecheck + tests` check.
96
+ - Stable is the only release that moves `latest`. A prerelease channel keeps
97
+ its last version when a later stable publishes.
98
+ - Publish uses `--tag mantle-release`, so publication does not move
99
+ `alpha`, `beta`, `rc`, or `latest`. After the public-registry consumer
100
+ gate, each registry's promote step moves the real channel and then removes
101
+ `mantle-release` when that tag points at this version.
67
102
 
68
103
  ## Prepare and run
69
104
 
@@ -84,7 +119,8 @@ is introduced. The runnable release-order check guards these transitions.
84
119
  ```
85
120
 
86
121
  3. Review API compatibility and migration instructions for actual consumers.
87
- Frozen legacy consumers stay on alpha.17; do not make them follow new Core.
122
+ Frozen legacy consumers stay on their pinned version; do not make them
123
+ follow new Core.
88
124
  4. Run `pnpm check`, including exact packed Worker, optional products, Bun,
89
125
  Vercel, skills, release invariants, types and tests. Inspect the umbrella
90
126
  docs/skills payload: no workspace dependencies, secrets or local state.
@@ -94,7 +130,7 @@ is introduced. The runnable release-order check guards these transitions.
94
130
  stable, continue with the promotion below. The controller refuses an
95
131
  untagged source that is no longer the expected branch tip.
96
132
 
97
- The ten public packages remain in dependency order:
133
+ The eleven public packages remain in dependency order:
98
134
 
99
135
  1. @aotter/mantle-spec
100
136
  2. @aotter/mantle-admin-ui
@@ -102,10 +138,11 @@ The ten public packages remain in dependency order:
102
138
  4. @aotter/mantle-indexeddb
103
139
  5. @aotter/mantle-web
104
140
  6. @aotter/mantle-admin
105
- 7. @aotter/mantle-bun
106
- 8. @aotter/mantle-vercel
107
- 9. @aotter/mantle-cloudflare
108
- 10. @aotter/mantle
141
+ 7. @aotter/mantle-auth
142
+ 8. @aotter/mantle-bun
143
+ 9. @aotter/mantle-vercel
144
+ 10. @aotter/mantle-cloudflare
145
+ 11. @aotter/mantle
109
146
 
110
147
  ## Promote to main (beta, RC, stable)
111
148
 
@@ -113,9 +150,9 @@ Every non-alpha release is the version PR above, one promotion PR and one
113
150
  dispatch. The version PR still merges into `develop`, so `develop` always
114
151
  contains what `main` publishes and promotions never conflict.
115
152
 
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.
153
+ 1. Stable only: the version's release-gate issue records owner acceptance.
154
+ Every gate item passes with linked evidence or is explicitly deferred
155
+ there, and no `release-gate` issue stays open against the version.
119
156
  Beta and RC need the gate defined, not passed.
120
157
  2. Merge the version PR into `develop` with a merge commit; note its SHA.
121
158
  3. Pin the promotion head at that SHA so later `develop` merges cannot ride
@@ -148,18 +185,20 @@ the next promotion. Branch from `main`, include the version bump, PR into
148
185
  and resolve version files in favour of `develop`. Until that lands, the next
149
186
  promotion conflicts on the version files.
150
187
 
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.
188
+ GitHub generates notes from the immediately previous tag, which for a stable
189
+ is usually its own last RC. To cover the whole line instead, regenerate from
190
+ the previous stable and edit the release body after the run. The body is not
191
+ an immutable artifact; the tag and packages are.
156
192
 
157
193
  ```sh
158
194
  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
195
+ -f tag_name=v<version> -f previous_tag_name=v<previous stable> --jq .body > notes.md
196
+ gh release edit v<version> --notes-file notes.md
161
197
  ```
162
198
 
199
+ Add the version's entry to [Releases](handbook/releases/index.md) in the same
200
+ pass, so the handbook and the GitHub release describe the same thing.
201
+
163
202
  After publication, move docs/examples that were pinned to a packed checkout
164
203
  back to registry installation with an updated lockfile, and close the gate
165
204
  issue with the run link and completion evidence.
@@ -171,12 +210,14 @@ tag/release and mirrors GitHub Packages. No cross-repository fanout token is
171
210
  needed. Before tagging, verify credentials and new-version absence on both
172
211
  registries. Existing artifacts on retry must have matching integrity.
173
212
 
174
- Completion requires the Core tag SHA, all ten npmjs/GPR packages, exact
213
+ Completion requires the Core tag SHA, all eleven npmjs/GPR packages, exact
175
214
  integrity, no workspace dependencies, a passing public-registry Worker gate,
176
- correct channel tags and the GitHub release. Retain run links and gate evidence.
177
- This does not prove stable production soak or upgrade safety; #826 owns those
178
- acceptance requirements. A first-stable agent acceptance uses only the
179
- version-matched authoring instructions, not an SDK checkout or generated site.
215
+ correct channel tags, no `mantle-release` tag left on this version, and the
216
+ GitHub release. Retain run links and gate evidence.
217
+ This does not prove stable production soak or upgrade safety; the version's
218
+ release-gate issue owns those acceptance requirements. An agent acceptance run
219
+ uses only the version-matched authoring instructions, not an SDK checkout or
220
+ generated site.
180
221
 
181
222
  ## Recovery
182
223
 
@@ -6,7 +6,7 @@ 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.2`. Pin the package, record the tested version, and
9
+ This recipe targets `0.1.3-alpha.2`. Pin the package, record the tested version, and
10
10
  rerun compatibility checks when upgrading.
11
11
 
12
12
  ## What stays with the host