create-ailk 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +68 -0
  2. package/component-catalog.json +279 -45
  3. package/dist/add-module.d.ts +20 -0
  4. package/dist/add-module.js +43 -7
  5. package/dist/add-route.d.ts +56 -0
  6. package/dist/add-route.js +286 -0
  7. package/dist/apply-design-md.d.ts +7 -0
  8. package/dist/apply-design-md.js +50 -0
  9. package/dist/apply-design.d.ts +64 -0
  10. package/dist/apply-design.js +273 -0
  11. package/dist/claude-md.d.ts +111 -0
  12. package/dist/claude-md.js +334 -0
  13. package/dist/cli.js +92 -4
  14. package/dist/derive-architecture.js +41 -36
  15. package/dist/design-compile.d.ts +71 -0
  16. package/dist/design-compile.js +98 -0
  17. package/dist/design-package.d.ts +83 -0
  18. package/dist/design-package.js +468 -0
  19. package/dist/design-presets.d.ts +86 -0
  20. package/dist/design-presets.js +642 -0
  21. package/dist/design-scaffold.d.ts +76 -0
  22. package/dist/design-scaffold.js +220 -0
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.js +4 -1
  25. package/dist/legacy-nav-renderers.d.ts +45 -0
  26. package/dist/legacy-nav-renderers.js +545 -0
  27. package/dist/lib/auth-secret-file.d.ts +19 -0
  28. package/dist/lib/auth-secret-file.js +112 -0
  29. package/dist/lib/design-checks.d.ts +78 -0
  30. package/dist/lib/design-checks.js +174 -0
  31. package/dist/lib/license-key-files.d.ts +9 -0
  32. package/dist/lib/license-key-files.js +2 -2
  33. package/dist/lib/module-license-gate.d.ts +19 -9
  34. package/dist/lib/module-license-gate.js +19 -8
  35. package/dist/lib/render-verdict.d.ts +52 -0
  36. package/dist/lib/render-verdict.js +77 -0
  37. package/dist/lib/scaffold-render-sweep.d.ts +105 -0
  38. package/dist/lib/scaffold-render-sweep.js +236 -0
  39. package/dist/module-architecture.d.ts +19 -16
  40. package/dist/module-architecture.js +64 -21
  41. package/dist/parse-args.d.ts +12 -2
  42. package/dist/parse-args.js +74 -13
  43. package/dist/programmatic.d.ts +30 -6
  44. package/dist/programmatic.js +206 -17
  45. package/dist/site-chrome.d.ts +19 -9
  46. package/dist/site-chrome.js +23 -13
  47. package/dist/site-manifest.d.ts +25 -0
  48. package/dist/site-manifest.js +254 -0
  49. package/dist/site-roster.d.ts +41 -0
  50. package/dist/site-roster.js +141 -8
  51. package/dist/starter-grid.d.ts +32 -16
  52. package/dist/starter-grid.js +129 -33
  53. package/dist/surfaces.d.ts +41 -9
  54. package/dist/surfaces.js +200 -83
  55. package/dist/template-manifest.d.ts +30 -13
  56. package/dist/template-manifest.js +49 -24
  57. package/package.json +5 -4
  58. package/site-templates/_base/content/en/UseCase/persona-1.mdx +7 -6
  59. package/site-templates/_base/content/en/UseCase/persona-2.mdx +7 -6
  60. package/site-templates/_base/content/en/UseCase/persona-3.mdx +7 -6
  61. package/site-templates/{minimalism-site/TEMPLATE-MANIFEST.json → aliases/minimalism-site.TEMPLATE-MANIFEST.json} +72 -40
  62. package/site-templates/designs/minimalism/DESIGN.md +98 -6
  63. package/site-templates/designs/minimalism/sample/README.md +48 -0
  64. package/site-templates/designs/standard/DESIGN.md +98 -6
  65. package/site-templates/marketing-site/DESIGN.md +98 -6
  66. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +60 -27
  67. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +50 -30
  68. package/site-templates/marketing-site-free/DESIGN.md +98 -6
  69. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +60 -24
  70. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +44 -27
  71. package/site-templates/marketing-site-free/ailk-template.json +1 -1
  72. package/site-templates/saas-product/DESIGN.md +98 -6
  73. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +127 -18
  74. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +74 -20
  75. package/site-templates/shapes/local-business-service/ailk-template.json +1 -1
  76. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +127 -18
  77. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +74 -20
  78. package/site-templates/shapes/organization-service/ailk-template.json +1 -1
  79. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +127 -18
  80. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +75 -21
  81. package/site-templates/shapes/person-service/ailk-template.json +1 -1
  82. package/site-templates/shapes/person-service/content/en/AboutPage/about.mdx +1 -1
  83. package/site-templates/shapes/person-service/content/en/HomePage/home.mdx +2 -2
  84. package/site-templates/shapes/person-service/content/en/PortfolioList/portfolio.mdx +4 -2
  85. package/site-templates/shapes/person-service/content/en/ServicesList/services.mdx +1 -1
  86. package/templates/.claude/rules/architecture.md +7 -0
  87. package/templates/.claude/skills/README.md +3 -2
  88. package/templates/.claude/skills/add-auth/references/env-vars.md +22 -15
  89. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +3 -2
  90. package/templates/.claude/skills/add-page/SKILL.md +241 -238
  91. package/templates/.claude/skills/add-page/references/page-types.md +85 -76
  92. package/templates/.claude/skills/add-page/scripts/site-pages.mjs +87 -0
  93. package/templates/.claude/skills/add-page/templates/comparison-page.mdx.tmpl +99 -0
  94. package/templates/.claude/skills/add-page/templates/content.mdx.tmpl +8 -18
  95. package/templates/.claude/skills/add-page/templates/flow-landing-page.mdx.tmpl +43 -0
  96. package/templates/.claude/skills/add-page/templates/report-page.mdx.tmpl +52 -0
  97. package/templates/.claude/skills/add-page/templates/reports-list.mdx.tmpl +38 -0
  98. package/templates/.claude/skills/check-site/SKILL.md +23 -0
  99. package/templates/.claude/skills/fill-page/SKILL.md +26 -7
  100. package/templates/.claude/skills/fill-page/profiles/plumbing.yaml +1 -1
  101. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +28 -11
  102. package/templates/.claude/skills/update-page/SKILL.md +117 -0
  103. package/templates/.claude/skills/update-page/scripts/update-page.ts +640 -0
  104. package/templates/.claude/skills/update-page/templates/redirects.mjs.tmpl +31 -0
  105. package/templates/.claude/skills/upgrade-plan/SKILL.md +12 -8
  106. package/templates/.github/workflows/ci.yml +4 -0
  107. package/templates/.prettierignore +1 -0
  108. package/templates/CLAUDE.md +146 -103
  109. package/templates/DESIGN.md +98 -6
  110. package/templates/README.md +50 -38
  111. package/templates/apps/api/.env.example +2 -1
  112. package/templates/apps/api/src/__tests__/commerce-claim-registration.test.ts +2 -0
  113. package/templates/apps/api/src/__tests__/server.test.ts +116 -0
  114. package/templates/apps/api/src/lib/stripe.ts +9 -0
  115. package/templates/apps/api/src/middleware/__tests__/auth.optional-cookie.test.ts +140 -0
  116. package/templates/apps/api/src/middleware/auth.ts +54 -0
  117. package/templates/apps/api/src/routes/checkout/__tests__/session.test.ts +5 -2
  118. package/templates/apps/api/src/routes/checkout/__tests__/sessions.test.ts +628 -0
  119. package/templates/apps/api/src/routes/checkout/sessions.ts +222 -24
  120. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-flow-checkout.test.ts +1 -1
  121. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-org-billing.test.ts +5 -1
  122. package/templates/apps/api/src/routes/webhooks/__tests__/stripe.test.ts +521 -20
  123. package/templates/apps/api/src/routes/webhooks/stripe.ts +124 -32
  124. package/templates/apps/api/src/server.ts +28 -0
  125. package/templates/apps/api/src/services/__tests__/revalidation.test.ts +90 -15
  126. package/templates/apps/api/src/services/checkout-buyer.ts +72 -0
  127. package/templates/apps/api/src/services/revalidation.ts +60 -15
  128. package/templates/apps/mcp/__tests__/tools/create_project.test.ts +30 -24
  129. package/templates/apps/mcp/src/tools/purchase.ts +4 -2
  130. package/templates/apps/web/.env.example +13 -0
  131. package/templates/apps/web/CLAUDE.md +22 -28
  132. package/templates/apps/web/app/[locale]/(auth)/layout.tsx +1 -1
  133. package/templates/apps/web/app/[locale]/(authed)/leads/__tests__/page.test.tsx +24 -0
  134. package/templates/apps/web/app/[locale]/(authed)/leads/page.tsx +17 -6
  135. package/templates/apps/web/app/[locale]/[slug]/[detail]/__tests__/page.test.tsx +110 -0
  136. package/templates/apps/web/app/[locale]/[slug]/[detail]/page.tsx +60 -0
  137. package/templates/apps/web/app/[locale]/[slug]/page.tsx +1 -1
  138. package/templates/apps/web/app/[locale]/alternatives/__tests__/page.test.tsx +161 -0
  139. package/templates/apps/web/app/[locale]/alternatives/page.tsx +104 -0
  140. package/templates/apps/web/app/[locale]/{use-cases → for}/[slug]/page.tsx +4 -3
  141. package/templates/apps/web/app/[locale]/for/__tests__/page-renderer-migration.test.tsx +73 -0
  142. package/templates/apps/web/app/[locale]/{use-cases → for}/page.tsx +8 -7
  143. package/templates/apps/web/app/[locale]/glossary/page.tsx +1 -1
  144. package/templates/apps/web/app/[locale]/layout.tsx +35 -19
  145. package/templates/apps/web/app/[locale]/newsletter/page.tsx +1 -1
  146. package/templates/apps/web/app/[locale]/portfolio/[slug]/page.tsx +1 -1
  147. package/templates/apps/web/app/[locale]/portfolio/page.tsx +1 -1
  148. package/templates/apps/web/app/[locale]/vs/[slug]/__tests__/page.test.tsx +112 -0
  149. package/templates/apps/web/app/[locale]/vs/[slug]/page.tsx +70 -0
  150. package/templates/apps/web/app/api/revalidate/__tests__/route.test.ts +236 -44
  151. package/templates/apps/web/app/api/revalidate/route.ts +78 -36
  152. package/templates/apps/web/lib/__tests__/site-brand.test.ts +79 -0
  153. package/templates/apps/web/lib/__tests__/site-theme.test.ts +104 -11
  154. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +21 -4
  155. package/templates/apps/web/lib/locale-guard.ts +18 -0
  156. package/templates/apps/web/lib/meet-placeholder.ts +5 -0
  157. package/templates/apps/web/lib/nav-config.ts +14 -13
  158. package/templates/apps/web/lib/site-brand.tsx +13 -9
  159. package/templates/apps/web/lib/site-logo.tsx +36 -0
  160. package/templates/apps/web/lib/site-theme.ts +46 -26
  161. package/templates/apps/web/messages/en.json +23 -9
  162. package/templates/apps/web/middleware.ts +28 -4
  163. package/templates/content/en/BookCall/book-a-call.mdx +80 -0
  164. package/templates/content/en/BookCall/onsite-estimate.mdx +56 -0
  165. package/templates/content/en/BookCall/onsite-service.mdx +56 -0
  166. package/templates/content/en/BookCall/start-project.mdx +56 -0
  167. package/templates/content/en/ContactPage/contact.mdx +40 -1
  168. package/templates/content/en/HomePage/home.mdx +2 -6
  169. package/templates/content/en/LandingPage/meet.mdx +59 -0
  170. package/templates/content/en/UseCasesList/{use-cases.mdx → for.mdx} +19 -18
  171. package/templates/database/CHANGELOG.md +7 -0
  172. package/templates/database/package.json +1 -1
  173. package/templates/package.json +2 -1
  174. package/templates/tools/check-claude-md.ts +128 -0
  175. package/versions.json +33 -33
  176. package/site-templates/_base/content/en/BookCall/book-call.mdx +0 -52
  177. package/site-templates/minimalism-site/DESIGN.md +0 -162
  178. package/site-templates/minimalism-site/TEMPLATE-MANIFEST.md +0 -458
  179. package/site-templates/minimalism-site/ailk-template.json +0 -23
  180. package/site-templates/minimalism-site/content/en/AboutPage/about.mdx +0 -110
  181. package/site-templates/minimalism-site/content/en/BookCall/book-call.mdx +0 -52
  182. package/site-templates/minimalism-site/content/en/ContactPage/contact.mdx +0 -34
  183. package/site-templates/minimalism-site/content/en/FAQPage/faq.mdx +0 -57
  184. package/site-templates/minimalism-site/content/en/LandingPage/referral.mdx +0 -77
  185. package/site-templates/minimalism-site/content/en/LandingPage/reports.mdx +0 -73
  186. package/site-templates/minimalism-site/content/en/PurchasePolicyPage/purchase-policy.mdx +0 -123
  187. package/site-templates/minimalism-site/content/en/ReportPage/annual-letter-2024.mdx +0 -52
  188. package/site-templates/minimalism-site/content/en/ReportPage/field-notes-2023.mdx +0 -52
  189. package/site-templates/minimalism-site/content/en/ReportPage/platform-shift-2025.mdx +0 -52
  190. package/site-templates/minimalism-site/content/en/ReportPage/state-of-the-market-2026.mdx +0 -52
  191. package/site-templates/minimalism-site/content/en/Service/first-engagement.mdx +0 -38
  192. package/site-templates/minimalism-site/content/en/Service/second-engagement.mdx +0 -38
  193. package/site-templates/minimalism-site/content/en/Service/third-engagement.mdx +0 -38
  194. package/site-templates/minimalism-site/content/en/ServicesList/services.mdx +0 -73
  195. package/site-templates/minimalism-site/flows/referral.flow.json +0 -71
  196. package/site-templates/minimalism-site/provenance.json +0 -4
  197. package/templates/.claude/skills/add-page/templates/route.tsx.tmpl +0 -28
  198. package/templates/apps/web/app/[locale]/book-a-call/page.tsx +0 -50
  199. package/templates/apps/web/app/[locale]/use-cases/__tests__/page-renderer-migration.test.tsx +0 -72
  200. /package/site-templates/{minimalism-site → designs/minimalism/sample}/content/en/HomePage/home.mdx +0 -0
  201. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-1.svg +0 -0
  202. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-2.svg +0 -0
  203. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-3.svg +0 -0
  204. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-4.svg +0 -0
  205. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-5.svg +0 -0
  206. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/avatar-placeholder-6.svg +0 -0
  207. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/hero-backdrop.svg +0 -0
  208. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-1.svg +0 -0
  209. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-2.svg +0 -0
  210. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/logo-placeholder-3.svg +0 -0
  211. /package/site-templates/{minimalism-site/assets → designs/minimalism/sample/public}/wordmark-placeholder.svg +0 -0
@@ -1,257 +1,260 @@
1
1
  ---
2
2
  name: add-page
3
- description: Generate a new page on an AILK consumer site — App Router route + MDX content stub + typed JSON-LD attachment — in a single confirm-before-write pass. Use when the user says "scaffold me a /pricing page", "add an about page", "create a /contact route", or hands over a structured triple (e.g., "add home — Organization — anchor with hero, value prop, CTA"). Both invocation shapes flow through the same pipeline. MDX-only at v1; refuses on existing routes and points at the `schema:` frontmatter override for adding structured data to a page that already exists.
3
+ description: Add a new page to this AI Launch Kit site — a new service, a new "who it's for" page, a new booking page, a comparison against a competitor, a stand-alone landing page, or a whole route the site doesn't carry yet like /pricing — with its content file, its structured data and its nav link, in one confirm-before-write pass. Use this whenever the user wants a page that doesn't exist yet, even if they don't say "page" — "add a service for kitchen remodels", "I need a /pricing page", "make a page for dentists", "add a comparison with Acme", "we need a booking page for on-site estimates", "add a landing page for the spring offer", or a structured triple like "pricing — Pricing — plans and FAQ". Not for changing a page that already exists (fill-page writes content; update-page renames).
4
4
  ---
5
5
 
6
6
  # add-page
7
7
 
8
- Generate a new page in one pass. Three artifacts emit together:
8
+ Add a page this site can actually serve, at the path its routes really use,
9
+ with a nav link, and nothing else. One plan, one confirmation, then write.
9
10
 
10
- 1. **App Router route** at `app/<slug>/page.tsx`
11
- 2. **MDX content stub** at `content/<Type>/<slug>.mdx`
12
- 3. **JSON-LD attachment** via `<JsonLd schema={build<Type>(page)} />` from
13
- `@working-theory/jsonld` (component) and `@working-theory/schema` (typed builder)
11
+ The single most important fact about this site: **almost every page type
12
+ already has its route.** Routes live in `apps/web/app/[locale]/…` and render
13
+ whatever content file sits in `content/en/<Type>/`. So adding a page is
14
+ usually **adding one content file**, not writing route code. Route code is
15
+ only ever added by the `create-ailk add-route` command, never by hand — a
16
+ hand-written route drifts from the template the site is built from and
17
+ breaks the next `create-ailk` upgrade.
14
18
 
15
- Single confirm-before-write — no per-file or per-step prompts.
19
+ ## Step 1 — Read what this site can serve
16
20
 
17
- ## When to use
21
+ Run, from the site's root:
18
22
 
19
- The consumer wants a new page on their AILK site. Triggers:
20
-
21
- - "scaffold me a /pricing page" / "create a /contact route"
22
- - "add an about page" / "I need a /privacy page"
23
- - A structured triple: `home — Organization — anchor with hero, value prop, CTA`
24
- - "add that one" referring to a specific row from prior chat output
25
-
26
- Skip this skill when:
27
-
28
- - The consumer wants to **add supplementary schema to an existing
29
- page** — that's the `schema:` frontmatter override (see
30
- [Adding schema to an existing page](#adding-schema-to-an-existing-page)
31
- below), not a separate skill. This skill refuses on existing routes
32
- and points there.
33
- - The consumer's content backend is **not MDX**. v1 is MDX-only —
34
- other adapters (Sanity, Payload, additional adapters) are additive
35
- future PRs. Refuse with a clear message.
36
-
37
- ## What this skill does
38
-
39
- 1. Parses the consumer's input — structured triple
40
- (`<slug> — <Schema.orgType> — <purpose>`) OR free-text.
41
- 2. Resolves the **primary schema.org type** for the page using
42
- `references/page-types.md` (about → AboutPage, pricing → Pricing,
43
- etc.). Confirms the choice before writing.
44
- 3. Detects existing routes and refuses if `app/<slug>/page.tsx`
45
- already exists, pointing at the `schema:` frontmatter override.
46
- 4. Detects content adapter — only MDX is supported at v1; refuses
47
- on any other adapter with a clear message.
48
- 5. Emits three files via `templates/route.tsx.tmpl` and
49
- `templates/content.mdx.tmpl` (instantiated per page) plus a
50
- typed builder import from `@working-theory/schema`.
51
- 6. Shows the consumer a **single diff** of all three files and waits
52
- for one confirmation. After approval, writes all files.
53
- 7. Closing summary: pointer at the `schema:` frontmatter override for
54
- additional schema, pointer at `check-site` for citation-readiness check.
55
-
56
- ## What this skill does NOT do
57
-
58
- - Modify an existing route. Refuses + points at the `schema:`
59
- frontmatter override.
60
- - Run `pnpm dev` or rebuild content. The consumer does that.
61
- - Detect content-adapter type beyond "is it MDX?". v1 ships MDX
62
- only; other adapters are out of scope.
63
- - Use `<script type="application/ld+json">` blocks or
64
- `generateMetadata.other`. The canonical attachment is always
65
- `<JsonLd>` from `@working-theory/jsonld`.
66
- - Hand-code JSON-LD object literals. The typed builder from
67
- `@working-theory/schema` is the source of truth (e.g. `buildOrganization(...)`,
68
- `buildHomePage(...)`).
69
-
70
- ## The mechanic
71
-
72
- ### Step 1 — Parse the input
73
-
74
- The consumer's request can arrive in either shape:
75
-
76
- **Structured triple:**
77
-
78
- ```
79
- home — Organization — anchor with hero, value prop, CTA
80
- about — AboutPage — company story and team
81
- pricing — Pricing — public price tiers and feature comparison
23
+ ```bash
24
+ node .claude/skills/add-page/scripts/site-pages.mjs
82
25
  ```
83
26
 
84
- Three em-dash-separated fields: `<slug>` `<Schema.orgType>` `<purpose>`.
85
-
86
- **Free-text shape:**
87
-
88
- ```
89
- "scaffold me a /pricing page"
90
- "add an about page"
91
- "create a /contact route for sales"
92
- ```
93
-
94
- Both shapes resolve to the same internal triple: `(slug, type, purpose)`.
95
-
96
- For free-text:
97
-
98
- - Extract the slug from the URL-shaped fragment ("/pricing" → "pricing"; "an about page" → "about").
99
- - Resolve the `type` from `references/page-types.md` (the slug is the lookup key).
100
- - The `purpose` is whatever description the consumer gave — used as MDX `description` frontmatter.
101
-
102
- If you can't resolve a slug → type from the references file, **ask the consumer** rather than guessing. Don't fabricate types.
103
-
104
- ### Step 2 — Detect MDX adapter
105
-
106
- Quick check: does the consumer's project have an MDX content
107
- backend?
108
-
109
- - Look for `content/` directory at the project root.
110
- - Look for `apps/web/source.config.ts` or `next.config.ts` that
111
- references `@working-theory/content-adapters` MDX adapter.
112
-
113
- If neither exists, refuse:
114
-
115
- > "add-page only supports the MDX content backend at v1. Your
116
- > project doesn't appear to have one — file an issue at the upstream
117
- > repo if you'd like Sanity / Payload / additional adapter support."
118
-
119
- Stop. No writes.
120
-
121
- ### Step 3 — Detect existing route
122
-
123
- Check for `apps/web/app/<slug>/page.tsx` (or `app/<slug>/page.tsx`
124
- depending on the consumer's structure).
125
-
126
- If it exists, refuse:
127
-
128
- > "A route at `/<slug>` already exists. To **add structured data** to
129
- > an existing page, use the `schema:` frontmatter override (see this
130
- > skill's [Adding schema to an existing page](#adding-schema-to-an-existing-page)
131
- > section) instead. To **replace** the page entirely, delete the
132
- > existing files first and re-run this skill."
133
-
134
- Stop. No writes.
135
-
136
- ### Step 4 — Instantiate the templates
137
-
138
- Use `templates/route.tsx.tmpl` and `templates/content.mdx.tmpl` as
139
- sources. Substitute:
140
-
141
- | Placeholder | Source |
142
- | ----------------- | -------------------------------------------------- |
143
- | `{{SLUG}}` | from Step 1 (e.g., `pricing`) |
144
- | `{{TYPE}}` | from Step 1 (e.g., `Service`) |
145
- | `{{TYPE_KEBAB}}` | type lowercased + kebab (e.g., `service`) |
146
- | `{{TYPE_CAMEL}}` | type camelCased for builder name (e.g., `service`) |
147
- | `{{BUILDER}}` | builder function name (e.g., `buildService`) |
148
- | `{{TITLE}}` | derived from slug, title-cased (e.g., "Pricing") |
149
- | `{{DESCRIPTION}}` | the `purpose` field from input |
150
-
151
- Builder name resolution: every type in `references/page-types.md`
152
- maps to a `build<Type>` export from `@working-theory/schema`. Verify the
153
- builder exists in the consumer's installed `@working-theory/schema` (check
154
- `node_modules/@working-theory/schema/dist/index.d.ts` or its README) before
155
- emitting the import. If the builder is missing, surface a clear
156
- "`@working-theory/schema` doesn't export `build<Type>` yet — file an issue
157
- upstream" message and stop.
158
-
159
- ### Step 5 — Show the diff
160
-
161
- Present all three files (route + MDX + import path) in one
162
- combined diff message. Single confirmation question:
163
-
164
- > "I'll create:
165
- >
166
- > - `app/<slug>/page.tsx` (App Router route, ~30 lines)
167
- > - `content/<Type>/<slug>.mdx` (content stub with frontmatter)
168
- >
169
- > The route imports `<JsonLd>` from `@working-theory/jsonld` and `build<Type>` from
170
- > `@working-theory/schema`. JSON-LD is rendered server-side from the MDX
171
- > frontmatter via the typed builder.
172
- >
173
- > Confirm to write all three files, or tell me what to change."
174
-
175
- Wait for the consumer's confirmation. Do not write per-step.
176
-
177
- ### Step 6 — Write all three files
178
-
179
- After confirmation, write the route file and MDX stub atomically.
180
- The third "file" is the import line inside the route — already
181
- included in the route template.
182
-
183
- ### Step 7 — Closing summary
184
-
185
- Print:
186
-
187
- - The two paths written.
188
- - Reminder: `pnpm dev` to see the page, `pnpm build` to confirm it
189
- compiles.
190
- - Pointer at the `schema:` frontmatter override for adding
191
- supplementary schema (FAQPage-shaped Q&A, a `Review`, a richer
192
- `mainEntity`, etc.) to this page later.
193
- - Pointer at `check-site` for citation-readiness check after
194
- adding pages.
195
-
196
- ## Adding schema to an existing page
197
-
198
- There is no separate skill for this — a page's MDX frontmatter
199
- already carries an escape hatch. `page.schema` is a
200
- `Record<string, unknown>`, opaque to the typed builder, that the
201
- builder merges on top of its derived fields after deriving them
202
- (frontmatter wins on conflict). Use it to add structured sub-entities,
203
- enrich a page with additional fields, or override any derived field
204
- — without re-scaffolding the route.
27
+ It prints the site's shape, design and level (from `.ailk-site-manifest.json`),
28
+ then one row per page type this site renders: its route, whether it takes new
29
+ pages (a route with a `[slug]` does; a fixed route like `/about` is one page),
30
+ and the pages already written. Add `--json` if you want to parse it.
31
+
32
+ Treat this output as the truth about the site. `references/page-types.md`
33
+ lists every page type AI Launch Kit knows — the vocabulary — but many of them
34
+ are not on this site. Never offer a page type the script doesn't list unless
35
+ you are also going to add its route (Step 3, case D).
36
+
37
+ Then read `.ailk-site-manifest.json` at the site root yourself, the site's
38
+ roster of record:
39
+
40
+ - `modules` — the modules this site has. Add any module the `# Modules:`
41
+ line of `architecture.yaml` names that `modules` does not: `create-ailk
42
+ add-module` records a module it adds there. With no manifest, or none
43
+ carrying `modules`, that line is the set.
44
+ - `rows` — every route the site already has (`route`) and the page type
45
+ each renders (`pageType`).
46
+ - `level` — present only when the scaffold derived it from the licence key.
47
+ It never decides what to offer; `modules` does.
48
+
49
+ A page type renders on this site only when the **Module** column of
50
+ `references/page-types.md` names a module in that set. Never offer,
51
+ suggest or write any other page type: a type whose Module the site lacks is
52
+ case E, never case D.
53
+
54
+ ## Step 2 — Work out which page type the user wants
55
+
56
+ The user may give a structured triple (`<slug> — <Type> — <purpose>`) or plain
57
+ words. Resolve plain words to a type with `references/page-types.md`: an exact
58
+ slug match first (`pricing` → `Pricing`), then a prefix (`services/…` →
59
+ `Service`), then the purpose ("company story" → `AboutPage`). If two types
60
+ fit, or none does, ask — a wrong type gives the page the wrong structured
61
+ data, which is what search and answer engines read.
62
+
63
+ Also settle the slug: lowercase, hyphenated, from the user's words
64
+ (`kitchen-remodels`, not `kitchen_remodels` or `KitchenRemodels`).
65
+
66
+ ## Step 3 — Decide which case this is
67
+
68
+ Check case C first: if the page the user describes already exists (the type is on a fixed route and its one page is in the "existing" column, or the slug is taken), stop there — nothing else in this skill applies.
69
+
70
+ | Case | When | What you'll write |
71
+ |---|---|---|
72
+ | **A. New page on an existing route** | The type is listed and takes new pages (`Service`, `UseCase`, `PortfolioItem`, `BookCall`, `ThankYouPage`, …) | One content file: `content/en/<Type>/<slug>.mdx`. Plus a nav link if the page belongs in the nav. |
73
+ | **B. Stand-alone landing page** | A one-off page at `/<slug>` that isn't any specific type (an offer, a campaign) | One content file: `content/en/LandingPage/<slug>.mdx`. The site's catch-all route serves it. |
74
+ | **C. The page already exists** | A fixed-route type already has its page (`/about`, `/contact`, `/faq`), or `<slug>` is taken | Nothing. Say so. To change its words, use `fill-page`; to rename it or move its URL, use `update-page`. |
75
+ | **D. The route isn't on this site** | The type exists in `page-types.md` but not in the script's output (e.g. `/pricing` on a person-service site) | First the route: `pnpm create ailk@latest add-route <route-id>` (run in the site root). `<route-id>` is the route family's name as `pnpm create ailk@latest --help` lists it under `--surfaces` — usually the first path segment (`pricing`, `alternatives`, `careers`). Then continue as case A (or case C for a fixed route — `add-route` seeds its page). |
76
+ | **E. Needs a module the site doesn't have** | The type's **Module** in `page-types.md` is not in the site's modules (Step 1), or `add-route` refuses, naming a module (e.g. docs, blog, scheduling-backed booking) | Nothing yet. Tell the user which module renders it and which level carries it (the **Level** column), and point at the `upgrade-plan` skill. Don't try to recreate the module's routes by hand. |
77
+
78
+ Why case B uses `LandingPage` rather than a new route: a route directory is
79
+ template code the site inherits and upgrades; a content file is the owner's.
80
+ Keeping one-off pages as content keeps upgrades clean.
81
+
82
+ Comparison pages (`/vs/<competitor>`, listed on `/alternatives`) are case A on
83
+ the `alternatives` route family, or case D when the site doesn't carry it yet
84
+ (`add-route alternatives`). The `/alternatives` hub lists every comparison
85
+ automatically — never hand-list them on the hub's page.
86
+
87
+ Reports and flow landing pages are content on routes the **signal-collectors
88
+ module** owns — see "Reports" and "Flow landing pages" below.
89
+
90
+ ## Step 4 — Draft the content file
91
+
92
+ Copy the shape of a page the site already has **of the same type** — pick one
93
+ from the "existing" column (e.g. `content/en/Service/first-engagement.mdx`).
94
+ Its frontmatter is exactly what that type's route and structured-data builder
95
+ expect, so matching it is how the new page renders and emits valid JSON-LD.
96
+ Keep the same keys and section structure; replace the words.
97
+
98
+ - Pick the page to copy with care: if the only page of this type is an odd one
99
+ (a hub slug, a stub), start from `templates/content.mdx.tmpl` instead and
100
+ borrow the section shapes from `content/en/HomePage/home.mdx`.
101
+ - Set `slug` to the new slug and write a real `title` and `description` from
102
+ what the user said. `description` becomes the meta description and feeds the
103
+ structured data, so make it a true one-sentence summary.
104
+ - Use the site's own name from `content/_site.mdx` wherever the page names
105
+ the business (a comparison's "us" side, a CTA) — don't leave `{Your Name}`
106
+ when the answer is on disk.
107
+ - A time-limited offer carries its end date in structured data
108
+ (`schema: { offers: { validThrough: "2027-05-31" } }`) and says it in the
109
+ copy, so the page doesn't keep advertising an expired deal.
110
+ - Where you don't have the owner's facts (prices, names, results), write
111
+ clearly-marked placeholder copy — never invent facts about their business.
112
+ Offer `fill-page` afterwards to write it properly.
113
+ - If no page of this type exists yet, start from `templates/content.mdx.tmpl`
114
+ (or `templates/comparison-page.mdx.tmpl` for a comparison) and fill in the
115
+ `type` from `page-types.md`. Reports and flow landing pages have their own
116
+ templates — see their sections below.
117
+ - Extra structured data (an `Offer`, a `Review`, an `author`) goes in the
118
+ frontmatter `schema:` block — see "Adding schema to a page" below. Don't
119
+ hand-write JSON-LD anywhere.
120
+
121
+ ## Step 5 — Link the page from its hub and the nav
122
+
123
+ **The hub page.** Detail types sit under a list page: `Service` under
124
+ `ServicesList` (`/services`), `UseCase` under `UseCasesList` (`/for`),
125
+ `PortfolioItem` under `PortfolioList` (`/portfolio`). Open the hub's content
126
+ file. If it lists its entries by hand (an `items` section with one entry per
127
+ page, each with an `href`), add an entry for the new page in the same shape —
128
+ otherwise visitors can't find it. The comparisons hub (`/alternatives`) and the
129
+ reports hub (`/reports`) are the exceptions: they list their pages automatically.
130
+
131
+ **The nav.**
132
+
133
+ The site nav is `apps/web/lib/nav-config.ts`; its labels are keys in the
134
+ `nav` section of `apps/web/messages/<locale>.json` (one file per language
135
+ under `apps/web/messages/`).
136
+
137
+ - A detail page under a list (a new service, a new persona) usually belongs in
138
+ that list's flyout or group in `nav-config.ts`. A stand-alone landing page
139
+ usually doesn't belong in the nav at all — ask if unsure. If it isn't in the
140
+ nav or a hub, tell the user how visitors will reach it (a link from the home
141
+ page, an email, an ad), because nothing on the site points to it yet.
142
+ - Name a new `labelKey` after the page in camelCase (`kitchenRemodels`), not
143
+ after its position (`service4`), so it still makes sense after reordering.
144
+ - A flyout may list the same links twice — once in `features` (the compact
145
+ view) and once in `groups` (the grouped view). Add the link to both.
146
+ - To add a link: add an entry with the new `labelKey` and the locale-free path
147
+ (`/services/kitchen-remodels`, not `/en/…`), and add that key with its label
148
+ to **every** messages file (a site with one language has one file). A key
149
+ missing from one language breaks that language's nav.
150
+ - Know the trade-off and tell the user once: `create-ailk` regenerates the nav
151
+ when a route or module is added, but only while `nav-config.ts` is exactly as
152
+ generated. Once hand-edited, later `add-route`/`add-module` runs leave it
153
+ alone and print the change they wanted instead.
154
+
155
+ ## Step 6 — Show the plan, confirm once, write
156
+
157
+ Show every file you will create or change — the content file in full, and the
158
+ exact lines added to the hub page, `nav-config.ts` and each messages file — plus any
159
+ `add-route` command you'll run first. Wait for one confirmation. Then run the
160
+ command (if any) and write the files. Don't write anything before the user
161
+ confirms, and don't touch any other file.
162
+
163
+ ## Step 7 — Check it
164
+
165
+ Run `pnpm build` from the site root. Then tell the user:
166
+
167
+ - the new page's URL (with the locale, e.g. `/en/services/kitchen-remodels`)
168
+ - that `fill-page` can write its real copy, and `check-site` can score it
169
+ for search and answer-engine readiness.
170
+
171
+ If the build fails, the usual cause is frontmatter that doesn't match the
172
+ type — compare the new file with the page you copied in Step 4.
173
+
174
+ ## Reports
175
+
176
+ `ReportPage` (the `/reports/<slug>` report reader) is a hub-and-spoke family
177
+ listed on the `/reports` hub (`ReportsList`). Its routes are
178
+ **module-owned code** (the signal-collectors module's own
179
+ `app/[locale]/reports/[slug]/page.tsx` and `app/[locale]/reports/page.tsx`),
180
+ so this skill writes report **content only**, never report route code
181
+ (spec 6892 D5).
182
+
183
+ When the resolved type is `ReportPage` — a structured triple naming it, or
184
+ free text like "add a report on Q3 results" — do this instead of Steps 3–4:
185
+
186
+ 1. Refuse when `app/[locale]/reports/[slug]/page.tsx` is absent, naming the
187
+ `signal-collectors` module: "This site has no report reader yet — run
188
+ `create-ailk add-module signal-collectors` first."
189
+ 2. Write `content/en/ReportPage/<slug>.mdx` from
190
+ `templates/report-page.mdx.tmpl` (substituting `{{SLUG}}`, `{{TITLE}}`,
191
+ `{{DESCRIPTION}}`, `{{DATE_PUBLISHED}}` — an ISO date — and
192
+ `{{DATE_LABEL}}` — the display string, e.g. "March 2025"). Refuse only
193
+ when that file already exists.
194
+ 3. When `content/en/ReportsList/reports.mdx` is absent, write it from
195
+ `templates/reports-list.mdx.tmpl` (substituting `{{TITLE}}`/`{{DESCRIPTION}}`
196
+ for the hub's own copy).
197
+
198
+ The hub's own card list is **generated at request time** from whichever
199
+ `ReportPage` seeds exist (`app/[locale]/reports/page.tsx` injects them) —
200
+ never hand-list reports on the hub's MDX. Steps 5–7 apply as usual.
201
+
202
+ ## Flow landing pages
203
+
204
+ A flow landing page is a single, standalone `LandingPage` whose CTA opens a
205
+ named flow at `/flows/<slug>/start` — the referral-request shape (spec 6892
206
+ D3). It belongs to no hub, but like the report family its route is
207
+ **module-owned code** (the signal-collectors module's own
208
+ `app/[locale]/flows/[slug]/start/page.tsx`), so this skill writes content
209
+ only.
210
+
211
+ When the consumer asks for a flow landing page — "add a referral page",
212
+ "add a landing page for the intake flow" — given a flow slug:
213
+
214
+ 1. Refuse when `app/[locale]/flows/[slug]/start/page.tsx` is absent, naming
215
+ the `signal-collectors` module: "This site has no flow engine yet — run
216
+ `create-ailk add-module signal-collectors` first."
217
+ 2. Refuse when `content/en/LandingPage/<slug>.mdx` already exists — this
218
+ is a single standalone page, not a family member with its own detail
219
+ route.
220
+ 3. Write `content/en/LandingPage/<slug>.mdx` from
221
+ `templates/flow-landing-page.mdx.tmpl`, substituting `{{SLUG}}`,
222
+ `{{TITLE}}`, `{{DESCRIPTION}}` as usual and `{{FLOW_SLUG}}` — the flow's
223
+ own slug, which may differ from the page's `{{SLUG}}`.
224
+
225
+ This skill writes no flow definition (`database/flows/<slug>.flow.json`) —
226
+ that is a separate artifact, seeded through the flow engine, not through a
227
+ page.
228
+
229
+ ## Adding schema to a page
230
+
231
+ Every page's frontmatter has an escape hatch, `schema:`, that the page's
232
+ structured-data builder merges on top of what it derives (frontmatter wins).
233
+ Use it to add sub-entities or enrich fields, on a new page or an existing one:
205
234
 
206
235
  ```yaml
207
- # in an existing page's MDX frontmatter
208
236
  ---
209
- type: BlogPosting
210
- slug: hello-world
211
- title: Hello, World
212
- description: First post.
237
+ type: Service
238
+ slug: kitchen-remodels
239
+ title: Kitchen remodels
240
+ description: Full kitchen remodels, from design to final inspection.
213
241
  schema:
214
- author:
215
- "@type": Person
216
- name: Jane Doe
242
+ offers:
243
+ "@type": Offer
244
+ priceCurrency: USD
245
+ price: "15000"
217
246
  ---
218
247
  ```
219
248
 
220
- Where an override key lands depends on the builder's shape — a
221
- two-layer builder (a `WebPage`-family envelope wrapping a described
222
- `mainEntity`, e.g. `BlogPosting`, `Service`, `Product`, `JobPosting`)
223
- routes most keys to the entity and a known few to the envelope; every
224
- other builder shallow-merges `page.schema` onto the top level. The
225
- full routing table is `packages/schema/README.md` § `schema` field
226
- override — read it before guiding a consumer through a non-obvious
227
- placement (e.g. `mainEntity` object merges, `@type` retyping).
228
-
229
- This is also how a page picks up a **supplementary** schema type that
230
- has no builder of its own — an `Offer`, a `Review`, an `AggregateRating`
231
- — since those are expressed as plain objects inside `schema:`, not as
232
- a distinct AILK page type.
233
-
234
- ## What lives in `references/page-types.md`
235
-
236
- The type-to-schema mapping is data, not logic. Read the references
237
- file at runtime — don't try to remember the table. It is generated
238
- from `packages/schema/src/registry/entries.ts` by
239
- `packages/create-ailk/scripts/generate-page-types-reference.ts` —
240
- never hand-edit it; regenerate it instead (`pnpm page-types:build` from
241
- `packages/create-ailk`) whenever a registry key changes.
242
-
243
- The mapping covers every registered AILK page type — family, chassis,
244
- schema.org `@type`, and the route convention — with list/detail pairs
245
- (e.g. `ServicesList` / `Service`) shown together.
246
-
247
- ## Coordination
248
-
249
- - **`check-site`** — citation-readiness check. Runs after
250
- pages exist; not invoked from inside this skill.
251
- - **`@working-theory/jsonld`** — the React component for JSON-LD
252
- rendering. Single source of truth for the attachment pattern.
253
- - **`@working-theory/schema`** — typed builders (`buildHomePage`,
254
- `buildAboutPage`, etc.). The skill's emit imports from here, and its
255
- README documents the `schema` frontmatter override in full.
256
- - **`@working-theory/content-adapters`** (MDX) — the content backend. v1 is
257
- MDX-only; other adapters are deferred.
249
+ On types that wrap a described entity in a page (`Service`, `Product`,
250
+ `BlogPosting`, `JobPosting`), most keys land on the entity; on others they
251
+ merge at the top level. This is also how a page gets a supplementary type
252
+ with no page type of its own — `Offer`, `Review`, `AggregateRating`.
253
+
254
+ ## What this skill does not do
255
+
256
+ - Write or copy route code by hand — `create-ailk add-route` does that.
257
+ - Change an existing page's words (`fill-page`), name or URL (`update-page`).
258
+ - Add a module or change the site's level (`upgrade-plan` explains; the
259
+ owner decides).
260
+ - Edit `_site.mdx`, the design, or another page's content.