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
@@ -20,6 +20,13 @@ The skill resolves in this order:
20
20
  3. **Free-text hint match** — "company story" / "team" → `AboutPage`.
21
21
  4. **Ask** — if nothing matches, ask the consumer rather than guessing.
22
22
 
23
+ **Level** and **Module** name what a page type needs: the module whose
24
+ code renders it, and the level that module comes with. Read the site's
25
+ `.ailk-site-manifest.json` `modules` first — a page type whose Module is
26
+ not in that list is one this site cannot render, so it is never offered;
27
+ name its module and level instead (the `upgrade-plan` skill explains the
28
+ levels). The level is the module's, never a claim about this site's key.
29
+
23
30
  `<slug>` in a route below is the page's own slug (e.g. `hello-world`);
24
31
  `<Type>` families using two-layer builders route supplementary schema
25
32
  through the `schema:` frontmatter override — see this skill's
@@ -28,88 +35,90 @@ override contract.
28
35
 
29
36
  ## Core
30
37
 
31
- | Key | `@type` | Family | Chassis | Route |
32
- | --- | --- | --- | --- | --- |
33
- | `HomePage` | `HomePage` | core | home | / |
34
- | `AboutPage` | `AboutPage` | core | detail | /about |
35
- | `ContactPage` | `ContactPage` | core | detail | /contact |
36
- | `PrivacyPage` | `WebPage` | core | detail | /privacy |
37
- | `TermsPage` | `WebPage` | core | detail | /terms |
38
- | `PurchasePolicyPage` | `WebPage` | core | detail | /purchase-policy |
39
- | `WorkingAgreementPage` | `WebPage` | core | detail | /working-agreement |
40
- | `LandingPage` | `WebPage` | core | home | /<slug> |
41
- | `ThankYouPage` | `WebPage` | core | detail | /thanks/<slug> |
42
- | `BookCall` | `WebPage` | core | home | /book-a-call |
43
- | `NewsletterSignup` | `WebPage` | core | home | /newsletter |
44
- | `DemoRequest` | `WebPage` | core | home | /demo-request |
45
- | `TrialSignup` | `WebPage` | core | home | /trial-signup |
46
- | `Waitlist` | `WebPage` | core | home | /waitlist |
47
- | `Assessment` | `WebApplication` | core | home | /assessment |
48
- | `Calculator` | `WebApplication` | core | home | /calculator |
49
- | `CampaignLP` | `WebPage` | core | home | /<slug> |
38
+ | Key | `@type` | Family | Chassis | Route | Level | Module |
39
+ | --- | --- | --- | --- | --- | --- | --- |
40
+ | `HomePage` | `HomePage` | core | home | / | Free | `marketing` |
41
+ | `AboutPage` | `AboutPage` | core | detail | /about | Free | `marketing` |
42
+ | `ContactPage` | `ContactPage` | core | detail | /contact | Free | `marketing` |
43
+ | `PrivacyPage` | `WebPage` | core | detail | /privacy | Free | `marketing` |
44
+ | `TermsPage` | `WebPage` | core | detail | /terms | Free | `marketing` |
45
+ | `PurchasePolicyPage` | `WebPage` | core | detail | /purchase-policy | Free | `marketing` |
46
+ | `WorkingAgreementPage` | `WebPage` | core | detail | /working-agreement | Free | `marketing` |
47
+ | `LandingPage` | `WebPage` | core | home | /<slug> | Free | `marketing` |
48
+ | `ThankYouPage` | `WebPage` | core | detail | /thanks/<slug> | Free | `marketing` |
49
+ | `BookCall` | `WebPage` | core | home | /meet/:slug | Pro | `scheduling` |
50
+ | `NewsletterSignup` | `WebPage` | core | home | /newsletter | Free | `marketing` |
51
+ | `DemoRequest` | `WebPage` | core | home | /demo-request | Free | `marketing` |
52
+ | `TrialSignup` | `WebPage` | core | home | /trial-signup | Free | `marketing` |
53
+ | `Waitlist` | `WebPage` | core | home | /waitlist | Free | `marketing` |
54
+ | `Assessment` | `WebApplication` | core | home | /assessment | Pro | `signal-collectors` |
55
+ | `Calculator` | `WebApplication` | core | home | /calculator | Pro | `signal-collectors` |
56
+ | `CampaignLP` | `WebPage` | core | home | /<slug> | Free | `marketing` |
50
57
 
51
58
  ## Identity
52
59
 
53
- | Key | `@type` | Family | Chassis | Route |
54
- | --- | --- | --- | --- | --- |
55
- | `Organization` | `Organization` | identity | detail | — site-wide identity — emitted on the home page or in a layout |
56
- | `Person` | `Person` | identity | detail | — site-wide identity — emitted on the home page or in a layout |
57
- | `BreadcrumbList` | `BreadcrumbList` | identity | detail | — site-wide — attached alongside another page's own schema |
58
- | `ContactPoint` | `ContactPoint` | identity | detail | — site-wide — embedded in `Organization` or `Person` |
60
+ | Key | `@type` | Family | Chassis | Route | Level | Module |
61
+ | --- | --- | --- | --- | --- | --- | --- |
62
+ | `Organization` | `Organization` | identity | detail | — site-wide identity — emitted on the home page or in a layout | Free | `marketing` |
63
+ | `Person` | `Person` | identity | detail | — site-wide identity — emitted on the home page or in a layout | Free | `marketing` |
64
+ | `BreadcrumbList` | `BreadcrumbList` | identity | detail | — site-wide — attached alongside another page's own schema | Free | `marketing` |
65
+ | `ContactPoint` | `ContactPoint` | identity | detail | — site-wide — embedded in `Organization` or `Person` | Free | `marketing` |
59
66
 
60
67
  ## Canonical
61
68
 
62
- | Key | `@type` | Family | Chassis | Route |
63
- | --- | --- | --- | --- | --- |
64
- | `ServicesList` | `CollectionPage` | canonical-list | list | /services |
65
- | `Service` | `Service` | canonical-detail | detail | /services/<slug> |
66
- | `ProductsList` | `CollectionPage` | canonical-list | list | /products |
67
- | `Product` | `Product` | canonical-detail | detail | /products/<slug> |
68
- | `ProjectsList` | `CollectionPage` | canonical-list | list | /projects |
69
- | `Project` | `CreativeWork` | canonical-detail | detail | /projects/<slug> |
70
- | `FAQPage` | `FAQPage` | canonical-list | list | /faq |
71
- | `CareersList` | `CollectionPage` | canonical-list | list | /careers |
72
- | `JobPosting` | `JobPosting` | canonical-detail | detail | /careers/<slug> |
73
- | `UseCasesList` | `CollectionPage` | canonical-list | list | /use-cases |
74
- | `UseCase` | `WebPage` | canonical-detail | detail | /use-cases/<slug> |
75
- | `PortfolioList` | `CollectionPage` | canonical-list | list | /portfolio |
76
- | `PortfolioItem` | `WebPage` | canonical-detail | detail | /portfolio/<slug> |
77
- | `FeaturesList` | `CollectionPage` | canonical-list | list | /features |
78
- | `Feature` | `WebPage` | canonical-detail | detail | /features/<slug> |
79
- | `TestimonialsList` | `CollectionPage` | canonical-list | list | /testimonials |
80
- | `ClientsList` | `CollectionPage` | canonical-list | list | /clients |
81
- | `DownloadsList` | `CollectionPage` | canonical-list | list | /downloads |
82
- | `EventsList` | `CollectionPage` | canonical-list | list | /events |
83
- | `Event` | `Event` | canonical-detail | detail | /events/<slug> |
84
- | `CoursesList` | `CollectionPage` | canonical-list | list | /courses |
85
- | `Course` | `Course` | canonical-detail | detail | /courses/<slug> |
86
- | `TeamList` | `CollectionPage` | canonical-list | list | /team |
87
- | `TeamMember` | `ProfilePage` | canonical-detail | detail | /team/<slug> |
88
- | `PartnersList` | `CollectionPage` | canonical-list | list | /partners |
89
- | `Partner` | `AboutPage` | canonical-detail | detail | /partners/<slug> |
90
- | `IntegrationsList` | `CollectionPage` | canonical-list | list | /integrations |
91
- | `Integration` | `WebPage` | canonical-detail | detail | /integrations/<slug> |
92
- | `GlossaryList` | `CollectionPage` | canonical-list | list | /glossary |
93
- | `LocationsList` | `CollectionPage` | canonical-list | list | /locations |
94
- | `Location` | `Place` | canonical-detail | detail | /locations/<slug> |
95
- | `DocsList` | `CollectionPage` | canonical-list | list | /docs |
96
- | `SoftwareProduct` | `WebPage` | canonical-detail | detail | /software/<slug> |
97
- | `ServiceAreaPage` | `WebPage` | canonical-detail | detail | /service-areas/<slug> |
98
- | `Pricing` | `WebPage` | canonical-detail | detail | /pricing |
99
- | `ComparisonPage` | `WebPage` | canonical-detail | detail | /comparisons/<slug> |
100
- | `ReportPage` | `Report` | canonical-detail | detail | /reports/<slug> |
69
+ | Key | `@type` | Family | Chassis | Route | Level | Module |
70
+ | --- | --- | --- | --- | --- | --- | --- |
71
+ | `ServicesList` | `CollectionPage` | canonical-list | list | /services | Free | `marketing` |
72
+ | `Service` | `Service` | canonical-detail | detail | /services/<slug> | Free | `marketing` |
73
+ | `ProductsList` | `CollectionPage` | canonical-list | list | /products | Free | `marketing` |
74
+ | `Product` | `Product` | canonical-detail | detail | /products/<slug> | Free | `marketing` |
75
+ | `ProjectsList` | `CollectionPage` | canonical-list | list | /projects | Free | `marketing` |
76
+ | `Project` | `CreativeWork` | canonical-detail | detail | /projects/<slug> | Free | `marketing` |
77
+ | `FAQPage` | `FAQPage` | canonical-list | list | /faq | Free | `marketing` |
78
+ | `CareersList` | `CollectionPage` | canonical-list | list | /careers | Free | `marketing` |
79
+ | `JobPosting` | `JobPosting` | canonical-detail | detail | /careers/<slug> | Free | `marketing` |
80
+ | `UseCasesList` | `CollectionPage` | canonical-list | list | /for | Free | `marketing` |
81
+ | `UseCase` | `WebPage` | canonical-detail | detail | /for/<slug> | Free | `marketing` |
82
+ | `PortfolioList` | `CollectionPage` | canonical-list | list | /portfolio | Free | `marketing` |
83
+ | `PortfolioItem` | `WebPage` | canonical-detail | detail | /portfolio/<slug> | Free | `marketing` |
84
+ | `FeaturesList` | `CollectionPage` | canonical-list | list | /features | Free | `marketing` |
85
+ | `Feature` | `WebPage` | canonical-detail | detail | /features/<slug> | Free | `marketing` |
86
+ | `ComparisonsList` | `CollectionPage` | canonical-list | list | /alternatives | Free | `marketing` |
87
+ | `ComparisonPage` | `WebPage` | canonical-detail | detail | /vs/<slug> | Free | `marketing` |
88
+ | `ReportsList` | `CollectionPage` | canonical-list | list | /reports | Free | `marketing` |
89
+ | `ReportPage` | `Report` | canonical-detail | detail | /reports/<slug> | Pro | `signal-collectors` |
90
+ | `TestimonialsList` | `CollectionPage` | canonical-list | list | /testimonials | Free | `marketing` |
91
+ | `ClientsList` | `CollectionPage` | canonical-list | list | /clients | Free | `marketing` |
92
+ | `DownloadsList` | `CollectionPage` | canonical-list | list | /downloads | Free | `marketing` |
93
+ | `EventsList` | `CollectionPage` | canonical-list | list | /events | Free | `marketing` |
94
+ | `Event` | `Event` | canonical-detail | detail | /events/<slug> | Free | `marketing` |
95
+ | `CoursesList` | `CollectionPage` | canonical-list | list | /courses | Free | `marketing` |
96
+ | `Course` | `Course` | canonical-detail | detail | /courses/<slug> | Free | `marketing` |
97
+ | `TeamList` | `CollectionPage` | canonical-list | list | /team | Free | `marketing` |
98
+ | `TeamMember` | `ProfilePage` | canonical-detail | detail | /team/<slug> | Free | `marketing` |
99
+ | `PartnersList` | `CollectionPage` | canonical-list | list | /partners | Free | `marketing` |
100
+ | `Partner` | `AboutPage` | canonical-detail | detail | /partners/<slug> | Free | `marketing` |
101
+ | `IntegrationsList` | `CollectionPage` | canonical-list | list | /integrations | Free | `marketing` |
102
+ | `Integration` | `WebPage` | canonical-detail | detail | /integrations/<slug> | Free | `marketing` |
103
+ | `GlossaryList` | `CollectionPage` | canonical-list | list | /glossary | Free | `marketing` |
104
+ | `LocationsList` | `CollectionPage` | canonical-list | list | /locations | Free | `marketing` |
105
+ | `Location` | `Place` | canonical-detail | detail | /locations/<slug> | Free | `marketing` |
106
+ | `DocsList` | `CollectionPage` | canonical-list | list | /docs | Pro | `docs-blog` |
107
+ | `SoftwareProduct` | `WebPage` | canonical-detail | detail | /software/<slug> | Free | `marketing` |
108
+ | `ServiceAreaPage` | `WebPage` | canonical-detail | detail | /service-areas/<slug> | Free | `marketing` |
109
+ | `Pricing` | `WebPage` | canonical-detail | detail | /pricing | Free | `marketing` |
101
110
 
102
111
  ## Editorial
103
112
 
104
- | Key | `@type` | Family | Chassis | Route |
105
- | --- | --- | --- | --- | --- |
106
- | `BlogList` | `Blog` | editorial-list | list | /blog |
107
- | `BlogPosting` | `BlogPosting` | editorial-detail | detail | /blog/<slug> |
108
- | `ResourcesHub` | `CollectionPage` | editorial-list | list | /resources |
109
- | `ResourceDetail` | `Article` | editorial-detail | detail | /resources/<slug> |
110
- | `CaseStudiesList` | `CollectionPage` | editorial-list | list | /case-studies |
111
- | `CaseStudy` | `Article` | editorial-detail | detail | /case-studies/<slug> |
112
- | `HowTo` | `HowTo` | editorial-detail | detail | /how-to/<slug> |
113
- | `Whitepaper` | `Article` | editorial-detail | detail | /whitepapers/<slug> |
114
- | `TechArticle` | `TechArticle` | editorial-detail | detail | /tech-articles/<slug> |
115
- | `DocsDetail` | `TechArticle` | editorial-detail | detail | /docs/<slug> |
113
+ | Key | `@type` | Family | Chassis | Route | Level | Module |
114
+ | --- | --- | --- | --- | --- | --- | --- |
115
+ | `BlogList` | `Blog` | editorial-list | list | /blog | Free | `marketing` |
116
+ | `BlogPosting` | `BlogPosting` | editorial-detail | detail | /blog/<slug> | Pro | `docs-blog` |
117
+ | `ResourcesHub` | `CollectionPage` | editorial-list | list | /resources | Free | `marketing` |
118
+ | `ResourceDetail` | `Article` | editorial-detail | detail | /resources/<slug> | Free | `marketing` |
119
+ | `CaseStudiesList` | `CollectionPage` | editorial-list | list | /case-studies | Free | `marketing` |
120
+ | `CaseStudy` | `Article` | editorial-detail | detail | /case-studies/<slug> | Free | `marketing` |
121
+ | `HowTo` | `HowTo` | editorial-detail | detail | /how-to/<slug> | Free | `marketing` |
122
+ | `Whitepaper` | `Article` | editorial-detail | detail | /whitepapers/<slug> | Free | `marketing` |
123
+ | `TechArticle` | `TechArticle` | editorial-detail | detail | /tech-articles/<slug> | Free | `marketing` |
124
+ | `DocsDetail` | `TechArticle` | editorial-detail | detail | /docs/<slug> | Pro | `docs-blog` |
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ // site-pages.mjs — report what THIS site can serve, read from the site itself.
3
+ //
4
+ // Usage: node .claude/skills/add-page/scripts/site-pages.mjs [--json] [<site-root>]
5
+ //
6
+ // It scans apps/web/app/[locale]/**/page.tsx for the page type each route
7
+ // renders (the `type: "X"` literal in renderPage / renderPageMetadata, or a
8
+ // getMdxSource("X", …) call), then pairs each type with its content folder and
9
+ // the pages already written there. It also echoes .ailk-site-manifest.json's
10
+ // shape, design and (when recorded) level. Read-only: it never writes.
11
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
12
+ import { join, relative, sep } from "node:path";
13
+
14
+ const args = process.argv.slice(2);
15
+ const asJson = args.includes("--json");
16
+ const root = args.find((a) => !a.startsWith("--")) ?? process.cwd();
17
+ const appRoot = join(root, "apps/web/app/[locale]");
18
+ if (!existsSync(appRoot)) {
19
+ console.error(`site-pages: ${appRoot} not found — run from the site's root.`);
20
+ process.exit(2);
21
+ }
22
+
23
+ // Types whose content lives outside content/<locale>/<Type>.
24
+ const CONTENT_OVERRIDES = {
25
+ BlogPosting: "apps/web/content/en/blog",
26
+ BlogList: "apps/web/content/en/blog",
27
+ DocsDetail: "apps/web/content/en/docs",
28
+ DocsList: "apps/web/content/en/docs",
29
+ };
30
+
31
+ function walk(dir, out = []) {
32
+ for (const name of readdirSync(dir)) {
33
+ const abs = join(dir, name);
34
+ if (name === "__tests__" || name === "node_modules") continue;
35
+ if (statSync(abs).isDirectory()) walk(abs, out);
36
+ else if (name === "page.tsx") out.push(abs);
37
+ }
38
+ return out;
39
+ }
40
+
41
+ const routes = [];
42
+ for (const file of walk(appRoot)) {
43
+ const src = readFileSync(file, "utf8");
44
+ const types = new Set();
45
+ for (const m of src.matchAll(/type:\s*"([A-Z][A-Za-z]+)"/g)) types.add(m[1]);
46
+ for (const m of src.matchAll(/getMdxSource\(\s*"([A-Z][A-Za-z]+)"/g)) types.add(m[1]);
47
+ const dir = relative(appRoot, file).split(sep).slice(0, -1);
48
+ // Route groups like (auth) do not appear in the URL.
49
+ const path = "/" + dir.filter((s) => !/^\(.*\)$/.test(s)).join("/");
50
+ const dynamic = dir.some((s) => s.startsWith("["));
51
+ routes.push({ route: path === "/" ? "/" : path, file: relative(root, file), types: [...types], dynamic });
52
+ }
53
+
54
+ const byType = {};
55
+ for (const r of routes) {
56
+ for (const t of r.types) {
57
+ const entry = (byType[t] ??= { type: t, routes: [], contentDir: CONTENT_OVERRIDES[t] ?? `content/en/${t}`, pages: [] });
58
+ entry.routes.push(r.route);
59
+ }
60
+ }
61
+ for (const e of Object.values(byType)) {
62
+ const abs = join(root, e.contentDir);
63
+ if (existsSync(abs)) {
64
+ e.pages = readdirSync(abs).filter((f) => /\.mdx?$/.test(f)).map((f) => f.replace(/\.mdx?$/, ""));
65
+ }
66
+ // A type served by a dynamic route takes new pages; a static-only type is one page.
67
+ e.takesNewPages = routes.some((r) => r.dynamic && r.types.includes(e.type));
68
+ }
69
+
70
+ let manifest = null;
71
+ const manifestPath = join(root, ".ailk-site-manifest.json");
72
+ if (existsSync(manifestPath)) {
73
+ const m = JSON.parse(readFileSync(manifestPath, "utf8"));
74
+ manifest = { shape: m.shape ?? null, design: m.design ?? null, level: m.level ?? null, modules: m.modules ?? m.requires ?? null };
75
+ }
76
+
77
+ const result = { manifest, types: Object.values(byType).sort((a, b) => a.type.localeCompare(b.type)) };
78
+ if (asJson) {
79
+ console.log(JSON.stringify(result, null, 2));
80
+ } else {
81
+ if (manifest) console.log(`shape: ${manifest.shape} design: ${manifest.design} level: ${manifest.level ?? "(not recorded)"}`);
82
+ console.log("");
83
+ console.log("type".padEnd(22) + "route(s)".padEnd(34) + "new pages?".padEnd(12) + "existing");
84
+ for (const e of result.types) {
85
+ console.log(e.type.padEnd(22) + e.routes.join(" ").padEnd(34) + (e.takesNewPages ? "yes" : "no").padEnd(12) + (e.pages.join(", ") || "—"));
86
+ }
87
+ }
@@ -0,0 +1,99 @@
1
+ ---
2
+ type: ComparisonPage
3
+ slug: {{SLUG}}
4
+ placeholder: true
5
+ title: {{TITLE}}
6
+ description: {{DESCRIPTION}}
7
+ sections:
8
+ [
9
+ {
10
+ "id": "hero",
11
+ "type": "hero",
12
+ "data":
13
+ {
14
+ "eyebrow": "Comparisons",
15
+ "headline": "{{TITLE}}",
16
+ "subheadline": "{{DESCRIPTION}}",
17
+ "primaryCta": { "label": "{Primary CTA}", "href": "/contact" },
18
+ },
19
+ },
20
+ {
21
+ "id": "decision-split",
22
+ "type": "decision-split",
23
+ "data":
24
+ {
25
+ "headline": "{Which one fits you}",
26
+ "panels":
27
+ [
28
+ {
29
+ "title": "{{TITLE}}",
30
+ "checklist":
31
+ [
32
+ "{Reason 1 to choose us}",
33
+ "{Reason 2 to choose us}",
34
+ "{Reason 3 to choose us}",
35
+ ],
36
+ },
37
+ {
38
+ "title": "{The alternative}",
39
+ "glyph": "cross",
40
+ "checklist":
41
+ [
42
+ "{Reason 1 to choose them instead}",
43
+ "{Reason 2 to choose them instead}",
44
+ ],
45
+ },
46
+ ],
47
+ },
48
+ },
49
+ {
50
+ "id": "comparison-table",
51
+ "type": "comparison-table",
52
+ "data":
53
+ {
54
+ "headline": "{How they compare}",
55
+ "columns":
56
+ [
57
+ { "key": "us", "name": "{{TITLE}}", "highlighted": true },
58
+ { "key": "them", "name": "{The alternative}" },
59
+ ],
60
+ "groups":
61
+ [
62
+ {
63
+ "groupName": "{Core features}",
64
+ "rows":
65
+ [
66
+ {
67
+ "featureName": "{Feature 1}",
68
+ "values": { "us": true, "them": false },
69
+ },
70
+ {
71
+ "featureName": "{Feature 2}",
72
+ "values": { "us": true, "them": true },
73
+ },
74
+ ],
75
+ },
76
+ ],
77
+ },
78
+ },
79
+ {
80
+ "id": "cta",
81
+ "type": "cta",
82
+ "data":
83
+ {
84
+ "variant": "box",
85
+ "headline": "{Ready to switch?}",
86
+ "description": "{One sentence on what happens next}",
87
+ "primaryCta": { "label": "{Primary CTA}", "href": "/contact" },
88
+ "secondaryCta":
89
+ {
90
+ "label": "See all alternatives",
91
+ "href": "/alternatives",
92
+ "variant": "outline",
93
+ },
94
+ },
95
+ },
96
+ ]
97
+ ---
98
+
99
+ {/* Rendered from frontmatter `sections[]` by the /vs/<slug> route (D10 — the generic detail chassis: hero, decision-split, comparison-table, cta; no dedicated comparison section). Listed automatically by the /alternatives hub. Placeholder copy — replace every {brace} with your own words before you launch. */}
@@ -5,24 +5,14 @@ title: {{TITLE}}
5
5
  description: {{DESCRIPTION}}
6
6
  ---
7
7
 
8
+ {/*
9
+ Written by the add-page skill, used only when this site had no other page of
10
+ this type to copy. The frontmatter drives the page's route and its JSON-LD:
11
+ keep `type` as it is, and make `description` a true one-sentence summary.
12
+ Run `fill-page` to write the real copy, then `check-site` to score it.
13
+ Extra structured data goes in a `schema:` block — see the add-page skill.
14
+ */}
15
+
8
16
  # {{TITLE}}
9
17
 
10
18
  {{DESCRIPTION}}
11
-
12
- <!--
13
- This is the MDX content stub emitted by `add-page`.
14
- The frontmatter is the source of truth for JSON-LD — the
15
- `{{BUILDER}}(page)` call in `app/{{SLUG}}/page.tsx` reads it.
16
-
17
- Edit this file freely:
18
- - Add sections, prose, components imported from your project.
19
- - Update `description` (it's used both as the meta description
20
- and as input to the JSON-LD builder).
21
- - Don't change `type` unless you also update the route's import
22
- to match a different `@working-theory/schema` builder.
23
-
24
- When you're happy with the page, run `check-site` to see
25
- how it scores on citation-readiness. Use the `schema:` frontmatter
26
- override to add supplementary schema (FAQPage, HowTo, etc.) without
27
- re-scaffolding.
28
- -->
@@ -0,0 +1,43 @@
1
+ ---
2
+ type: LandingPage
3
+ slug: {{SLUG}}
4
+ placeholder: true
5
+ title: {{TITLE}}
6
+ description: {{DESCRIPTION}}
7
+ sections:
8
+ [
9
+ {
10
+ "id": "hero",
11
+ "type": "hero",
12
+ "data":
13
+ {
14
+ "variant": "centered",
15
+ "eyebrow": "{{TITLE}}",
16
+ "headline": "{{TITLE}}",
17
+ "subheadline": "{{DESCRIPTION}}",
18
+ "primaryCta":
19
+ { "label": "{Get started →}", "href": "/flows/{{FLOW_SLUG}}/start" },
20
+ "ctaSize": "xl",
21
+ },
22
+ },
23
+ {
24
+ "id": "request",
25
+ "type": "cta",
26
+ "data":
27
+ {
28
+ "variant": "minimal",
29
+ "headline": "{Ready?}",
30
+ "primaryCta":
31
+ { "label": "{Get started →}", "href": "/flows/{{FLOW_SLUG}}/start" },
32
+ },
33
+ },
34
+ ]
35
+ ---
36
+
37
+ {/* This page's CTA opens the `{{FLOW_SLUG}}` flow at
38
+ /flows/{{FLOW_SLUG}}/start — a signal-collectors module route, not a page
39
+ this seed owns. The flow definition itself
40
+ (`database/flows/{{FLOW_SLUG}}.flow.json`) is a separate artifact this
41
+ skill does not write; seed it via the flow engine before this page's CTA
42
+ resolves. Placeholder copy — replace every {brace} with your own words
43
+ before you launch. */}
@@ -0,0 +1,52 @@
1
+ ---
2
+ type: ReportPage
3
+ slug: {{SLUG}}
4
+ placeholder: true
5
+ title: {{TITLE}}
6
+ description: {{DESCRIPTION}}
7
+ schema:
8
+ datePublished: "{{DATE_PUBLISHED}}"
9
+ author:
10
+ "@type": Organization
11
+ name: "{Your Company}"
12
+ sections:
13
+ [
14
+ {
15
+ "id": "header",
16
+ "type": "report-header",
17
+ "data":
18
+ {
19
+ "title": "{{TITLE}}",
20
+ "eyebrow": "{{DATE_LABEL}}",
21
+ "backHref": "/reports",
22
+ "backLabel": "All reports",
23
+ "tone": "on-dark",
24
+ },
25
+ },
26
+ {
27
+ "id": "document",
28
+ "type": "document-viewer",
29
+ "data":
30
+ {
31
+ "src": "/reports/sample-report.pdf",
32
+ "geometry": "16:9",
33
+ "pages": 8,
34
+ "downloadFilename": "{{SLUG}}.pdf",
35
+ "outline":
36
+ [
37
+ { "id": "opening", "label": "Opening", "startPage": 1 },
38
+ { "id": "findings", "label": "Findings", "startPage": 3 },
39
+ { "id": "outlook", "label": "Outlook", "startPage": 6 },
40
+ ],
41
+ },
42
+ },
43
+ ]
44
+ ---
45
+
46
+ {/* A PLACEHOLDER report. Its bytes are the signal-collectors module's own
47
+ sample PDF (apps/web/public/reports/sample-report.pdf), shared by every
48
+ sample report so the site ships no binary of its own. Point `src` at your
49
+ real document and set `pages` to its real page count. Rendered by the
50
+ signal-collectors module's own /reports/<slug> route (`app/[locale]/reports/[slug]/page.tsx`)
51
+ and listed automatically by the /reports hub (ReportsList) — never
52
+ hand-list a report there. */}
@@ -0,0 +1,38 @@
1
+ ---
2
+ type: ReportsList
3
+ slug: reports
4
+ placeholder: true
5
+ title: {{TITLE}}
6
+ description: {{DESCRIPTION}}
7
+ sections:
8
+ [
9
+ {
10
+ "id": "hero",
11
+ "type": "hero",
12
+ "data":
13
+ {
14
+ "variant": "centered",
15
+ "eyebrow": "Reports",
16
+ "headline": "{{TITLE}}",
17
+ "subheadline": "{{DESCRIPTION}}",
18
+ },
19
+ },
20
+ {
21
+ "id": "closing",
22
+ "type": "cta",
23
+ "data":
24
+ {
25
+ "variant": "minimal",
26
+ "headline": "{Want the next one as it lands?}",
27
+ "primaryCta": { "label": "{Contact me →}", "href": "/contact" },
28
+ },
29
+ },
30
+ ]
31
+ ---
32
+
33
+ {/* Rendered from frontmatter `sections[]` by the /reports route
34
+ (`app/[locale]/reports/page.tsx`). Its card list is GENERATED, not
35
+ authored here (spec 6892 D2): the route appends one `reports-list`
36
+ section listing every ReportPage seed, so this seed carries only its own
37
+ hero and closing cta. Placeholder copy — replace every {brace} with your
38
+ own words before you launch. */}
@@ -34,6 +34,23 @@ Skip this skill when:
34
34
 
35
35
  ## The mechanic
36
36
 
37
+ ### Step 0 — Read what this site can render
38
+
39
+ Read `.ailk-site-manifest.json` at the site root, the site's roster of
40
+ record:
41
+
42
+ - `modules` — the modules this site has. Add any module the
43
+ `# Modules:` line of `architecture.yaml` names that `modules` does not:
44
+ `create-ailk add-module` records a module it adds there. With no
45
+ manifest, or none carrying `modules`, that line is the set.
46
+ - `rows` — every route the site carries and the page type each renders.
47
+ - `level` — present only when the scaffold derived it from the licence
48
+ key. It never decides what to suggest; `modules` does.
49
+
50
+ A page type renders on this site only when its **Module** in
51
+ `.claude/skills/add-page/references/page-types.md` is in that set.
52
+ Step 7 suggests a page only of such a type.
53
+
37
54
  ### Step 1 — Invoke the CLI
38
55
 
39
56
  Run `ailk-audit --json` from the consumer's project root. Use
@@ -136,6 +153,12 @@ themselves on a subsequent turn.
136
153
  | `entity-markup` | Manual edit — ensure `Organization` (or `Person`) JSON-LD is emitted somewhere site-wide |
137
154
  | `faq-howto-incentive` | `add-page`'s `schema:` frontmatter override — add an `FAQPage` or `HowTo` block to a relevant page |
138
155
 
156
+ When a fix means adding a page, name only a page type this site can
157
+ render (Step 0) — for `faq-howto-incentive`, a `FAQPage` or `HowTo`
158
+ page, never one the site's modules do not render. When only a type the
159
+ site cannot render would fix a finding, say which module renders it and
160
+ which level carries it, and point at the `upgrade-plan` skill.
161
+
139
162
  Phrase the pointer as a single sentence:
140
163
 
141
164
  > "Missing `Product` schema on `/pricing` — add it via `add-page`'s
@@ -67,15 +67,30 @@ comes from `_site.mdx` `siteIdentity.name`.
67
67
 
68
68
  ## Step 0 — Read
69
69
 
70
- 1. Read the profile: `profiles/<slug>.yaml`.
71
- 2. Read `content/_site.mdx` for `siteIdentity.name`.
72
- 3. Read the page file. Note its stack (`sections[].type` in order).
73
- 4. For each section type in the stack, read its data schema: the
70
+ 1. Read `.ailk-site-manifest.json` at the site root, the site's roster
71
+ of record: `modules` (the modules this site has) and `rows` (every
72
+ route it carries). Add any module the `# Modules:` line of
73
+ `architecture.yaml` names that `modules` does not — `create-ailk
74
+ add-module` records a module it adds there; with no manifest, or none
75
+ carrying `modules`, that line is the set. `level`, when present, never
76
+ decides anything here.
77
+
78
+ The page's `type` must render on this site: its **Module** in
79
+ `../add-page/references/page-types.md` is in that set, or a row
80
+ already renders it (`rows[].pageType` — a Free starter's `/meet/<slug>`
81
+ `BookCall` placeholders). When it does not,
82
+ say which module renders the type and which level carries it, point at
83
+ the `upgrade-plan` skill, and stop. Never fill a page this site cannot
84
+ render.
85
+ 2. Read the profile: `profiles/<slug>.yaml`.
86
+ 3. Read `content/_site.mdx` for `siteIdentity.name`.
87
+ 4. Read the page file. Note its stack (`sections[].type` in order).
88
+ 5. For each section type in the stack, read its data schema: the
74
89
  `<Type>SectionDataSchema` (or `<Type>DataSchema`) export in the
75
90
  installed `@working-theory/validation`'s `schemas/page-sections`. Fill
76
91
  only fields the schema declares. Every field a section renders from
77
92
  copy gets content; a field the source page did not use stays unused.
78
- 5. Find the route that renders this page type under `apps/web/app/[locale]/`
93
+ 6. Find the route that renders this page type under `apps/web/app/[locale]/`
79
94
  and read its `bodyMode`. When it is `"mdx-body"`, the MDX body is
80
95
  rendered and must be filled too. Otherwise the body is a short note,
81
96
  and you rewrite it as one plain sentence that names no braces.
@@ -88,7 +103,9 @@ fields and intake answers that fill it.
88
103
  1. **Sections.** For each section, in place, write every copy field from
89
104
  the profile using `references/section-sources.md`:
90
105
  - offerings → `items` entries (`title` = the offering `name`,
91
- `description` = its `job`, `link.href` = `/services/<kebab name>`);
106
+ `description` = its `job`, `link.href` = `/services/<kebab name>`
107
+ only when the manifest's `rows` carry `/services/[slug]`; otherwise
108
+ no `link`, so no entry points at a page the site does not have);
92
109
  - vocabulary → headlines, eyebrows and FAQ questions (the buyer's own
93
110
  words: the `problem` list for what went wrong, `outcome` for what
94
111
  they get);
@@ -176,5 +193,7 @@ and run both again. Stop only when both are clean.
176
193
  - Tier 3 (the Messaging Canvas through the content pipeline).
177
194
  - Create a page — use `add-page`.
178
195
  - Edit `_site.mdx`, the nav or the page roster. A profile's `roster` and
179
- `nav` entries are declared for a later step and are not applied here.
196
+ `nav` entries are declared for a later step and are not applied here,
197
+ and a profile page type this site cannot render (Step 0) is never
198
+ suggested.
180
199
  - Write a price, a name or an address the owner did not give.
@@ -50,7 +50,7 @@ vocabulary:
50
50
  - tidy job, nothing left behind
51
51
  roster:
52
52
  - op: add
53
- route: /emergency
53
+ route: /meet/emergency
54
54
  pageType: BookCall
55
55
  reason: Emergency jobs book a call, not a form.
56
56
  - op: drop