@aotter/mantle 0.0.11-alpha.63 → 0.0.11-alpha.64
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 +87 -12
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/generate.d.ts +2 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +181 -0
- package/dist/generate.js.map +1 -0
- package/dist/skills.d.ts +2 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +80 -0
- package/dist/skills.js.map +1 -0
- package/dist/update.d.ts +2 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +387 -0
- package/dist/update.js.map +1 -0
- package/docs/adr/0001-four-atom-manifest-model.md +6 -7
- package/docs/adr/0007-ai-as-primary-author.md +100 -138
- package/docs/adr/0008-structured-diagnostic-shape.md +79 -99
- package/docs/adr/0009-consumer-supplied-manifests.md +101 -228
- package/docs/adr/0012-views-as-public-rest.md +43 -15
- package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +43 -17
- package/docs/adr/0018-core-starters-repository-boundary.md +155 -0
- package/docs/adr/README.md +8 -6
- package/docs/cloudflare-low-level-composition.md +94 -0
- package/docs/design-atoms.md +59 -57
- package/docs/design-references/editorial-blog-2026-05-05.md +7 -7
- package/docs/labels.md +1 -1
- package/docs/media-uploads.md +1 -1
- package/docs/release-process.md +156 -523
- package/package.json +9 -6
- package/skills/README.md +20 -16
- package/skills/develop/SKILL.md +4 -4
- package/skills/install/SKILL.md +16 -2
- package/skills/plugin/SKILL.md +1 -1
- package/skills/provision/SKILL.md +1 -1
- package/skills/theme/SKILL.md +12 -10
- package/skills/update/SKILL.md +31 -19
- package/skills/customize-design/SKILL.md +0 -215
- package/skills/extend/SKILL.md +0 -257
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# ADR-0018: Keep Core and public starters in separate repositories
|
|
2
|
+
|
|
3
|
+
**Status:** Accepted for now; revisit only under the triggers below
|
|
4
|
+
|
|
5
|
+
**Date:** 2026-08-02
|
|
6
|
+
|
|
7
|
+
**Related:** [#542](https://github.com/aotter/mantle/issues/542),
|
|
8
|
+
[#191](https://github.com/aotter/mantle/issues/191),
|
|
9
|
+
[#97](https://github.com/aotter/mantle/issues/97),
|
|
10
|
+
[#99](https://github.com/aotter/mantle/issues/99)
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
Core and the public starter source currently form a producer-consumer
|
|
15
|
+
boundary:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Core (SDK producer)
|
|
19
|
+
-> published npm contract
|
|
20
|
+
mantle-starters (external consumer and bundle producer)
|
|
21
|
+
-> immutable provision bundle
|
|
22
|
+
mantle-landing (provisioner)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The repositories were originally split because premium starters needed a
|
|
26
|
+
private ACL. That reason does not determine where public starters must live,
|
|
27
|
+
and the private premium repository remains a stub. A later decision, #191,
|
|
28
|
+
made Core, starters, and landing mirror the same version and connected them
|
|
29
|
+
with an automated release fanout.
|
|
30
|
+
|
|
31
|
+
The fanout accumulated real costs: release-only commits, `main`/`develop`
|
|
32
|
+
backports, fallback tag creation, commit-subject detection, cross-repository
|
|
33
|
+
credentials, and a Core-skill drift check that can skip when the sibling
|
|
34
|
+
checkout is unavailable. Issue #542 therefore proposed moving public starters
|
|
35
|
+
back into this repository.
|
|
36
|
+
|
|
37
|
+
That operational pain does not by itself prove source cohesion. The separate
|
|
38
|
+
starter repository now provides a useful invariant that did not exist in the
|
|
39
|
+
original rationale: the canonical generated-site fixture consumes published
|
|
40
|
+
SDK packages and cannot silently link Core workspace packages.
|
|
41
|
+
|
|
42
|
+
A heuristic review of merged PRs from 2026-06-03 through 2026-08-02 also did
|
|
43
|
+
not show sustained majority co-change. After excluding release, promotion,
|
|
44
|
+
backport, and dependency PRs, 9 of 64 Core PRs explicitly referenced starters,
|
|
45
|
+
and 13 of 79 starter PRs explicitly referenced Core. Explicit references
|
|
46
|
+
undercount forced adaptations, so these numbers are directional rather than a
|
|
47
|
+
permanent threshold. They do show that release noise is not a sufficient proxy
|
|
48
|
+
for product coupling.
|
|
49
|
+
|
|
50
|
+
## Decision
|
|
51
|
+
|
|
52
|
+
Keep `aotter/mantle` and `aotter/mantle-starters` separate for now.
|
|
53
|
+
|
|
54
|
+
The boundary is a release-contract boundary, not an ACL boundary:
|
|
55
|
+
|
|
56
|
+
- Core produces versioned npm artifacts.
|
|
57
|
+
- Starters validate those artifacts as an external consumer and produce
|
|
58
|
+
immutable provision bundles.
|
|
59
|
+
- Landing consumes the released bundle and provisions end-user repositories.
|
|
60
|
+
|
|
61
|
+
Do not merge or archive the starters repository until the following no-regret
|
|
62
|
+
work has landed:
|
|
63
|
+
|
|
64
|
+
1. **Pre-publish downstream harness.** Validate starters against the exact SDK
|
|
65
|
+
tarballs that would be published, preferably through an ephemeral registry,
|
|
66
|
+
before a release tag exists.
|
|
67
|
+
2. **Fail-closed Core-skill drift check.** Compare starter-vendored skills with
|
|
68
|
+
the installed SDK package in normal starter CI; never depend on an optional
|
|
69
|
+
sibling checkout.
|
|
70
|
+
3. **One release controller.** Replace the bump/tag/dispatch/fallback chain and
|
|
71
|
+
remove avoidable `main`/`develop` backport noise without moving source code.
|
|
72
|
+
4. **Repository-agnostic updates.** Make generated sites resolve a configured
|
|
73
|
+
bundle base URL instead of hard-coding `aotter/mantle-starters`.
|
|
74
|
+
|
|
75
|
+
Issue #542 remains the work and reconsideration tracker. This ADR is the
|
|
76
|
+
canonical explanation of the repository-boundary decision. The current
|
|
77
|
+
mechanics belong in `docs/release-process.md`; implementation details should
|
|
78
|
+
not be duplicated here.
|
|
79
|
+
|
|
80
|
+
## Reconsideration triggers
|
|
81
|
+
|
|
82
|
+
Re-evaluate a monorepo after the four items above land if either signal persists:
|
|
83
|
+
|
|
84
|
+
- the release path still needs at least two special-case workaround fixes per
|
|
85
|
+
quarter, such as fallback tags, backports, or commit-message detectors; or
|
|
86
|
+
- SDK contract changes require same-release starter adaptations more often than
|
|
87
|
+
roughly once per month, making atomic cross-repository work a recurring cost.
|
|
88
|
+
|
|
89
|
+
A future merge proposal must also resolve:
|
|
90
|
+
|
|
91
|
+
- how the same tagged starter version is validated against the exact package
|
|
92
|
+
artifacts before npm publication;
|
|
93
|
+
- a real last-legacy-version to first-new-location update for an existing site;
|
|
94
|
+
- landing dispatch and release credentials, which do not disappear merely by
|
|
95
|
+
moving starters;
|
|
96
|
+
- premium-repository direction;
|
|
97
|
+
- nested pnpm/Dependabot/lockfile CI, licensing, open issues, and repository
|
|
98
|
+
history migration.
|
|
99
|
+
|
|
100
|
+
These are decision inputs, not a disguised permanent prohibition. A monorepo
|
|
101
|
+
is appropriate if its atomicity benefit remains material after the release
|
|
102
|
+
machinery is simplified.
|
|
103
|
+
|
|
104
|
+
## Consequences
|
|
105
|
+
|
|
106
|
+
### Positive
|
|
107
|
+
|
|
108
|
+
- The published-package consumer guarantee remains structural rather than
|
|
109
|
+
simulated by workspace exclusions and realpath assertions.
|
|
110
|
+
- The four improvements reduce risk and complexity under either eventual
|
|
111
|
+
repository shape.
|
|
112
|
+
- Existing generated-site update URLs remain valid while the updater contract
|
|
113
|
+
is made portable.
|
|
114
|
+
- Starter-only product work keeps an independent source boundary.
|
|
115
|
+
|
|
116
|
+
### Negative
|
|
117
|
+
|
|
118
|
+
- Cross-repository changes cannot land in one atomic PR.
|
|
119
|
+
- A release event still crosses repository boundaries and needs a narrowly
|
|
120
|
+
scoped credential or GitHub App.
|
|
121
|
+
- Release noise remains until the controller and branch flow are simplified.
|
|
122
|
+
- Core-skill drift remains possible until the fail-closed check lands.
|
|
123
|
+
|
|
124
|
+
## Alternatives
|
|
125
|
+
|
|
126
|
+
### Merge immediately
|
|
127
|
+
|
|
128
|
+
Rejected. The proposed release order cannot both start from an immutable tag
|
|
129
|
+
and regenerate a same-version registry-backed starter lockfile after publish.
|
|
130
|
+
Existing generated sites also cannot cross the hard-coded repository boundary
|
|
131
|
+
without a bridge.
|
|
132
|
+
|
|
133
|
+
### Keep the repositories separate without simplifying the release path
|
|
134
|
+
|
|
135
|
+
Rejected. The current fanout complexity and silent skill-check escape hatch are
|
|
136
|
+
real defects; retaining the boundary does not justify retaining those defects.
|
|
137
|
+
|
|
138
|
+
### Declare that the repositories must never merge
|
|
139
|
+
|
|
140
|
+
Rejected. The current boundary is valuable, but it is replaceable with explicit
|
|
141
|
+
and tested invariants if future co-change and release evidence justify the cost.
|
|
142
|
+
|
|
143
|
+
## How to apply
|
|
144
|
+
|
|
145
|
+
- Treat starters as a downstream SDK consumer in CI and release design.
|
|
146
|
+
- Do not add starter projects to the Core pnpm workspace as a shortcut for
|
|
147
|
+
cross-contract validation.
|
|
148
|
+
- Track the four prerequisite changes and future merge evidence in #542.
|
|
149
|
+
- Any future repository-move proposal must supersede this ADR and #191
|
|
150
|
+
explicitly, with the transition tests listed above.
|
|
151
|
+
|
|
152
|
+
## Implementation status
|
|
153
|
+
|
|
154
|
+
The repository-boundary decision is active. The four no-regret improvements are
|
|
155
|
+
tracked from #542 and may land independently; none requires a repository move.
|
package/docs/adr/README.md
CHANGED
|
@@ -8,15 +8,17 @@ Records of *why* mantle ended up shaped this way. The numbering preserves POC AD
|
|
|
8
8
|
|---|---|---|
|
|
9
9
|
| [0001](0001-four-atom-manifest-model.md) | Four-atom manifest model (Schema / View / Procedure / Trigger). Folds POC ADR-0005 (grammar discipline) and POC ADR-0006 (multi-doc YAML). | Accepted (refreshed) |
|
|
10
10
|
| [0002](0002-closed-enums-for-bindings.md) | Closed enums for `x-mantle-bind` and `ctx.*` predicates. | Accepted (refreshed) |
|
|
11
|
-
| [0007](0007-ai-as-primary-author.md) | AI is the primary author of consumer projects; SDK contract is
|
|
12
|
-
| [0008](0008-structured-diagnostic-shape.md) | Diagnostic shape
|
|
13
|
-
| [0009](0009-consumer-supplied-manifests.md) | Consumers
|
|
11
|
+
| [0007](0007-ai-as-primary-author.md) | AI is the primary author of consumer projects; SDK contract is three pre-serve feedback loops, runtime diagnostics, and coder/operator role surfaces. | Accepted + amended |
|
|
12
|
+
| [0008](0008-structured-diagnostic-shape.md) | Diagnostic shape for validate/boot/runtime failures, with a reserved consumer-test phase; measured harnesses keep purpose-shaped reports. | Accepted + amended |
|
|
13
|
+
| [0009](0009-consumer-supplied-manifests.md) | Consumers own manifest YAML; the installed CLI emits the parser-free runtime module and handler types. Core ships no application manifests. | Accepted + amended |
|
|
14
14
|
| [0010](0010-locale-and-translates.md) | Locale 3-layer (manifest / D1 site_config / data field) + translates pattern. Boot decoupled from `site_config` (issue #60 fix). | Accepted (refreshed) |
|
|
15
15
|
| [0011](0011-adapter-port-spec.md) | Adapter port spec. Required runtime ports plus optional feature ports. CF impl + Netlify stub. | Accepted (new) |
|
|
16
|
-
| [0012](0012-views-as-public-rest.md) | Views auto-expose `
|
|
16
|
+
| [0012](0012-views-as-public-rest.md) | Views auto-expose matching REST and `query_view_*` MCP reads on their declared `public` or `staff` surface. Schemas never get a public REST endpoint. | Accepted + amended |
|
|
17
17
|
| [0013](0013-agent-provisioned-consumer-projects.md) | Historical agent-provisioned consumer projects path. Superseded for first launch by landing provision bundles. | Superseded |
|
|
18
|
-
| [0014](0014-auth-better-auth-and-multi-tenant-mcp.md) |
|
|
18
|
+
| [0014](0014-auth-better-auth-and-multi-tenant-mcp.md) | The Cloudflare adapter owns the curated Better Auth identity/session facade and top-level `@cloudflare/workers-oauth-provider` MCP transport. Both normalize verified callers into runtime context; mutable staff role and target authorization are re-evaluated per call. | Accepted + amended |
|
|
19
19
|
| [0016](0016-site-semantic-layer.md) | Site semantic layer: `AGENTS.md` (cross-tool entry) + `.mantle/launch-state.json` (deterministic install context). The older `mantle/site.md` letter surface is suspended from first-run scaffolds. | Accepted (slimmed) |
|
|
20
|
+
| [0017](0017-media-multi-variant-agent-side-optimization.md) | Multi-variant media assets with agent-side optimization and asset-id entry references. | Accepted |
|
|
21
|
+
| [0018](0018-core-starters-repository-boundary.md) | Core produces published SDK artifacts; the separate starters repository validates them as an external consumer. Revisit after release-contract simplification. | Accepted for now |
|
|
20
22
|
|
|
21
23
|
## Reading order
|
|
22
24
|
|
|
@@ -50,7 +52,7 @@ The rebuild's ADR-0011 (new) is the most load-bearing addition — the POC accum
|
|
|
50
52
|
|
|
51
53
|
## Contributing a new ADR
|
|
52
54
|
|
|
53
|
-
1. Pick the next number (currently
|
|
55
|
+
1. Pick the next number (currently 0019).
|
|
54
56
|
2. File: `docs/adr/<NNNN>-<kebab-title>.md`.
|
|
55
57
|
3. Sections: Status, Date, Context, Decision, Consequences, Alternatives, How to apply, Implementation status.
|
|
56
58
|
4. Link from this README's table.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Low-level Cloudflare Worker composition
|
|
2
|
+
|
|
3
|
+
Use `createMantleWorker` unless the application must own the top-level Worker
|
|
4
|
+
assembly. This copyable fixture keeps Mantle's standard bindings, Auth,
|
|
5
|
+
Admin/API routes, OAuth/MCP dispatch, cache policy and redacted error boundary,
|
|
6
|
+
while adding one application-owned post-response Queue audit across every route.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { Hono } from "hono";
|
|
10
|
+
import {
|
|
11
|
+
createCmsRef,
|
|
12
|
+
createConventionalAuth,
|
|
13
|
+
createConventionalBindings,
|
|
14
|
+
createMcpApiHandler,
|
|
15
|
+
createOAuthProvider,
|
|
16
|
+
mountAuthorize,
|
|
17
|
+
mountServerEndpoints,
|
|
18
|
+
runMantleWorkerRequest,
|
|
19
|
+
setupIncompleteAuthResponse,
|
|
20
|
+
type MantleCloudflareEnv,
|
|
21
|
+
} from "@aotter/mantle/cloudflare";
|
|
22
|
+
import { manifest } from "../.mantle/generated/site.js";
|
|
23
|
+
|
|
24
|
+
interface Env extends MantleCloudflareEnv {
|
|
25
|
+
readonly AUDIT_QUEUE: Queue<{
|
|
26
|
+
readonly kind: "request-complete";
|
|
27
|
+
readonly path: string;
|
|
28
|
+
readonly status: number;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let assembled: ReturnType<typeof assemble> | undefined;
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
|
36
|
+
return runMantleWorkerRequest(async () => {
|
|
37
|
+
assembled ??= assemble(env);
|
|
38
|
+
const incomplete = await setupIncompleteAuthResponse(request, assembled.auth);
|
|
39
|
+
const response = incomplete ?? await assembled.fetch(request, env, ctx);
|
|
40
|
+
ctx.waitUntil(env.AUDIT_QUEUE.send({
|
|
41
|
+
kind: "request-complete",
|
|
42
|
+
path: new URL(request.url).pathname,
|
|
43
|
+
status: response.status,
|
|
44
|
+
}));
|
|
45
|
+
return response;
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
} satisfies ExportedHandler<Env>;
|
|
49
|
+
|
|
50
|
+
function assemble(env: Env) {
|
|
51
|
+
const bindings = createConventionalBindings(env);
|
|
52
|
+
const auth = createConventionalAuth(env);
|
|
53
|
+
const ref = createCmsRef({ manifests: manifest, bindings, auth });
|
|
54
|
+
const app = new Hono<{ Bindings: Env }>();
|
|
55
|
+
|
|
56
|
+
mountServerEndpoints(app, ref);
|
|
57
|
+
mountAuthorize(app, { auth, loginPath: "/admin/sign-in" });
|
|
58
|
+
app.get("/cache-probe", () => new Response("public", {
|
|
59
|
+
headers: { "cache-control": "public, s-maxage=60" },
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
const provider = createOAuthProvider<Env>({
|
|
63
|
+
defaultHandler: {
|
|
64
|
+
fetch: (request, workerEnv, ctx) => app.fetch(request, workerEnv, ctx),
|
|
65
|
+
},
|
|
66
|
+
apiHandlers: {
|
|
67
|
+
"/mcp/staff": createMcpApiHandler<Env>({ ref, surface: "staff" }),
|
|
68
|
+
"/mcp": createMcpApiHandler<Env>({ ref, surface: "public" }),
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
return { auth, fetch: provider.fetch.bind(provider) };
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Keep the conventional `DB`, `KV` and `OAUTH_KV` bindings and
|
|
76
|
+
`nodejs_compat`; add the Queue producer in `wrangler.jsonc`:
|
|
77
|
+
|
|
78
|
+
```jsonc
|
|
79
|
+
{
|
|
80
|
+
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
|
|
81
|
+
"queues": {
|
|
82
|
+
"producers": [
|
|
83
|
+
{ "binding": "AUDIT_QUEUE", "queue": "my-site-audit" }
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
After copying, the Worker entry, request audit, custom route and Queue contract
|
|
90
|
+
belong to the application. Mantle still owns the imported adapters and
|
|
91
|
+
standard route behavior; update them through the package version. Do not copy
|
|
92
|
+
their source or replace Auth, MCP or cache handling locally. A copied
|
|
93
|
+
composition has no automatic merge path back to `createMantleWorker`; keep it
|
|
94
|
+
only while the custom top-level lifecycle remains necessary.
|
package/docs/design-atoms.md
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
>
|
|
6
6
|
> **Status**: v0.1 grammar lock. Atoms are shipped; rich sub-spec
|
|
7
7
|
> grammar (policies, recursive views, temporal predicates, quotas,
|
|
8
|
-
> projection triggers,
|
|
8
|
+
> projection triggers, cron/queue sources, and extended lifecycle hooks) is
|
|
9
9
|
> reserved as **DRAFT** — see "Future grammar" appendix. Editorial
|
|
10
10
|
> lifecycle is the one shipped grammar key whose runtime is **deferred
|
|
11
|
-
> to v0.1.x**:
|
|
12
|
-
> `
|
|
13
|
-
>
|
|
11
|
+
> to v0.1.x**: parser and boot accept the shape, while
|
|
12
|
+
> `request_publish` rejects it with `LIFECYCLE_NOT_IN_V010` until the approval
|
|
13
|
+
> queue lands. Do not use editorial for a v0.1 publishing workflow.
|
|
14
14
|
>
|
|
15
15
|
> **This is the reference manual** — what the system is. For *why* it
|
|
16
16
|
> ended up this shape (alternatives considered, trade-offs accepted),
|
|
17
17
|
> see the Architecture Decision Records under [`docs/adr/`](adr/README.md).
|
|
18
18
|
> For the SDK's contract with its primary author (CLI feedback loops,
|
|
19
|
-
>
|
|
20
|
-
> [
|
|
19
|
+
> structured diagnostics, deterministic authoring), see
|
|
20
|
+
> [ADR-0007](adr/0007-ai-as-primary-author.md).
|
|
21
21
|
|
|
22
22
|
## TL;DR
|
|
23
23
|
|
|
@@ -31,7 +31,7 @@ primitives Postgres has shipped for 30 years.
|
|
|
31
31
|
| Our atom | Postgres equivalent | Externally exposed by itself? | Has user code? |
|
|
32
32
|
|---|---|---|---|
|
|
33
33
|
| **`Schema`** | `CREATE TABLE` | no (manipulated via View / Procedure) | no |
|
|
34
|
-
| **`View`** | `CREATE VIEW` | **yes** (auto-mounted
|
|
34
|
+
| **`View`** | `CREATE VIEW` | **yes** (auto-mounted on its declared public/staff REST and MCP surface; see ADR-0012) | no |
|
|
35
35
|
| **`Procedure`** | `CREATE FUNCTION ... LANGUAGE plpgsql` | **no** (transport-agnostic; needs a `Trigger` to bind it) | **yes — handler ref to consumer's TS file** |
|
|
36
36
|
| **`Trigger`** | `CREATE TRIGGER` + `pg_cron` + PostgREST route + `LISTEN/NOTIFY` | yes (the binding atom — turns Procedures into HTTP endpoints, cron jobs, MCP tools, lifecycle hooks) | no |
|
|
37
37
|
|
|
@@ -73,7 +73,7 @@ A logical feature commonly bundles a Procedure + a Trigger (and often a
|
|
|
73
73
|
Schema and a View). Put related atoms in one file separated by `---`:
|
|
74
74
|
|
|
75
75
|
```yaml
|
|
76
|
-
#
|
|
76
|
+
# manifests/contact.yaml
|
|
77
77
|
apiVersion: cms.mantle.aotter.net/v1
|
|
78
78
|
kind: Procedure
|
|
79
79
|
metadata: { name: send-contact-message }
|
|
@@ -112,7 +112,7 @@ metadata: { name: posts }
|
|
|
112
112
|
spec:
|
|
113
113
|
title: Posts # required: human-readable label for the admin UI
|
|
114
114
|
localized: true # opt-in: row carries data.locale (ADR-0010)
|
|
115
|
-
lifecycle: simple #
|
|
115
|
+
lifecycle: simple # default; 'none' is operational, 'editorial' is reserved
|
|
116
116
|
schema:
|
|
117
117
|
$schema: https://json-schema.org/draft/2020-12/schema
|
|
118
118
|
type: object
|
|
@@ -157,12 +157,11 @@ entry's state machine.
|
|
|
157
157
|
in v0.1.0.**
|
|
158
158
|
- `editorial` — the six-state machine with an approval queue
|
|
159
159
|
(`draft → review → approved → scheduled → published → archived`,
|
|
160
|
-
with `published` returnable to `draft` for republish).
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
`lifecycle: editorial` in v0.1.0 manifests; it will fail boot.
|
|
160
|
+
with `published` returnable to `draft` for republish). The grammar and
|
|
161
|
+
state-machine vocabulary are reserved for forward compatibility, but the
|
|
162
|
+
approval/request-publish runtime is on the v0.1.x roadmap. In v0.1,
|
|
163
|
+
`request_publish` rejects with `LIFECYCLE_NOT_IN_V010`; do not declare
|
|
164
|
+
editorial for a current publishing workflow.
|
|
166
165
|
- `none` — **operational records**, not authored content: orders,
|
|
167
166
|
inventory snapshots, grant/audit rows — anything written by
|
|
168
167
|
Procedures as a side effect rather than drafted by a person. No
|
|
@@ -291,12 +290,14 @@ appendix.
|
|
|
291
290
|
**Postgres analogue**: `CREATE TABLE posts (id UUID PRIMARY KEY, ...,
|
|
292
291
|
UNIQUE (slug, locale));`
|
|
293
292
|
|
|
294
|
-
### 2. `View` — the read surface (auto-exposed)
|
|
293
|
+
### 2. `View` — the read surface (auto-exposed by surface)
|
|
295
294
|
|
|
296
|
-
A named, declarative read over Schemas.
|
|
297
|
-
`
|
|
298
|
-
`
|
|
299
|
-
|
|
295
|
+
A named, declarative read over Schemas. No Trigger is required. A View with
|
|
296
|
+
no `spec.surface` (or `surface: public`) mounts at
|
|
297
|
+
`GET /api/views/<name>` and becomes `query_view_<name>` on `/mcp`.
|
|
298
|
+
`surface: staff` instead mounts at `GET /admin/api/views/<name>` behind the
|
|
299
|
+
staff gate and appears only on `/mcp/staff`. See ADR-0012 for the full design
|
|
300
|
+
rationale.
|
|
300
301
|
|
|
301
302
|
```yaml
|
|
302
303
|
apiVersion: cms.mantle.aotter.net/v1
|
|
@@ -334,7 +335,7 @@ spec:
|
|
|
334
335
|
limit: 100
|
|
335
336
|
```
|
|
336
337
|
|
|
337
|
-
|
|
338
|
+
REST callers paginate via reserved query-string knobs `?page=&show=`
|
|
338
339
|
(1-indexed page, server caps `show` at `View.spec.limit`). Reserved
|
|
339
340
|
names — `page` / `show` / `cursor` — must NOT appear in
|
|
340
341
|
`spec.params.properties` (the parser rejects with
|
|
@@ -405,9 +406,12 @@ spec:
|
|
|
405
406
|
```
|
|
406
407
|
|
|
407
408
|
```ts
|
|
408
|
-
//
|
|
409
|
+
// src/mantle/config.ts
|
|
409
410
|
import { sendContactMessage } from "./handlers/send-contact-message";
|
|
410
|
-
|
|
411
|
+
|
|
412
|
+
export const handlers = {
|
|
413
|
+
"send-contact-message": sendContactMessage,
|
|
414
|
+
};
|
|
411
415
|
```
|
|
412
416
|
|
|
413
417
|
**v0.1 `requires.auth`**: `{ all: [<predicate>] }` only. Predicates:
|
|
@@ -442,11 +446,10 @@ the consumer guard handler, not in a new atom or Core repository. See
|
|
|
442
446
|
|
|
443
447
|
**v0.1.0 `handler.kind`**: `ref` (author-supplied function) or
|
|
444
448
|
`builtin` (SDK-supplied CRUD shortcut). For `builtin`, declare
|
|
445
|
-
`op: <create | update | upsert | delete>` and
|
|
446
|
-
in place of `ref`. The runtime dispatch path is
|
|
447
|
-
`InvokeBuiltinUseCase`;
|
|
448
|
-
|
|
449
|
-
runtime path.
|
|
449
|
+
`op: <create | update | upsert | delete | archive>` and
|
|
450
|
+
`schema: <Schema name>` in place of `ref`. The runtime dispatch path is
|
|
451
|
+
implemented by `InvokeBuiltinUseCase`; parser and boot validation fail closed
|
|
452
|
+
on unknown ops, Schemas, or incompatible lifecycle use.
|
|
450
453
|
|
|
451
454
|
**Postgres analogue**: `CREATE FUNCTION send_contact_message(input
|
|
452
455
|
JSONB) RETURNS JSONB LANGUAGE plpgsql AS $$ ... $$;`. PG functions are
|
|
@@ -467,7 +470,7 @@ kind: Trigger
|
|
|
467
470
|
metadata: { name: contact-http }
|
|
468
471
|
spec:
|
|
469
472
|
source:
|
|
470
|
-
kind: http # v0.1
|
|
473
|
+
kind: http # v0.1 also supports mcp and lifecycle
|
|
471
474
|
method: POST # POST | PUT | PATCH | DELETE
|
|
472
475
|
path: /api/contact # OpenAPI {param} syntax for path params
|
|
473
476
|
# path params auto-bind to identically-named input fields
|
|
@@ -484,7 +487,7 @@ shared.
|
|
|
484
487
|
**v0.1 `Trigger.source.kind`**: `http` (public endpoint), `mcp` (named
|
|
485
488
|
tool on `surface: public | staff`), or `lifecycle` (entry-writer hook). For `lifecycle`, declare `schema`,
|
|
486
489
|
`on: [<hook>, ...]` from `LifecycleHook`, and optional `errorPolicy`
|
|
487
|
-
(`abort`
|
|
490
|
+
(`abort` is the `before_*` default; `continue` is the `after_*` default).
|
|
488
491
|
Lifecycle hooks are wired through `LifecycleHookingEntryRepository`, so
|
|
489
492
|
MCP, admin, and builtin write paths share the same hook behavior.
|
|
490
493
|
|
|
@@ -494,8 +497,8 @@ MCP, admin, and builtin write paths share the same hook behavior.
|
|
|
494
497
|
The state-machine "lifecycle" from the Schema atom
|
|
495
498
|
(`Schema.spec.lifecycle: simple | editorial`) is a separate domain
|
|
496
499
|
that shares the word. The Schema setting governs which states an
|
|
497
|
-
entry can be in; lifecycle Triggers
|
|
498
|
-
|
|
500
|
+
entry can be in; shipped lifecycle Triggers govern what fires around
|
|
501
|
+
mutations.
|
|
499
502
|
|
|
500
503
|
**Postgres analogue**: `CREATE TRIGGER ... AFTER INSERT ON posts
|
|
501
504
|
EXECUTE FUNCTION ...` (lifecycle); `pg_cron` extension (cron); plus
|
|
@@ -771,10 +774,10 @@ narrow at v0.1.0 and grows in two tiers:
|
|
|
771
774
|
1. **v0.1.0 shipped** — grammar parses and runtime behavior is wired
|
|
772
775
|
in the current rebuild.
|
|
773
776
|
2. **v0.1.x committed** — on the patch-release roadmap. Spec is
|
|
774
|
-
documented; implementation lands within the v0.1 series.
|
|
775
|
-
|
|
777
|
+
documented; implementation lands within the v0.1 series. The unsupported
|
|
778
|
+
runtime path fails closed with a code naming the feature.
|
|
776
779
|
3. **DRAFT (v0.2+)** — speculative, gated by concrete consumer
|
|
777
|
-
demand.
|
|
780
|
+
demand. Parser/static validation rejects with `DRAFT_KEY_USED`. May or may
|
|
778
781
|
not ship — depends on whether real use cases apply pressure.
|
|
779
782
|
|
|
780
783
|
### v0.1.0 shipped
|
|
@@ -790,7 +793,7 @@ Full shape lives further down.
|
|
|
790
793
|
|
|
791
794
|
Grammar lives in v0.1.0. Runtime is the
|
|
792
795
|
`InvokeBuiltinUseCase` that dispatches `op: create | update | upsert
|
|
793
|
-
| delete` against the entry-writer chokepoint with `x-mantle-bind`
|
|
796
|
+
| delete | archive` against the entry-writer chokepoint with `x-mantle-bind`
|
|
794
797
|
stamping and `input ∩ Schema.properties` projection. Full shape lives
|
|
795
798
|
further down.
|
|
796
799
|
|
|
@@ -801,19 +804,18 @@ surface. Procedures/Views share `ctx.auth`/scope predicates and optional guard
|
|
|
801
804
|
orchestration across REST and MCP. Staff role is loaded live for each protected
|
|
802
805
|
call; staff Views remain absent and un-callable on public MCP.
|
|
803
806
|
|
|
804
|
-
### v0.1.x
|
|
807
|
+
### Detailed shipped grammar and v0.1.x reservation
|
|
805
808
|
|
|
806
809
|
> The `handler.kind: builtin` and `Trigger.source.kind: lifecycle`
|
|
807
|
-
> sections below
|
|
808
|
-
> `Schema.spec.lifecycle: editorial` subsection remains v0.1.x-
|
|
809
|
-
> committed proper.
|
|
810
|
+
> sections below describe shipped v0.1.0 behavior. Only the
|
|
811
|
+
> `Schema.spec.lifecycle: editorial` subsection remains v0.1.x-committed.
|
|
810
812
|
|
|
811
813
|
#### `Schema.spec.lifecycle: editorial` runtime
|
|
812
814
|
|
|
813
|
-
Grammar
|
|
814
|
-
|
|
815
|
-
runtime
|
|
816
|
-
|
|
815
|
+
Grammar and boot already accept the key, but `request_publish` emits
|
|
816
|
+
`LIFECYCLE_NOT_IN_V010` because the approval-queue runtime ships in v0.1.x.
|
|
817
|
+
When that runtime lands, the same manifest can use the publish workflow without
|
|
818
|
+
a grammar change.
|
|
817
819
|
|
|
818
820
|
#### `handler.kind: builtin` — thin shortcut over the storage adapter for trivial CRUD-shaped Procedures
|
|
819
821
|
|
|
@@ -832,11 +834,11 @@ spec:
|
|
|
832
834
|
|
|
833
835
|
| op | Behavior |
|
|
834
836
|
|---|---|
|
|
835
|
-
| `create` | INSERT a new row. Project `input ∩ Schema.spec.schema.properties`; stamp `x-mantle-bind` fields; status
|
|
837
|
+
| `create` | INSERT a new row. Project `input ∩ Schema.spec.schema.properties`; stamp `x-mantle-bind` fields; generated id; status is `draft`, or immediately `published` for `lifecycle: none`. |
|
|
836
838
|
| `update` | UPDATE in place. `input.id` + `input.expectedVersion` (OCC) required. Bumps version. |
|
|
837
839
|
| `upsert` | If `input.id` resolves, behaves as `update`; else as `create`. |
|
|
838
840
|
| `delete` | Hard DELETE by id. |
|
|
839
|
-
| `archive` | Soft-archive (status='archived').
|
|
841
|
+
| `archive` | Soft-archive (status='archived'). The manifest validator permits this builtin only for `editorial` Schemas; the archive transition itself is runtime-wired, while editorial approval/request-publish remains deferred. |
|
|
840
842
|
|
|
841
843
|
The Procedure's `input` is the contract with the *caller*. It MAY
|
|
842
844
|
declare fields the Schema does not (e.g. a Turnstile token). The
|
|
@@ -876,8 +878,8 @@ spec:
|
|
|
876
878
|
| `after_update` | After UPDATE. Default best-effort. |
|
|
877
879
|
| `before_delete` | Before DELETE. Throw cancels. |
|
|
878
880
|
| `after_delete` | After DELETE. Default best-effort. |
|
|
879
|
-
| `before_publish` | Before status
|
|
880
|
-
| `after_publish` | After status
|
|
881
|
+
| `before_publish` | Before any supported status transition to `published` (the shipped workflow is `simple`). |
|
|
882
|
+
| `after_publish` | After any supported status transition to `published` (the shipped workflow is `simple`). |
|
|
881
883
|
|
|
882
884
|
**Atomicity defaults by phase**:
|
|
883
885
|
- `before_*`: `errorPolicy: abort`. Handler throw cancels the
|
|
@@ -921,15 +923,15 @@ Cloudflare wiring, the 128 KB platform limit, retry/DLQ configuration,
|
|
|
921
923
|
idempotency, and legacy-envelope draining are specified in
|
|
922
924
|
[Deferred lifecycle hooks on Cloudflare Queues](deferred-lifecycle-queues.md).
|
|
923
925
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
926
|
+
`before_publish` and `after_publish` already wrap the shipped simple publish
|
|
927
|
+
transition. When editorial approval lands, the same hooks wrap its final
|
|
928
|
+
transition to `published`; no second hook grammar is planned.
|
|
927
929
|
|
|
928
930
|
### DRAFT (v0.2+, speculative)
|
|
929
931
|
|
|
930
932
|
Each item below lands when the first concrete real-world use case
|
|
931
|
-
forces it, not on speculation. Today, do not implement;
|
|
932
|
-
|
|
933
|
+
forces it, not on speculation. Today, do not implement; parser/static
|
|
934
|
+
validation rejects it with `DRAFT_KEY_USED`.
|
|
933
935
|
|
|
934
936
|
#### Schema future
|
|
935
937
|
- **`x-mantle-ref` auto-lift to virtual column** — when a property
|
|
@@ -983,13 +985,13 @@ validator rejects with `DRAFT_KEY_USED`.
|
|
|
983
985
|
#### Trigger future
|
|
984
986
|
- **`source.kind: cron`** with `expr:` — scheduled invocation.
|
|
985
987
|
- **`source.kind: queue`** — async fan-out / message-driven invocation.
|
|
986
|
-
- **`source.kind: lifecycle.foo`** — DRAFT extensions to the
|
|
988
|
+
- **`source.kind: lifecycle.foo`** — DRAFT extensions to the shipped
|
|
987
989
|
lifecycle hooks (e.g. `before_archive`, `after_request_publish`).
|
|
988
|
-
The 8 hooks listed in the
|
|
990
|
+
The 8 hooks listed in the detailed shipped section are the floor,
|
|
989
991
|
not the ceiling.
|
|
990
992
|
|
|
991
|
-
(Full lifecycle Trigger spec for the 8
|
|
992
|
-
in the
|
|
993
|
+
(Full lifecycle Trigger spec for the 8 shipped hooks lives
|
|
994
|
+
in the detailed section above. The remaining DRAFT items
|
|
993
995
|
below are the speculative v0.2+ shapes that haven't yet been promoted
|
|
994
996
|
to a committed roadmap.)
|
|
995
997
|
|
|
@@ -5,9 +5,9 @@ This document preserves the visual system from the retired
|
|
|
5
5
|
it looked like a maintained template, but the design work is still useful as a
|
|
6
6
|
reference for future themes.
|
|
7
7
|
|
|
8
|
-
Use this as a design specimen, not as implementation guidance.
|
|
9
|
-
|
|
10
|
-
and `
|
|
8
|
+
Use this as a design specimen, not as implementation guidance. Apply it through
|
|
9
|
+
the version-matched `mantle:theme` workflow and the generated project's owned
|
|
10
|
+
theme paths, such as `styles/globals.css`, `components/`, and `src/web/`.
|
|
11
11
|
|
|
12
12
|
## Design Thesis
|
|
13
13
|
|
|
@@ -209,10 +209,10 @@ will drift from the maintained SDK packages.
|
|
|
209
209
|
Revive it as one of these:
|
|
210
210
|
|
|
211
211
|
- A documented visual preset selectable during agent seeding.
|
|
212
|
-
- A
|
|
212
|
+
- A project-owned theme preset applied through `mantle:theme`.
|
|
213
213
|
- A generated design prompt that tells the provisioning agent how to style a
|
|
214
214
|
user's own brand.
|
|
215
215
|
|
|
216
|
-
Do not bring it back
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
Do not bring it back as a runnable starter in this SDK repository. Agents treat
|
|
217
|
+
runnable code as current product surface, so the preserved design belongs only
|
|
218
|
+
in this reference.
|
package/docs/labels.md
CHANGED
|
@@ -29,7 +29,7 @@ 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, render, 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` | `starters
|
|
32
|
+
| `area:starters` | External `aotter/mantle-starters` integration, release fanout, and the local moved-starter stub. |
|
|
33
33
|
| `area:skills` | `skills/*` agent briefs and install/extend/provision workflows. |
|
|
34
34
|
| `area:admin-ui` | `packages/mantle-admin-ui` React admin SPA. |
|
|
35
35
|
| `area:docs` | Repo-wide human docs, governance docs, ADR text, release docs, root README content, and cross-cutting documentation work. |
|
package/docs/media-uploads.md
CHANGED