fimo 0.8.0 → 0.9.0-experimental.10

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 (218) hide show
  1. package/assets/agent-templates/content-translator/scripts/write-locale-files.ts +66 -0
  2. package/assets/agents-starter/claude/settings.json +19 -0
  3. package/assets/content-templates/hooks-template.eta +4 -2
  4. package/assets/content-templates/types-template.eta +67 -1
  5. package/assets/skills/fimo/SKILL.md +1 -1
  6. package/assets/skills/fimo/references/content.md +86 -15
  7. package/assets/skills/fimo/references/translations.md +75 -0
  8. package/assets/skills/fimo-cli/SKILL.md +6 -2
  9. package/assets/skills/fimo-cli/references/content.md +61 -2
  10. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +20 -4
  11. package/assets/skills/fimo-cli/references/integrations.md +5 -1
  12. package/assets/skills/fimo-cli/references/webhooks.md +162 -0
  13. package/assets/skills/fimo-migration/SKILL.md +24 -2
  14. package/assets/skills/fimo-migration/references/content.md +24 -0
  15. package/assets/skills/fimo-migration/references/manifest.md +46 -0
  16. package/assets/skills/fimo-migration/references/pages.md +234 -0
  17. package/assets/skills/fimo-migration/references/qa.md +24 -2
  18. package/assets/skills/fimo-migration/references/workflow.md +12 -1
  19. package/assets/skills/fimo-migration/references/wrap.md +662 -0
  20. package/assets/skills/fimo-studio/SKILL.md +5 -3
  21. package/assets/skills/fimo-studio/references/cms.md +9 -1
  22. package/assets/skills/fimo-studio/references/visual-editing.md +5 -3
  23. package/assets/skills/fimo-studio/references/webhooks.md +42 -0
  24. package/dist/build/vite/plugins/translations.d.ts +2 -8
  25. package/dist/build/vite/plugins/translations.js +31 -131
  26. package/dist/cli/bundle.json +1 -1
  27. package/dist/cli/index.js +1337 -189
  28. package/dist/runtime/app/FimoProviders.d.ts +1 -11
  29. package/dist/runtime/app/FimoProviders.js +31 -30
  30. package/dist/runtime/astro/index.d.ts +2 -0
  31. package/dist/runtime/astro/index.js +3 -0
  32. package/dist/runtime/astro/server.d.ts +3 -0
  33. package/dist/runtime/astro/server.js +6 -0
  34. package/dist/runtime/content/client/internal.js +1 -0
  35. package/dist/runtime/content/client/types.d.ts +16 -0
  36. package/dist/runtime/core/BuiltWithBadge.d.ts +2 -0
  37. package/dist/runtime/core/BuiltWithBadge.js +68 -0
  38. package/dist/runtime/i18n/FimoLocaleContext.js +1 -0
  39. package/dist/runtime/next/FimoNextProviders.d.ts +24 -0
  40. package/dist/runtime/next/FimoNextProviders.js +20 -0
  41. package/dist/runtime/next/FimoNextScripts.d.ts +10 -0
  42. package/dist/runtime/next/FimoNextScripts.js +19 -0
  43. package/dist/runtime/next/index.d.ts +14 -0
  44. package/dist/runtime/next/index.js +14 -0
  45. package/dist/runtime/next/server.d.ts +2 -0
  46. package/dist/runtime/next/server.js +4 -0
  47. package/dist/runtime/nuxt/composables.d.ts +9 -0
  48. package/dist/runtime/nuxt/composables.js +57 -0
  49. package/dist/runtime/nuxt/index.d.ts +3 -0
  50. package/dist/runtime/nuxt/index.js +6 -0
  51. package/dist/runtime/nuxt/server.d.ts +3 -0
  52. package/dist/runtime/nuxt/server.js +6 -0
  53. package/dist/runtime/primitives/components/RichText.d.ts +5 -1
  54. package/dist/runtime/primitives/components/RichText.js +2 -2
  55. package/dist/runtime/primitives/labels-hook.d.ts +33 -0
  56. package/dist/runtime/primitives/labels-hook.js +41 -0
  57. package/dist/runtime/primitives/labels-store.d.ts +12 -0
  58. package/dist/runtime/primitives/labels-store.js +60 -0
  59. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +5 -3
  60. package/dist/runtime/primitives/lib/useFimoLiveValue.js +11 -4
  61. package/dist/runtime/primitives/translations.d.ts +1 -27
  62. package/dist/runtime/primitives/translations.js +7 -85
  63. package/dist/runtime/react/FimoSpaProviders.d.ts +36 -0
  64. package/dist/runtime/react/FimoSpaProviders.js +122 -0
  65. package/dist/runtime/react/index.d.ts +35 -0
  66. package/dist/runtime/react/index.js +40 -0
  67. package/dist/runtime/react/spa-content-cache.d.ts +38 -0
  68. package/dist/runtime/react/spa-content-cache.js +64 -0
  69. package/dist/runtime/remix/FimoRemixProviders.d.ts +16 -0
  70. package/dist/runtime/remix/FimoRemixProviders.js +12 -0
  71. package/dist/runtime/remix/FimoRemixScripts.d.ts +10 -0
  72. package/dist/runtime/remix/FimoRemixScripts.js +19 -0
  73. package/dist/runtime/remix/index.d.ts +12 -0
  74. package/dist/runtime/remix/index.js +11 -0
  75. package/dist/runtime/remix/server.d.ts +2 -0
  76. package/dist/runtime/remix/server.js +2 -0
  77. package/dist/runtime/seo/neutral.d.ts +22 -0
  78. package/dist/runtime/seo/neutral.js +17 -0
  79. package/dist/runtime/shared/display-routes.d.ts +14 -0
  80. package/dist/runtime/shared/display-routes.js +25 -0
  81. package/dist/runtime/shared/fimo-config.server.d.ts +0 -1
  82. package/dist/runtime/shared/fimo-config.server.js +1 -13
  83. package/dist/runtime/shared/fimo-config.types.d.ts +2 -0
  84. package/dist/runtime/shared/i18n-messages.d.ts +29 -0
  85. package/dist/runtime/shared/i18n-messages.js +79 -0
  86. package/dist/runtime/shared/labels-fetch.pure.d.ts +17 -0
  87. package/dist/runtime/shared/labels-fetch.pure.js +71 -0
  88. package/dist/runtime/shared/labels-fetch.server.d.ts +7 -0
  89. package/dist/runtime/shared/labels-fetch.server.js +97 -0
  90. package/dist/runtime/shared/labels-t.pure.d.ts +2 -0
  91. package/dist/runtime/shared/labels-t.pure.js +10 -0
  92. package/dist/runtime/strapi/client.d.ts +30 -0
  93. package/dist/runtime/strapi/client.js +132 -0
  94. package/dist/runtime/strapi/index.d.ts +5 -0
  95. package/dist/runtime/strapi/index.js +6 -0
  96. package/dist/runtime/strapi/reshape.d.ts +50 -0
  97. package/dist/runtime/strapi/reshape.js +121 -0
  98. package/dist/runtime/svelte/index.d.ts +3 -0
  99. package/dist/runtime/svelte/index.js +7 -0
  100. package/dist/runtime/svelte/server.d.ts +3 -0
  101. package/dist/runtime/svelte/server.js +6 -0
  102. package/dist/runtime/vue/index.d.ts +3 -0
  103. package/dist/runtime/vue/index.js +5 -0
  104. package/dist/runtime/vue/server.d.ts +3 -0
  105. package/dist/runtime/vue/server.js +6 -0
  106. package/dist/runtime/wrapped/FimoFileLink.d.ts +17 -0
  107. package/dist/runtime/wrapped/FimoFileLink.js +19 -0
  108. package/dist/runtime/wrapped/FimoMediaImage.d.ts +14 -0
  109. package/dist/runtime/wrapped/FimoMediaImage.js +20 -0
  110. package/dist/runtime/wrapped/FimoMediaVideo.d.ts +14 -0
  111. package/dist/runtime/wrapped/FimoMediaVideo.js +20 -0
  112. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +26 -0
  113. package/dist/runtime/wrapped/FimoRichTextBlock.js +22 -0
  114. package/dist/runtime/wrapped/FimoText.d.ts +22 -0
  115. package/dist/runtime/wrapped/FimoText.js +20 -0
  116. package/dist/runtime/wrapped/WrappedContentContext.d.ts +28 -0
  117. package/dist/runtime/wrapped/WrappedContentContext.js +30 -0
  118. package/dist/runtime/wrapped/WrappedProviders.d.ts +33 -0
  119. package/dist/runtime/wrapped/WrappedProviders.js +101 -0
  120. package/dist/runtime/wrapped/content-fetch.pure.d.ts +20 -0
  121. package/dist/runtime/wrapped/content-fetch.pure.js +106 -0
  122. package/dist/runtime/wrapped/dom.d.ts +4 -0
  123. package/dist/runtime/wrapped/dom.js +23 -0
  124. package/dist/runtime/wrapped/server.d.ts +80 -0
  125. package/dist/runtime/wrapped/server.js +207 -0
  126. package/dist/scripts/apply-wrap-templates.d.ts +61 -0
  127. package/dist/scripts/apply-wrap-templates.js +137 -0
  128. package/dist/scripts/apply-wrap.d.ts +73 -0
  129. package/dist/scripts/apply-wrap.js +340 -0
  130. package/dist/scripts/cms/discover.d.ts +2 -0
  131. package/dist/scripts/cms/discover.js +17 -0
  132. package/dist/scripts/cms/example-content.d.ts +33 -0
  133. package/dist/scripts/cms/example-content.js +165 -0
  134. package/dist/scripts/cms/strapi/detect.d.ts +2 -0
  135. package/dist/scripts/cms/strapi/detect.js +186 -0
  136. package/dist/scripts/cms/strapi/index.d.ts +3 -0
  137. package/dist/scripts/cms/strapi/index.js +25 -0
  138. package/dist/scripts/cms/strapi/list-source.d.ts +17 -0
  139. package/dist/scripts/cms/strapi/list-source.js +90 -0
  140. package/dist/scripts/cms/strapi/schema-map.d.ts +9 -0
  141. package/dist/scripts/cms/strapi/schema-map.js +289 -0
  142. package/dist/scripts/cms/strapi/shapes.d.ts +25 -0
  143. package/dist/scripts/cms/strapi/shapes.js +48 -0
  144. package/dist/scripts/cms/strapi/touchpoints.d.ts +31 -0
  145. package/dist/scripts/cms/strapi/touchpoints.js +145 -0
  146. package/dist/scripts/cms/strapi/wire-client.d.ts +15 -0
  147. package/dist/scripts/cms/strapi/wire-client.js +107 -0
  148. package/dist/scripts/cms/strapi/wiring.d.ts +17 -0
  149. package/dist/scripts/cms/strapi/wiring.js +46 -0
  150. package/dist/scripts/cms/types.d.ts +145 -0
  151. package/dist/scripts/cms/types.js +11 -0
  152. package/dist/scripts/detect-framework.d.ts +39 -0
  153. package/dist/scripts/detect-framework.js +139 -0
  154. package/dist/scripts/draft-rows.d.ts +19 -0
  155. package/dist/scripts/draft-rows.js +178 -0
  156. package/dist/scripts/draft-schemas.d.ts +27 -0
  157. package/dist/scripts/draft-schemas.js +247 -0
  158. package/dist/scripts/extract-translations.js +16 -11
  159. package/dist/scripts/frameworks/astro/routes.d.ts +3 -0
  160. package/dist/scripts/frameworks/astro/routes.js +44 -0
  161. package/dist/scripts/frameworks/astro/template-style.d.ts +7 -0
  162. package/dist/scripts/frameworks/astro/template-style.js +19 -0
  163. package/dist/scripts/frameworks/discover.d.ts +83 -0
  164. package/dist/scripts/frameworks/discover.js +288 -0
  165. package/dist/scripts/frameworks/discovered-route.d.ts +9 -0
  166. package/dist/scripts/frameworks/discovered-route.js +17 -0
  167. package/dist/scripts/frameworks/next/rewire.d.ts +43 -0
  168. package/dist/scripts/frameworks/next/rewire.js +282 -0
  169. package/dist/scripts/frameworks/next/routes.d.ts +30 -0
  170. package/dist/scripts/frameworks/next/routes.js +176 -0
  171. package/dist/scripts/frameworks/next/wiring.d.ts +33 -0
  172. package/dist/scripts/frameworks/next/wiring.js +186 -0
  173. package/dist/scripts/frameworks/nuxt/routes.d.ts +3 -0
  174. package/dist/scripts/frameworks/nuxt/routes.js +38 -0
  175. package/dist/scripts/frameworks/nuxt/template-style.d.ts +9 -0
  176. package/dist/scripts/frameworks/nuxt/template-style.js +27 -0
  177. package/dist/scripts/frameworks/remix/routes.d.ts +3 -0
  178. package/dist/scripts/frameworks/remix/routes.js +36 -0
  179. package/dist/scripts/frameworks/support.d.ts +75 -0
  180. package/dist/scripts/frameworks/support.js +165 -0
  181. package/dist/scripts/frameworks/sveltekit/routes.d.ts +3 -0
  182. package/dist/scripts/frameworks/sveltekit/routes.js +35 -0
  183. package/dist/scripts/frameworks/sveltekit/template-style.d.ts +9 -0
  184. package/dist/scripts/frameworks/sveltekit/template-style.js +54 -0
  185. package/dist/scripts/frameworks/vite/routes.d.ts +20 -0
  186. package/dist/scripts/frameworks/vite/routes.js +143 -0
  187. package/dist/scripts/frameworks/vite/wiring.d.ts +22 -0
  188. package/dist/scripts/frameworks/vite/wiring.js +144 -0
  189. package/dist/scripts/i18n-namespace.d.ts +27 -0
  190. package/dist/scripts/i18n-namespace.js +155 -0
  191. package/dist/scripts/lib/humanize.d.ts +14 -0
  192. package/dist/scripts/lib/humanize.js +54 -0
  193. package/dist/scripts/lib/validation-report.d.ts +1 -3
  194. package/dist/scripts/lib/validation-report.js +3 -9
  195. package/dist/scripts/render-parity/capture.d.ts +64 -0
  196. package/dist/scripts/render-parity/capture.js +436 -0
  197. package/dist/scripts/render-parity/compare.d.ts +59 -0
  198. package/dist/scripts/render-parity/compare.js +0 -0
  199. package/dist/scripts/render-parity/normalize-html.d.ts +13 -0
  200. package/dist/scripts/render-parity/normalize-html.js +223 -0
  201. package/dist/scripts/render-parity/types.d.ts +41 -0
  202. package/dist/scripts/render-parity/types.js +1 -0
  203. package/dist/scripts/routes/bindings.d.ts +93 -0
  204. package/dist/scripts/routes/bindings.js +117 -0
  205. package/dist/scripts/routes/label-prefixes.d.ts +49 -0
  206. package/dist/scripts/routes/label-prefixes.js +136 -0
  207. package/dist/scripts/routes/module-resolve.d.ts +20 -0
  208. package/dist/scripts/routes/module-resolve.js +78 -0
  209. package/dist/scripts/routes/page-structure.d.ts +72 -0
  210. package/dist/scripts/routes/page-structure.js +234 -0
  211. package/dist/scripts/scan-wrappable.d.ts +200 -0
  212. package/dist/scripts/scan-wrappable.js +1355 -0
  213. package/dist/scripts/validate-route-metadata.js +11 -0
  214. package/dist/scripts/validate-schemas.js +42 -1
  215. package/package.json +88 -4
  216. package/release.json +2 -2
  217. package/templates/react-router/package.json +1 -1
  218. package/templates/react-router/translations/en.json +1 -0
@@ -67,7 +67,7 @@ Use `connect` for provider accounts, workspaces, OAuth installs, and API-key acc
67
67
  fimo integrations run firecrawl scrape --url https://example.com
68
68
  fimo integrations run firecrawl scrape --url https://example.com --formats markdown,summary,links
69
69
  fimo integrations run firecrawl scrape --url https://example.com --connection client-b
70
- fimo integrations run firecrawl search --query "Example Domain" --max-results 3
70
+ fimo integrations run firecrawl search --query "Example Domain" --max-results 3 --include-domains example.com
71
71
  fimo integrations run firecrawl map --url https://example.com --limit 20
72
72
  fimo integrations run firecrawl crawl --url https://example.com --limit 3 --formats markdown
73
73
  fimo integrations run firecrawl monitor.create --name pricing --url https://example.com/pricing --schedule hourly
@@ -76,6 +76,10 @@ fimo integrations run firecrawl monitor.list
76
76
 
77
77
  Firecrawl execution supports `search`, `scrape`, `map`, `crawl`, and `monitor.*` lifecycle tools. The default scrape/crawl output format is `markdown`; supported formats are `markdown`, `summary`, `links`, `images`, `html`, and `raw-html`.
78
78
 
79
+ Firecrawl search returns query-relevant excerpts by default. Use them for direct, sourced answers and scrape only when
80
+ full context or exact wording is needed. Search can be narrowed with source, category, domain, freshness, location,
81
+ and country options; see the Firecrawl reference for the full command shape.
82
+
79
83
  Use `--connection <alias>` only for one run when a named connection already exists. It does not change the project default
80
84
  integration setup.
81
85
 
@@ -0,0 +1,162 @@
1
+ # Outbound webhooks
2
+
3
+ > **Run via `npx fimo@latest <command>`** so the event catalog and delivery commands match the platform.
4
+
5
+ > **Beta:** Test each destination and inspect its delivery history before depending on it in production.
6
+
7
+ Use `fimo webhooks` to send project events to external HTTPS endpoints. The CLI and Studio edit the same project-wide configurations and delivery history. The CLI has no provider presets: inspect the destination's API documentation, then pass its URL, headers, and JSON body explicitly.
8
+
9
+ Webhook commands require Full Access to the project. Do not attempt them when the current CLI identity has Edit, Comment, View, or agent access; the API enforces the same permission boundary as Studio.
10
+
11
+ ## Start from the live event catalog
12
+
13
+ ```bash
14
+ fimo webhooks events
15
+ fimo webhooks events form.submitted
16
+ ```
17
+
18
+ Run this before writing a custom payload. The list shows supported event types, descriptions, and valid
19
+ `event.data...` template variables. Pass one event name to get its example payload too. The initial families are:
20
+
21
+ - Forms: `form.submitted`
22
+ - Publish: `publish.started`, `publish.succeeded`, `publish.failed`, `publish.unpublished`
23
+ - Agents: run started/completed/failed/cancelled and review requested/resolved
24
+ - Analytics: `analytics.report_ready`
25
+ - Media: uploaded/updated/deleted/generated/processing_failed
26
+ - Entries: `entry.changed`
27
+
28
+ Do not guess variable paths. The common envelope is:
29
+
30
+ ```json
31
+ {
32
+ "id": "event-id",
33
+ "type": "form.submitted",
34
+ "version": 1,
35
+ "test": false,
36
+ "createdAt": "2026-07-17T10:00:00.000Z",
37
+ "project": { "id": "project-id" },
38
+ "env": { "name": "main" },
39
+ "data": {}
40
+ }
41
+ ```
42
+
43
+ Omit `--body` to send this full envelope. Prefer that default when the receiver can accept Fimo's shape.
44
+
45
+ ## Create a provider-specific request
46
+
47
+ Store credentials as project secrets, never literal header flags:
48
+
49
+ ```bash
50
+ printf '%s' "$RESEND_API_KEY" | fimo secrets set RESEND_API_KEY --stdin
51
+
52
+ fimo webhooks create waitlist-resend \
53
+ --event form.submitted \
54
+ --form waitlist \
55
+ --url https://api.resend.com/contacts \
56
+ --header "Authorization=bearer:RESEND_API_KEY" \
57
+ --body '{"email":"{{ event.data.submission.data.email }}"}'
58
+ ```
59
+
60
+ Header sources:
61
+
62
+ - `Name=secret:KEY`: secret is the complete value
63
+ - `Name=bearer:KEY`: `Bearer ` plus the secret
64
+ - `Name=token:KEY`: `token ` plus the secret
65
+ - `Name=literal:value`: non-secret fixed value
66
+
67
+ Secret-backed values resolve when a delivery runs, so rotating a project secret updates later deliveries without editing the webhook. Fimo masks destination URLs, credentials, payload secrets, and response excerpts in CLI and Studio output.
68
+
69
+ ## Shape custom JSON safely
70
+
71
+ `--body` accepts JSON with exact `{{ event... }}` substitutions in values:
72
+
73
+ ```bash
74
+ fimo webhooks create publish-slack \
75
+ --event publish.succeeded \
76
+ --url https://hooks.slack.com/services/... \
77
+ --body '{"text":"Published {{ event.data.publication.url }}"}'
78
+ ```
79
+
80
+ Use `--body @path/to/payload.json` for a file or `--body -` for stdin. Paths resolve from `-C` or the current
81
+ project directory.
82
+
83
+ When a variable occupies the entire JSON value, objects and arrays retain their JSON type:
84
+
85
+ ```json
86
+ {
87
+ "submission": "{{ event.data.submission }}",
88
+ "email": "{{ event.data.submission.data.email }}"
89
+ }
90
+ ```
91
+
92
+ Do not add executable transform scripts or workers to a project just to reshape a payload. Use the JSON template for deterministic mappings; use an external workflow endpoint only when the integration genuinely needs branching or code.
93
+
94
+ Available filters are event-specific:
95
+
96
+ - `--environments <main|all>` for the event origin; the default is `main`
97
+ - `--form <id>` for `form.submitted`
98
+ - `--agent <name>` for agent events
99
+ - `--media-type <image|video|audio|document|other>` for media events
100
+ - `--action <created|updated|deleted>`, `--content-type <name>`, and `--locale <locale>` for `entry.changed`
101
+ - `--debounce-changes <immediate|5s|30s|1m>` for direct `entry.changed` delivery grouping
102
+
103
+ `entry.changed` represents content accepted in the selected environments. New entry webhooks wait 5 seconds after the last direct edit by default, then send one delivery with the combined `data.changes`. Exact repeated autosave changes appear once. Use `--debounce-changes immediate` to disable grouping. Accepted agent edits and environment merges already carry compact batches and send immediately. Operations above the delivery batch size share an `operationId` and include `{ index, total }` batch metadata. Every event includes its origin at `event.env.name`.
104
+
105
+ ## Inspect before depending on it
106
+
107
+ ```bash
108
+ fimo webhooks list
109
+ fimo webhooks get <webhook-id>
110
+ fimo webhooks test <webhook-id> --wait
111
+ fimo webhooks deliveries <webhook-id> --limit 20
112
+ fimo webhooks delivery <webhook-id> <delivery-id>
113
+ ```
114
+
115
+ `test` uses the selected event's documented example data and adds `X-Fimo-Test: true`. `--wait` waits up to 60
116
+ seconds for success or failure. Pass `--data '{...}'` only when a specific shape needs testing.
117
+
118
+ Fimo automatically retries temporary failures with backoff. After retries are exhausted:
119
+
120
+ ```bash
121
+ fimo webhooks retry <webhook-id> <delivery-id>
122
+ ```
123
+
124
+ Use the delivery error code and attempt history to distinguish destination errors, timeouts, missing secrets, invalid templates, and blocked unsafe URLs. A delivery accepts up to five manual retries.
125
+
126
+ ## Manage configurations
127
+
128
+ ```bash
129
+ fimo webhooks update <webhook-id> --enabled off
130
+ fimo webhooks update <webhook-id> --url https://example.com/hooks/fimo
131
+ fimo webhooks update <webhook-id> --default-body
132
+ fimo webhooks delete <webhook-id>
133
+ ```
134
+
135
+ Webhooks belong to the project, with up to 20 configurations per project. The same configuration is visible from every environment. Delivery listens to `main` by default. Use `--environments all` to include branch activity, or `--environments main` to return to main-only delivery.
136
+
137
+ ## Verify Fimo signatures
138
+
139
+ Signing is on by default. Save the signing secret shown once at creation. Fimo sends:
140
+
141
+ - `X-Fimo-Delivery`: stable delivery ID
142
+ - `X-Fimo-Event`: event type
143
+ - `X-Fimo-Event-Id`: stable event ID for receiver deduplication
144
+ - `X-Fimo-Test`: `true` for synthetic test deliveries
145
+ - `X-Fimo-Timestamp`: Unix timestamp for the attempt
146
+ - `X-Fimo-Signature`: `v1=` plus HMAC-SHA256 of `<timestamp>.<raw-request-body>`
147
+
148
+ At the receiver, reject stale timestamps and compare the computed signature with a timing-safe comparison before parsing or acting on the payload. Rotate an exposed signing secret with:
149
+
150
+ ```bash
151
+ fimo webhooks rotate-secret <webhook-id>
152
+ ```
153
+
154
+ Save the returned value immediately; it is not shown again.
155
+
156
+ ## Guardrails
157
+
158
+ - Destinations must use public HTTPS URLs in production. Local/private/link-local addresses and redirects are blocked.
159
+ - Do not place access tokens in URLs, literal headers, payload templates, logs, or committed files.
160
+ - Do not retry a pending or actively retrying delivery manually.
161
+ - Do not assume a successful queue operation means the destination accepted the request; inspect the delivery result.
162
+ - Use `--json` when another agent or script needs stable, parseable output.
@@ -17,7 +17,10 @@ exports, source repositories, CMS exports, media folders, or any hybrid of those
17
17
  It owns intake, source inventory, URL crawl bootstrapping, ledger normalization,
18
18
  imports, and QA so any LLM can run the work without silently dropping content.
19
19
 
20
- > Run every `fimo` command as `npx fimo@latest <command>` — always the latest CLI, no global install.
20
+ > Run every `fimo` command as `npx fimo <command>` when the project declares a
21
+ > `fimo` dependency (adopted/wrapped projects pin an exact version tied to their
22
+ > backend — never override it with `@latest`). Only fall back to
23
+ > `npx fimo@latest` when the project has no `fimo` dependency.
21
24
 
22
25
  ## Non-Negotiables
23
26
 
@@ -30,6 +33,13 @@ imports, and QA so any LLM can run the work without silently dropping content.
30
33
  ledger.
31
34
  - Source exports beat inferred crawls. If CSV/XML/JSON exports, media folders, or
32
35
  source code exist, treat the public URL as visual/SEO reference only.
36
+ - A working JS codebase is wrapped, not rewritten. Wrap mode
37
+ (`references/wrap.md`) keeps the user's routing, styling, and components
38
+ untouched; the diff is wiring + wrappers + config only. As the coding
39
+ agent you own the whole wrap loop — run `npx fimo migrate` yourself and
40
+ follow `references/wrap.md` § W0 (relay the recorded data-source
41
+ decisions to the user, then loop `npx fimo migrate wrap --check` to
42
+ exit 0).
33
43
  - Builder HTML is evidence, not the final runtime. Rebuild with Fimo conventions,
34
44
  schemas, forms, media primitives, translations, and routes.
35
45
  - Do not report completion until the QA gate passes or every failed check is
@@ -59,7 +69,15 @@ imports, and QA so any LLM can run the work without silently dropping content.
59
69
  pack.
60
70
  - **hybrid**: source files plus public URL. Use source-backed as truth and URL
61
71
  for route, SEO, visual, and behavior comparison.
62
- 4. Create or update the canonical ledger described in
72
+ 4. Pick the mode:
73
+ - **wrap** (default for a source-backed, working JS codebase — Next.js,
74
+ Vite/React, React Router): keep the user's stack, adopt the repo with
75
+ `fimo init`, and make content editable by wrapping it in place. Never
76
+ rewrite routing, styling, or components. Follow `references/wrap.md`.
77
+ - **rebuild**: url-only sources, builder exports/HTML dumps, non-JS
78
+ backends, or codebases that do not build. Follow the standard workflow
79
+ phases.
80
+ 5. Create or update the canonical ledger described in
63
81
  `references/manifest.md`.
64
82
 
65
83
  ## Workflow
@@ -96,7 +114,11 @@ node <this-skill>/scripts/write-migration-report.mjs <project-root>
96
114
  ## References
97
115
 
98
116
  - `references/workflow.md` - full decision tree and phase order.
117
+ - `references/wrap.md` - wrap mode: adopt a working JS codebase and wrap its
118
+ content in place (default for source-backed JS sites).
99
119
  - `references/manifest.md` - canonical migration ledger schema.
120
+ - `references/pages.md` - the page registry (templates, schema bindings,
121
+ instances), Studio preview navigation, and the opt-in per-page SEO recipes.
100
122
  - `references/content.md` - CMS, entries, references, and source value rules.
101
123
  - `references/media.md` - media inventory, upload, dedupe, and replacement rules.
102
124
  - `references/forms.md` - form classification and Fimo replacement rules.
@@ -18,6 +18,14 @@ ways:
18
18
  news teasers, and feature lists are almost always collections even when the
19
19
  source renders them inside one page.
20
20
 
21
+ > **Rebuild path only.** These rules apply when Fimo re-authors the site
22
+ > (URL/export migrations): the rebuilt code is disposable, so content belongs
23
+ > in collections aggressively. **Wrap mode is deliberately stricter** — the
24
+ > user's code stays primary, page furniture and nav stay in code with `t()`
25
+ > labels, and every collection candidate is confirmed with the user first.
26
+ > See `wrap.md` (W0 and the generated agent-prompt) — in wrap mode that
27
+ > guidance overrides this section.
28
+
21
29
  After the source-faithful rebuild, treat **any hardcoded array of 3+ items with
22
30
  the same shape** as a collection candidate. Do not leave it hardcoded.
23
31
 
@@ -97,3 +105,19 @@ Skipped fields or entries require a manifest note with:
97
105
  - reason
98
106
  - owner impact
99
107
  - suggested action
108
+
109
+ ## Scaffolded CMS — verify pages render
110
+
111
+ When `fimo migrate --scaffold-cms` wires the site to Fimo, the machine does the
112
+ deterministic work: it maps the CMS's components and dynamic zones to editable
113
+ Fimo blocks, seeds every block with generic example content in the shape the
114
+ components expect, and swaps the client's fetch for the generated Fimo adapter —
115
+ so the whole site reads from Fimo with no per-view wiring.
116
+
117
+ The last mile is yours and it is per-site. Open the main pages in `pnpm dev` (a
118
+ list, a detail, the page-builder home) and confirm each renders. Every renderer is
119
+ the site's own code, so a component may read a field the generic content did not
120
+ fill, or expect a slightly different shape. Where a section renders blank or
121
+ throws, fix it at that component — a defensive default, or the field it truly
122
+ needs — and re-check. Record anything you cannot resolve as a caveat. Do not
123
+ re-scaffold, re-wire, or hand-wrap content; the machine owns those.
@@ -34,6 +34,7 @@ follow-up agents, and import/QA checks.
34
34
  "seo": [],
35
35
  "unsupported": [],
36
36
  "unresolved": [],
37
+ "wrap": null,
37
38
  "qa": {
38
39
  "status": "not-run|passed|failed|passed-with-unresolved",
39
40
  "checks": []
@@ -41,6 +42,51 @@ follow-up agents, and import/QA checks.
41
42
  }
42
43
  ```
43
44
 
45
+ ## Wrap Block (wrap mode only)
46
+
47
+ When the migration is a wrap (see `references/wrap.md`), set
48
+ `source.mode: "source-backed"` and fill the `wrap` block; leave it `null` for
49
+ rebuild migrations:
50
+
51
+ ```json
52
+ {
53
+ "wrap": {
54
+ "mode": "wrap",
55
+ "framework": "next|react-router|vite",
56
+ "adopted": true,
57
+ "wired": true,
58
+ "coverage": {
59
+ "wrappable": 0,
60
+ "wrapped": 25,
61
+ "ignored": 0,
62
+ "unresolvedItems": 0
63
+ },
64
+ "seeded": {
65
+ "labels": 21,
66
+ "wrappedMedia": 3,
67
+ "wrappedRichText": 1
68
+ },
69
+ "seo": { "decision": "external", "decidedBy": "default" },
70
+ "planPath": ".fimo/migration/plan.json"
71
+ }
72
+ }
73
+ ```
74
+
75
+ `wrap.seo` records who owns the site's SEO metadata — a USER decision, like
76
+ `wrap.dataSources`: `decision` is `"fimo"` (Fimo manages per-page SEO,
77
+ editable in the Studio) or `"external"` (the code / an external SEO tool
78
+ keeps ownership — the DEFAULT, nothing is ever wired on it). `decidedBy` is
79
+ `"default"` until the user actually answered; relay defaulted records and
80
+ rewrite them with `decidedBy: "user"`. Page bindings themselves live in the
81
+ page registry (`fimo-config.json#routes` →
82
+ `params: { "<param>": { "schema", "queryField", "displayField" } }`), not in
83
+ the manifest — see `references/pages.md`.
84
+
85
+ `coverage` mirrors the final `fimo migrate wrap --check` output: `wrappable`
86
+ must be 0 (or fully accounted for by `ignored` + `unresolvedItems`, each with a
87
+ ledger entry). `seeded` counts must match what `fimo labels list` /
88
+ `fimo entries list` report — fallback-only content is not seeded.
89
+
44
90
  ## Required Item Fields
45
91
 
46
92
  Every route, content type, entry batch, media asset, form, redirect, locale, SEO
@@ -0,0 +1,234 @@
1
+ # Pages — the page registry, Preview navigation, and opt-in SEO
2
+
3
+ A **Page** is a navigable URL surface of the site, in two forms:
4
+
5
+ - **Page template** — what the app's routing declares: `/pricing` (static),
6
+ `/blog/:slug` (dynamic). The app's CODE is the source of truth for page
7
+ structure; `fimo migrate` discovers templates per framework and reconciles
8
+ them into the registry, `fimo-config.json#routes` (manual entries are
9
+ preserved). Param syntax is ALWAYS `:param` / catch-all `:param*` — never
10
+ `[param]`.
11
+ - **Page instance** — a concrete page: template × content entry
12
+ (`/blog/:slug` × `hello-world`). Instances are NEVER stored; they derive
13
+ from entries through the template's binding, so they cannot drift.
14
+
15
+ The registry entry shape:
16
+
17
+ ```json
18
+ "blog-post": {
19
+ "label": "Blog post",
20
+ "path": "/blog/:slug",
21
+ "params": { "slug": { "schema": "BlogPost", "queryField": "slug", "displayField": "title" } },
22
+ "seo": { "title": "{{blog-post.title}} — {{siteName}}" }
23
+ }
24
+ ```
25
+
26
+ - `params[<param>]` is the **binding**: the schema whose entries materialize
27
+ the instances. `queryField` = the entry field substituted into the URL
28
+ (entry `slug` metadata always qualifies); `displayField` = the label the
29
+ Studio's page picker shows.
30
+ - The Studio preview navigates ONLY what the registry describes: static pages
31
+ as-is, dynamic pages once bound. An unbound dynamic page navigates to a
32
+ literal `/blog/:slug` URL — broken by definition.
33
+ - Locale params (`:locale`, `:lang`) are never schema-bound; tooling
34
+ substitutes the project's default locale. (Studio locale switching for
35
+ dynamic pages is a platform follow-up, not your problem.)
36
+
37
+ ## Completing the bindings (agent workflow)
38
+
39
+ `fimo migrate` writes strong-evidence bindings itself (a rewired parent list
40
+ page; a wired CMS with a single page-builder type) and lists candidates +
41
+ unbound pages in the generated prompt. Your job:
42
+
43
+ 1. `npx fimo pages list` — see every template and its status
44
+ (`static | dynamic:bound | dynamic:unbound`).
45
+ 2. For each candidate/unbound page, find the schema whose entries the page
46
+ renders (read the page component's fetch). Apply with
47
+ `npx fimo pages set <id> --params '{"<param>":{"schema":"<Type>","queryField":"slug","displayField":"<field>"}}'`
48
+ — it validates the schema and both fields against the server. Never
49
+ hand-edit the JSON. If drafts are not adopted yet, run
50
+ `schemas adopt-drafts` FIRST and bind with the FINAL names.
51
+ 3. Add pages the scanner missed (SPA relative/wildcard routes):
52
+ `npx fimo pages set <id> --path /the/path --label "Label"`.
53
+ Never repeat the folder/category in the label: the `/features/agents` page
54
+ is labeled "Agents", NOT "Feature: Agents" — the Studio tree already nests
55
+ it under Features.
56
+ Labels must read like a human wrote them: acronyms uppercase ("Agentic
57
+ CMS", "AI Stack", "SEO GEO" — never "Agentic Cms"), no two sibling pages
58
+ with the same name (a bound template is named after its schema — "Blog
59
+ Post" next to the "Blog" index; the machine does this when it binds, fix
60
+ any leftover with `--label`).
61
+ When the site's NAV groups flat pages editorially (a "Resources" menu over
62
+ /for-developers, /for-founders…), mirror it with
63
+ `npx fimo pages set <id> --group "Resources"` — the Studio Pages tree
64
+ folds them under that group even without a shared URL segment.
65
+ 4. Map each page to its label keys when they diverge. The Studio shows a
66
+ page's labels by key prefix, defaulting to `<pageId>.` — but wrapped keys
67
+ derive from FILE names (`AiCms.tsx` → `ai-cms.*`) or data files
68
+ (`personas.*`), which can differ from the URL-derived page id
69
+ (`agentic-cms`). A page whose Studio view is EMPTY almost always means
70
+ this mismatch. `fimo migrate` PREFILLS `labelPrefixes` wherever it can
71
+ prove the join (a staged key appears verbatim in the route's component
72
+ file) and the prompt § Routes & pages lists every UNCLAIMED prefix left.
73
+ Your job: place each unclaimed prefix — claim it with
74
+ `npx fimo pages set <id> --label-prefix "<prefix>"` (comma-separated for
75
+ several; claims MERGE into the existing list so machine-prefilled
76
+ prefixes survive, `""` clears the whole list) when one page renders those keys, or leave it
77
+ deliberately when it is shared (chrome, multi-page data files) and say so
78
+ in your report. No prefix may end up merely forgotten.
79
+ 5. Give each page the Lucide icon that best matches its CONTENT:
80
+ `npx fimo pages set <id> --icon <kebab-name>` (pricing → `tag`, blog →
81
+ `newspaper`, contact → `mail`, legal pages → `scale`, team/about →
82
+ `users`, docs → `book-open`). Read the page component to judge. Use
83
+ well-known Lucide names only — an unknown name silently falls back to
84
+ the default file icon in the Studio. Skip the flag when nothing clearly
85
+ fits.
86
+ 6. Verify: `npx fimo pages list --expand` materializes every instance —
87
+ each page the site's nav links to must appear as a real URL.
88
+
89
+ ## Shared chrome → Single Types (the content-model rule)
90
+
91
+ A site's content model must read like a CMS, not like an implementation:
92
+
93
+ - **Chrome** (header, footer, nav, menus, banners) is edited as ONE thing →
94
+ a SINGLE TYPE per piece (`src/schemas/<Name>.json` with
95
+ `"isSingleton": true`, real fields mirroring the source: nav items as an
96
+ array/blocks field, logo as media), pushed with `npx fimo schemas push`,
97
+ its ONE document written from the source values with
98
+ `npx fimo documents set <Name> --body '<json>'` (singletons REJECT the
99
+ entries endpoints), component rewired to read it. Never a loose label
100
+ pile, never a collection.
101
+ - **Page-scoped structure** (a pricing page's FAQ list) → a component array
102
+ on that page's Single, or a collection + reference when genuinely reused
103
+ across pages. Never an orphan collection nobody can situate. CLAIM the
104
+ single on its page (`npx fimo pages set pricing --single Pricing`) — it
105
+ then edits inline in the page's Studio view and leaves the Singles tab.
106
+ - **Real repeating content** (blog posts, team members) → a collection, with
107
+ HUMAN slugs derived from the display field (never `faq-item-<hash>`), and
108
+ schema field order matching reading order (question before answer).
109
+ - **A page's SECTIONS are its Single's nested blocks.** A marketing page is
110
+ a sequence of sections (hero, logo strip, features grid with grouped
111
+ cards, testimonials, integrations, stats, FAQ) — model the page as ONE
112
+ Single whose fields are nested block components mirroring that structure
113
+ (blocks nest: a `features` field holds groups, each group holds cards).
114
+ Section card lists are NEVER "page furniture" exemptions when they carry
115
+ real copy — an exemption hides marketing content from the editor, which
116
+ is a failed migration for that section. Claim the Single on its page.
117
+ **The machine BUILDS this model for you**: `fimo migrate` writes, per
118
+ multi-section page, an analysis draft (`.fimo/migration/page-drafts/`,
119
+ regenerate with `npx fimo pages draft`) AND a ready page Single
120
+ (`.fimo/migration/page-singles/<Uid>.json` — singleton schema + document
121
+ filled with the staged label values and the source block rows). Sections
122
+ flagged `"shared": true` render on several pages — that is chrome: model
123
+ each once as a Single Type, never as a per-page block. The `wrap --check`
124
+ Content-model gate fails while a built Single is neither claimed
125
+ (`pages set <id> --single <Uid>`) nor recorded under
126
+ `wrap.modelDeviations` (`{"page": "<id>", "reason": "…"}`) — a reason the
127
+ user would accept; "faster as labels" is not one. Your work per page:
128
+ rename machine field keys to editorial names, push, `documents set`,
129
+ rewire the reads with source fallback, claim.
130
+
131
+ **Worked real example** (the Fimo homepage, the model the user ratified):
132
+ the page renders hero → logo strip → features grid (3 groups, each with
133
+ cards) → testimonials → integrations → stats bar → FAQ. Its Single:
134
+
135
+ ```json
136
+ {
137
+ "uid": "Home",
138
+ "isSingleton": true,
139
+ "fields": {
140
+ "builtOnTheBest": {
141
+ "type": "blocks",
142
+ "schema": { "fields": { "name": { "type": "string" }, "domain": { "type": "string" } } }
143
+ },
144
+ "features": {
145
+ "type": "blocks",
146
+ "schema": {
147
+ "fields": {
148
+ "title": { "type": "string" },
149
+ "subtitle": { "type": "string" },
150
+ "cards": {
151
+ "type": "blocks",
152
+ "schema": { "fields": { "title": { "type": "string" }, "description": { "type": "text" } } }
153
+ }
154
+ }
155
+ }
156
+ },
157
+ "testimonials": {
158
+ "type": "blocks",
159
+ "schema": {
160
+ "fields": {
161
+ "quote": { "type": "text" },
162
+ "metricValue": { "type": "string" },
163
+ "metricLabel": { "type": "string" },
164
+ "author": { "type": "string" },
165
+ "role": { "type": "string" }
166
+ }
167
+ }
168
+ },
169
+ "ecosystem": {
170
+ "type": "blocks",
171
+ "max": 1,
172
+ "schema": {
173
+ "fields": {
174
+ "title": { "type": "string" },
175
+ "stats": { "type": "blocks", "schema": { "fields": { "label": { "type": "string" } } } }
176
+ }
177
+ }
178
+ },
179
+ "faqs": { "type": "blocks", "schema": { "fields": { "q": { "type": "string" }, "a": { "type": "text" } } } }
180
+ }
181
+ }
182
+ ```
183
+
184
+ Note what made it right: block names are the on-page section titles
185
+ ("Built on top of the best" → `builtOnTheBest`), field names are ROLES
186
+ (`title`, `quote`, `author`) never copy slugs, a logo strip carries its
187
+ ITEMS (not just its heading), computed live values (stat numbers) stay in
188
+ code, and the whole thing was claimed on the page. Smart deviations were
189
+ reported, not silent.
190
+
191
+ - **Plumbing** (`WrappedRichText`, `WrappedMedia`) is storage — the Studio
192
+ hides it from Collections and shows the entries under their pages; never
193
+ present it as content in your report.
194
+
195
+ ## SEO — a USER decision, never wired by default
196
+
197
+ Who owns SEO metadata is recorded in `.fimo/migration/manifest.json` →
198
+ `wrap.seo` (`{ "decision": "fimo" | "external", "decidedBy": "user" | "default" }`).
199
+ The default is ALWAYS `external` (nothing touched — the site's code or an
200
+ external SEO tool keeps ownership). When the prompt shows the decision as
201
+ DEFAULTED, relay it to the user once; only an explicit user "fimo" unlocks
202
+ wiring. Never migrate, edit, or inject metadata on the default.
203
+
204
+ When the user opted into Fimo-managed SEO, the engine is the neutral
205
+ `fimo/seo` export — pure resolution over the registry, no framework coupling:
206
+
207
+ ```ts
208
+ import { getFimoSeoForPath } from 'fimo/seo';
209
+ const seo = getFimoSeoForPath(pathname, { routeData: { 'blog-post': entry } });
210
+ // seo.title / seo.description / seo.image / seo.robots …
211
+ ```
212
+
213
+ Per-framework injection (map the resolved values to the framework's head API):
214
+
215
+ - **Next (app router)** — in the layout or page, `generateMetadata()` calls
216
+ `getFimoSeoForPath` with the resolved pathname (+ the entry as `routeData`
217
+ on dynamic pages) and returns `{ title, description, openGraph: {...} }`.
218
+ - **React Router** — already shipped: `loadFimoMetaData` / `buildFimoMeta` /
219
+ `fimoHtmlProps` from `fimo/react-router`.
220
+ - **Astro** — a head partial calling `getFimoSeoForPath(Astro.url.pathname)`
221
+ server-side and rendering the `<meta>` tags.
222
+ - **Nuxt** — `useSeoMeta()` fed from a server util wrapping `getFimoSeoForPath`.
223
+ - **SvelteKit** — resolve in `+layout.server` load, render in the root
224
+ layout's `<svelte:head>`.
225
+
226
+ Route-level `seo` blocks support `{{variables}}` resolved against
227
+ `routeData` — per-INSTANCE metadata from one template.
228
+
229
+ ## Sitemap / robots
230
+
231
+ Once bindings exist, `getFimoPaths` (from `fimo/paths`) materializes the full
232
+ instance list for prerender/sitemap use. It reads the API base URL from
233
+ `VITE_API_URL` (a plain env var or `.env` line works outside Vite). The
234
+ `fimo pages list --expand` output is the same list, CLI-side.
@@ -18,8 +18,11 @@ Run this gate before reporting completion.
18
18
  ## Behavior
19
19
 
20
20
  - Dependencies are installed in the target project.
21
- - The project builds successfully.
22
- - Local dev starts without Vite loader/schema/form generation errors.
21
+ - The project builds successfully **with its own toolchain** (`next build`,
22
+ `vite build`, …) — wrapped sites are not Vite/React-Router projects; never
23
+ assume Fimo-template tooling.
24
+ - Local dev starts without loader/schema/form generation errors (Vite errors
25
+ apply to rebuild-mode projects only).
23
26
  - Primary routes render without console/runtime errors.
24
27
  - Collection listing/detail pages work with imported data, seed data, or explicit
25
28
  empty states.
@@ -33,6 +36,25 @@ Run this gate before reporting completion.
33
36
  - Remove generated placeholder copy from visible UI.
34
37
  - Verify media aspect ratios and no broken images on primary routes.
35
38
 
39
+ ## Wrap Mode (additional blocking checks)
40
+
41
+ When the manifest says `mode: "wrap"`:
42
+
43
+ - `fimo migrate wrap --check` exits zero — it enforces coverage (zero
44
+ unwrapped items), render parity (rendered text/marks/media/links identical
45
+ to the pre-wrap baseline), and seeding (every wrapped key exists in the
46
+ database) — or every remaining item is an explicit ignored/unresolved
47
+ ledger entry with a reason.
48
+ - Labels are seeded: every `FimoText`/`t()` key exists in `fimo labels list`
49
+ with the original string. Fallback-only content fails the gate.
50
+ - Wrapped media/rich text have their `WrappedMedia`/`WrappedRichText` entries
51
+ created and assets uploaded.
52
+ - Render parity: pages render identically to pre-migration — same text, same
53
+ formatting marks (bold/italic/underline/links), same media.
54
+ - Diff audit: the migration diff contains only wiring, wrappers, label calls,
55
+ config, and dependency changes. Any routing/styling/component rewrite fails
56
+ the gate.
57
+
36
58
  ## Import Verification
37
59
 
38
60
  Record:
@@ -2,6 +2,14 @@
2
2
 
3
3
  Use this as the phase contract for complete migrations.
4
4
 
5
+ > **Mode fork.** For a source-backed, WORKING JS codebase (Next.js, Vite/React,
6
+ > React Router), wrap mode is the default: skip Phases 0 and 6 below and follow
7
+ > `references/wrap.md` (adopt via `fimo init`, scan via `fimo migrate wrap`,
8
+ > wrap in place, seed, verify). Phases 3–5 (content model, media/forms, import)
9
+ > and Phase 8 (QA + report) still apply — wrap changes how content becomes
10
+ > editable, not the accounting obligations. Everything else here is the rebuild
11
+ > path.
12
+
5
13
  ## Phase 0: Target Safety
6
14
 
7
15
  1. Confirm the target path.
@@ -119,7 +127,10 @@ Required order:
119
127
  Record target IDs, import counts, failures, and unresolved items in the
120
128
  canonical ledger. Generated JSON without import counts is still draft state.
121
129
 
122
- ## Phase 6: Fimo Implementation
130
+ ## Phase 6: Fimo Implementation (rebuild mode)
131
+
132
+ In wrap mode this phase is replaced by `references/wrap.md` phases W3–W5
133
+ (wire, wrap, seed); do not rebuild pages for a wrapped site.
123
134
 
124
135
  Implement routes, schemas, forms, entries, media, redirects, translations, and
125
136
  React pages with Fimo conventions.