create-ailk 0.19.1 → 0.21.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 (199) hide show
  1. package/README.md +84 -7
  2. package/component-catalog.json +184 -6
  3. package/component-catalog.md +20 -9
  4. package/dist/apply-design.d.ts +9 -0
  5. package/dist/apply-design.js +78 -31
  6. package/dist/cli.js +35 -0
  7. package/dist/copy.d.ts +41 -0
  8. package/dist/copy.js +87 -21
  9. package/dist/design-home.d.ts +54 -11
  10. package/dist/design-home.js +160 -22
  11. package/dist/lib/design-checks.d.ts +6 -1
  12. package/dist/lib/design-checks.js +23 -2
  13. package/dist/lib/fetch-template-snapshot.d.ts +21 -0
  14. package/dist/lib/fetch-template-snapshot.js +205 -0
  15. package/dist/lib/merge-three-way.d.ts +31 -0
  16. package/dist/lib/merge-three-way.js +65 -0
  17. package/dist/module-architecture.js +55 -2
  18. package/dist/programmatic.d.ts +7 -1
  19. package/dist/programmatic.js +76 -22
  20. package/dist/site-roster.d.ts +4 -2
  21. package/dist/site-roster.js +7 -5
  22. package/dist/spoke-checkout.d.ts +7 -0
  23. package/dist/spoke-checkout.js +8 -1
  24. package/dist/starter-grid.js +16 -0
  25. package/dist/surfaces.js +78 -2
  26. package/dist/sync-routes.d.ts +28 -0
  27. package/dist/sync-routes.js +123 -1
  28. package/dist/template-record.d.ts +59 -0
  29. package/dist/template-record.js +183 -0
  30. package/dist/update.d.ts +53 -0
  31. package/dist/update.js +606 -0
  32. package/package.json +3 -3
  33. package/site-templates/_base/ailk-template.json +2 -2
  34. package/site-templates/_base/content/en/WorkingAgreementPage/working-agreement.mdx +78 -0
  35. package/site-templates/designs/minimalism/DESIGN.md +1 -1
  36. package/site-templates/designs/minimalism/contact/local-business-service.mdx +23 -0
  37. package/site-templates/designs/minimalism/contact/organization-product.mdx +23 -0
  38. package/site-templates/designs/minimalism/contact/organization-service.mdx +23 -0
  39. package/site-templates/designs/minimalism/contact/person-service.mdx +23 -0
  40. package/site-templates/marketing-site/TEMPLATE-MANIFEST.json +18 -1
  41. package/site-templates/marketing-site/TEMPLATE-MANIFEST.md +11 -0
  42. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.json +18 -1
  43. package/site-templates/marketing-site-free/TEMPLATE-MANIFEST.md +34 -23
  44. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.json +18 -1
  45. package/site-templates/shapes/local-business-service/TEMPLATE-MANIFEST.md +33 -23
  46. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.json +18 -1
  47. package/site-templates/shapes/organization-service/TEMPLATE-MANIFEST.md +33 -23
  48. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.json +18 -1
  49. package/site-templates/shapes/person-service/TEMPLATE-MANIFEST.md +31 -21
  50. package/templates/.claude/cloudparity-repo-hooks.json +9 -0
  51. package/templates/.claude/hooks/architecture-check.sh +8 -0
  52. package/templates/.claude/rules/loop-contract.md +129 -0
  53. package/templates/.claude/settings.json +3 -2
  54. package/templates/.env.example +13 -0
  55. package/templates/CLAUDE.md +1 -1
  56. package/templates/CONVENTIONS.md +3 -2
  57. package/templates/README.md +26 -25
  58. package/templates/_gitignore +162 -0
  59. package/templates/apps/api/CLAUDE.md +18 -10
  60. package/templates/apps/api/jest.config.cjs +1 -0
  61. package/templates/apps/api/package.json +2 -1
  62. package/templates/apps/api/src/__tests__/factories/in-memory-prisma.ts +22 -2
  63. package/templates/apps/api/src/__tests__/setup.ts +7 -0
  64. package/templates/apps/api/src/bin/__tests__/rate-limit-probe.test.ts +184 -0
  65. package/templates/apps/api/src/bin/rate-limit-probe.ts +53 -0
  66. package/templates/apps/api/src/lib/proposal-paid-store.ts +49 -0
  67. package/templates/apps/api/src/lib/rate-limit-probe.ts +165 -0
  68. package/templates/apps/api/src/lib/rate-limit-store.ts +142 -0
  69. package/templates/apps/api/src/middleware/__tests__/auth.hub-session-path.test.ts +5 -2
  70. package/templates/apps/api/src/middleware/__tests__/default-tenant.test.ts +2 -0
  71. package/templates/apps/api/src/middleware/__tests__/rate-limit-cross-isolate.db.test.ts +220 -0
  72. package/templates/apps/api/src/middleware/__tests__/rate-limit-store.test.ts +430 -0
  73. package/templates/apps/api/src/middleware/__tests__/rate-limit.test.ts +21 -14
  74. package/templates/apps/api/src/middleware/auth.ts +8 -4
  75. package/templates/apps/api/src/middleware/default-tenant.ts +9 -0
  76. package/templates/apps/api/src/middleware/rate-limit.ts +290 -82
  77. package/templates/apps/api/src/routes/project-listings/__tests__/drafts.test.ts +26 -0
  78. package/templates/apps/api/src/routes/webhooks/README.md +33 -5
  79. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-proposal-paid.test.ts +369 -0
  80. package/templates/apps/api/src/routes/webhooks/__tests__/stripe-site-filter.test.ts +442 -0
  81. package/templates/apps/api/src/routes/webhooks/stripe.ts +184 -6
  82. package/templates/apps/api/src/server.ts +14 -2
  83. package/templates/apps/api/src/services/__tests__/audit-log.test.ts +91 -0
  84. package/templates/apps/api/src/services/audit-log.ts +72 -10
  85. package/templates/apps/api/src/services/default-tenant.ts +12 -3
  86. package/templates/apps/api/src/services/hub-sign-in.ts +2 -1
  87. package/templates/apps/api/src/services/project-listings.ts +6 -1
  88. package/templates/apps/api/src/services/public-site-resolver.ts +21 -2
  89. package/templates/apps/api/vercel.json +1 -1
  90. package/templates/apps/mcp/CLAUDE.md +19 -7
  91. package/templates/apps/mcp/__tests__/catalog-drift.test.ts +139 -44
  92. package/templates/apps/mcp/jest.config.cjs +1 -0
  93. package/templates/apps/mcp/src/tools/person_notes.ts +25 -0
  94. package/templates/apps/mcp/src/tools/proposals.ts +27 -0
  95. package/templates/apps/mcp/src/workspace-server.ts +16 -0
  96. package/templates/apps/web/CLAUDE.md +26 -1
  97. package/templates/apps/web/_gitignore +6 -0
  98. package/templates/apps/web/app/[locale]/(auth)/sign-up/__tests__/sign-up-card.test.tsx +165 -0
  99. package/templates/apps/web/app/[locale]/(auth)/sign-up/page.tsx +19 -0
  100. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up-card.tsx +106 -23
  101. package/templates/apps/web/app/[locale]/(auth)/sign-up/sign-up.actions.ts +125 -0
  102. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/agreements-prompt.test.tsx +281 -0
  103. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/general.test.tsx +28 -83
  104. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/hub-mode.test.tsx +27 -13
  105. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/item.test.tsx +57 -2
  106. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/layout.test.tsx +2 -0
  107. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/notifications.test.tsx +102 -18
  108. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/onboarding.test.tsx +323 -0
  109. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/privacy.test.tsx +365 -0
  110. package/templates/apps/web/app/[locale]/(authed)/account/__tests__/settings.test.tsx +3 -2
  111. package/templates/apps/web/app/[locale]/(authed)/account/actions.ts +8 -0
  112. package/templates/apps/web/app/[locale]/(authed)/account/agreements-actions.ts +170 -0
  113. package/templates/apps/web/app/[locale]/(authed)/account/agreements-prompt.tsx +181 -0
  114. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/[pieceId]/page.tsx +88 -3
  115. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/[pieceId]/pay-form.tsx +65 -0
  116. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/[pieceId]/review-form.tsx +27 -0
  117. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/__tests__/page.test.tsx +176 -3
  118. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/__tests__/pay.test.tsx +193 -0
  119. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/__tests__/review.test.tsx +188 -0
  120. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/artifact-actions.ts +65 -4
  121. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/artifact-data.ts +17 -0
  122. package/templates/apps/web/app/[locale]/(authed)/account/artifacts/page.tsx +11 -2
  123. package/templates/apps/web/app/[locale]/(authed)/account/general/page.tsx +5 -24
  124. package/templates/apps/web/app/[locale]/(authed)/account/notifications/page.tsx +64 -18
  125. package/templates/apps/web/app/[locale]/(authed)/account/onboarding/actions.ts +120 -0
  126. package/templates/apps/web/app/[locale]/(authed)/account/onboarding/onboarding-form.tsx +322 -0
  127. package/templates/apps/web/app/[locale]/(authed)/account/onboarding/page.tsx +126 -0
  128. package/templates/apps/web/app/[locale]/(authed)/account/page.tsx +43 -1
  129. package/templates/apps/web/app/[locale]/(authed)/account/privacy/actions.ts +65 -0
  130. package/templates/apps/web/app/[locale]/(authed)/account/privacy/page.tsx +226 -0
  131. package/templates/apps/web/app/[locale]/(authed)/account/settings-frame.tsx +5 -3
  132. package/templates/apps/web/app/[locale]/about/[slug]/page.tsx +46 -0
  133. package/templates/apps/web/app/[locale]/about/__tests__/about-routes.test.tsx +350 -0
  134. package/templates/apps/web/app/[locale]/about/page.tsx +83 -1
  135. package/templates/apps/web/app/[locale]/careers/__tests__/page-renderer-migration.test.tsx +2 -2
  136. package/templates/apps/web/app/[locale]/case-studies/__tests__/page-renderer-migration.test.tsx +2 -2
  137. package/templates/apps/web/app/[locale]/consent-banner.tsx +32 -0
  138. package/templates/apps/web/app/[locale]/consent.actions.ts +71 -0
  139. package/templates/apps/web/app/[locale]/contact/ConversationalIntakeWrapper.tsx +7 -0
  140. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-magnet.test.ts +138 -0
  141. package/templates/apps/web/app/[locale]/contact/__tests__/contact-form-text.test.ts +17 -0
  142. package/templates/apps/web/app/[locale]/contact/__tests__/contact-magnet-page.test.tsx +347 -0
  143. package/templates/apps/web/app/[locale]/contact/__tests__/contact.actions.test.ts +73 -0
  144. package/templates/apps/web/app/[locale]/contact/__tests__/page-renderer-migration.test.tsx +5 -3
  145. package/templates/apps/web/app/[locale]/contact/contact-form-magnet.ts +77 -0
  146. package/templates/apps/web/app/[locale]/contact/contact-form-text.ts +2 -0
  147. package/templates/apps/web/app/[locale]/contact/contact.actions.ts +48 -4
  148. package/templates/apps/web/app/[locale]/contact/page.tsx +81 -9
  149. package/templates/apps/web/app/[locale]/courses/__tests__/page-renderer-migration.test.tsx +2 -2
  150. package/templates/apps/web/app/[locale]/flows/[slug]/flow.actions.ts +25 -3
  151. package/templates/apps/web/app/[locale]/how-to/__tests__/page-renderer-migration.test.tsx +1 -1
  152. package/templates/apps/web/app/[locale]/integrations/__tests__/page-renderer-migration.test.tsx +2 -2
  153. package/templates/apps/web/app/[locale]/layout.tsx +46 -4
  154. package/templates/apps/web/app/[locale]/newsletter/newsletter.actions.ts +12 -1
  155. package/templates/apps/web/app/[locale]/partners/__tests__/page-renderer-migration.test.tsx +2 -2
  156. package/templates/apps/web/app/[locale]/products/__tests__/page-renderer-migration.test.tsx +2 -2
  157. package/templates/apps/web/app/[locale]/services/__tests__/page-renderer-migration.test.tsx +2 -2
  158. package/templates/apps/web/app/[locale]/software/__tests__/page-renderer-migration.test.tsx +1 -1
  159. package/templates/apps/web/app/[locale]/tech-articles/__tests__/page-renderer-migration.test.tsx +1 -1
  160. package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe-rsc-boundary.test.tsx +209 -0
  161. package/templates/apps/web/app/[locale]/unsubscribe/__tests__/unsubscribe.test.tsx +158 -0
  162. package/templates/apps/web/app/[locale]/unsubscribe/page.tsx +54 -0
  163. package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe-button.tsx +73 -0
  164. package/templates/apps/web/app/[locale]/unsubscribe/unsubscribe.actions.ts +55 -0
  165. package/templates/apps/web/app/[locale]/whitepapers/__tests__/page-renderer-migration.test.tsx +1 -1
  166. package/templates/apps/web/app/[locale]/working-agreement/__tests__/page.test.tsx +63 -0
  167. package/templates/apps/web/app/[locale]/working-agreement/page.tsx +41 -0
  168. package/templates/apps/web/app/robots.txt/route.ts +13 -10
  169. package/templates/apps/web/jest.config.cjs +4 -0
  170. package/templates/apps/web/lib/__tests__/consent-visitor.test.ts +163 -0
  171. package/templates/apps/web/lib/__tests__/deck-page.test.ts +244 -0
  172. package/templates/apps/web/lib/__tests__/relay.test.ts +49 -0
  173. package/templates/apps/web/lib/__tests__/structured-data.test.tsx +100 -9
  174. package/templates/apps/web/lib/account-config.ts +31 -16
  175. package/templates/apps/web/lib/consent-visitor.ts +103 -0
  176. package/templates/apps/web/lib/deck-page.ts +186 -0
  177. package/templates/apps/web/lib/relay.ts +20 -0
  178. package/templates/apps/web/messages/en.json +83 -9
  179. package/templates/apps/web/next.config.mjs +8 -2
  180. package/templates/database/CHANGELOG.md +48 -0
  181. package/templates/database/__tests__/outbound-message-action.db.test.ts +80 -0
  182. package/templates/database/__tests__/person-notes.db.test.ts +249 -0
  183. package/templates/database/__tests__/piece-kind-migration.test.ts +67 -0
  184. package/templates/database/__tests__/piece-kind.db.test.ts +208 -0
  185. package/templates/database/__tests__/seed.test.ts +39 -2
  186. package/templates/database/_gitignore +8 -0
  187. package/templates/database/inbox/schema.prisma +38 -12
  188. package/templates/database/jest.config.cjs +1 -0
  189. package/templates/database/migrations/20261015120000_person_notes/migration.sql +77 -0
  190. package/templates/database/migrations/20261015120000_rate_limit_counters/migration.sql +43 -0
  191. package/templates/database/migrations/20261016120000_piece_kind/migration.sql +95 -0
  192. package/templates/database/migrations/20261017120000_outbound_message_action/migration.sql +30 -0
  193. package/templates/database/ops/schema.prisma +16 -0
  194. package/templates/database/package.json +1 -1
  195. package/templates/database/seed.ts +29 -0
  196. package/templates/project.yaml +6 -3
  197. package/templates/tools/jest/pin-timezone.cjs +34 -0
  198. package/versions.json +35 -35
  199. package/templates/.claude/rules/preserve-existing-style.md +0 -51
@@ -232,6 +232,14 @@ _Code route — no content, no sections._
232
232
 
233
233
  <!-- generated:end -->
234
234
 
235
+ <!-- generated:begin page=/working-agreement -->
236
+
237
+ | # | Section | Component | Copy (first line) |
238
+ | --- | ----------------------------------- | ----------------- | ----------------- |
239
+ | 1 | `document-chassis` (layout=article) | `DocumentChassis` | Working Agreement |
240
+
241
+ <!-- generated:end -->
242
+
235
243
  `/blog` (the Free teaser row, § 1.9 — served by the generic `[slug]` route over the always-copied overlay's `BlogList/blog.mdx`):
236
244
 
237
245
  <!-- generated:begin page=/blog -->
@@ -287,8 +295,9 @@ The standard page set for this shape (`derive-roster.py --shape person-service -
287
295
  | `PortfolioList` · `PortfolioItem` | the portfolio pair belongs to every shape's standard roster (operator, 2026-09-25; roadmap § 4) |
288
296
  | `BlogList` | every Free scaffold's nav links `/blog` unconditionally (`renderNavConfig`, operator ruling 2026-09-23); the Free teaser serves it, as on organization-product (#6753 D3) |
289
297
  | `LandingPage` | the Free `/meet` meeting-types hub is a LandingPage seed, the same generic `[slug]` route serves it through (#6897 D3); the four `/meet/[slug]` BookCall detail seeds ride the `BookCall` type already in the standard roster |
298
+ | `WorkingAgreementPage` | the Contact form's terms checkbox links `/working-agreement` beside `/terms` and `/privacy`, so every starter ships the page from `_base` (#8661 D10) |
290
299
 
291
- `|S − D| = 13` and `|R| = 18`.
300
+ `|S − D| = 13` and `|R| = 19`.
292
301
 
293
302
  `/sign-in` and `/sign-up` are also rostered (#6797) — code routes (`kind: route`) with no page type, so they sit outside this set equation: the locale layout's header links both, and the roster of record lists every page the scaffold serves.
294
303
 
@@ -305,26 +314,27 @@ person-service:
305
314
  shape: person-service
306
315
  design: standard
307
316
  roster:
308
- - { route: "/", kind: page, content: ["content/en/HomePage/home.mdx"] }
309
- - { route: "/services", kind: page, content: ["content/en/ServicesList/services.mdx"] }
310
- - { route: "/services/[slug]", kind: page, contentDir: "content/en/Service" }
311
- - { route: "/for", kind: page, content: ["content/en/UseCasesList/for.mdx"] }
312
- - { route: "/for/[slug]", kind: page, contentDir: "content/en/UseCase" }
313
- - { route: "/about", kind: page, content: ["content/en/AboutPage/about.mdx"] }
314
- - { route: "/contact", kind: page, content: ["content/en/ContactPage/contact.mdx"] }
315
- - { route: "/faq", kind: page, content: ["content/en/FAQPage/faq.mdx"] }
316
- - { route: "/glossary", kind: page, content: ["content/en/GlossaryList/glossary.mdx"] }
317
- - { route: "/newsletter", kind: page, content: ["content/en/NewsletterSignup/newsletter.mdx"] }
318
- - { route: "/sign-in", kind: route }
319
- - { route: "/sign-up", kind: route }
320
- - { route: "/purchase-policy", kind: page, content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"] }
321
- - { route: "/privacy", kind: page, content: ["content/en/PrivacyPage/privacy.mdx"] }
322
- - { route: "/terms", kind: page, content: ["content/en/TermsPage/terms.mdx"] }
323
- - { route: "/blog", kind: page, content: ["content/en/BlogList/blog.mdx"] }
324
- - { route: "/meet", kind: page, content: ["content/en/LandingPage/meet.mdx"] }
325
- - { route: "/meet/[slug]", kind: page, content: ["content/en/BookCall/book-a-call.mdx", "content/en/BookCall/onsite-estimate.mdx", "content/en/BookCall/start-project.mdx", "content/en/BookCall/onsite-service.mdx"] }
326
- - { route: "/portfolio", kind: page, content: ["content/en/PortfolioList/portfolio.mdx"] }
327
- - { route: "/portfolio/[slug]", kind: page, contentDir: "content/en/PortfolioItem" }
317
+ - { route: "/", kind: page, content: ["content/en/HomePage/home.mdx"] }
318
+ - { route: "/services", kind: page, content: ["content/en/ServicesList/services.mdx"] }
319
+ - { route: "/services/[slug]", kind: page, contentDir: "content/en/Service" }
320
+ - { route: "/for", kind: page, content: ["content/en/UseCasesList/for.mdx"] }
321
+ - { route: "/for/[slug]", kind: page, contentDir: "content/en/UseCase" }
322
+ - { route: "/about", kind: page, content: ["content/en/AboutPage/about.mdx"] }
323
+ - { route: "/contact", kind: page, content: ["content/en/ContactPage/contact.mdx"] }
324
+ - { route: "/faq", kind: page, content: ["content/en/FAQPage/faq.mdx"] }
325
+ - { route: "/glossary", kind: page, content: ["content/en/GlossaryList/glossary.mdx"] }
326
+ - { route: "/newsletter", kind: page, content: ["content/en/NewsletterSignup/newsletter.mdx"] }
327
+ - { route: "/sign-in", kind: route }
328
+ - { route: "/sign-up", kind: route }
329
+ - { route: "/purchase-policy", kind: page, content: ["content/en/PurchasePolicyPage/purchase-policy.mdx"] }
330
+ - { route: "/privacy", kind: page, content: ["content/en/PrivacyPage/privacy.mdx"] }
331
+ - { route: "/terms", kind: page, content: ["content/en/TermsPage/terms.mdx"] }
332
+ - { route: "/working-agreement", kind: page, content: ["content/en/WorkingAgreementPage/working-agreement.mdx"] }
333
+ - { route: "/blog", kind: page, content: ["content/en/BlogList/blog.mdx"] }
334
+ - { route: "/meet", kind: page, content: ["content/en/LandingPage/meet.mdx"] }
335
+ - { route: "/meet/[slug]", kind: page, content: ["content/en/BookCall/book-a-call.mdx", "content/en/BookCall/onsite-estimate.mdx", "content/en/BookCall/start-project.mdx", "content/en/BookCall/onsite-service.mdx"] }
336
+ - { route: "/portfolio", kind: page, content: ["content/en/PortfolioList/portfolio.mdx"] }
337
+ - { route: "/portfolio/[slug]", kind: page, contentDir: "content/en/PortfolioItem" }
328
338
  ```
329
339
 
330
340
  <!-- generated:end -->
@@ -0,0 +1,9 @@
1
+ {
2
+ "hooks": [
3
+ {
4
+ "event": "PostToolUse",
5
+ "matcher": "Edit|Write",
6
+ "command": "bash .claude/hooks/architecture-check.sh"
7
+ }
8
+ ]
9
+ }
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ # PostToolUse (Edit|Write): run the architecture boundary lint after an edit.
3
+ # Exits 0 until dependencies are installed, and 2 on a violation so Claude
4
+ # reads the finding. Registered in .claude/settings.json and declared in
5
+ # .claude/cloudparity-repo-hooks.json; keep the two in step.
6
+ cd "$CLAUDE_PROJECT_DIR" || exit 0
7
+ [ -x node_modules/.bin/tsx ] || exit 0
8
+ pnpm --silent architecture >&2 || exit 2
@@ -0,0 +1,129 @@
1
+ # Per-Issue Workflow
2
+
3
+ The contract every change goes through. One issue in, one PR out, no
4
+ scope creep.
5
+
6
+ This is the single-developer flow. If you're working solo on this
7
+ project, this is what every meaningful change looks like.
8
+
9
+ ## Pick
10
+
11
+ Open an issue or claim one from your backlog. The issue must have:
12
+
13
+ - A `## Acceptance Criteria` section listing observable, verifiable
14
+ outcomes.
15
+ - A `## Scope` section listing the files or path globs you intend
16
+ to touch.
17
+
18
+ If either is missing, write them before you start — not as a
19
+ formality but because the rest of the workflow depends on them.
20
+
21
+ ## Read
22
+
23
+ Before any edits:
24
+
25
+ 1. The issue body in full — every acceptance bullet, scope path,
26
+ and dependency note.
27
+ 2. `CLAUDE.md` — the operating manual you're already reading.
28
+ 3. The files inside `## Scope` — confirm they exist and your mental
29
+ model matches what's actually there.
30
+
31
+ If anything is missing or the issue is infeasible as written, stop
32
+ and refine the issue before coding.
33
+
34
+ ## Branch
35
+
36
+ ```bash
37
+ git checkout main
38
+ git pull --ff-only origin main
39
+ git checkout -b issue-<N>-<kebab-slug>
40
+ ```
41
+
42
+ Use a 3–6 word slug from the issue title. Branch names show up in
43
+ your PR list — make them scannable.
44
+
45
+ ## TDD: RED → GREEN
46
+
47
+ For functional acceptance criteria:
48
+
49
+ 1. Write tests from the criteria first. They should fail (RED) —
50
+ your implementation doesn't exist yet.
51
+ 2. Implement the smallest change that makes the tests pass (GREEN).
52
+ 3. Refactor if the implementation is messy. Tests stay green
53
+ throughout.
54
+
55
+ Skip TDD only for: pure documentation, prompt-only changes, or
56
+ single-line fixes already covered by an existing test.
57
+
58
+ ## Verify
59
+
60
+ Before commit AND before push:
61
+
62
+ ```bash
63
+ pnpm preflight
64
+ ```
65
+
66
+ This runs `architecture` + `claude-md:check` + `type-check` + `lint` +
67
+ `build`. It runs no tests, so it is not a stand-in for CI: run
68
+ `pnpm test` as well whenever your change has tests, and read CI's own
69
+ result on the PR.
70
+
71
+ For PRs touching specific surfaces:
72
+
73
+ - `database/` schema changes — also run `pnpm db:migrate` locally if
74
+ you added a migration.
75
+
76
+ ## Commit + PR
77
+
78
+ - Commit message format: `feat(area): description (#N)`. Include
79
+ the issue number when one exists.
80
+ - Multiple commits on the branch are fine; squash-merge collapses
81
+ them.
82
+ - PR title: same as the commit message format.
83
+ - PR body must include:
84
+ - **Summary** — what the PR does, in plain language.
85
+ - **Scope** — paths actually touched (a subset of the issue's
86
+ scope).
87
+ - **Verification** — checklist of what you ran, with
88
+ `[x] pnpm preflight` ticked.
89
+ - `Closes #N` line — required for issue PRs; triggers GitHub's
90
+ auto-close on merge.
91
+
92
+ ## After PR open
93
+
94
+ 1. Wait for CI. If it goes red, diagnose and fix; do not merge red.
95
+ 2. Wait for any automated reviewers (Bugbot, code review bots) to
96
+ return. Address every finding — either fix it or write a short
97
+ reply explaining why it's not actionable.
98
+ 3. Merge once CI is green and reviews are reconciled.
99
+
100
+ ## After merge
101
+
102
+ 1. Close the issue if the PR didn't auto-close it.
103
+ 2. Delete the local and remote branch.
104
+ 3. Pick the next issue.
105
+
106
+ ## Mid-task scope expansion
107
+
108
+ If you realize mid-task that the issue's `## Scope` was insufficient:
109
+
110
+ 1. Stop before writing outside scope.
111
+ 2. Update the PR description to add the new path with a one-line
112
+ reason.
113
+ 3. Continue.
114
+
115
+ That short pause is the entire point — it forces you to acknowledge
116
+ that the work has grown, instead of letting it grow silently.
117
+
118
+ ## When to escalate
119
+
120
+ Stop and surface the question rather than make the call alone if:
121
+
122
+ - An architecture invariant in `.claude/rules/architecture.md` would
123
+ have to bend.
124
+ - A change to a published `@working-theory/*` package is needed (file the
125
+ issue upstream; don't fork locally).
126
+ - The acceptance criteria contradict each other or the existing code.
127
+ - You'd be deleting or moving more than five files at once.
128
+
129
+ A short clarifying question beats a long detour down the wrong path.
@@ -6,7 +6,7 @@
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
9
- "command": "cd \"$CLAUDE_PROJECT_DIR\" && [ -x node_modules/.bin/tsx ] || exit 0; pnpm --silent architecture >&2 || exit 2"
9
+ "command": "bash .claude/hooks/architecture-check.sh"
10
10
  }
11
11
  ]
12
12
  }
@@ -23,5 +23,6 @@
23
23
  },
24
24
  "enabledPlugins": {
25
25
  "ailk@working-theory": true
26
- }
26
+ },
27
+ "x-cloudparity-managed-keys": ["hooks"]
27
28
  }
@@ -14,6 +14,7 @@ AILK_PUBLIC_DOMAIN=ailaunchkit.ai
14
14
  # 3. <meta name="robots" content="noindex,nofollow"> tag (apps/web/app/[locale]/layout.tsx)
15
15
  # At launch, set STEALTH=false on the hosting platform's env vars and redeploy.
16
16
  # See README.md § "Going live" for the full flip checklist.
17
+ # Accepted (any case): true, 1, yes, on hide the site; false, 0, no, off or empty allow indexing. Any other value fails the build.
17
18
  STEALTH=true
18
19
 
19
20
  # Blog-OFF launch gate (#3413) — SITE-ARCHITECTURE §4.1 parks the blog at
@@ -520,6 +521,18 @@ CONTENT_ADAPTER=mdx
520
521
  # it from one egress address. A whole number from 1 to 999999. Default: 120.
521
522
  # AILK_RATE_LIMIT_DIRECTORY_PER_MINUTE=120
522
523
  #
524
+ # apps/api. Which store rateLimitMiddleware's per-IP/per-key counters use
525
+ # (#5040). `database` counts in the deployment's own Postgres (DATABASE_URL),
526
+ # so the limit holds across every concurrent isolate; `memory` keeps the
527
+ # pre-#5040 in-process Map, which does not. Default: `database` when
528
+ # DATABASE_URL is set, else `memory`. A database failure or a 1s-slow call
529
+ # falls back to the in-process Map for that request rather than letting it
530
+ # through uncounted. Run `pnpm --filter @working-theory/api rate-limit:probe
531
+ # --origin <https origin>` against a live deployment to check which store it
532
+ # selected and whether a burst holds — see
533
+ # docs/runbooks/site-configuration.md.
534
+ # AILK_RATE_LIMIT_STORE=
535
+ #
523
536
  # SPOKE (apps/web, server-only — never NEXT_PUBLIC_). This spoke's key: one
524
537
  # entry of the hub's AILK_VISITOR_FORWARD_KEYS. Sent only when AILK_API_URL
525
538
  # is https (or loopback). Issue a key only to a spoke whose platform
@@ -64,7 +64,7 @@ your module set; `pnpm architecture` enforces it, and a hook in
64
64
  | Change the look | `create-ailk apply-design <name\|path>` (keeps `brand:`); at scaffold, `--design <folder>` |
65
65
  | Logos, photos, brand reference | `brand_assets/` |
66
66
  | Repo identity, labels, hard floors | `project.yaml` |
67
- | Diff hygiene when editing existing files | `.claude/rules/preserve-existing-style.md` |
67
+ | Diff hygiene when editing existing files | `CONVENTIONS.md` § Commit + diff hygiene |
68
68
  | Code style, testing, security | `CONVENTIONS.md` |
69
69
  | Environment variables and what they unlock | `.env.example` |
70
70
  | Deploy configuration | `apps/api/vercel.json`; the `/ailk:setup-deploy` skill |
@@ -196,8 +196,9 @@ move.
196
196
  cleanup goes in its own follow-up PR.
197
197
  - **Diff is the contract.** A 20-line behavioral change should produce
198
198
  a ~20-line diff. If your editor reformatted unrelated lines, revert
199
- the formatting before committing. See
200
- `.claude/rules/preserve-existing-style.md`.
199
+ the formatting before committing. Match the file's existing quotes,
200
+ indentation and import order, and check `git diff --stat` before you
201
+ commit.
201
202
  - **Commit message format:** `feat(area): description (#N)`. Include
202
203
  the issue number when one exists.
203
204
  - **Squash merge only.** Multiple commits on the branch are fine; the
@@ -43,31 +43,32 @@ The pages of the Free `organization-product` shape, and where each one's copy li
43
43
 
44
44
  <!-- generated:begin content -->
45
45
 
46
- | Page | Content file | Ships in |
47
- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
48
- | `/` | `content/en/HomePage/home.mdx` | every scaffold |
49
- | `/features` | `content/en/FeaturesList/features.mdx` | `--shape organization-product` |
50
- | `/features/[slug]` | — (a code route) | `--shape organization-product` |
51
- | `/for` | `content/en/UseCasesList/for.mdx` | `--shape organization-product` |
52
- | `/for/[slug]` | — (a code route) | `--shape organization-product` |
53
- | `/pricing` | `content/en/Pricing/pricing.mdx` | `--shape organization-product` |
54
- | `/about` | `content/en/AboutPage/about.mdx` | every scaffold |
55
- | `/faq` | `content/en/FAQPage/faq.mdx` | every scaffold |
56
- | `/contact` | `content/en/ContactPage/contact.mdx` | every scaffold |
57
- | `/glossary` | `content/en/GlossaryList/glossary.mdx` | `--shape organization-product` |
58
- | `/newsletter` | `content/en/NewsletterSignup/newsletter.mdx` | `--shape organization-product` |
59
- | `/sign-in` | — (a code route) | every scaffold |
60
- | `/sign-up` | — (a code route) | every scaffold |
61
- | `/privacy` | `content/en/PrivacyPage/privacy.mdx` | `--shape organization-product` |
62
- | `/terms` | `content/en/TermsPage/terms.mdx` | `--shape organization-product` |
63
- | `/purchase-policy` | `content/en/PurchasePolicyPage/purchase-policy.mdx` | every scaffold |
64
- | `/blog` | `content/en/BlogList/blog.mdx` | every scaffold |
65
- | `/meet` | `content/en/LandingPage/meet.mdx` | every scaffold |
66
- | `/meet/[slug]` | `content/en/BookCall/book-a-call.mdx`, `content/en/BookCall/onsite-estimate.mdx`, `content/en/BookCall/start-project.mdx`, `content/en/BookCall/onsite-service.mdx` | every scaffold |
67
- | `/portfolio` | `content/en/PortfolioList/portfolio.mdx` | `--shape organization-product` |
68
- | `/portfolio/[slug]` | — (a code route) | `--shape organization-product` |
69
- | `/team` | `content/en/TeamList/team.mdx` | `--shape organization-product` |
70
- | `/team/[slug]` | — (a code route) | `--shape organization-product` |
46
+ | Page | Content file | Ships in |
47
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
48
+ | `/` | `content/en/HomePage/home.mdx` | every scaffold |
49
+ | `/features` | `content/en/FeaturesList/features.mdx` | `--shape organization-product` |
50
+ | `/features/[slug]` | — (a code route) | `--shape organization-product` |
51
+ | `/for` | `content/en/UseCasesList/for.mdx` | `--shape organization-product` |
52
+ | `/for/[slug]` | — (a code route) | `--shape organization-product` |
53
+ | `/pricing` | `content/en/Pricing/pricing.mdx` | `--shape organization-product` |
54
+ | `/about` | `content/en/AboutPage/about.mdx` | every scaffold |
55
+ | `/faq` | `content/en/FAQPage/faq.mdx` | every scaffold |
56
+ | `/contact` | `content/en/ContactPage/contact.mdx` | every scaffold |
57
+ | `/glossary` | `content/en/GlossaryList/glossary.mdx` | `--shape organization-product` |
58
+ | `/newsletter` | `content/en/NewsletterSignup/newsletter.mdx` | `--shape organization-product` |
59
+ | `/sign-in` | — (a code route) | every scaffold |
60
+ | `/sign-up` | — (a code route) | every scaffold |
61
+ | `/privacy` | `content/en/PrivacyPage/privacy.mdx` | `--shape organization-product` |
62
+ | `/terms` | `content/en/TermsPage/terms.mdx` | `--shape organization-product` |
63
+ | `/working-agreement` | `content/en/WorkingAgreementPage/working-agreement.mdx` | `--shape organization-product` |
64
+ | `/purchase-policy` | `content/en/PurchasePolicyPage/purchase-policy.mdx` | every scaffold |
65
+ | `/blog` | `content/en/BlogList/blog.mdx` | every scaffold |
66
+ | `/meet` | `content/en/LandingPage/meet.mdx` | every scaffold |
67
+ | `/meet/[slug]` | `content/en/BookCall/book-a-call.mdx`, `content/en/BookCall/onsite-estimate.mdx`, `content/en/BookCall/start-project.mdx`, `content/en/BookCall/onsite-service.mdx` | every scaffold |
68
+ | `/portfolio` | `content/en/PortfolioList/portfolio.mdx` | `--shape organization-product` |
69
+ | `/portfolio/[slug]` | — (a code route) | `--shape organization-product` |
70
+ | `/team` | `content/en/TeamList/team.mdx` | `--shape organization-product` |
71
+ | `/team/[slug]` | — (a code route) | `--shape organization-product` |
71
72
 
72
73
  <!-- generated:end -->
73
74
 
@@ -0,0 +1,162 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+ build/
7
+ .next/
8
+ *.tsbuildinfo
9
+
10
+ # Turborepo local task cache
11
+ .turbo/
12
+
13
+ # Fumadocs MDX codegen output (generated by fumadocs-mdx/next at build time)
14
+ apps/web/.source/
15
+ apps-paid/marketing-web/.source/
16
+
17
+ # Prisma generated client (regenerated via `pnpm db:generate`)
18
+ database/generated/
19
+ apps-paid/license-issuer/src/generated/
20
+
21
+ # api-client generated types (regenerated via `pnpm codegen`, run at build time)
22
+ packages/api-client/src/generated/
23
+
24
+ # Environment files
25
+ .env
26
+ .env.local
27
+ .env.*.local
28
+
29
+ # Logs
30
+ *.log
31
+ npm-debug.log*
32
+ pnpm-debug.log*
33
+
34
+ # Editor / OS
35
+ .DS_Store
36
+ .vscode/
37
+ .idea/
38
+
39
+ # Test coverage
40
+ coverage/
41
+
42
+ # Coverage audit baseline output (tools/audit-coverage.ts; on-demand only)
43
+ coverage-baseline-*.json
44
+
45
+ # Stryker mutation testing — temp sandbox + per-run report output
46
+ .stryker-tmp/
47
+ **/reports/mutation/
48
+
49
+ # Caches
50
+ .eslintcache
51
+ .cache/
52
+
53
+ # Claude Code session state (worktree manager)
54
+ .claude/worktrees/
55
+
56
+ # AILK file-fallback inbox (OSS standalone mode; leads written here when DB unavailable)
57
+ .ailk/
58
+
59
+ # AILK license refresh-cached JWT (default storage path for @working-theory/license)
60
+ .ailk-license.jwt
61
+
62
+ # Lead capture JSONL store (contains customer contact data — never commit)
63
+ apps/api/leads.jsonl
64
+ apps/api/leads.jsonl.*
65
+
66
+ # Build-time content manifest (generated by pnpm content:compile; not committed)
67
+ content/.compiled/
68
+
69
+ # Preflight success marker (written by pnpm preflight; read by require-preflight-on-push hook)
70
+ .claude/.preflight-ok
71
+
72
+ # Maintainer-only orchestration (Sam's /loop, dispatch, autonomy, babysit/cron skills).
73
+ # These live on the maintainer's filesystem and are not part of the public template.
74
+ .claude/rules/dispatch-defaults.md
75
+ .claude/rules/parallel-agent-discipline.md
76
+ .claude/rules/autonomy-ailk.md
77
+ .claude/skills/babysit/
78
+ .claude/skills/post-merge-sweeper/
79
+ .claude/skills/pr-pruner/
80
+
81
+ # Other ephemeral Claude Code state
82
+ .claude/.continue-after-simplify-attempts
83
+ .claude/.simplify-last-run
84
+ .claude/.enforce-checkpoint-before-stop-attempts
85
+ .claude/.worktree-root
86
+ .claude/scheduled_tasks.lock
87
+ .claude/logs/
88
+ .claude/settings.local.json
89
+ .claude/review-findings/
90
+
91
+ # db:generate advisory lock dir (runtime-only; created/removed by database/scripts/db-generate-locked.sh)
92
+ .claude/.db-generate.lock
93
+
94
+ # Playwright MCP session artifacts (accessibility snapshots auto-created during browser_* runs)
95
+ .playwright-mcp/
96
+
97
+ # Saved Playwright login sessions the extract-*-from-reference skills write
98
+ # (cookies for an auth-gated reference site). This file is also every
99
+ # scaffold's .gitignore (build-templates.mjs SNAPSHOT_FILES), so a customer
100
+ # never commits one either.
101
+ brand_assets/.playwright-auth/
102
+
103
+ # Visual-iteration scratch — directory tracked via .gitkeep, contents ignored
104
+ screenshots/*
105
+ !screenshots/.gitkeep
106
+
107
+ # Content pipeline per-repo scratch (PAGE-COPY, site architecture files, etc.)
108
+ # Collocated with repo for /copywriting and /compile-page skills. See claude-setup#423.
109
+ strategy/
110
+ # Allow versioned strategy docs in docs/internal/strategy/ (claude-setup#486)
111
+ !docs/internal/strategy/
112
+ # Allow the flat versioned strategy docs in docs/strategy/ (claude-setup#3424).
113
+ # Kept out of the public OSS repo via project.yaml strip_for_oss.exclude_dirs.
114
+ !docs/strategy/
115
+
116
+ # Storybook build output
117
+ storybook-static/
118
+
119
+ # Playwright test-run bookkeeping (per-run status + failure artifacts) — never
120
+ # committed; a local `pnpm visual:test` run previously left `.last-run.json`
121
+ # and a per-failure `error-context.md` tracked in the repo (#6577).
122
+ test-results/
123
+
124
+ # Static export output — @working-theory/design-reference-gallery's build
125
+ # artifact (the ailk-storybook hosting shape: a static tree served from a
126
+ # protected origin). Rebuilt by `pnpm --filter @working-theory/design-reference-gallery build`.
127
+ apps-paid/design-reference-gallery/out/
128
+
129
+ # Vercel CLI local state — `vercel pull` writes project settings + a pulled
130
+ # .env.<env>.local here, and `vercel build` writes the Build Output API tree.
131
+ # The deploy workflow creates all of it at the repo root at run time (#4482).
132
+ .vercel/
133
+
134
+ # impeccable detect CLI pilot (epic #4501, issue #4511) — per-developer
135
+ # override + ephemeral working state. .impeccable/config.json itself IS
136
+ # committed (e.g. packages/ui/.impeccable/config.json) — only these are not.
137
+ # Patterns are `**/`-prefixed since .impeccable/ lives under packages/ui, not
138
+ # the repo root.
139
+ **/.impeccable/config.local.json
140
+ **/.impeccable/*.ndjson
141
+ **/.impeccable/cache/
142
+ **/.impeccable/hook.cache.json
143
+
144
+ # Root-anchored scratch-artifact guard (#5179 / PUB-902, PUB-903, PUB-910).
145
+ # Design-iteration screenshots and profiling dumps have no directory to live
146
+ # under at the repository root, so nothing else stops them from recurring
147
+ # there. The leading `/` anchors each pattern to the repo root only — images
148
+ # tracked elsewhere (brand_assets/**, package public/ assets, visual-regression
149
+ # baselines) are untouched. Bytecode caches are unwanted anywhere, so those two
150
+ # patterns are unanchored.
151
+ /*.png
152
+ /*.jpeg
153
+ /*.jpg
154
+ __pycache__/
155
+ *.pyc
156
+
157
+ # e2e journey tests (.claude/skills/e2e): the running stack's state, logs and secrets, and each run's raw results
158
+ tests/e2e/.stack/
159
+ tests/e2e/.results/
160
+
161
+ # create-ailk licence key file (`--license`, `ailk license set`) — owner-only, never committed
162
+ ailk.key