@aotter/mantle 0.1.4 → 0.1.5-alpha.1
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.
- package/README.md +16 -16
- package/dist/cli/generate-cloudflare.d.ts +7 -0
- package/dist/cli/generate-cloudflare.d.ts.map +1 -0
- package/dist/cli/generate-cloudflare.js +123 -0
- package/dist/cli/generate-cloudflare.js.map +1 -0
- package/dist/cli/generate-project.d.ts +25 -0
- package/dist/cli/generate-project.d.ts.map +1 -0
- package/dist/cli/generate-project.js +282 -0
- package/dist/cli/generate-project.js.map +1 -0
- package/dist/cli/generate-sites.d.ts +8 -0
- package/dist/cli/generate-sites.d.ts.map +1 -0
- package/dist/cli/generate-sites.js +273 -0
- package/dist/cli/generate-sites.js.map +1 -0
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +121 -10
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +10 -10
- package/docs/adr/0021-retire-starter-scaffolding.md +1 -1
- package/docs/adr/0026-progressive-generate.md +36 -0
- package/docs/adr/0027-scheduled-procedure-triggers.md +31 -0
- package/docs/adr/0028-schema-ttl-expiry.md +33 -0
- package/docs/adr/README.md +5 -2
- package/docs/agent-prompts.md +40 -78
- package/docs/examples/host-chatgpt-sites/README.md +1 -1
- package/docs/examples/host-chatgpt-sites/drizzle/0004_mantle.sql +10 -0
- package/docs/examples/host-chatgpt-sites/drizzle/0005_mantle.sql +24 -0
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +1 -1
- package/docs/examples/host-chatgpt-sites/drizzle/meta/mantle-state.json +60 -0
- package/docs/examples/host-chatgpt-sites/package.json +1 -1
- package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +42 -8
- package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +9 -6
- package/docs/examples/host-local-admin-otp/package.json +2 -2
- package/docs/examples/host-minimal-worker/package.json +2 -2
- package/docs/handbook/chatgpt-sites/generated-app.md +84 -0
- package/docs/handbook/chatgpt-sites/index.md +21 -11
- package/docs/handbook/cloudflare/authentication.md +19 -2
- package/docs/handbook/cloudflare/bindings.md +4 -11
- package/docs/handbook/cloudflare/conventional-worker.md +7 -3
- package/docs/handbook/cloudflare/deploy-and-operate.md +1 -1
- package/docs/handbook/concepts/runtime-and-adapters.md +7 -0
- package/docs/handbook/guides/agent-setup.md +3 -3
- package/docs/handbook/navigation.json +3 -2
- package/docs/handbook/reference/diagnostics.md +5 -0
- package/docs/handbook/reference/procedure.md +52 -1
- package/docs/handbook/reference/schema.md +27 -1
- package/docs/handbook/reference/surface.md +3 -3
- package/docs/handbook/reference/trigger.md +21 -1
- package/docs/handbook/releases/index.md +55 -0
- package/docs/handbook/start/overview.md +5 -2
- package/docs/handbook/start/project-and-cli.md +103 -119
- package/docs/handbook/start/quickstart-admin.md +6 -4
- package/docs/handbook/start/quickstart-worker.md +17 -8
- package/docs/skills/develop/SKILL.md +14 -6
- package/docs/skills/integrate/SKILL.md +60 -0
- package/package.json +18 -17
- package/skills/README.md +3 -1
- package/skills/develop/SKILL.md +14 -6
- package/skills/install/SKILL.md +100 -137
- package/skills/integrate/SKILL.md +60 -0
- package/templates/chatgpt-sites/auth.ts +66 -0
- package/templates/chatgpt-sites/build.mjs +14 -0
- package/templates/chatgpt-sites/env.ts +1 -0
- package/templates/chatgpt-sites/mcp.ts +48 -0
- package/templates/chatgpt-sites/public-mcp.ts +29 -0
- package/templates/chatgpt-sites/smoke-local.mjs +20 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate a blank Mantle app for ChatGPT Sites, apply D1 migrations, and verify local Admin and MCP.
|
|
3
|
+
---
|
|
4
|
+
# Generate a ChatGPT Sites app
|
|
5
|
+
|
|
6
|
+
`mantle generate --host chatgpt-sites` creates a blank home, a D1-backed Runtime,
|
|
7
|
+
public API and MCP, and Mantle Admin. It adds no article Schema, media bucket, or
|
|
8
|
+
demo content. Edit `src/home.ts` and add your own manifests and handlers as needed.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
mkdir my-site && cd my-site
|
|
12
|
+
npm init -y
|
|
13
|
+
npm pkg set type=module
|
|
14
|
+
npm install --save-exact @aotter/mantle
|
|
15
|
+
npx mantle generate --host chatgpt-sites
|
|
16
|
+
npm install
|
|
17
|
+
npx mantle generate
|
|
18
|
+
npm run build
|
|
19
|
+
npx wrangler d1 migrations apply my-site --local
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The first generate declares the exact Mantle package versions it needs; the
|
|
23
|
+
second runs after those packages are installed. Review `drizzle/0000_mantle.sql`
|
|
24
|
+
before applying it. The D1 name comes from `wrangler.jsonc`. Generation does not
|
|
25
|
+
apply a migration, provision a Site, or publish one. `npm run build` removes the
|
|
26
|
+
old `dist` before copying the current migrations and Admin assets.
|
|
27
|
+
|
|
28
|
+
For local Admin, copy `.dev.vars.example` to `.dev.vars`, set `OWNER_EMAIL` to
|
|
29
|
+
the email of the ChatGPT account that will own this Site, and keep
|
|
30
|
+
`PUBLIC_ORIGIN` equal to the local URL. Run `npm run dev`.
|
|
31
|
+
The plain local browser has no ChatGPT Sites identity, so it will redirect to
|
|
32
|
+
Sites sign-in and cannot prove owner access. To exercise the identity contract
|
|
33
|
+
locally, set `MANTLE_TEST_OWNER_EMAIL` to the same email and run
|
|
34
|
+
`npm run smoke:local`. That script refuses non-loopback
|
|
35
|
+
targets. Its identity headers are a local simulation; the production Worker
|
|
36
|
+
contains no identity-injection path and must run behind Sites' trusted
|
|
37
|
+
identity-stripping dispatcher. The generated Wrangler config disables the
|
|
38
|
+
independent `workers.dev` URL; do not add a direct Worker route. A passing
|
|
39
|
+
local smoke does not verify a deployed ChatGPT sign-in.
|
|
40
|
+
|
|
41
|
+
Without `OWNER_EMAIL`, sign-in grants no Mantle staff role. If the intended
|
|
42
|
+
owner signed in before configuration, their existing `sites_users` row remains
|
|
43
|
+
unprivileged. Configure the owner email and deliberately assign `role='owner'`
|
|
44
|
+
to that account's exact email and `chatgpt:` ID in D1, or reset a disposable
|
|
45
|
+
local database and sign in again. Mantle never gives ownership to the first
|
|
46
|
+
visitor.
|
|
47
|
+
|
|
48
|
+
The anonymous public MCP endpoint is `/api/mcp`; it discovers only public
|
|
49
|
+
manifest capabilities. `/api/mcp/staff` uses the current Sites browser session
|
|
50
|
+
and a Mantle staff role. Admin advertises these endpoints, and Admin WebMCP
|
|
51
|
+
works in supporting browsers. The staff endpoint is not a remote OAuth MCP
|
|
52
|
+
connector. A remote agent needs a separately implemented verified OAuth flow.
|
|
53
|
+
|
|
54
|
+
When a Schema changes, run `npx mantle generate --check` to detect drift, then
|
|
55
|
+
`npx mantle generate`. Review the newly appended SQL and apply pending D1
|
|
56
|
+
migrations before deploying code that expects the new Schema. Previous
|
|
57
|
+
migration files remain untouched; an unapplied migration keeps the old database
|
|
58
|
+
fingerprint, and managed boot refuses to use an older database. Sites owns
|
|
59
|
+
`.openai/hosting.json` project metadata and production D1 migration delivery.
|
|
60
|
+
|
|
61
|
+
Replacing a Schema's `uniqueIndexes` tuple requires an explicit reviewed
|
|
62
|
+
migration. With the old local D1 migration applied, edit the Manifest and run
|
|
63
|
+
`npx mantle generate --review-unique-indexes --check` to inspect the proposed
|
|
64
|
+
source/target fingerprints, affected tuples and checksum without writing. Then
|
|
65
|
+
run `npx mantle generate --review-unique-indexes`, review the new
|
|
66
|
+
`drizzle/meta/000N_mantle.review.json` and matching SQL, and apply that SQL
|
|
67
|
+
through the normal Sites D1 migration path. The CLI checks **local D1 only**
|
|
68
|
+
for duplicate target tuples and reports a count and sample before writing;
|
|
69
|
+
inspect production data separately before applying there. SQLite also refuses
|
|
70
|
+
to create the new unique index if production has conflicts; do
|
|
71
|
+
not deploy the target Worker until the migration has succeeded. Old Workers
|
|
72
|
+
cannot safely reactivate after the old uniqueness guarantee is removed.
|
|
73
|
+
This option is limited to managed Sites SQLite and unique tuple changes;
|
|
74
|
+
field conversions and runtime-managed CF boot still reject destructive
|
|
75
|
+
changes.
|
|
76
|
+
|
|
77
|
+
For a complete article, media, and publishing example, use the
|
|
78
|
+
[Sites reference](../../examples/host-chatgpt-sites/README.md).
|
|
79
|
+
|
|
80
|
+
## Source
|
|
81
|
+
|
|
82
|
+
- [Sites generator](../../../packages/mantle/src/cli/generate-sites.ts)
|
|
83
|
+
- [Generated Sites templates](../../../packages/mantle/templates/chatgpt-sites)
|
|
84
|
+
- [Runnable Sites reference](../../examples/host-chatgpt-sites/README.md)
|
|
@@ -16,6 +16,10 @@ repository. Sites owns hosting, visitor access, and ChatGPT sign-in; Mantle owns
|
|
|
16
16
|
the content model, staff roles, and publishing workflow. For platform access and
|
|
17
17
|
sharing options, see [OpenAI's Sites documentation](https://learn.chatgpt.com/docs/sites).
|
|
18
18
|
|
|
19
|
+
For a new project, start with the [blank generated app](./generated-app.md).
|
|
20
|
+
The article reference below demonstrates a complete editorial Site with R2
|
|
21
|
+
media after you choose that content model.
|
|
22
|
+
|
|
19
23
|
## What you get
|
|
20
24
|
|
|
21
25
|
| Capability | In the Mantle Sites reference |
|
|
@@ -34,12 +38,17 @@ boundaries.
|
|
|
34
38
|
|
|
35
39
|
## Start with the supported SDK
|
|
36
40
|
|
|
37
|
-
You need Node.js 22
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
You need Node.js 22+ and Sites access with D1. Start with the
|
|
42
|
+
[blank generated app](./generated-app.md) to choose your own content model;
|
|
43
|
+
it requires no R2 bucket. The article reference also needs R2 for cover
|
|
44
|
+
images. Build and smoke-test locally before deployment, and keep your
|
|
45
|
+
application outside the SDK checkout.
|
|
46
|
+
|
|
47
|
+
## Follow the article reference when it fits
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
The steps below apply to the optional prebuilt article example. A new blank
|
|
50
|
+
generated Site has no article Schema, media bucket or content; add those only
|
|
51
|
+
when your requirements call for them.
|
|
43
52
|
|
|
44
53
|
1. **Prepare the application.** Follow the
|
|
45
54
|
[runnable reference](../../examples/host-chatgpt-sites/README.md#install-and-run).
|
|
@@ -81,15 +90,15 @@ staff connector needs its own verified OAuth flow; see the [host reference](./ho
|
|
|
81
90
|
|
|
82
91
|
## Ask your agent to set it up
|
|
83
92
|
|
|
84
|
-
Install the Mantle
|
|
85
|
-
|
|
93
|
+
Install the Mantle skill and exact SDK version, then describe your audience
|
|
94
|
+
and content requirements:
|
|
86
95
|
|
|
87
96
|
```text
|
|
88
97
|
Build a content site with ChatGPT Sites and Mantle. Read
|
|
89
|
-
handbook/chatgpt-sites/
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
sign-in
|
|
98
|
+
handbook/chatgpt-sites/generated-app.md from the installed Mantle docs, and
|
|
99
|
+
start from the blank generated Site when that CLI supports it. Use the article
|
|
100
|
+
reference only if its content model matches my requirements. Include ChatGPT
|
|
101
|
+
sign-in and Mantle staff roles; add cover uploads only if I request media.
|
|
93
102
|
Run the local checks and show me a draft-to-publish walkthrough before
|
|
94
103
|
deploying through Sites. Keep remote staff OAuth MCP outside this scope.
|
|
95
104
|
```
|
|
@@ -112,6 +121,7 @@ evidence from the equipment and Slack work still required in your application.
|
|
|
112
121
|
## Integration details
|
|
113
122
|
|
|
114
123
|
- [Host reference](./host-reference.md): identity, migrations, R2 routes, MCP, and deployment checks.
|
|
124
|
+
- [Generated blank app](./generated-app.md): local composition, D1 migration, Admin, and MCP.
|
|
115
125
|
- [Equipment checkout](./equipment-checkout.md): custom business rules and external API delivery without payments.
|
|
116
126
|
- [Runnable application](../../examples/host-chatgpt-sites/README.md): installation, build artifacts, and smoke tests.
|
|
117
127
|
- [Conventional Cloudflare Worker](../cloudflare/conventional-worker.md): the separate path for a Worker you deploy directly.
|
|
@@ -7,11 +7,28 @@ Conventional Auth is chosen by one variable, `MANTLE_AUTH_MODE`, and fails close
|
|
|
7
7
|
|
|
8
8
|
## Local Admin: email OTP
|
|
9
9
|
|
|
10
|
-
The
|
|
10
|
+
The generated CF app writes `.dev.vars.example`. Copy it to `.dev.vars` for
|
|
11
|
+
local use, then set `MANTLE_AUTH_MODE=local-otp`, the real `ADMIN_EMAIL`, a
|
|
12
|
+
random `BETTER_AUTH_SECRET`, and the exact loopback `PUBLIC_ORIGIN`. It configures
|
|
13
|
+
its email-OTP auth factory only for a
|
|
14
|
+
loopback origin. If you author the Worker yourself, pass `auth` to
|
|
15
|
+
`createMantleWorker` with `email-otp`, `ConsoleEmailSender`, and
|
|
16
|
+
`bootstrapOwner.match: "email"`; that factory does not read the conventional
|
|
17
|
+
mode matrix. The one-time code is printed in wrangler logs. See
|
|
18
|
+
[Quickstart: local Admin](../start/quickstart-admin.md). `ConsoleEmailSender`
|
|
19
|
+
is for `wrangler dev` only; production needs a real sender. Match
|
|
20
|
+
`PUBLIC_ORIGIN` to wrangler's actual `127.0.0.1:8787` origin or Better Auth
|
|
21
|
+
will reject OTP with `INVALID_ORIGIN`.
|
|
22
|
+
|
|
23
|
+
For production, the generated Worker's local OTP branch is disabled outside
|
|
24
|
+
loopback. Configure the conventional `self-managed` or `hosted` Auth mode,
|
|
25
|
+
including its required provider credentials and `ADMIN_GITHUB_LOGIN`, instead
|
|
26
|
+
of editing the CLI-owned Worker. An application that needs production email
|
|
27
|
+
delivery should author its own Worker Auth factory and real `EmailSender`.
|
|
11
28
|
|
|
12
29
|
With `auth` set, the mode matrix below is not read. Core still owns `/admin` and `/api/auth/*`.
|
|
13
30
|
|
|
14
|
-
For production email OTP, keep the custom `createAuth()` factory, replace
|
|
31
|
+
For production email OTP in a manually authored Worker, keep the custom `createAuth()` factory, replace
|
|
15
32
|
`ConsoleEmailSender` with the application's production `EmailSender`, and keep
|
|
16
33
|
`bootstrapOwner: { match: "email", value: <owner email> }`. Store the sender
|
|
17
34
|
credentials and `BETTER_AUTH_SECRET` as Worker secrets. If the application has
|
|
@@ -186,26 +186,19 @@ the interface is one `record(event)` method.
|
|
|
186
186
|
"triggers": { "crons": ["*/5 * * * *"] }
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
A `
|
|
189
|
+
A `schedule` Trigger declares the Procedure, and the Worker export reuses the same runtime as `fetch`:
|
|
190
190
|
|
|
191
191
|
```ts
|
|
192
|
-
import { bindMantle } from "../.mantle/generated/mantle.js";
|
|
193
|
-
|
|
194
192
|
const worker = createMantleWorker<Env>({ plan, handlers });
|
|
195
193
|
|
|
196
194
|
export default {
|
|
197
195
|
fetch: worker.fetch,
|
|
198
|
-
|
|
199
|
-
const mantle = bindMantle(await worker.getRuntime(env));
|
|
200
|
-
const result = await mantle.procedures.sweepExpiredOrders(
|
|
201
|
-
{ now: Date.now() },
|
|
202
|
-
{ user: null, staff: null, env, waitUntil: (p) => ctx.waitUntil(p) },
|
|
203
|
-
);
|
|
204
|
-
if (!result.ok) throw new Error(`sweep failed: ${result.diagnostic.code}`);
|
|
205
|
-
},
|
|
196
|
+
scheduled: worker.scheduled,
|
|
206
197
|
} satisfies ExportedHandler<Env>;
|
|
207
198
|
```
|
|
208
199
|
|
|
200
|
+
Register the exact enabled `cron` expression in `wrangler.jsonc`; Mantle does not create provider triggers. The Procedure takes `{}` input and sees `ctx.schedule.id` for retry-safe idempotency. See [Trigger](../reference/trigger.md#schedule-source).
|
|
201
|
+
|
|
209
202
|
## Durable Objects (application-owned)
|
|
210
203
|
|
|
211
204
|
Durable Objects are not a Core primitive. Use one as an application-owned coordinator when a decision must be serialized, for example reserving inventory exactly once. Export the class from the Worker entry, then bind and migrate it:
|
|
@@ -3,7 +3,10 @@ description: Assemble a Mantle Worker with createMantleWorker, add handlers and
|
|
|
3
3
|
---
|
|
4
4
|
# The conventional Worker
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
New applications can start with `mantle generate --host cf`, which writes a
|
|
7
|
+
blank home, Worker entry and selected Admin/API/MCP wiring. This page covers
|
|
8
|
+
the lower-level `createMantleWorker` facade for applications that author their
|
|
9
|
+
own Worker entry: its options, extension seam, readiness and reserved paths.
|
|
7
10
|
|
|
8
11
|
## Minimal entry
|
|
9
12
|
|
|
@@ -14,7 +17,7 @@ import { plan } from "../.mantle/generated/mantle.js";
|
|
|
14
17
|
export default createMantleWorker({ plan, cacheScope: "my-site-production" });
|
|
15
18
|
```
|
|
16
19
|
|
|
17
|
-
`plan` is the sealed plan that `mantle generate` writes to `.mantle/generated/mantle.ts`. With only `plan`,
|
|
20
|
+
`plan` is the sealed plan that `mantle generate` writes to `.mantle/generated/mantle.ts`. With only `plan`, this manually assembled Worker serves public View REST, HTTP Triggers, Admin, Auth, OAuth and MCP. It renders no public pages and `/` is a 404; see [Public web](./public-web.md). A newly generated full CF project wires a separate editable blank home. Local Admin with email OTP replaces Auth construction; see [Quickstart: local Admin](../start/quickstart-admin.md). Admin still requires the `ASSETS` binding.
|
|
18
21
|
|
|
19
22
|
## Options
|
|
20
23
|
|
|
@@ -64,9 +67,10 @@ If `auth.ready` rejects, the memoized assembly is evicted so the next request re
|
|
|
64
67
|
const worker = createMantleWorker<Env>({ plan });
|
|
65
68
|
worker.fetch(request, env, ctx); // HTTP entry
|
|
66
69
|
worker.getRuntime(env); // the runtime fetch uses, resolved after auth.ready
|
|
70
|
+
worker.scheduled(controller, env, ctx); // declared scheduled Procedure Triggers
|
|
67
71
|
```
|
|
68
72
|
|
|
69
|
-
Queue
|
|
73
|
+
Queue handlers call `worker.getRuntime(env)` and then generated `bindMantle(runtime)` so they reuse the assembled runtime. Scheduled Procedure Triggers use `worker.scheduled` with expressions registered in Wrangler. See [Bindings](./bindings.md#cron-triggers), [Trigger](../reference/trigger.md#schedule-source), and [Deferred hooks](./deferred-hooks-queues.md).
|
|
70
74
|
|
|
71
75
|
## Readiness rule
|
|
72
76
|
|
|
@@ -10,7 +10,7 @@ This page is the production checklist for a Mantle Worker on Cloudflare: what to
|
|
|
10
10
|
- Pin every `@aotter/mantle*` package to one exact version and commit the lockfile. Install with `pnpm install --frozen-lockfile` (or `npm ci`) from then on. See [Project and CLI](../start/project-and-cli.md).
|
|
11
11
|
- Set `PUBLIC_ORIGIN` to the real HTTPS origin, without a trailing slash. It drives canonical URLs, `.md` mirrors, `llms.txt`, the MCP resource and the OAuth callback. If a static documentation build also emits absolute URLs, give it the same value.
|
|
12
12
|
- Set the production D1 `database_id` (and `account_id` if your deployment needs it) in `wrangler.jsonc`. A local `database_name` is not a production identifier, and local D1 is not production data.
|
|
13
|
-
- Choose production Auth:
|
|
13
|
+
- Choose production Auth: a generated CF app uses `MANTLE_AUTH_MODE=self-managed` or `hosted` with `ADMIN_GITHUB_LOGIN` and the matching provider credentials. Local `local-otp` works only on loopback. If you author your own Worker Auth factory, replace console email delivery with a real `EmailSender`. Store secrets with `wrangler secret put`. See [Authentication](./authentication.md).
|
|
14
14
|
- Keep `compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"]`.
|
|
15
15
|
- Enable observability:
|
|
16
16
|
|
|
@@ -95,6 +95,13 @@ A storage adapter prepares one `RuntimePlan` into semantic ports. Three are requ
|
|
|
95
95
|
|
|
96
96
|
Two are optional and only when a feature needs them: `MediaStorage` for upload flows, and `DeferredHookDispatcher` for at-least-once `after_*` delivery. `DatabaseDriver` is not a portability contract — it is the reusable SQLite/D1 seam. A PostgreSQL, MongoDB or application-owned-table adapter implements the semantic ports directly rather than emulating D1.
|
|
97
97
|
|
|
98
|
+
`PreparedMantleStorage.atomicEntries` is an optional semantic write capability.
|
|
99
|
+
An adapter exposes it only when it can commit an ordered group of entry
|
|
100
|
+
mutations all-or-nothing, including zero-row version/status failures. The
|
|
101
|
+
SQLite implementation covers Cloudflare D1 and Bun; IndexedDB and custom
|
|
102
|
+
adapters without that guarantee leave it absent. Ref Procedures use
|
|
103
|
+
`ctx.writeAtomically` as described in [Procedure](../reference/procedure.md#atomic-entry-writes-in-a-ref-handler).
|
|
104
|
+
|
|
98
105
|
Declarative Views compile to logical plans once, and preparation lowers those plans to native queries. `View.spec.sql` is the exception: it is explicitly SQLite-only in v0.1. Storage that does not declare that dialect rejects such a View at preparation with `VIEW_DIALECT_UNSUPPORTED`, before mutating any state. Mantle does not guess a translation and ships no universal query driver. A View that must run everywhere uses `from` with a filter AST; see [View](../reference/view.md).
|
|
99
106
|
|
|
100
107
|
## Embedding each adapter
|
|
@@ -62,7 +62,7 @@ pnpm exec mantle skills --check
|
|
|
62
62
|
|---|---|
|
|
63
63
|
| `.agents/skills/mantle-{develop,plugin,theme,update}/SKILL.md` | The installed package's four project-scoped workflows. |
|
|
64
64
|
| `.claude/skills/mantle-{develop,plugin,theme,update}/SKILL.md` | Identical bytes for Claude compatibility. |
|
|
65
|
-
| `node_modules/@aotter/mantle/skills/` | All
|
|
65
|
+
| `node_modules/@aotter/mantle/skills/` | All eight shipped skills, including opt-in `mantle`, `integrate`, `provision` and `media-gc`. |
|
|
66
66
|
| `node_modules/@aotter/mantle/docs/` | Handbook and examples matched to the package. |
|
|
67
67
|
|
|
68
68
|
`mantle skills` overwrites these four generated projections. Keep project-specific
|
|
@@ -84,9 +84,9 @@ It does not prove a server, login, Admin assets or MCP connection works.
|
|
|
84
84
|
| `skills/install/SKILL.md` is missing | That is source provenance. Read the installer's destination instead. |
|
|
85
85
|
| `docs/...` is missing after `skills add` | The skill does not carry the handbook. Install the pinned SDK and read its embedded docs. |
|
|
86
86
|
| `mantle` is missing | Install local `@aotter/mantle`; run its binary through the project package manager. |
|
|
87
|
-
| `MANIFEST_ROOT_NOT_FOUND` |
|
|
87
|
+
| `MANIFEST_ROOT_NOT_FOUND` | Check the installed CLI and saved project selection. New generated projects may start with an empty manifest set; legacy compile mode still needs the configured source. |
|
|
88
88
|
| `mantle skills --check` exits 1 | Run `mantle skills`, then read the refreshed project skill. |
|
|
89
|
-
| No projected provision/media-gc skill | These are intentionally opt-in. Read their installed package files when the task calls for them. |
|
|
89
|
+
| No projected integrate/provision/media-gc skill | These are intentionally opt-in. Read their installed package files when the task calls for them. |
|
|
90
90
|
| A documented feature fails on an older release | Use that release's docs or explicitly upgrade; changing a skill does not change Runtime. |
|
|
91
91
|
|
|
92
92
|
## Source
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"text": "Start here",
|
|
6
6
|
"items": [
|
|
7
7
|
{ "text": "Handbook overview", "link": "/start/overview" },
|
|
8
|
-
{ "text": "
|
|
8
|
+
{ "text": "Generate a project and use the CLI", "link": "/start/project-and-cli" },
|
|
9
9
|
{ "text": "Quickstart: a minimal Worker", "link": "/start/quickstart-worker" },
|
|
10
|
-
{ "text": "Quickstart:
|
|
10
|
+
{ "text": "Quickstart: authored Worker Admin", "link": "/start/quickstart-admin" },
|
|
11
11
|
{ "text": "When the host is ChatGPT Sites", "link": "/chatgpt-sites/index" }
|
|
12
12
|
]
|
|
13
13
|
},
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"text": "ChatGPT Sites",
|
|
51
51
|
"items": [
|
|
52
52
|
{ "text": "Get started", "link": "/chatgpt-sites/index" },
|
|
53
|
+
{ "text": "Generate a blank app", "link": "/chatgpt-sites/generated-app" },
|
|
53
54
|
{ "text": "Host reference", "link": "/chatgpt-sites/host-reference" },
|
|
54
55
|
{ "text": "Equipment checkout and external APIs", "link": "/chatgpt-sites/equipment-checkout" },
|
|
55
56
|
{ "text": "Earlier guide URL", "link": "/cloudflare/chatgpt-sites" }
|
|
@@ -81,11 +81,16 @@ Raised by the parser, the graph validator and the code generator. `mantle valida
|
|
|
81
81
|
| `UNIQUE_INDEX_FIELD_UNKNOWN` | A `uniqueIndexes` field is not a top-level Schema property. | — |
|
|
82
82
|
| `SCHEMA_SEARCH_INVALID` | `searchableFields` repeats an entry or names a non-string property. | — |
|
|
83
83
|
| `SCHEMA_SEARCH_FIELD_UNKNOWN` | A `searchableFields` entry is not a Schema property. | — |
|
|
84
|
+
| `SCHEMA_TTL_INVALID` | TTL must name a top-level date-time field and a finite nonnegative duration. | — |
|
|
85
|
+
| `SCHEMA_TTL_TRANSLATION_UNSUPPORTED` | TTL on either side of a translation join cannot guarantee the joined content's expiry. | — |
|
|
86
|
+
| `VIEW_TTL_NATIVE_UNSAFE` | A native SQL View cannot guarantee logical expiry while a Schema has TTL. | — |
|
|
84
87
|
| `SCHEMA_UI_INVALID` | A Schema or Procedure `uiSchema` rule is broken, including unknown roots, invalid `nav.standalone`, or a Schema declaring `uiSchema.collectionAction`. | — |
|
|
85
88
|
| `HANDLER_BUILTIN_NOT_IN_V010` | A builtin Procedure was invoked on a runtime assembled without the builtin collaborator. | — |
|
|
86
89
|
| `MANIFEST_ROOT_NOT_FOUND` | The manifests directory is missing, unreadable, or contains no `.yaml` or `.yml` file. | — |
|
|
87
90
|
| `MANIFEST_READ_FAILED` | A manifest source could not be read. | — |
|
|
88
91
|
| `CODEGEN_IDENTIFIER_COLLISION` | Two names in one group collapse to the same generated lower-camel identifier. | — |
|
|
92
|
+
| `SCHEDULE_INPUT_INVALID` | A scheduled Procedure cannot accept the empty object supplied by its system Trigger. | — |
|
|
93
|
+
| `SCHEDULE_AUTH_INVALID` | A scheduled Procedure requires user or staff authority that the system caller never has. | — |
|
|
89
94
|
| `FIXTURE_SCHEMA_VIOLATION` | Reserved for consumer-authored test diagnostics on the `test` phase. Core emits purpose-shaped harness reports instead. | — |
|
|
90
95
|
|
|
91
96
|
## Cross-phase
|
|
@@ -207,7 +207,7 @@ An HTTP Trigger wraps a success as `{ "ok": true, "data": <EntryRow> }` with sta
|
|
|
207
207
|
|
|
208
208
|
## Conflicts and idempotency
|
|
209
209
|
|
|
210
|
-
A unique-index preflight runs before
|
|
210
|
+
A unique-index preflight runs before individual writes, and the database's own constraints catch the races the preflight misses. Atomic groups rely on the transaction's database constraints so an earlier operation may free a unique value for a later one. Both paths surface collisions as `CONFLICT` (409), as do a stale `expectedVersion` and an illegal lifecycle transition. **There is no automatic retry** — the caller decides whether to re-read and try again.
|
|
211
211
|
|
|
212
212
|
Idempotency has no grammar key. The convention is an `input` property marked `x-mcp-hint: idempotency-key`: Admin generates and hides one UUID per form submission, and other callers generate one and reuse it across retries of the same logical request. The handler is responsible for acting on it.
|
|
213
213
|
|
|
@@ -215,6 +215,57 @@ Optimistic concurrency uses the reserved input name `expectedVersion` — the ve
|
|
|
215
215
|
|
|
216
216
|
Deferred lifecycle hooks have a stronger guarantee to work with: delivery is at-least-once, and handlers key on `${ctx.event.id}:${ctx.event.trigger}` — stable across enqueue fallback, queue retries and replay. See [Deferred hooks on Queues](../cloudflare/deferred-hooks-queues.md).
|
|
217
217
|
|
|
218
|
+
## Atomic entry writes in a ref handler
|
|
219
|
+
|
|
220
|
+
When one request must change several Schemas together, a `ref` handler can call
|
|
221
|
+
`ctx.writeAtomically(operations)`. Cloudflare D1 and Bun SQLite support it; an
|
|
222
|
+
adapter without the optional `atomicEntries` capability returns
|
|
223
|
+
`RESOURCE_UNAVAILABLE` (503)
|
|
224
|
+
instead of committing part of the group. Operations use the `createDraft`,
|
|
225
|
+
`updateDraft`, or `deleteEntry` request shape; atomic deletes additionally
|
|
226
|
+
require `expectedVersion`. Operational Schemas become live on create;
|
|
227
|
+
publishing Schemas create drafts. Updates and deletes require the version the
|
|
228
|
+
caller read.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
const sessionId = crypto.randomUUID();
|
|
232
|
+
const rows = await ctx.writeAtomically!([
|
|
233
|
+
{ kind: "create", id: sessionId, request: {
|
|
234
|
+
collection: "sessions", data: { name: input.name }, authorId: ctx.user?.id ?? null, ctx,
|
|
235
|
+
} },
|
|
236
|
+
{ kind: "create", request: {
|
|
237
|
+
collection: "exercise-blocks", data: { sessionId, exercise: input.exercise },
|
|
238
|
+
authorId: ctx.user?.id ?? null, ctx,
|
|
239
|
+
} },
|
|
240
|
+
{ kind: "create", request: {
|
|
241
|
+
collection: "receipts", data: { token: input.requestId }, authorId: ctx.user?.id ?? null, ctx,
|
|
242
|
+
} },
|
|
243
|
+
]);
|
|
244
|
+
return { sessionId: rows[0]!.id };
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Declare `receipts.token` as a Schema `uniqueIndexes: [[token]]`. A duplicate
|
|
248
|
+
receipt rejects the whole group, including the session and block. The handler
|
|
249
|
+
can then read the existing receipt **after** the failed transaction to answer
|
|
250
|
+
an idempotent retry. A stale update or delete rejects the whole group even
|
|
251
|
+
when it is the final operation. The group may touch each entry only once;
|
|
252
|
+
read and authorization decisions happen before the batch, and the expected
|
|
253
|
+
version/status is checked again by the conditional database write.
|
|
254
|
+
|
|
255
|
+
All Schema projection, stamping, validation, uniqueness, and lifecycle rules
|
|
256
|
+
still apply. `before_*` hooks run in operation order before the batch and can
|
|
257
|
+
veto it; their external effects cannot be rolled back. `after_*` hooks run
|
|
258
|
+
only after commit, in operation order. Publishing-content invalidation runs
|
|
259
|
+
once for the group. Deferred Queue delivery is separate from the database
|
|
260
|
+
transaction. Application-owned tables can use their host's transaction
|
|
261
|
+
facility inside a ref handler, but that does not give those tables Mantle
|
|
262
|
+
entry semantics. Direct SQL writes to Mantle Schema tables are unsupported.
|
|
263
|
+
Authorization guard Procedures do not receive `ctx.writeAtomically`.
|
|
264
|
+
|
|
265
|
+
## TTL sweep in a ref handler
|
|
266
|
+
|
|
267
|
+
`ctx.sweepExpired({ collection, limit })` previews a bounded page of expired rows; `delete: true` explicitly removes it. The result contains `scanned`, `removed` and an optional `nextCursor`. Continue with that cursor until absent. D1 and Bun SQLite implement this semantic capability; unsupported storage returns `RESOURCE_UNAVAILABLE`. Authorization guard Procedures do not receive the sweep function. For a scheduled cleanup, declare a [schedule Trigger](./trigger.md#schedule-source) targeting a no-input ref Procedure. No sweep is scheduled automatically. See [Schema TTL](./schema.md#ttl).
|
|
268
|
+
|
|
218
269
|
## `uiSchema`
|
|
219
270
|
|
|
220
271
|
Admin presentation only. It never affects input validation, the MCP tool schema or the OpenAPI document. Roots are closed: `collectionAction` and `fields`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Schema field reference — JSON Schema subset,
|
|
2
|
+
description: Schema field reference — JSON Schema subset, uiSchema, indexes, translates, lifecycle and TTL rules.
|
|
3
3
|
---
|
|
4
4
|
# Schema
|
|
5
5
|
|
|
@@ -19,6 +19,7 @@ A Schema declares one collection: the JSON Schema for each entry's `data`, its i
|
|
|
19
19
|
| `localized` | boolean | no | `false` | When `false`, a `locale` property is rejected. Must be a boolean. |
|
|
20
20
|
| `translates` | `{ parent, on }` | no | — | Marks a translation child. Requires `localized: true`. |
|
|
21
21
|
| `lifecycle` | `publishing` \| `operational` | no | `publishing` | Selects the [state machine](#lifecycle). |
|
|
22
|
+
| `ttl` | `{ field, expireAfterSeconds }` | no | — | Logical expiry over one top-level date-time property. See [TTL](#ttl). |
|
|
22
23
|
|
|
23
24
|
### Reserved entry columns
|
|
24
25
|
|
|
@@ -242,6 +243,31 @@ Every authoring path (Admin, Staff MCP, builtin Procedures) runs the same guard
|
|
|
242
243
|
|
|
243
244
|
Site locales are configured in [Site config](./site-config.md).
|
|
244
245
|
|
|
246
|
+
## TTL
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
spec:
|
|
250
|
+
ttl: { field: expiresAt, expireAfterSeconds: 0 }
|
|
251
|
+
schema:
|
|
252
|
+
type: object
|
|
253
|
+
properties:
|
|
254
|
+
expiresAt: { type: string, format: date-time, nullable: true }
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
`field` must name one top-level `date-time` string property; `expireAfterSeconds` is finite and nonnegative. An entry expires when its timestamp plus the duration is **at or before** the current instant. Missing or null dates never expire. `SCHEMA_TTL_INVALID` rejects invalid policies.
|
|
258
|
+
|
|
259
|
+
Legacy values that SQLite cannot parse as dates also remain visible and are not swept; correct those rows before relying on TTL. New writes must pass the Schema's date-time validation.
|
|
260
|
+
|
|
261
|
+
Expiry is logical first: Entry, declarative View, Admin, MCP and Web reads stop returning the row at the boundary, even before a sweep deletes it. A native SQL View cannot guarantee that filter and is rejected (`VIEW_TTL_NATIVE_UNSAFE`) while any Schema has TTL. A View over a TTL Schema cannot use shared caching (`VIEW_CACHE_INVALID`). Bun and D1 use the same SQLite predicate; other storage adapters must supply equivalent read filtering or reject the plan.
|
|
262
|
+
|
|
263
|
+
TTL is currently rejected on either side of a `translates` relationship (`SCHEMA_TTL_TRANSLATION_UNSUPPORTED`), because a translation child could otherwise remain visible after its parent expires.
|
|
264
|
+
|
|
265
|
+
Physical cleanup is **explicit**. `runtime.sweepExpired({ collection: "events", limit: 50 })` previews one page; add `delete: true` to remove it. Follow `nextCursor` until absent. The limit is 1–100, `scanned` counts expired candidates and `removed` counts successful deletes. A failure throws and the previous cursor is safe to retry. Ref Procedures can call `ctx.sweepExpired`; a Cloudflare schedule may invoke such a Procedure. The sweep does not fire entry lifecycle hooks: expiration already changed logical visibility, and the sweep only reclaims storage (ADR-0028).
|
|
266
|
+
|
|
267
|
+
The Developer Console shows declared TTL policies. It does not infer sweep history from a policy; a scheduled Procedure can return `scanned` and `removed` counts to include them in its run observation.
|
|
268
|
+
|
|
269
|
+
Adding or shortening TTL on an existing Schema immediately changes **read visibility**, but never starts a deletion job. Preview a sweep and review its counts before requesting `delete: true`. Keep a backup when changing the policy on populated data. Physical unique constraints still see expired rows until cleanup, so a reused unique value may conflict before the sweep.
|
|
270
|
+
|
|
245
271
|
## Source
|
|
246
272
|
|
|
247
273
|
- [`packages/mantle-spec/src/domain/model/ManifestGrammar.ts`](../../../packages/mantle-spec/src/domain/model/ManifestGrammar.ts)
|
|
@@ -116,14 +116,14 @@ The `@aotter/mantle` package installs two binaries, `mantle` and `mantle-harness
|
|
|
116
116
|
|
|
117
117
|
| Command | Flags |
|
|
118
118
|
|---|---|
|
|
119
|
-
| `mantle generate` | `--manifests <dir>` (default `./manifests`), `-o, --output <dir>` (default `.mantle/generated`), `--namespace <name>` (default `Mantle`), `--check`, `-h, --help` |
|
|
119
|
+
| `mantle generate` | `--manifests <dir>` (default `./manifests`), `-o, --output <dir>` (default `.mantle/generated`), `--namespace <name>` (default `Mantle`), `--host cf\|chatgpt-sites`, `--features <list>`, `--review-unique-indexes` (managed Sites only), `--check`, `-h, --help` |
|
|
120
120
|
| `mantle skills` | `--check`, `-h, --help` |
|
|
121
121
|
| `mantle validate` | `--manifests <dir>` (default `./manifests`), `--source <dir>` (default `./src`), `--no-source`, `--phase preview\|deploy` (default `preview`), `--format json\|text` (default by TTY), `--json`, `-h, --help` |
|
|
122
122
|
| `mantle emit-openapi` | `--manifests <dir>`, `--title <str>` (default `mantle`), `--version <str>` (default `0.1.0`), `--session-cookie-name <str>`, `-o, --output <file>`, `-h, --help` |
|
|
123
123
|
| `mantle-harness indexes` | `--manifests <dir>`, `--rows <n>`, `--require <view>` (repeatable), `--require-public`, `--format json\|text`, `-h, --help` |
|
|
124
124
|
| `mantle-harness http` | `--route <name=url>` (repeatable, required), `--base-url <url>`, `--rounds <n>`, `--warmup <n>`, `--format json\|text`, `-h, --help` |
|
|
125
125
|
|
|
126
|
-
`generate`
|
|
126
|
+
`generate` assembles new hosted projects with full Spec/Runtime/API/MCP/Admin/Web by default, or a smaller positive `--features` selection, then validates and compiles manifests into a typed module. Saved selections rerun safely; legacy authored projects keep compile mode. Selected Admin syncs its prebuilt SPA into `public/_mantle/admin/`. `--check` fails without writing on drift. `skills` copies project-scoped skills into `.agents/skills/mantle-*` and `.claude/skills/mantle-*`. `validate --phase deploy` adds pre-deploy checks; `emit-openapi` covers HTTP Triggers and View REST routes. `mantle-harness indexes` checks SQLite plans, while `http` samples a running Worker. [Project and CLI](../start/project-and-cli.md) has the install and ownership sequence.
|
|
127
127
|
|
|
128
128
|
## The generated module
|
|
129
129
|
|
|
@@ -182,7 +182,7 @@ This handbook describes the snapshot in this source tree. Pin every `@aotter/man
|
|
|
182
182
|
|
|
183
183
|
The documentation site pins its handbook commit in `docs/handbook.json` and records its vendored SDK source in `vendor/mantle/SOURCE.txt`. Those commits may differ when the intervening changes are behavior-neutral; the site verifies that condition during the build.
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
New projects can use `generate` to assemble a blank hosted app. Existing authored Workers can keep their own entry and use the same CLI for typed compilation. Pin all selected packages to one exact SDK version; prerelease APIs can change until stable publication.
|
|
186
186
|
|
|
187
187
|
## Source
|
|
188
188
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Trigger field reference — http, mcp and
|
|
2
|
+
description: Trigger field reference — http, mcp, lifecycle and schedule sources, routing rules, and delivery semantics.
|
|
3
3
|
---
|
|
4
4
|
# Trigger
|
|
5
5
|
|
|
@@ -19,9 +19,29 @@ A Trigger binds one source to one [Procedure](./procedure.md). Every external su
|
|
|
19
19
|
| `http` | `method`, `path` | One REST endpoint under `/api/`. |
|
|
20
20
|
| `mcp` | `surface` | One tool on `/mcp` or `/mcp/staff`. |
|
|
21
21
|
| `lifecycle` | `schema`, `on`, `errorPolicy` | Entry-writer hooks on one Schema. |
|
|
22
|
+
| `schedule` | `cron`, optional `enabled` | A Cloudflare Cron Trigger calling one Procedure. |
|
|
22
23
|
|
|
23
24
|
An unknown `kind`, a missing `kind`, or a key that does not belong to the chosen kind is `INVALID_MANIFEST_ENVELOPE`. One Procedure may carry several Triggers — that is how the same handler becomes an HTTP endpoint and an MCP tool without duplicating logic.
|
|
24
25
|
|
|
26
|
+
## `schedule` source
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
30
|
+
kind: Trigger
|
|
31
|
+
metadata: { name: nightly-cleanup }
|
|
32
|
+
spec:
|
|
33
|
+
source: { kind: schedule, cron: "0 2 * * *" }
|
|
34
|
+
target: { procedure: clean-expired-records }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`cron` is a five-field Cloudflare UTC expression (minute, hour, day, month, weekday). Each field accepts `*`, a number, a range, comma-separated values, or `*/step` / `start-end/step`. Weekdays are **1 = Sunday through 7 = Saturday**; use `2-6` for Monday–Friday. Month and weekday names and provider-specific extensions are outside this subset. `enabled` defaults to `true`; a disabled schedule remains in the compiled plan but never invokes its Procedure. The target Procedure must accept `{}` as input (`SCHEDULE_INPUT_INVALID`) and have no user/staff authorization requirements (`SCHEDULE_AUTH_INVALID`). The schedule creates no public HTTP or MCP route.
|
|
38
|
+
|
|
39
|
+
On Cloudflare, add each enabled expression to `wrangler.jsonc` under `triggers.crons` and export the `scheduled` method returned by `createMantleWorker`. Mantle does not provision the provider trigger. A disabled expression still registered in Wrangler is ignored; an expression absent from the Mantle plan fails visibly. If the Worker also owns unrelated cron tasks, route those expressions in the application's `scheduled` export. Multiple Mantle Triggers may share one expression and run in Trigger-name order; all run even if an earlier one fails, then the event reports failure.
|
|
40
|
+
|
|
41
|
+
Handlers receive `ctx.schedule` with `id`, `trigger`, `cron`, and `scheduledTime` (Unix milliseconds). The stable ID is `${trigger}:${scheduledTime}`. The caller is always `user: null`, `staff: null`, with no credential metadata; normal Procedure guards still apply. Cloudflare executes cron events in UTC, but its Cron Trigger documentation does not promise automatic retries. Duplicate/manual replay is still possible, so use `ctx.schedule.id` as an idempotency key for writes. A failure rejects the scheduled event; exactly-once execution is not promised. Bun, Vercel, and ChatGPT Sites do not register schedules and reject enabled schedules at boot or generation.
|
|
42
|
+
|
|
43
|
+
Cloudflare's default D1 composition records each attempt under that stable run ID. The owner-only Developer Console shows declared schedules even before the first run, separately from recent observations; Wrangler registration is **not observed** by Core. Records include scheduled/start/finish times, status, attempt, duration, a diagnostic code or generic handler-error summary, and optional sweep counts. A started attempt with no finish record says **Completion not observed**, not success. Inputs, outputs, exception text, credentials and secrets are not stored. The default history retains 30 days, hides older rows on reads, and prunes them during later runs (at most once per day per runtime instance). If observation start fails, the Procedure is skipped and the scheduled event rejects; if recording completion fails, the event also rejects. Use the stable ID to make replay safe. If the host supplies custom storage without a durable observation store, the Console says **Unavailable**; it never reports a missing record as success.
|
|
44
|
+
|
|
25
45
|
## `http` source
|
|
26
46
|
|
|
27
47
|
```yaml
|
|
@@ -21,6 +21,61 @@ All eleven packages share a single version and are published together, so mixed
|
|
|
21
21
|
versions across `@aotter/mantle*` are never a supported combination. Pin the
|
|
22
22
|
version you install and upgrade the whole set at once.
|
|
23
23
|
|
|
24
|
+
## 0.1.5 — in preparation
|
|
25
|
+
|
|
26
|
+
`mantle generate` now assembles a blank, editable full site by default for
|
|
27
|
+
Cloudflare Workers or ChatGPT Sites. `--features` positively selects a smaller
|
|
28
|
+
composition; Spec-only needs no host. The first run declares exact matching
|
|
29
|
+
dependencies, and a second run after installation completes the project.
|
|
30
|
+
Existing directly authored applications retain their compile path. Saved
|
|
31
|
+
choices and user-owned files survive reruns, while `--check` reports drift
|
|
32
|
+
without writing. On Sites, review and apply append-only D1 migrations before
|
|
33
|
+
running code that expects the new Schema. The new Sites worker trusts identity
|
|
34
|
+
only behind the Sites dispatcher and does not expose a separate `workers.dev`
|
|
35
|
+
URL.
|
|
36
|
+
|
|
37
|
+
Reviewed Sites unique-index tuple replacement can now generate an immutable
|
|
38
|
+
SQL migration with source/target fingerprints, checksum and an explicit report.
|
|
39
|
+
Local D1 duplicate preflight fails before writing files; production D1 still
|
|
40
|
+
enforces the new constraint when the reviewed migration is applied. Runtime-
|
|
41
|
+
managed CF boot continues to reject uniqueness changes without a reviewed
|
|
42
|
+
artifact path.
|
|
43
|
+
|
|
44
|
+
The owner-only Developer Console can inspect live Schema entries and run
|
|
45
|
+
declared Views on demand through guarded Admin routes. Its HTTP and MCP lists
|
|
46
|
+
link to the owning declarations. UI action placement is no longer shown as a
|
|
47
|
+
Procedure-to-Schema execution path; custom handlers and native SQL Views state
|
|
48
|
+
when their data relationships cannot be inferred from the Manifest.
|
|
49
|
+
|
|
50
|
+
Ref Procedures can now group create, update and delete operations across
|
|
51
|
+
Schemas with `ctx.writeAtomically`. D1 and Bun commit the group or roll it
|
|
52
|
+
back, including when the last conditional write finds a stale version. Other
|
|
53
|
+
adapters must explicitly implement the optional capability before using it.
|
|
54
|
+
|
|
55
|
+
Cloudflare Cron Triggers now target ordinary Procedures through `source.kind:
|
|
56
|
+
schedule`. The generated runtime plan records each schedule, while Wrangler
|
|
57
|
+
registration remains application-owned. Scheduled calls have no user or staff
|
|
58
|
+
authority, carry a stable retry key, and pass through Procedure validation and
|
|
59
|
+
authorization. D1-backed Workers retain owner-only run observations
|
|
60
|
+
for 30 days; the Console distinguishes a declaration from registration and
|
|
61
|
+
observed executions. Managed SQLite hosts must apply the append-only
|
|
62
|
+
`0007-schedule-run-observations` migration before boot. Other hosts do not
|
|
63
|
+
register schedules.
|
|
64
|
+
|
|
65
|
+
Schemas may declare a `ttl` date-time policy. D1 and Bun hide expired entries
|
|
66
|
+
from semantic reads and declarative Views before any deletion. Physical cleanup
|
|
67
|
+
is an explicit bounded sweep, previewed by default and resumable by cursor;
|
|
68
|
+
there is no automatic bulk deletion when a policy is introduced or shortened.
|
|
69
|
+
Native SQL Views and shared View caches are rejected for TTL Schemas because
|
|
70
|
+
they cannot guarantee the expiry boundary. Cloudflare public routes that can
|
|
71
|
+
include TTL content use `no-store` so a cached page cannot outlive its entries.
|
|
72
|
+
|
|
73
|
+
Agents installed through `npx skills add aotter/mantle` must still inspect the
|
|
74
|
+
target project's actual SDK version. Published 0.1.4 packages do **not**
|
|
75
|
+
support the new project flags; 0.1.5-alpha.1 does. Use the installed docs and
|
|
76
|
+
upgrade all selected packages together. The bootstrap skill remains a small directory,
|
|
77
|
+
not a repository clone.
|
|
78
|
+
|
|
24
79
|
## 0.1.4 — 2026-09-24
|
|
25
80
|
|
|
26
81
|
0.1.4 repairs the published consumer path without changing the Manifest
|
|
@@ -21,6 +21,7 @@ current npm `latest` contains it.
|
|
|
21
21
|
|---|---|---|
|
|
22
22
|
| Understand what manifests can express | [Manifest feature reference](../reference/features.md) | A capability-to-field map across the four atoms. |
|
|
23
23
|
| Validate manifests in an existing tool | [Spec-only adoption](../../spec-only-host-adoption.md) | Parse and link without Runtime, storage or a UI. |
|
|
24
|
+
| Bring Mantle into an existing application | [Integration skill](../../skills/integrate/SKILL.md) | Inspect the app and choose embedding, incremental replacement or rebuilding with data migration. |
|
|
24
25
|
| Embed Runtime in an existing host | [Runtime and adapters](../concepts/runtime-and-adapters.md), then [typed queries](../guides/typed-queries.md) | Bind your storage and call the generated API. |
|
|
25
26
|
| Build a local Cloudflare API | [Minimal Worker tutorial](./quickstart-worker.md) | A running public View and a verified HTTP response. |
|
|
26
27
|
| Add a staff console | [Local Admin tutorial](./quickstart-admin.md) | Email OTP, Admin assets and a local human workflow. |
|
|
@@ -28,8 +29,10 @@ current npm `latest` contains it.
|
|
|
28
29
|
| Work through a coding agent | [Skill installation and handoff](../guides/agent-setup.md) | Bootstrap skill, pinned package, then project-local instructions. |
|
|
29
30
|
|
|
30
31
|
Human authors can follow these pages directly; installing an agent skill is
|
|
31
|
-
optional.
|
|
32
|
-
|
|
32
|
+
optional. For a new app, install an exact SDK version and run
|
|
33
|
+
`mantle generate --host cf` or `--host chatgpt-sites`. The CLI assembles a blank
|
|
34
|
+
site by default; add your own Manifests after generation. Use explicit
|
|
35
|
+
`--features` for a smaller composition, including host-free Spec-only.
|
|
33
36
|
|
|
34
37
|
## Find the right kind of documentation
|
|
35
38
|
|