@aotter/mantle 0.0.11-alpha.23 → 0.0.11-alpha.25

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Status
4
4
 
5
- Accepted (slimmed 2026-05-12 per Epic #116; original 2026-05-12).
5
+ Accepted (slimmed 2026-05-12 per Epic #116; letter surface suspended 2026-06-19).
6
6
 
7
7
  ## Decision
8
8
 
@@ -11,12 +11,14 @@ Every agent-authored mantle project carries two files at fixed paths. They serve
11
11
  | File | Audience | Size budget | Format |
12
12
  |---|---|---|---|
13
13
  | `AGENTS.md` | Any cross-tool agent harness (Codex / Cursor / Aider / Amp / Factory / Claude Code) | ~30 lines | Plain markdown |
14
- | `mantle/site.md` | Mantle (install / customize / deploy persona — Epic #47, scoped per Epic #116) | ~300 lines | Frontmatter + section bodies |
14
+ | `mantle/site.md` | Mantle install / customize / deploy context | ~300 lines | Frontmatter + section bodies |
15
15
 
16
16
  `AGENTS.md` answers "what is this and how do I run it." `mantle/site.md` carries the site's semantic layer:
17
17
 
18
18
  - Frontmatter: machine-readable (`archetype`, `brand`, `locales`, `site_url`, `revisions[]`, `futures[]`, `dont_touch[]`).
19
- - Body sections (`## site`, `## voice`, `## welcome` (5 cards), `## editor`, `## history`) each open with a `> purpose:` header so agents can route reads without parsing prose. Mantle reads the whole file on return, edits sections, writes the whole file back. **Atomic replace, not append.**
19
+ - Body sections (`## site`, `## voice`, `## editor`, `## history`) each open with a `> purpose:` header so agents can route reads without parsing prose. Mantle reads the whole file on return, edits sections, writes the whole file back. **Atomic replace, not append.**
20
+
21
+ The earlier `## welcome` 5-card letter surface is suspended. Provisioning must not block on prose completion in `mantle/site.md`; a first deploy should be possible from deterministic scaffold state.
20
22
 
21
23
  ## Placeholder macros
22
24
 
@@ -38,7 +40,7 @@ New macros must be added here, to `_common/*.template`, and to the substitution
38
40
 
39
41
  ## Update rules
40
42
 
41
- - **Mantle on return**: read whole `mantle/site.md`, edit relevant sections, write whole atomically, append one paragraph to `## history`. Voice rules (Epic #116 scope-narrow) apply only when editing the `## welcome` 5 cards and the closing handoff line.
43
+ - **Mantle on return**: read whole `mantle/site.md`, edit relevant sections, write whole atomically, append one paragraph to `## history`.
42
44
  - **provision on deploy**: rewrite frontmatter `site_url:` placeholder → real Workers URL; append a `revisions:` entry. Same `Public site:` rewrite in `AGENTS.md`. Single commit at end of provision.
43
45
  - **No mid-section staged-and-running mutation.** A section is prose-replaced atomically, or a frontmatter scalar/list is replaced — never partial writes.
44
46
 
@@ -50,6 +52,6 @@ New macros must be added here, to `_common/*.template`, and to the substitution
50
52
 
51
53
  - Templates: `mantle-starters/_common/AGENTS.md.template` and `mantle-starters/_common/mantle/site.md.template`.
52
54
  - Substitution: `packages/create-mantle/src/placeholder.ts`.
53
- - Install handoff: `skills/install/SKILL.md` describes the post-substitution prose-fill (HTML comments prose drawn from interview).
55
+ - Install handoff: `skills/install/SKILL.md` describes deterministic scaffold validation and the short post-substitution notes fill.
54
56
  - Provision update: `skills/provision/SKILL.md` describes the `site_url:` + `revisions:` write after deploy.
55
57
  - Theme overlay merge (Epic #116): `themes/<theme-key>/` overlay applies after the archetype starter and may touch `src/theme/` — never these two files.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aotter/mantle",
3
- "version": "0.0.11-alpha.23",
3
+ "version": "0.0.11-alpha.25",
4
4
  "description": "Umbrella entry for @aotter/mantle. Adopters install this one package and import from subpaths: /spec, /runtime, /cloudflare, /admin-ui. Sub-packages remain individually installable on npm for tooling / alt-adapter authors. The Netlify adapter ships as a private workspace stub in v0.1 — its subpath will be added when the impl lands in v0.2.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://mantle.tools/",
@@ -47,10 +47,10 @@
47
47
  "README.md"
48
48
  ],
49
49
  "dependencies": {
50
- "@aotter/mantle-admin-ui": "0.0.11-alpha.23",
51
- "@aotter/mantle-runtime": "0.0.11-alpha.23",
52
- "@aotter/mantle-spec": "0.0.11-alpha.23",
53
- "@aotter/mantle-cloudflare": "0.0.11-alpha.23"
50
+ "@aotter/mantle-admin-ui": "0.0.11-alpha.25",
51
+ "@aotter/mantle-runtime": "0.0.11-alpha.25",
52
+ "@aotter/mantle-spec": "0.0.11-alpha.25",
53
+ "@aotter/mantle-cloudflare": "0.0.11-alpha.25"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@cloudflare/workers-oauth-provider": "^0.7.0",
@@ -63,7 +63,7 @@
63
63
  "@cloudflare/workers-oauth-provider": "^0.7.0",
64
64
  "@types/node": "^25",
65
65
  "aws4fetch": "^1.0.20",
66
- "better-auth": "^1.6.11",
66
+ "better-auth": "^1.6.14",
67
67
  "hono": "^4.12.23",
68
68
  "typescript": "^6.0.3",
69
69
  "zod": "^4.4.2"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mantle install
3
- description: Install a mantle consumer project. Preferred path consumes a landing-created launch session and scaffolds immediately via create-mantle; fallback path is interview-driven, elicits the user's purpose/audience/timing/identity, then delegates the Mantle welcome letter to a background subagent. Use when the user pasted a launch command/session URL, a composed-skill URL generated by the landing page, or when starting from an empty repo.
3
+ description: Install a mantle consumer project. Preferred path consumes a landing-created launch session and scaffolds immediately via create-mantle; fallback path is interview-driven, elicits the user's purpose/audience/timing/identity, then scaffolds deterministically and continues to provision. Use when the user pasted a launch command/session URL, a composed-skill URL generated by the landing page, or when starting from an empty repo.
4
4
  when_to_invoke: |
5
5
  Empty repo + landing-page launch command/session URL; empty repo + landing-page composed-skill prompt; or the user describes a site they want to build. A composed URL may inline the per-archetype hint with this brief.
6
6
  ---
@@ -41,8 +41,7 @@ pnpm introspect # current manifest dump (atoms inventory)
41
41
  pnpm emit-openapi # generated HTTP surface
42
42
  pnpm emit-types # generated TS types
43
43
  pnpm validate # grammar + cross-ref check (preview phase by default).
44
- # For the pre-deploy gate (re-enables MANTLE_LETTER_NOT_WRITTEN
45
- # and any future production-only checks), use
44
+ # For production-only checks, use
46
45
  # `pnpm validate --phase deploy` or `pnpm validate:deploy`.
47
46
  ```
48
47
 
@@ -126,7 +125,7 @@ Listed in discovery order — purpose comes first, brand near the end. **Do not
126
125
 
127
126
  | Value | For |
128
127
  |---|---|
129
- | **purpose / audience / emotional weight** | Mantle subagent surfaces through the archetype probes; feeds the welcome letter |
128
+ | **purpose / audience / emotional weight** | site summary + future content direction; surfaces through the archetype probes |
130
129
  | **audience scope + locales** | `--locales` (count + first is canonical) |
131
130
  | **description** | `--description` — one-line site identity, agent-drafted in user's language |
132
131
  | **summary** | `--summary` — one-line install-moment marker, agent-drafted in user's language |
@@ -191,7 +190,7 @@ Invoking the `create-mantle` release tarball is **not low-risk work**. The comma
191
190
 
192
191
  - every page's SEO `<meta description>`
193
192
  - locale routing for the entire site (canonical + redirects)
194
- - Mantle's welcome-card surface in `## welcome`
193
+ - the persistent site notes in `mantle/site.md`
195
194
  - 22 starter files' `{{PLACEHOLDER}}` substitution
196
195
  - `revisions[0]` — the permanent install-moment entry in the changelog
197
196
 
@@ -209,7 +208,7 @@ Same discovery order as the Goal table above — purpose first, brand later. The
209
208
 
210
209
  | Value | Marker | Authorized when |
211
210
  |---|---|---|
212
- | **purpose / audience / emotional weight** | (feeds Mantle, not a CLI flag) | enough texture for Mantle's letter — surfaced through the archetype probes (open-question discovery), not inferred |
211
+ | **purpose / audience / emotional weight** | (not a CLI flag) | enough texture to summarize the site intent — surfaced through the archetype probes (open-question discovery), not inferred |
213
212
  | **audience scope** | (drives `<<LOCALES>>`) | user explicitly stated: domestic (which country / region) OR international (which language[s]) |
214
213
  | **locales** | `<<LOCALES>>` | derived from audience scope; user nodded on the resulting BCP 47 list |
215
214
  | **description** | `<<DESCRIPTION>>` | agent-drafted in user's language; user nodded on the exact one-liner |
@@ -230,7 +229,7 @@ If any value is unauthorized — including auto-derivation that "looks reasonabl
230
229
 
231
230
  3. **Read the RUN_NOTES.** The `files_written` list is your scaffold inventory. If `features` is non-empty, read `.mantle/features.json` and the generated `src/.mantle/generated.*.ts` glue before deciding anything else. Walk the ground-truth files — at minimum `manifests/`, `src/mantleConfig.ts`, `mantle/site.md` — before deciding anything else.
232
231
 
233
- 4. **Adjustment window** (optional, see § below). Only if the interview surfaced a concrete deletion or single-field gap. Always `pnpm validate` after edit; commit before the Mantle subagent runs.
232
+ 4. **Adjustment window** (optional, see § below). Only if the interview surfaced a concrete deletion or single-field gap. Always `pnpm validate` after edit.
234
233
 
235
234
  5. **Validate locally:**
236
235
 
@@ -239,9 +238,9 @@ If any value is unauthorized — including auto-derivation that "looks reasonabl
239
238
  pnpm typecheck
240
239
  ```
241
240
 
242
- `pnpm validate` runs in the **preview phase** by default — grammar + cross-Schema checks only. `MANTLE_LETTER_NOT_WRITTEN` is silenced here on purpose (it's a deploy-only gate), so this step is expected to exit 0 on a fresh scaffold. Anything non-zero → surface `code` + `suggestion` verbatim.
241
+ `pnpm validate` runs in the **preview phase** by default — grammar + cross-Schema checks only. Anything non-zero → surface `code` + `suggestion` verbatim.
243
242
 
244
- The deploy-phase variant (`pnpm validate --phase deploy`, or `pnpm validate:deploy` if the starter ships that script) re-enables `MANTLE_LETTER_NOT_WRITTEN`; provision runs that before `wrangler deploy`. Until step 9 fills the welcome letter cards, deploy-phase will fail — that's the intended sequencing.
243
+ The deploy-phase variant (`pnpm validate --phase deploy`, or `pnpm validate:deploy` if the starter ships that script) is safe to run on a fresh scaffold. It must not block on unfinished prose in `mantle/site.md`.
245
244
 
246
245
  **Then set up `.dev.vars` so `pnpm dev` works.** Starters that ship `.dev.vars.example` (publication / transaction / intake / presence) require a real `BETTER_AUTH_SECRET` before `pnpm dev` — the worker returns `auth_not_configured` on every request until it's filled. Copy the file, generate a value, and write it in:
247
246
 
@@ -257,56 +256,32 @@ If any value is unauthorized — including auto-derivation that "looks reasonabl
257
256
 
258
257
  When the public home route is empty/404, tell the user plainly: "the worker is running; the public homepage has no content yet." Then ask whether they want a **local preview seed** so they can see the homepage and, for post-shaped archetypes, a couple of sample posts in the browser. Do not run generic test fixtures or seed content without explicit consent. If they say yes, keep the seed preview-only and local: use user-approved copy from the interview or step 6 drafting, make it clear it is not production content, and do not commit local DB/KV artifacts or `.dev.vars`. If they say no, continue with the install flow; production content can be created later through `/admin` or MCP.
259
258
 
260
- 6. **Pre-provision dialogue preview + voice elicitation (this is a chatter zone, not a checklist).**
259
+ 6. **Write the deterministic `mantle/site.md` notes in your normal register.**
261
260
 
262
- Before writing `mantle/site.md` prose or dispatching the Mantle subagent, open a small conversation with the user. The goals are (a) let them peek at what just got built, (b) **draw voice material out of them by writing something concrete together** rather than asking abstract "what's your register" questions.
263
-
264
- Read RUN_NOTES `files_written` to see which collections the archetype actually ships. The drafting medium depends on what's there:
265
-
266
- - **Archetypes with a post-like collection** (`publication`, `community`, `membership`): offer to draft 1–2 sample posts/entries. Propose 2–4 topics anchored in what the interview surfaced (training log, a parenting moment, a brand-voice opener, etc.). Let the user pick, add, kill. Drafts get saved to `mantle/drafts/<slug>.md`; admin can pick them up later.
267
- - **Archetypes without posts** (`presence`, `intake`, `transaction`, `reservation`, `blank`): no `posts` collection exists — **do not fabricate one**. Instead, offer to draft one short concrete piece of copy the archetype actually needs: the home-page opening sentence, the intake form intro, the reservation page tagline. One paragraph max. Save into `mantle/drafts/home-opener.md` (or similar archetype-fitting name) only if the user wants it kept.
268
- - **Roadmap archetypes**: skip this step entirely. The refuse path already routed the conversation.
269
-
270
- For any drafting that happens, the dynamic is the same: show the user, let them react, capture the reactions. Each correction / line cut / tone push / pronoun-choice complaint is gold for voice elicitation.
271
-
272
- For cover images (post-shaped drafts only): use LoremFlickr (`source.unsplash.com` was deprecated in 2023; LoremFlickr is the closest keyword-based replacement). Pick 1–3 comma-separated keywords from the draft content. URL pattern: `https://loremflickr.com/<width>/<height>/<keyword1>,<keyword2>`. **Verify each URL resolves with a GET request before embedding — expect a 302 redirect to a cached JPG (`curl -sL -o /dev/null -w "%{http_code} %{content_type}"`), and confirm final status is 200 and content-type starts with `image/`.** Don't use `HEAD` — LoremFlickr's resized-cache path responds to GET only. If verification fails, leave the cover slot empty and tell the user.
273
-
274
- This step's length is responsive to the user. Curt user / no-deadline / "just go" → keep it to one offer and skip on a no. Engaged user → spend 5–10 minutes drafting together. The investment here pays off in the next step.
275
-
276
- 7. **Write the non-letter `mantle/site.md` sections + the editor `first_prompt:` body in your normal register.**
277
-
278
- You fill these — Mantle (the subagent in step 9) only owns the welcome letter cards. Use what came out of the interview + step 6's drafting dialogue. **Reflect what the user said and how they reacted.** Imagination is fine where the user left blank space; don't fabricate vocabulary they pushed back on or never used.
261
+ Keep this short and practical. The goal is to persist what the user authorized so the next agent is not guessing, not to finish brand prose before deploy.
279
262
 
280
263
  - `## site` — one paragraph reflecting why this site exists.
281
- - `## voice` — a few lines of register markers, with priority on phrases the user actually used / words they killed during drafting / titles they liked vs hated. If voice didn't surface concretely, write SHORT; honest brevity beats invented detail.
282
- - `## history` — one paragraph: what was decided, what the user said in their words, what's still open. Note any emotional weight (excited / anxious / curt / grieving). If you drafted posts in step 6, mention the drafts + how user reacted — Mantle reads this as transcript material.
264
+ - `## voice` — a few honest register markers only when the user gave you real language or reactions. If voice did not surface, write short.
265
+ - `## history` — one paragraph: what was decided, what the user said in their words, and what's still open.
283
266
  - `## editor first_prompt:` body — mechanical fill. Copy the archetype hint's `Editor first-prompt template` block, substitute `<<BRAND>>` with the actual brand, paste as plain text under the YAML `first_prompt: |` key (indented properly).
284
267
 
285
- 8. **Get the Mantle subagent prompt:**
268
+ 7. **Run deploy validation.**
286
269
 
287
270
  ```bash
288
- pnpm -s mantle:prompt > /tmp/mantle-letter-prompt.md
271
+ pnpm validate:deploy
289
272
  ```
290
273
 
291
- `-s` suppresses pnpm's banner so the file is just the prompt body. The script reads `mantle/site.md` (frontmatter + your `## site` / `## voice` / `## history` sections), fetches the archetype hint from `mantle-starters`, substitutes `<<MANTLE_*>>` placeholders in the scaffolded `mantle-subagent-prompt.md`, prints to stdout. Fails fast if any of the three sections still hold template placeholders.
292
-
293
- 9. **Dispatch the Mantle subagent (in background)** with `/tmp/mantle-letter-prompt.md` as its only prompt body. Use a `general-purpose` subagent with `run_in_background: true`.
294
-
295
- The subagent writes **three welcome cards** (card1 with Mantle's self-intro + a noticed detail; card4 — when you need me back; card5 — done + closing line) plus the closing handoff line at the end of `## welcome`. Cards 2 (mcp install command) and 3 (editor first prompt) are mechanical — admin UI renders them at display time from `<SITE_URL>`, the brand, and your filled `## editor first_prompt:`. They don't live in `mantle/site.md`.
296
-
297
- **You stay in your normal register throughout.** You never write the welcome letter yourself; Mantle's voice is encapsulated in the subagent prompt template that `pnpm mantle:prompt` filled. This is the whole reason for the delegation — register isolation. Don't peek-and-confirm the cards before they're written; the letter is a small surprise the user discovers in `mantle/site.md`.
298
-
299
- While the subagent works, prepare provision context: `gh auth status`, confirm the GitHub identity from the interview matches. If `gh auth status` reports an invalid token, missing login, or the wrong GitHub account, do not end with a bare "run `gh auth login`" instruction. Say that install is complete and provision is blocked only on GitHub re-auth, tell the user exactly which login is expected, ask them to run `gh auth login -h github.com` (or switch accounts) and reply when done, then resume from provision preflight in the same conversation.
274
+ If the project only exposes the CLI command, run `pnpm validate --phase deploy`. This is the readiness gate before handing off to provision.
300
275
 
301
- 10. **When the Mantle subagent returns**, run `pnpm validate --phase deploy` (or `pnpm validate:deploy` if the starter ships that script) — `MANTLE_LETTER_NOT_WRITTEN` should now clear, since the cards are filled. If it still fires, card1 / card4 / card5 weren't all written; check the subagent's reply for what went wrong, fix or re-dispatch. This is also the readiness gate before handing off to provision.
276
+ 8. **Commit.** If step 4 produced an adjustment, that's its own commit. Then the main commit: `mantle: deterministic scaffold`.
302
277
 
303
- 11. **Commit.** If step 4 produced an adjustment, that's its own commit. Then the main commit: `mantle: notes from install interview`.
278
+ 9. **Continue to provision — don't push a URL onto the user.** Provision is the next phase in the same conversation. If you came from the fallback composed-prompt path, replace `install` with `provision` in the composed URL you read at the start, keep the same `?type=`, `?theme=`, and future `?feature=` query values, fetch that URL, follow it. If you came from launch-session path, read `.mantle/launch-state.json` for the GitHub owner/admin metadata, then fetch `https://raw.githubusercontent.com/aotter/mantle/develop/skills/provision/SKILL.md` unless the landing origin supplied a provision URL.
304
279
 
305
- 12. **Continue to provision don't push a URL onto the user.** Provision is the next phase in the same conversation. If you came from the fallback composed-prompt path, replace `install` with `provision` in the composed URL you read at the start, keep the same `?type=`, `?theme=`, and future `?feature=` query values, fetch that URL, follow it. If you came from launch-session path, read `.mantle/launch-state.json` for the GitHub owner/admin metadata, then fetch `https://raw.githubusercontent.com/aotter/mantle/develop/skills/provision/SKILL.md` unless the landing origin supplied a provision URL. The user's next involvement is supplying the Cloudflare API token when provision asks — everything before that is your job. If GitHub CLI auth is invalid, the user's next involvement is re-auth first; after they reply that it is fixed, re-run `gh auth status` and then continue provision. Don't promise production-readiness until provision completes and a second agent connects through MCP.
280
+ The current provision shape is deterministic first: create/push the private GitHub repo, guide the user through Cloudflare's GitHub-backed first deploy, then use Wrangler to take over follow-up bindings/secrets/migrations. If GitHub CLI auth is invalid, the user's next involvement is re-auth first; after they reply that it is fixed, re-run `gh auth status` and then continue provision. Don't promise production-readiness until provision completes and a second agent connects through MCP.
306
281
 
307
282
  ## Adjustment window — between scaffold and provision
308
283
 
309
- A permitted modification turn after `create-mantle` returns and before the Mantle subagent fires. Small concrete edits to match what the user said.
284
+ A permitted modification turn after `create-mantle` returns and before provision starts. Small concrete edits to match what the user said.
310
285
 
311
286
  ### In scope
312
287
 
@@ -327,13 +302,12 @@ A permitted modification turn after `create-mantle` returns and before the Mantl
327
302
 
328
303
  ### Discipline
329
304
 
330
- - `pnpm validate` after every edit. Non-clean tree never advances to the Mantle subagent.
305
+ - `pnpm validate` after every edit. Non-clean tree never advances to provision.
331
306
  - Show the diff before applying. A deleted manifest deserves a one-line confirm.
332
307
  - Don't speculate. "I think you might also want X" is generation, not interview.
333
308
 
334
309
  ## Don't
335
310
 
336
- - Don't put on Mantle's voice yourself — that's the subagent's job. Register isolation is the whole point of the delegation in step 9.
337
311
  - Don't write into `src/theme.default/` or any "system-looking" path during install — design changes happen after deploy via the customize-design skill.
338
312
  - Don't keep speaking after the handoff to provision — the handoff IS the end of this Skill.
339
- - Don't echo the same specific user detail across multiple cards (that's Mantle's rule, but you also shouldn't paste card1's detail back into `## site` — let each section have its own).
313
+ - Don't echo the same specific user detail across every generated note — let each section have its own job.
@@ -112,6 +112,45 @@ read -rsp "GitHub OAuth client secret: " GITHUB_CLIENT_SECRET && export GITHUB_C
112
112
  pnpm run provision:up -- --worker-url <worker-url> --github-username <gh-login> --client-id <client-id>
113
113
  ```
114
114
 
115
+ ## Presenting browser steps (non-coder handoff)
116
+
117
+ Flow steps 3 and 5 hand the user into a browser. That user is usually a
118
+ non-coder who is trusting the agent — present those steps the way you'd
119
+ guide someone over the phone, not as a terse engineer checklist. The
120
+ plan that `provision:plan` prints is *your* reference; re-present it, do
121
+ not paste it through.
122
+
123
+ Rules:
124
+
125
+ - **One task at a time.** Send the Cloudflare deploy, wait for the URL,
126
+ *then* send the GitHub OAuth App. Never dump both browser tasks in one
127
+ message.
128
+ - **Number only what they see.** Label the block `STEP 1 of 2` /
129
+ `STEP 2 of 2`. Do not leak your internal plan numbering — a user
130
+ seeing "Step 2" and "Step 4" with gaps assumes they missed something.
131
+ - **Lead with one plain "why".** A single sentence on what the step
132
+ accomplishes ("this is what puts your site on the internet").
133
+ - **Full-sentence click paths, not arrows.** "Click *Create
134
+ application*, then open the *Import a repository* tab" — not
135
+ `Create application → Import a repository`. Quote the exact labels the
136
+ user sees on screen.
137
+ - **Say what they'll see and what to copy.** Name the landmark and the
138
+ success signal ("a link ending in `.workers.dev` — copy that"), and a
139
+ rough time ("about a minute").
140
+ - **Ask for values in plain language.** "Paste me the live link, and
141
+ the Client ID." Never ask for `KEY=value` shell syntax, and never make
142
+ them type literal `<...>` placeholders.
143
+ - **Protect the secret in words, not jargon.** Tell them to copy the
144
+ Client Secret and keep it on their clipboard, and that you'll ask for
145
+ it privately so it never lands in the chat. Don't say "stdin" or "env".
146
+ - **Give an escape hatch.** "If a screen doesn't match what I describe,
147
+ paste a screenshot and I'll point you to the right button."
148
+
149
+ Keep agent-internal correctness rules out of the user-facing text. The
150
+ `localhost` / `127.0.0.1` callback rule (see Don't) governs what *you*
151
+ write; a dashboard user is handed the real Worker URL and never needs to
152
+ hear that warning.
153
+
115
154
  ## Flow
116
155
 
117
156
  1. **Preflight.** Read `.mantle/launch-state.json` if present, then
@@ -136,6 +175,8 @@ pnpm run provision:up -- --worker-url <worker-url> --github-username <gh-login>
136
175
  Cloudflare Dashboard, create a Worker, choose GitHub as source, pick
137
176
  the repo, keep the Worker name aligned with the repo/project name,
138
177
  and run the first deploy. They report the deployed Worker URL back.
178
+ Present this as `STEP 1 of 2` per **Presenting browser steps** above,
179
+ and wait for the Worker URL before moving on.
139
180
 
140
181
  4. **Print the plan.**
141
182
 
@@ -156,7 +197,10 @@ pnpm run provision:up -- --worker-url <worker-url> --github-username <gh-login>
156
197
  `<worker-url>/api/auth/callback/github`
157
198
  - Device Flow: unchecked
158
199
 
159
- The user returns Client ID and Client Secret.
200
+ Present this as `STEP 2 of 2` per **Presenting browser steps** above.
201
+ Ask for the Client ID in chat; have them keep the Client Secret on
202
+ the clipboard for the hidden prompt in step 6 — do not ask them to
203
+ paste the secret in chat.
160
204
 
161
205
  6. **Authorize Wrangler and run provision.**
162
206
 
@@ -220,7 +264,7 @@ accepts any extra provider/billing requirement.
220
264
  ## Handoff
221
265
 
222
266
  After smoke checks pass, render a short final handoff in the user's
223
- language:
267
+ language, in plain words (no `wrangler.toml` / secret / CLI jargon):
224
268
 
225
269
  - Public URL.
226
270
  - Admin sign-in URL.
@@ -253,3 +297,7 @@ repo-local `.agent/skills/` directory.
253
297
  locally and the real Worker URL in production.
254
298
  - Don't use `/admin/auth/github/callback`; the Better Auth callback path
255
299
  is `/api/auth/callback/github`.
300
+ - Don't recite a browser step to a non-coder as a terse `A → B → C`
301
+ breadcrumb, a `KEY=value` reply contract, a `<placeholder>` they might
302
+ paste literally, or an internal correctness warning (e.g. the
303
+ `127.0.0.1` rule). See **Presenting browser steps**.