fimo 2.3.2 → 2.4.0-staging.2

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 (34) hide show
  1. package/assets/skills/fimo-cli/SKILL.md +1 -1
  2. package/assets/skills/fimo-cli/references/deploy.md +8 -11
  3. package/assets/skills/fimo-cli/references/init.md +1 -1
  4. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +1 -1
  5. package/assets/skills/fimo-cli/references/preview.md +12 -42
  6. package/assets/skills/fimo-code/references/frameworks/next/app-router.md +7 -21
  7. package/assets/skills/fimo-code/references/frameworks/next/seo.md +168 -0
  8. package/assets/skills/fimo-code/references/frameworks/next.md +1 -1
  9. package/assets/skills/fimo-migration/SKILL.md +29 -33
  10. package/assets/skills/fimo-migration/references/content.md +1 -1
  11. package/assets/skills/fimo-migration/references/frameworks/nextjs.md +7 -0
  12. package/assets/skills/fimo-migration/references/import-contract.md +4 -6
  13. package/assets/skills/fimo-migration/references/manifest.md +4 -3
  14. package/assets/skills/fimo-migration/references/questions-and-improvements.md +1 -1
  15. package/assets/skills/fimo-migration/references/workflow.md +7 -5
  16. package/dist/cli/bundle.json +1 -1
  17. package/dist/cli/index.js +494 -981
  18. package/dist/runtime/seo/index.d.ts +1 -0
  19. package/dist/runtime/seo/resolver.js +10 -0
  20. package/dist/runtime/seo/server.d.ts +13 -0
  21. package/dist/runtime/seo/server.js +23 -0
  22. package/dist/runtime/shared/fimo-config.server.d.ts +2 -0
  23. package/dist/runtime/shared/fimo-config.server.js +18 -14
  24. package/package.json +12 -8
  25. package/release.json +2 -2
  26. package/templates/astro/package.json +2 -2
  27. package/templates/nextjs/AGENTS.md +1 -1
  28. package/templates/nextjs/package.json +3 -3
  29. package/templates/nextjs/src/app/layout.tsx +5 -3
  30. package/templates/nextjs/src/app/page.tsx +6 -0
  31. package/templates/react-router/package.json +4 -4
  32. package/templates/sveltekit/package.json +2 -2
  33. package/templates/vite/package.json +4 -4
  34. package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +0 -595
@@ -100,7 +100,7 @@ Load the matching reference when the user's request fires its trigger. Recipes t
100
100
  - "List history / create a restore point / recover content and code / restore a previous version / snapshot usage or retention" → `references/history.md`
101
101
  - "Create a Branch / feature Branch / switch Branches / merge Branches / diff two Branches / Branch status / what changed on this Branch / sync from parent / cut a release / tag a version / go to prod" → `references/branches.md`
102
102
  - "List my projects / clone an existing project locally / check out a project / delete this project / unpublish / rename the project / manage projects across the org" → `references/projects.md`
103
- - "Migrate an existing Webflow / Framer / Squarespace / Wix / Carrd site from only a published URL" → load the `fimo-migration` skill and start with `fimo migrate <url> [dir]` to prepare the agent-ready migration draft
103
+ - "Migrate an existing Webflow / Framer / Squarespace / Wix / Carrd site from only a published URL" → load the `fimo-migration` skill, set the target up with `fimo migrate init <dir>`, and read the published site yourself with a browser — the CLI does not crawl it
104
104
  - "Migrate from an exported project, source repository, Webflow code export plus CMS CSVs, Framer CMS CSVs, Squarespace XML/CSV, Wix CSVs, Carrd/static export, or downloaded site files" → load the `fimo-migration` skill and use the source repo/export as the migration source of truth
105
105
  - "How do AI agents read my site / markdown for agents" → `references/deploy.md`
106
106
  - "Modify the URL of the website / change my project's address / connect a custom domain (e.g. blog.example.com) / rename the Fimo-provided `*.fimo.site` subdomain / buy a new domain through Fimo / set up a domain" → `references/domains.md`
@@ -8,7 +8,7 @@
8
8
 
9
9
  Before deploying, Fimo fast-forwards a clean checkout that is behind and stops on dirty-behind or diverged branches. This syncs the whole branch, including config commits from Studio or locale commands.
10
10
 
11
- > **Just need the current preview URL?** That's `fimo preview url` — no commit or push. A cold sandbox can still take time to resolve. See `references/preview.md`. `fimo deploy` is only for pushing code changes.
11
+ > **Just need the current preview URL?** That's `fimo preview url` — no commit or push. It waits if the hosted generation is still building. See `references/preview.md`.
12
12
 
13
13
  ## Commands
14
14
 
@@ -19,7 +19,7 @@ fimo deploy --no-restart # skip dev-server restart (HMR-safe
19
19
  fimo deploy -m "<commit message>" --publish # also publish a new live version
20
20
  ```
21
21
 
22
- - **`fimo deploy`** — commits pending changes, pushes to the current Branch, syncs that Branch's preview sandbox, and links to the Preview and Fimo dashboard.
22
+ - **`fimo deploy`** — commits pending changes, pushes to the current Branch, syncs that Branch's preview sandbox, and links to Fimo Studio.
23
23
  - **`fimo deploy --publish`** — same as above, then triggers a live publish and prints the live URL. Runs from the configured Production source Branch only. **Only use `--publish` when the user signals "ship it"** — first-time site completion, or an explicit "publish" / "go live" request. Otherwise stick to plain `fimo deploy`. (For a _versioned_ prod release, use `fimo publish` instead — see below.)
24
24
  - **`-m`** is the commit message used when there are uncommitted local changes; required in non-interactive shells. Omit if the working tree is already clean.
25
25
  - **`--no-restart`** — tells the sandbox to skip the dev-server restart and let Vite HMR pick up the change. Shaves ~3s per deploy. See "Skipping the dev-server restart" below for when it's safe.
@@ -35,16 +35,13 @@ fimo deploy -m "<commit message>" --publish --json
35
35
 
36
36
  Read these fields from `data`:
37
37
 
38
- | Field | Destination |
39
- | -------------------- | ---------------------------------------------------------------- |
40
- | `preview_url` | Stable, authenticated full-screen viewer for project members. |
41
- | `sandbox_url` | Short-lived raw site URL for agents, curl, and screenshot tools. |
42
- | `sandbox_expires_at` | Expiry of the raw sandbox URL. |
43
- | `studio_url` | Stable, authenticated Fimo Studio project and Branch page. |
44
- | `dashboard_url` | Deprecated compatibility alias for `studio_url`. |
45
- | `app_url` | Public live site, returned after a successful `--publish`. |
38
+ | Field | Destination |
39
+ | --------------- | ---------------------------------------------------------- |
40
+ | `studio_url` | Stable Fimo Studio project and Branch page. |
41
+ | `dashboard_url` | Deprecated compatibility alias for `studio_url`. |
42
+ | `app_url` | Public live site, returned after a successful `--publish`. |
46
43
 
47
- When reporting the result, open `preview_url` for a person and use `sandbox_url` for machine reads. If no code changed and you only need fresh destinations, use `fimo preview url --json` instead of deploying again.
44
+ When reporting the result, give the user `studio_url`. If a person or tool needs the hosted site itself, run `fimo preview url` after deploy.
48
45
 
49
46
  Public project variables managed with `fimo vars add` and `fimo vars update` are injected into preview/build/deploy runtimes. Project secrets are not injected into app builds; agents request secrets separately through their own config. See `references/project-vars-and-secrets.md`.
50
47
 
@@ -165,7 +165,7 @@ Whenever `fimo init` created or scaffolded a new project — including a Studio-
165
165
  fimo deploy -m "chore: first preview" --json
166
166
  ```
167
167
 
168
- `-m` is required because you run non-interactively; the deploy validates, commits pending changes, pushes, and syncs the hosted preview. It is also the sandbox warm-up — never run a separate warm-up deploy on this path. Read `data.preview_url` and `data.studio_url` from the envelope and return both links. `data.dashboard_url` remains a deprecated compatibility alias for `data.studio_url`. If the initiating request described a concrete site, build a minimal meaningful first screen before this single deploy; otherwise deploy the scaffolded site as-is and then ask what to build.
168
+ `-m` is required because you run non-interactively; the deploy validates, commits pending changes, pushes, and syncs the preview sandbox. Return `data.studio_url` from the envelope. Run `fimo preview url --json` only when the hosted site URL itself is needed. If the initiating request described a concrete site, build a minimal meaningful first screen before this single deploy; otherwise deploy the scaffolded site as-is and then ask what to build.
169
169
 
170
170
  This first deploy creates a preview only — never add `--publish`, and treat every later deploy as offer-then-confirm. The rule does not apply when `init` cloned a project with existing code or when the work is a migration; those paths keep their normal deployment approval rules.
171
171
 
@@ -228,4 +228,4 @@ Visual/content QA before publish:
228
228
  fimo integrations run firecrawl scrape --url "$(fimo preview url)" --formats markdown,links --json
229
229
  ```
230
230
 
231
- Because command substitution captures stdout, `fimo preview url` emits the raw `sandbox_url` in this example. For JSON workflows, pass `data.sandbox_url` to Firecrawl and refresh it after `data.sandbox_expires_at`. The stable `data.preview_url` is an authenticated browser viewer and is not the Firecrawl destination.
231
+ `fimo preview url` emits the hosted deployment URL in this example. In JSON workflows, pass `data.preview_url` to Firecrawl.
@@ -1,27 +1,19 @@
1
- # Preview URL (without deploying)
1
+ # Hosted preview URL
2
2
 
3
- **Use `fimo preview url` whenever you need the current hosted preview — to open it, screenshot it, hand it to another tool, or verify a change you already deployed. Never trigger `fimo deploy` just to retrieve a URL.**
4
-
5
- `fimo deploy` commits, pushes, and syncs the sandbox before it prints destinations. `fimo preview url` skips those deployment steps and only resolves the current Branch's preview destinations.
6
-
7
- ## Commands
3
+ Use `fimo preview url` to get the current Branch's hosted preview without committing or pushing.
8
4
 
9
5
  ```bash
10
- fimo preview url # current Branch (from git)
11
- fimo --branch feat/redesign preview url # specific Branch
12
- fimo preview url --branch main --json # structured output for agents / scripts
13
- fimo preview url --all # print every destination as named raw URLs
14
- curl -L "$(fimo preview url)" # fetch the raw sandbox preview
6
+ fimo preview url
7
+ fimo --branch feat/redesign preview url
8
+ fimo preview url --branch main --json
9
+ curl -L "$(fimo preview url)"
15
10
  ```
16
11
 
17
- `--env <name>` is rejected as a Branch selector; use `--branch <name>`. The JSON envelope carries the canonical `branch` field and may include a deprecated `env` compatibility duplicate. Studio deep links still use the `/env/` path, which redirects to `/branch/`.
12
+ The command returns the hosted deployment URL in every output mode, whatever the project's Preview setting says: every live Branch except production owns a hosted build.
18
13
 
19
- ## Human and machine behavior
14
+ If the current generation is queued or building, the command waits up to five minutes, polling with a backoff. It stops at once — without waiting — on a state waiting cannot change: a build that failed, and a Branch with no hosted preview (production, or a Branch nothing has changed yet). Every failure returns `PREVIEW_URL_FAILED`; read `error.message` for which one it was and `error.hint` for the next step. Only the timeout is worth retrying.
20
15
 
21
- - **Interactive terminal:** shows the stable `preview_url` and `studio_url` as named links. `preview_url` opens a full-screen Fimo viewer and requires a logged-in user with access to the project.
22
- - **Piped or captured output:** prints only the short-lived `sandbox_url`. This preserves commands such as `curl -L "$(fimo preview url)"` and gives browsers, screenshot tools, and crawlers the directly fetchable site.
23
- - **`--all`:** prints `preview_url`, `studio_url`, `sandbox_url`, and `sandbox_expires_at` as named raw values for a person inspecting every destination.
24
- - **JSON mode** (or `FIMO_OUTPUT=json`): returns both destinations explicitly:
16
+ JSON output contains only the Branch identity and hosted URL:
25
17
 
26
18
  ```json
27
19
  {
@@ -32,33 +24,11 @@ curl -L "$(fimo preview url)" # fetch the raw sandbox pre
32
24
  "project_id": "prj_abc",
33
25
  "branch": "main",
34
26
  "env": "main",
35
- "preview_url": "https://fimo.ai/preview/prj_abc/main",
36
- "sandbox_url": "https://preview.provider.example/session",
37
- "sandbox_expires_at": "2026-08-20T18:42:00.000Z",
38
- "studio_url": "https://fimo.ai/app/projects/prj_abc/branch/main/preview",
39
- "dashboard_url": "https://fimo.ai/app/projects/prj_abc/branch/main/preview"
27
+ "preview_url": "https://fimo-preview-example.vercel.app"
40
28
  }
41
29
  }
42
30
  ```
43
31
 
44
- Agents must use `data.sandbox_url` for curl, Firecrawl, screenshots, and other machine reads. Use `data.preview_url` for the authenticated full-screen viewer and `data.studio_url` for the Branch inside Fimo Studio. `data.dashboard_url` is a deprecated compatibility alias for `data.studio_url`. The raw sandbox URL expires; resolve it again when `sandbox_expires_at` is near or has passed. The stable human URLs do not need to be regenerated.
45
-
46
- ## When to use it
47
-
48
- - **You deployed a change and want to inspect it** — open the interactive `preview_url`.
49
- - **An agent or tool needs to read the site** — pipe the command or use `data.sandbox_url` from JSON.
50
- - **The raw URL expired** — run `fimo preview url` again; do not redeploy.
51
-
52
- ## When NOT to use it
53
-
54
- - **You changed code and want it on the preview** — use `fimo deploy`. This command only retrieves destinations.
55
- - **You need the live published URL** — use `fimo deploy --publish` or `fimo publish`; see `references/deploy.md` and `references/domains.md`.
56
-
57
- ## Cold sandbox case
58
-
59
- Resolving `sandbox_url` may take roughly 60–90 seconds when an idle sandbox must be provisioned or restarted. The stable `preview_url` performs the same authenticated resolution when a project member opens it.
60
-
61
- ## See also
32
+ Use `fimo deploy` when code still needs to be pushed. Use `fimo deploy --publish` or `fimo publish` only when the site should go live.
62
33
 
63
- - `references/deploy.md` — when you need to push code.
64
- - `references/branches.md` — Branch semantics and the global `--branch <name>` flag.
34
+ See `references/deploy.md` for deployment and `references/branches.md` for Branch selection.
@@ -109,24 +109,10 @@ Do not add `'use client'` to a page solely because Fimo is present. Keep promise
109
109
 
110
110
  ## Metadata
111
111
 
112
- Fimo owns the site-wide defaults; the application owns per-page overrides. Keep (or add) the starter wiring in the root layout — it maps `.fimo/config.json#seo` (Studio's Settings → SEO: title, description, favicon, share image, robots, theme color, canonical) onto Next `Metadata`/`Viewport`:
113
-
114
- ```ts
115
- import { buildFimoMetadata, buildFimoViewport } from 'fimo-next';
116
-
117
- export const generateMetadata = () => buildFimoMetadata();
118
- export const generateViewport = () => buildFimoViewport();
119
- ```
120
-
121
- If the root layout lacks this wiring, add it (updating the fimo packages if `fimo-next` does not export the helpers); without it, Settings → SEO never reaches the rendered head.
122
-
123
- Per-page `metadata`/`generateMetadata` exports override the defaults field by field. Resolve labels/content on the server and convert tracked strings only where Next expects primitives:
124
-
125
- ```ts
126
- export async function generateMetadata() {
127
- const labels = await getLabels();
128
- return { title: String(labels.t('seo.home.title')) };
129
- }
130
- ```
131
-
132
- Do not expect `FimoProvider` to inject SEO, routes, language, or direction.
112
+ When creating a site, adding a route, or integrating SEO, load
113
+ `references/frameworks/next/seo.md` (`--ref frameworks/next/seo`). Keep root
114
+ global defaults separate from explicit Home and route SEO. Reuse the app's
115
+ established route integration for new pages; a dynamic route module covers all
116
+ its instances. Next replaces nested metadata objects, not their individual
117
+ fields. Preserve app-owned policies and image routes. `FimoProvider` does not
118
+ inject SEO.
@@ -0,0 +1,168 @@
1
+ # Next.js SEO
2
+
3
+ Use the installed package APIs. The app owns routing, metadata policy and
4
+ rendering mode. Fimo supplies editable values, not a router or a merge policy.
5
+
6
+ ## Read, resolve, convert
7
+
8
+ ```ts
9
+ import { getFimoSeo } from 'fimo/seo/server';
10
+ import { toNextMetadata, toNextViewport } from 'fimo-next/seo';
11
+
12
+ // Root layout: global defaults, never implicitly Home.
13
+ export const generateMetadata = () => toNextMetadata(getFimoSeo());
14
+ export const generateViewport = () => toNextViewport(getFimoSeo());
15
+ ```
16
+
17
+ For a new App Router site, keep this root wiring. Home is an explicit route:
18
+
19
+ ```ts
20
+ // app/page.tsx
21
+ export const generateMetadata = () => toNextMetadata(getFimoSeo({ pathname: '/' }));
22
+ ```
23
+
24
+ For each route module with configured route SEO, resolve its real pathname.
25
+ One dynamic module handles every slug. Reuse the app's content loader and URL
26
+ builder; do not try to infer a full pathname from Next's params in the root.
27
+
28
+ ```ts
29
+ // app/blog/[slug]/page.tsx, using the app's existing loader and URL builder
30
+ export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
31
+ const { slug } = await params;
32
+ const article = await getArticle(slug);
33
+ return toNextMetadata(
34
+ getFimoSeo({
35
+ pathname: articlePath(article),
36
+ routeData: { article },
37
+ })
38
+ );
39
+ }
40
+ ```
41
+
42
+ Loaders should retain their normal not-found and caching behavior. Add
43
+ `generateViewport` at a route only when route-specific `themeColor` needs to
44
+ apply; share the existing cached loader if both exports need its data. Other
45
+ routes inherit the root color. When adding a page, follow the established
46
+ pattern and keep its Fimo catalog entry aligned with a URL the app serves.
47
+
48
+ `getFimoSeo({ pathname?, routeData?, rootDir? })` is synchronous and Node-only.
49
+ No pathname reads global SEO. A pathname applies matching route overrides.
50
+ It reads current or legacy project config using Fimo's config discovery;
51
+ missing config/SEO returns `undefined`, malformed JSON and other I/O errors
52
+ throw. Pass `rootDir` for a monorepo app located away from the process cwd.
53
+ It does not cache, fetch content, infer locales or invalidate Next's caches.
54
+ Config edits reach static output on rebuild and cached output on the app's
55
+ normal revalidation path. Fetched route content can remain cached across
56
+ builds; use the app's data-cache invalidation/revalidation policy and verify
57
+ the rendered value after a content edit. Rebuild success is not freshness proof.
58
+
59
+ For bundled data or Edge, supply config yourself to the pure resolver instead
60
+ of importing the Node reader:
61
+
62
+ ```ts
63
+ import { resolveSeoForPath } from 'fimo/seo';
64
+ import { toNextMetadata } from 'fimo-next/seo';
65
+
66
+ const seo = resolveSeoForPath(pathname, publicSeoConfig, { article });
67
+ const metadata = toNextMetadata(seo);
68
+ ```
69
+
70
+ Bundle only public SEO/routes, not credentials or project connection data.
71
+ Every ancestor layout of an Edge page must also avoid the Node reader. Use
72
+ bundled public SEO for shared root defaults, not just for the Edge leaf.
73
+ The converters have no I/O or Next request dependency. Their output is for
74
+ App Router; Pages Router keeps its existing `next/head` or SEO library and
75
+ maps resolved Fimo values there. Do not convert routers for SEO.
76
+
77
+ ## Available fields
78
+
79
+ Global values live at `seo` and overrides at `routes.<id>.seo` in the project's
80
+ existing Fimo config (normally `.fimo/config.json`). Preserve other config keys.
81
+ `fimo pages set` manages the route catalog but has no `--seo` flag; edit the
82
+ config to author route SEO. For example:
83
+
84
+ ```json
85
+ {
86
+ "seo": { "title": "Journal", "description": "Notes from the field" },
87
+ "routes": {
88
+ "article": {
89
+ "path": "/blog/:slug",
90
+ "seo": { "title": "{{article.title}}", "description": "{{article.summary}}" }
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ `FimoSEO` from `fimo/seo` has these optional string fields:
97
+
98
+ | Fimo field | Next output |
99
+ | ------------- | ------------------------------------------------------ |
100
+ | `title` | `title` |
101
+ | `description` | `description` |
102
+ | `siteName` | `openGraph.siteName` |
103
+ | `url` | `metadataBase`, relative canonical and `openGraph.url` |
104
+ | `image` | `openGraph.images` |
105
+ | `favicon` | `icons.icon` and `icons.apple` |
106
+ | `twitterSite` | `twitter.site` |
107
+ | `robots` | `robots` meta, not robots.txt |
108
+ | `themeColor` | `Viewport.themeColor`, not Metadata |
109
+ | `locale` | `openGraph.locale`, not URL or translation selection |
110
+
111
+ Route fields use the same shape. `{{article.title}}` reads caller-supplied
112
+ `routeData.article.title`; `siteName` and route `label` are built-in context.
113
+ A missing, empty or nonscalar token falls back for the entire field to its
114
+ global value, then absence. Tracked Fimo strings are supported. This does not
115
+ invent content when an article is missing.
116
+
117
+ Converters return `{}` for undefined SEO. They leave social title/description
118
+ and Twitter images unset so Next derives them from final page metadata/OG.
119
+ They default OG type to `website` and Twitter card to `summary_large_image`.
120
+ `url` is a site base; relative canonical/OG URLs follow the active route.
121
+ App-specific canonical policies, hreflang, JSON-LD, sitemaps, robots.txt,
122
+ verification tags and generated social images remain app-owned.
123
+
124
+ ## Existing app: adopt only chosen fields
125
+
126
+ Inspect existing root/section/page exports and file-based icons/social images
127
+ first. Do not spread every resolved global value into a leaf: that can replace
128
+ a section's `noindex` policy or image. Keep the app's established metadata
129
+ builder and choose the fields Fimo should supply. For example, an app choosing
130
+ Fimo's editable description while retaining its title and policy:
131
+
132
+ ```ts
133
+ export async function generateMetadata(context: Props) {
134
+ const application = await getApplicationMetadata(context);
135
+ const seo = getFimoSeo({ pathname: await getApplicationPathname(context) });
136
+ return {
137
+ ...application,
138
+ ...(seo?.description ? { description: seo.description } : {}),
139
+ };
140
+ }
141
+ ```
142
+
143
+ The loader/path helpers above belong to the app, not Fimo. For nested fields,
144
+ explicitly retain the siblings the app intends to keep. Next replaces
145
+ `openGraph`, `twitter`, `icons` and `alternates` objects across segments; there
146
+ is no generic deep-merge or null-based suppression guarantee. Never spread
147
+ parent `ResolvedMetadata` wholesale. File-based images can mask config values;
148
+ preserve them unless the user chooses to replace that behavior.
149
+
150
+ Use one title-suffix owner. If a Fimo template already produces a complete
151
+ title, return `title: { absolute: seo.title }` to bypass an ancestor
152
+ `title.template`, or remove the duplicated suffix from the Fimo template.
153
+ Next's layout `title.template` does not apply to a page in that same segment;
154
+ give Home its complete app-owned title when it needs the suffix too.
155
+ Preserve deliberate Twitter-specific images; otherwise allow Next's OG fallback.
156
+
157
+ The existing `buildFimoMetadata(rootDir?)` and `buildFimoViewport(rootDir?)` from `fimo-next`
158
+ remain global-only helpers. Their string argument is a directory, not a route.
159
+
160
+ ## Prove the rendered result
161
+
162
+ Build and request representative Home, static and dynamic routes. Check the
163
+ actual title, description, canonical, OG/Twitter images, icons, robots and
164
+ theme color against configured values. Include missing template data and an
165
+ existing section policy. Confirm social titles follow the final page title,
166
+ suffixes occur once, and no Home values leak to other routes. A helper import
167
+ or a successful build alone does not prove SEO. Check supported runtime and
168
+ revalidation behavior when those are part of the task.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use this reference when `fimo describe --json` reports `framework.slug: "nextjs"`, or the project uses an App Router (`app/` or `src/app/`) or Pages Router (`pages/` or `src/pages/`) tree.
4
4
 
5
- Fimo supports schema-first content in both routers across static generation, ISR, request-time rendering, and Client Components. The application owns routes, locale resolution, links, `<html lang/dir>`, and per-page SEO overrides. Fimo receives the resolved locale and supplies content, labels, source metadata, client editing context, and the site-wide SEO defaults (App Router: `buildFimoMetadata`/`buildFimoViewport` in the root layout — see the router reference's Metadata section).
5
+ Fimo supports schema-first content in both routers across static generation, ISR, request-time rendering, and Client Components. The application owns routes, locale resolution, links, `<html lang/dir>`, and SEO policy. Fimo supplies content, labels, editing context and optional resolved SEO values. For site creation, new routes or SEO changes, load `references/frameworks/next/seo.md`.
6
6
 
7
7
  ## Choose the router reference
8
8
 
@@ -100,9 +100,9 @@ Pick the setup path from the evidence:
100
100
  and adds only the Fimo dependency, `.fimo/project.json`, the `fimo` remote,
101
101
  and `.fimo/config.json#runtime.framework`. It never overlays a template, so
102
102
  the target must already contain the source.
103
- - **Empty target, or an explicit framework conversion** — `fimo init` with the
104
- chosen `--framework`, or `fimo migrate init <url> <dir>` for a URL crawl.
105
- Both refuse a non-empty target and write nothing when they refuse.
103
+ - **Empty target, or an explicit framework conversion** — `fimo init` or
104
+ `fimo migrate init <dir>` with the chosen `--framework`. Both refuse a
105
+ non-empty target and write nothing when they refuse.
106
106
 
107
107
  If authentication, organization selection, project creation, environment
108
108
  resolution, linking, or the verification read fails, stop before workers and
@@ -151,7 +151,7 @@ report the exact failed command and setup requirement.
151
151
  unresolved item with the source evidence, the owner action, and the
152
152
  user-visible impact. Never claim completion while source content is
153
153
  unwired.
154
- - Prefer source code and exports over inferred crawl data. Use a public URL as
154
+ - Prefer source code and exports over what a page renders. Use a public URL as
155
155
  visual, SEO, route, and behavior evidence when better source material exists.
156
156
  When the source defines an active CMS but its deployed records are unavailable,
157
157
  rebuild published content from the public site only after the user explicitly
@@ -205,8 +205,12 @@ report the exact failed command and setup requirement.
205
205
  - **source-backed**: source repository, export, downloaded HTML, CMS data,
206
206
  or media folder. The source files are truth; the workers read them
207
207
  directly.
208
- - **url-only**: only a published URL. Run `fimo migrate <url> [dir]` to
209
- create the draft evidence pack.
208
+ - **url-only**: only a published URL. You read the site yourself: open each
209
+ route in a browser, let client-side rendering finish, and record the
210
+ sections, copy, images, links, and forms you actually see. Fetching HTML
211
+ without executing JavaScript is not evidence — a client-rendered page
212
+ returns an empty root element, which reads as a site with no content.
213
+ Never report a route as covered from a fetch that returned no sections.
210
214
  - **hybrid**: source material plus a public URL. Treat source material as
211
215
  truth and the URL as comparison evidence.
212
216
  4. Read `references/questions-and-improvements.md`, finish its read-only
@@ -254,7 +258,8 @@ instead of inventing an ID:
254
258
 
255
259
  `--source-platform` names what the site is migrated from (`wordpress`, `nextjs`,
256
260
  `astro`, `react-router`, `webflow`, `framer`, `squarespace`, `wix`, `carrd`,
257
- `other`); pass what the source checkout proves, `unknown` only when nothing does.
261
+ `other`); pass what the source proves, `unknown` only when nothing does. It is
262
+ explicit only — nothing detects it, and omitting it records `unknown`.
258
263
 
259
264
  After setup, check `.fimo/config.json#runtime.framework` and the scaffold's
260
265
  framework files before starting workers. A Next.js target must still have its
@@ -268,32 +273,23 @@ deploy happens only after successful local QA (see Completion and deployment).
268
273
 
269
274
  ## Command surface
270
275
 
271
- Plan-only commands operate on local artifacts and work before the target is
272
- linked:
273
-
274
- - `fimo migrate init <url> [dir]` — URL migrations only: crawl the live site
275
- into the draft evidence pack.
276
- - `fimo migrate inspect` — summarize the URL draft or an existing legacy ledger.
277
- - `fimo migrate import` — print the import plan; it writes no data.
278
- - `fimo migrate apply` / `fimo migrate refine` — URL-draft-only scaffold and
279
- refinement handoff; they play no role in a source-backed migration. `apply`
280
- must never run against an initialized non-React-Router target: it is the
281
- legacy React Router scaffold path and must fail instead of downgrading a
282
- Next.js (or another framework) project.
283
- - `fimo migrate manifest` / `fimo migrate report` — legacy URL-draft helpers.
284
- New source-backed migrations use the plain-text migration plan, worker
285
- reports, and final migration report; they do not bootstrap another JSON
286
- registry.
287
-
288
- Commands that perform actual data writes, all requiring the linked target:
276
+ `fimo migrate init <dir>` is the only migration subcommand. It sets the target
277
+ up and nothing else: it never reads, fetches, or renders the source site, and
278
+ it produces no evidence pack, draft, manifest, or scaffold to inspect. Reading
279
+ the source is your job, and every finding is yours to prove.
280
+
281
+ - `fimo migrate init <dir> --project-id <projectId>` — link an owner-supplied
282
+ project.
283
+ - `fimo migrate init <dir> --org <organizationId>` — create a new project.
284
+ - Both accept `--framework`, `--source-platform` (see Target setup),
285
+ `--install` / `--no-install`, `--agents` / `-a`, `--mode`, `--template-root`,
286
+ and `--json`; `-C <dir>` replaces the positional for an already-linked target.
287
+
288
+ The link/creation and its initial commit push are the only remote writes. Data
289
+ writes go through the normal commands against the linked target:
289
290
 
290
291
  - `fimo schemas push`, `fimo assets upload`, `fimo entries create|update`,
291
292
  `fimo singles update`, `fimo labels set|set-many`, `fimo forms push`.
292
- - `fimo migrate init` (source-backed form): the project link/creation and
293
- initial commit push described above. Pass `--source-platform <platform>`
294
- (webflow, framer, squarespace, wix, carrd, wordpress, nextjs, astro,
295
- react-router, other) when the source is known; URL crawls detect it.
296
-
297
293
  - `fimo link`: project creation or selection plus the in-place adoption of a
298
294
  copied source target.
299
295
  - `fimo deploy` / `fimo publish` — owner-approved only.
@@ -378,9 +374,9 @@ Commands that perform actual data writes, all requiring the linked target:
378
374
  - `references/workers/content-execution.md` - data import and code-wiring
379
375
  contracts.
380
376
  - `references/workers/validator.md` - independent fan-in validation.
381
- - Existing manifest/decision helper scripts are legacy compatibility tools for
382
- older migration artifacts. Do not invoke them in a new migration unless the
383
- user explicitly asks to replay an older artifact.
377
+ - `scripts/apply-decision.mjs` and `scripts/write-migration-report.mjs` replay
378
+ an older JSON-ledger migration. A new migration writes the plain-text plan
379
+ and report instead; do not invoke them unless the user asks for that replay.
384
380
 
385
381
  ## Completion and deployment
386
382
 
@@ -119,7 +119,7 @@ Then use source headers, values, and repeated patterns:
119
119
  - excerpt/summary/dek -> `text`
120
120
  - image/photo/thumbnail/media/asset/file -> `media`, carrying the source alt on
121
121
  the media value; never add a separate alt field (`references/media.md`)
122
- - date/published/created/updated -> `date`; use `datetime` only when the crawled
122
+ - date/published/created/updated -> `date`; use `datetime` only when the source
123
123
  values carry a time and a UTC offset, which `datetime` requires
124
124
  - event start/end time -> `datetime`
125
125
  - price/amount/rating/order/count -> `number`
@@ -86,6 +86,13 @@ behavior in place; when one cannot be preserved, record an explicit gap with
86
86
  the affected routes instead of shipping pages that silently lost their share
87
87
  metadata.
88
88
 
89
+ Before adopting Fimo SEO values, load the target's `fimo-code` reference
90
+ `frameworks/next/seo`. Record which fields remain app-owned and which become
91
+ editor-managed. Preserve section robots policies, title templates and
92
+ file-based images; verify the rendered result on representative routes. Link
93
+ the established route pattern in the project's instructions so later pages
94
+ reuse it. Do not replace an existing SEO library or add a universal merge wrapper.
95
+
89
96
  ## Fimo connection
90
97
 
91
98
  Follow the target project's `fimo-code` Next.js reference and render its
@@ -9,18 +9,16 @@ assets, schemas, entries, and forms, or the gaps are owner-visible unresolved
9
9
  items.
10
10
 
11
11
  Every data-plane write in this contract targets the linked project from
12
- workflow Phase 0. Local artifacts never require the link — `fimo migrate
13
- import` only prints the import plan (it writes no data) and warns in an
14
- unlinked directory — running the printed commands is what needs the link.
15
- When no owner-supplied target exists, the writes stay unresolved owner
16
- actions; do not fake a link to make them pass.
12
+ workflow Phase 0. Planning and payload authoring need no link; running the
13
+ writes does. When no owner-supplied target exists, the writes stay unresolved
14
+ owner actions; do not fake a link to make them pass.
17
15
 
18
16
  ## Media Files
19
17
 
20
18
  Discovery must include:
21
19
 
22
20
  - local export media folders
23
- - media URLs from crawled HTML/CSS
21
+ - media URLs found in the source HTML/CSS
24
22
  - CMS media fields
25
23
  - SEO/share images
26
24
  - downloadable files linked from pages or entries
@@ -4,9 +4,10 @@ New migrations do not create a canonical `manifest.json`. The coordinator uses
4
4
  the readable `.fimo/migration/migration-plan.md` and
5
5
  `.fimo/migration/migration-report.md` instead.
6
6
 
7
- Older URL-only migrations may contain `.fimo/migrations/current/manifest.json`.
8
- Read it as source evidence when useful, but do not copy it into another
9
- registry or ask workers to keep it synchronized.
7
+ A pre-existing project may still contain `.fimo/migrations/current/manifest.json`
8
+ from a retired URL crawl. Nothing writes it any more, and it was never
9
+ trustworthy on a client-rendered site: read it as a hint at most, re-verify
10
+ every claim against the source, and do not copy it into another registry.
10
11
 
11
12
  JSON remains appropriate for actual Fimo artifacts: schema files and the
12
13
  content payloads passed to data-plane commands. It is not needed to describe
@@ -94,7 +94,7 @@ The question should sound like this:
94
94
 
95
95
  If the owner chooses the public website, stay inside the selected route scope.
96
96
  Public retrieval does not authorize private endpoint discovery, credential use,
97
- or a broader crawl. Record the URL, retrieval time, redirects, and every field
97
+ or a broader sweep. Record the URL, retrieval time, redirects, and every field
98
98
  or relation that remains unknown.
99
99
 
100
100
  ## Ask what happens outside a partial migration
@@ -18,12 +18,11 @@ ask a generic optimization question.
18
18
  1. Confirm the target path. The target is a separate directory; the source
19
19
  checkout remains read-only evidence.
20
20
  2. Initialize or reuse exactly one linked Fimo target before workers start:
21
- - URL migration: `fimo migrate init <source-url> <target-dir> --framework <framework>`
22
21
  - link an existing project: `fimo migrate init <target-dir> --project-id <projectId> --framework <framework>`
23
22
  - create a project: `fimo migrate init <target-dir> --org <organizationId> --framework <framework>`
24
23
  - add `--source-platform <platform>` when the source platform is known
25
24
  (webflow, framer, squarespace, wix, carrd, wordpress, nextjs, astro,
26
- react-router, other); URL crawls detect it themselves.
25
+ react-router, other). Nothing detects it; omitting it records `unknown`.
27
26
  Use the detected source framework for source-backed migrations. A framework
28
27
  conversion requires an explicit user choice; URL-only and rebuild
29
28
  migrations ask the user which framework to use. Never choose a framework by
@@ -78,9 +77,12 @@ Treat absent/private fields as unknown, keep uncertain fields optional, and do
78
77
  not turn sampled values into enums. Bounded retrieval scripts are accelerators
79
78
  the planner may adapt or replace, never schema decision makers.
80
79
 
81
- For URL-only migrations, run `fimo migrate <url> [dir]` and inspect the
82
- generated `.fimo/migrations/current/` files as source evidence. Do not copy
83
- that crawl manifest into another canonical JSON registry.
80
+ For URL-only migrations, read the published site yourself with a browser. Open
81
+ every selected route, let client-side rendering finish, and record the sections,
82
+ copy, images, links, and forms you actually see. An HTML response fetched
83
+ without executing JavaScript is not evidence: a client-rendered page returns an
84
+ empty root element, and treating that as the page reports an empty site as a
85
+ complete one.
84
86
 
85
87
  ## Phase 2: Fan out workers
86
88
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bundled": true,
3
3
  "bundler": "esbuild",
4
- "bundledAt": "2026-09-04T18:04:09.580Z",
4
+ "bundledAt": "2026-09-05T10:27:58.561Z",
5
5
  "cliVersion": "2.3.2",
6
6
  "external": [
7
7
  "oxc-parser",