fimo 0.10.1-staging.4 → 0.11.0-staging.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 (89) hide show
  1. package/assets/agent-templates/content-translator/GOAL.md +3 -3
  2. package/assets/agent-templates/seo-audit/config.yaml +1 -1
  3. package/assets/skills/fimo/SKILL.md +5 -0
  4. package/assets/skills/fimo-cli/SKILL.md +12 -7
  5. package/assets/skills/fimo-cli/references/agents.md +71 -23
  6. package/assets/skills/fimo-cli/references/branches.md +2 -2
  7. package/assets/skills/fimo-cli/references/content.md +2 -0
  8. package/assets/skills/fimo-cli/references/credits.md +1 -1
  9. package/assets/skills/fimo-cli/references/deploy.md +1 -1
  10. package/assets/skills/fimo-cli/references/describe.md +1 -1
  11. package/assets/skills/fimo-cli/references/history.md +1 -1
  12. package/assets/skills/fimo-cli/references/init.md +51 -16
  13. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +12 -3
  14. package/assets/skills/fimo-cli/references/integrations.md +15 -3
  15. package/assets/skills/fimo-cli/references/invite.md +1 -1
  16. package/assets/skills/fimo-cli/references/labels.md +1 -1
  17. package/assets/skills/fimo-cli/references/locales.md +4 -4
  18. package/assets/skills/fimo-cli/references/mcp.md +85 -0
  19. package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +1 -1
  20. package/assets/skills/fimo-cli/references/projects.md +7 -7
  21. package/assets/skills/fimo-code/references/content.md +20 -15
  22. package/assets/skills/fimo-code/references/labels.md +2 -2
  23. package/assets/skills/fimo-code/references/locales.md +5 -5
  24. package/assets/skills/fimo-code/references/setup-plain-vite.md +12 -11
  25. package/assets/skills/fimo-code/references/setup-react-router.md +10 -5
  26. package/assets/skills/fimo-code/references/ui.md +4 -1
  27. package/assets/skills/fimo-migration/references/workflow.md +1 -1
  28. package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +32 -3
  29. package/assets/skills/fimo-studio/references/ai-chat.md +14 -0
  30. package/assets/skills/fimo-studio/references/custom-domains.md +1 -1
  31. package/assets/skills/fimo-studio/references/preview-and-responsive.md +1 -1
  32. package/assets/skills/fimo-studio/references/publish-and-deploy.md +8 -1
  33. package/assets/starters/fimo-site/manifest.json +64 -0
  34. package/assets/starters/fimo-site/template/.fimo/agents/content-guide/GOAL.md +8 -0
  35. package/assets/starters/fimo-site/template/.fimo/agents/content-guide/capabilities.yaml +2 -0
  36. package/assets/starters/fimo-site/template/.fimo/agents/content-guide/config.yaml +9 -0
  37. package/assets/starters/fimo-site/template/.fimo/agents/site-review/GOAL.md +14 -0
  38. package/assets/starters/fimo-site/template/.fimo/agents/site-review/capabilities.yaml +4 -0
  39. package/assets/starters/fimo-site/template/.fimo/agents/site-review/config.yaml +9 -0
  40. package/assets/starters/fimo-site/template/src/forms/contact.json +14 -0
  41. package/assets/starters/fimo-site/template/src/forms/contact.ts +46 -0
  42. package/assets/starters/fimo-site/template/src/pages/Contact.tsx +193 -0
  43. package/assets/starters/fimo-site/template/src/pages/Index.tsx +27 -0
  44. package/assets/starters/fimo-site/template/src/pages/SiteContent.tsx +191 -0
  45. package/assets/starters/fimo-site/template/src/schemas/HomePage.json +28 -0
  46. package/assets/starters/fimo-site/template/src/schemas/HomePage.ts +29 -0
  47. package/assets/starters/fimo-site/template/src/schemas/HomePage.types.ts +64 -0
  48. package/dist/build/vite/index.d.ts +3 -3
  49. package/dist/build/vite/index.js +12 -3
  50. package/dist/build/vite/plugins/fimo-config.d.ts +2 -2
  51. package/dist/build/vite/plugins/fimo-config.js +5 -5
  52. package/dist/build/vite/plugins/robots.d.ts +1 -1
  53. package/dist/build/vite/plugins/robots.js +3 -3
  54. package/dist/build/vite/plugins/server-config.js +1 -1
  55. package/dist/build/vite/plugins/sitemap.js +2 -2
  56. package/dist/build/vite/plugins/translations.js +14 -10
  57. package/dist/cli/bundle.json +1 -1
  58. package/dist/cli/index.js +147 -135
  59. package/dist/runtime/app/FimoProviders.js +18 -8
  60. package/dist/runtime/app/prefetch.d.ts +1 -1
  61. package/dist/runtime/app/prefetch.js +2 -2
  62. package/dist/runtime/content/client/createContentClient.d.ts +15 -0
  63. package/dist/runtime/content/client/createContentClient.js +23 -0
  64. package/dist/runtime/content/client/createSingletonClient.js +3 -0
  65. package/dist/runtime/content/client/internal.js +66 -5
  66. package/dist/runtime/content/utils/retrieve-data-sources.d.ts +13 -0
  67. package/dist/runtime/content/utils/retrieve-data-sources.js +45 -31
  68. package/dist/runtime/paths/get-fimo-paths.d.ts +1 -1
  69. package/dist/runtime/paths/get-fimo-paths.js +5 -5
  70. package/dist/runtime/paths/types.d.ts +1 -1
  71. package/dist/runtime/primitives/components/Json.d.ts +25 -0
  72. package/dist/runtime/primitives/components/Json.js +29 -0
  73. package/dist/runtime/primitives/index.d.ts +1 -0
  74. package/dist/runtime/primitives/index.js +1 -0
  75. package/dist/runtime/project-layout.d.ts +14 -0
  76. package/dist/runtime/project-layout.js +57 -0
  77. package/dist/runtime/seo/resolver.d.ts +1 -1
  78. package/dist/runtime/seo/resolver.js +1 -1
  79. package/dist/runtime/shared/fimo-config.server.d.ts +2 -0
  80. package/dist/runtime/shared/fimo-config.server.js +17 -4
  81. package/dist/runtime/templates.d.ts +4 -4
  82. package/dist/runtime/templates.js +11 -6
  83. package/dist/scripts/validate-route-metadata.js +8 -6
  84. package/package.json +12 -6
  85. package/templates/react-router/AGENTS.md +1 -1
  86. package/templates/react-router/package.json +6 -6
  87. package/templates/react-router/src/vite-env.d.ts +1 -1
  88. package/templates/react-router/vite.config.ts +1 -1
  89. /package/templates/react-router/{fimo-config.json → .fimo/config.json} +0 -0
@@ -0,0 +1,85 @@
1
+ # Project MCP
2
+
3
+ > **Run via `npx fimo@latest <command>`** — always the latest CLI, no install needed.
4
+
5
+ The **Project MCP** lets an AI coding client use Fimo's project workflows through the Model Context Protocol. It is
6
+ the same Fimo tool surface exposed in two ways:
7
+
8
+ - **Local MCP**: `fimo mcp` over stdio, for an AI client running next to a checkout.
9
+ - **Remote MCP**: `https://api.fimo.ai/api/mcp` over authenticated Streamable HTTP, for ChatGPT, Claude, and other
10
+ clients that support OAuth.
11
+
12
+ The local and remote Project MCP modes share the same catalog. The public Docs MCP at
13
+ `https://fimo.ai/docs/mcp` is separate: it is unauthenticated, read-only, and only provides Fimo documentation.
14
+
15
+ ## Set up the local MCP
16
+
17
+ Authenticate the CLI first:
18
+
19
+ ```bash
20
+ npx fimo@latest login
21
+ ```
22
+
23
+ Then configure the MCP client to launch:
24
+
25
+ ```text
26
+ npx fimo@latest mcp
27
+ ```
28
+
29
+ For clients that accept a JSON command configuration, the equivalent entry is:
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "fimo": {
35
+ "command": "npx",
36
+ "args": ["fimo@latest", "mcp"]
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ Do not add shell output or logging around the command: stdout is reserved for MCP JSON-RPC frames. Diagnostics are
43
+ written to stderr.
44
+
45
+ ## Project and environment scope
46
+
47
+ When launched inside a linked Fimo project, `fimo mcp` reads the project from `.fimo.settings.json` and uses the
48
+ current git branch as the default environment. This keeps an AI client working against the same project environment as
49
+ the checkout.
50
+
51
+ Outside a linked project, the server still works, but each project-scoped tool call must provide `projectId` and
52
+ `env`. The client can also pass an environment override when launching the CLI. Never edit `.fimo.settings.json`
53
+ manually to change scope.
54
+
55
+ The CLI credential represents the signed-in user's Fimo authority. If an MCP server is invoked from a Fimo agent
56
+ session, the session's frozen capability snapshot still limits the operations available to that agent.
57
+
58
+ ## Capabilities
59
+
60
+ The Project MCP catalog covers:
61
+
62
+ - **Identity and navigation** — current user, projects, and environments.
63
+ - **Content** — schemas, collection entries, search, create/update/delete, bounded bulk operations, and Singles.
64
+ - **Labels** — list, read, set, batch-set, and delete localized labels.
65
+ - **Media** — list and inspect assets, generate images or videos, create folders, move, and delete assets. Binary
66
+ upload remains `fimo assets upload`.
67
+ - **Forms** — create, read, update, and delete forms; inspect submissions and statistics.
68
+ - **Files** — read, glob, grep, write, edit, and delete project files within the scoped environment. Sensitive files
69
+ such as credentials and `.env` files are excluded.
70
+ - **Agents** — list agents, start a run, and inspect run status.
71
+
72
+ Use the MCP client's tool list as the wire-level source of truth. The catalog is shared with the remote endpoint, so a
73
+ client configured locally sees the same tool names and input shapes as a remote client.
74
+
75
+ ## Local versus remote authorization
76
+
77
+ Local MCP uses the stored CLI credential (or `FIMO_API_TOKEN` when explicitly configured). It does not use the
78
+ browser OAuth consent screen. Remote MCP uses Fimo OAuth with `read`, `write`, and `agents` scopes; the user selects
79
+ the optional capabilities during consent.
80
+
81
+ In both modes, Fimo still checks the user's project permissions, environment access, input validation, and file safety
82
+ rules for every operation. MCP does not grant access to projects the user cannot already access.
83
+
84
+ For ChatGPT, Claude, or another remote MCP client, use the setup guide in the public [MCP documentation](https://fimo.ai/docs/ai/mcp)
85
+ instead of the local stdio configuration above.
@@ -62,7 +62,7 @@ fimo agents secrets remove seo-publisher FIRECRAWL_API_KEY
62
62
  fimo agents validate
63
63
  ```
64
64
 
65
- `fimo agents secrets add` edits `agents/<name>/config.yaml`. It does not create or rotate the secret value. Use `fimo secrets add` to create the value or `fimo secrets update` to rotate it.
65
+ `fimo agents secrets add` edits `.fimo/agents/<name>/config.yaml`. It does not create or rotate the secret value. Use `fimo secrets add` to create the value or `fimo secrets update` to rotate it.
66
66
 
67
67
  `fimo agents validate` checks that required agent secrets exist in the project. A running agent keeps the environment it started with; the next run reads the deployed agent config again.
68
68
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Run via `npx fimo@latest <command>`** — always the latest CLI, no install needed.
4
4
 
5
- Commands for listing projects across an org, cloning a remote project locally, and managing the lifecycle of a single project (delete, publish, unpublish, rename). Most lifecycle commands operate on the **current project** (read from `.fimo.settings.json` in the cwd) by default; for `delete`, `publish`, and `unpublish` you can pass an explicit `[projectId]` to target another. (`rename` is local-only — it never targets a different project; see below.)
5
+ Commands for listing projects across an org, cloning a remote project locally, and managing the lifecycle of a single project (delete, publish, unpublish, rename). Most lifecycle commands operate on the **current project** (read from `.fimo/project.json`, or the legacy `.fimo.settings.json`, in the cwd) by default; for `delete`, `publish`, and `unpublish` you can pass an explicit `[projectId]` to target another. (`rename` only edits the linked local project; see below.)
6
6
 
7
7
  ## The `fimo projects` namespace
8
8
 
@@ -13,15 +13,15 @@ fimo projects clone [projectId] [dir] [--env <name>] # clone an existing project
13
13
  fimo projects delete [projectId] [-C <dir>] [-y] # delete (defaults to current project)
14
14
  fimo projects publish [projectId] [-C <dir>] # make the project live (publish from main)
15
15
  fimo projects unpublish [projectId] [-C <dir>] # take the project offline
16
- fimo projects rename <name> [projectId] [-C <dir>] # local-only: set seo.siteName in fimo-config.json
16
+ fimo projects rename <name> [projectId] [-C <dir>] # set seo.siteName in the linked project config
17
17
  ```
18
18
 
19
19
  - **`list`** — projects you can see in the org. Live projects are marked.
20
20
  - **`create`** — identical to `fimo init` (create-new path); see `references/init.md`.
21
- - **`clone`** — clone a remote Fimo project's git repo to your machine and write the local `.fimo.settings.json`/agent files. Use `fimo clone <projectId>` when scripting or when the ID is known. In an interactive terminal, bare `fimo clone` opens a project picker for the active org; JSON mode and non-TTY shells require an explicit project ID and fail fast instead of prompting. By default it clones `main`; pass `--env <name>` to clone a specific env. The target directory defaults to the project display name/name, or pass `[dir]` explicitly.
21
+ - **`clone`** — clone a remote Fimo project's git repo to your machine and write the local `.fimo/project.json` and agent files. Use `fimo clone <projectId>` when scripting or when the ID is known. In an interactive terminal, bare `fimo clone` opens a project picker for the active org; JSON mode and non-TTY shells require an explicit project ID and fail fast instead of prompting. By default it clones `main`; pass `--env <name>` to clone a specific env. The target directory defaults to the project display name/name, or pass `[dir]` explicitly.
22
22
  - **`delete`** — destructive; prompts unless `-y`. Removes the remote project.
23
23
  - **`publish` / `unpublish`** — toggle the project's public visibility. `publish` flips the current `main` state live (the same "go live" as `fimo deploy --publish`, minus the git push). This is **not** the versioned release path — for that, see `fimo publish` in `references/branches.md`.
24
- - **`rename`** — **local-only**, unlike the others. It does not touch the remote project record. It requires `.fimo.settings.json` in the cwd, and if you pass a `[projectId]` that doesn't match the linked project it errors and exits 1 (so you can't rename a different project). It writes `seo.siteName` into the local `fimo-config.json`; you must commit and run `fimo deploy` to apply the change.
24
+ - **`rename`** — edits only the linked local project immediately. It requires a project marker in the cwd, and if you pass a `[projectId]` that doesn't match the linked project it errors and exits 1 (so you can't rename a different project). It writes `seo.siteName` into the current or legacy project config; commit and run `fimo deploy` to reconcile the remote `displayName` and deploy the new site name.
25
25
 
26
26
  ## Top-level clone shortcut
27
27
 
@@ -33,15 +33,15 @@ Use the top-level shortcut for the common "get this project onto my machine" wor
33
33
 
34
34
  ## Top-level shortcuts (current project)
35
35
 
36
- These target the project linked in the cwd's `.fimo.settings.json` — handy from inside a project directory:
36
+ These target the project linked in the cwd's `.fimo/project.json` (or legacy `.fimo.settings.json`) — handy from inside a project directory:
37
37
 
38
38
  ```bash
39
39
  fimo delete [-C <dir>] [-y] # delete the current project
40
40
  fimo unpublish [-C <dir>] # unpublish the current project
41
- fimo rename "<Site Name>" # local edit: set seo.siteName in fimo-config.json
41
+ fimo rename "<Site Name>" # local edit: set seo.siteName in the project config
42
42
  ```
43
43
 
44
- `fimo rename` sets the **site name** (`seo.siteName`) in the local `fimo-config.json` — it is a local edit, not a remote update, so it requires a follow-up commit + `fimo deploy` to take effect. It does **not** change the project's remote display name (the `displayName` shown by `projects list`), which is set once at creation time from the project directory name. See `references/init.md` and `references/deploy.md`.
44
+ `fimo rename` sets the **site name** (`seo.siteName`) in the local project config — it is a local edit, not an immediate remote update, so it requires a follow-up commit + `fimo deploy` to take effect. Deploy reconciles the project's remote `displayName` with the committed site name while pushing the config. See `references/init.md` and `references/deploy.md`.
45
45
 
46
46
  ## Three "publish" verbs — don't confuse them
47
47
 
@@ -73,7 +73,7 @@ something else (e.g. `handle`, `permalink`).
73
73
  | `reference` | `{ "id": "..." }`, `null`, or an array of reference objects when `many: true` | References to another schema |
74
74
  | `blocks` | ordered array of objects | Fixed groups, repeated sections, or selectable page blocks |
75
75
 
76
- A `date` field currently generates as `any` in the TS client, so for typed access (and the `<Date>` component) prefer a `string` field holding an ISO date — which is what the `publishDate` examples below do.
76
+ A `date` field generates as `string` in the TS client and wraps in `FimoString` at read time — the same source-tracked shape as `string`/`text` — so `<Date value={post.someDate} />` and plain string methods (`.slice()`, template literals, …) both work directly.
77
77
 
78
78
  ## Enumerated strings
79
79
 
@@ -163,10 +163,12 @@ A field may declare `showIf` (every clause must match) or `showIfAny` (one claus
163
163
 
164
164
  - `blocks.schema.fields` repeats one homogeneous shape.
165
165
  - `blocks.schema.oneOf` lets the editor choose exactly one variant per item.
166
+ - Blocks schemas support at most 7 nested `blocks` levels, 40 variants in one `schema.oneOf`, and `min` or `max` values up to 200 items per blocks field.
166
167
  - Blocks always read and write arrays. A field with `max: 1` is `[]` or `[item]`, never a bare object.
167
168
  - `min` and `max` constrain the total number of blocks. Use `min: 1` to require at least one block; `required: true` has the same minimum-one behavior.
168
169
  - Fimo creates a stable `_key` for each item. A `oneOf` item also carries `_type`, matching the variant `uid`.
169
170
  - Nested fields support the same defaults and validators as top-level fields.
171
+ - **Each block item's own scalar fields wrap the same way their field type wraps at the top level** — a nested `string`/`text` field is a `FimoString`, a nested `richtext` field is a `FimoRichText`, a nested `media` field is a `FimoMedia`, a nested `boolean` is a `FimoBoolean`, a nested `date` is a `FimoString`, a nested `json` field is a shallow-cloned, source-tagged object, a nested `number` stays a plain `number`, and a nested `blocks` field recurses the same way. Pass those nested values to the matching `fimo/ui` component exactly like a top-level field — `<Text value={section.heading} />` or `<Json value={section.metadata} />` inside a `.map()` over `page.sections` stays inline-editable.
170
172
  - Blocks inherit the owning entry's locale.
171
173
  - Nested references use one fixed `target`. Unpopulated reads return `{ id, documentId }`, like top-level references.
172
174
  - Nested population and filtering are not supported yet.
@@ -516,22 +518,25 @@ Populate is depth-one. It only works for reference fields; trying to populate a
516
518
 
517
519
  The entry objects a hook returns are **not** plain JS values. The generated client wraps each _trackable_ field in a `fimo/ui` primitive that carries source metadata for inline editing. Which fields wrap, and which stay plain:
518
520
 
519
- | Schema field type | Field value you get | Notes |
520
- | ----------------- | ----------------------------------- | ------------------------------------------------------------------------------------- |
521
- | `string` | `FimoString` | `extends String` — **not** a primitive `string` |
522
- | `text` | `FimoString` | Multiline plain text with the same source tracking as `string` |
523
- | `richtext` | `FimoRichText` | Tiptap JSONContent + source metadata |
524
- | `boolean` | `FimoBoolean` | class; `.valueOf()` → `boolean` |
525
- | `media` | `FimoMedia` / `FimoMedia[]` | shape + rendering in `references/assets.md` |
526
- | `number` | `number` | plain — not wrapped |
527
- | `json` | `Record<string, any>` | plain — not wrapped |
528
- | `date` | `any` (raw ISO date string) | not wrapped (`FimoDate` is not emitted — see below) |
529
- | `reference` | `FimoReference` / `FimoReference[]` | reference object(s) with target `id`; use `populate` when embedded targets are needed |
521
+ | Schema field type | Field value you get | Notes |
522
+ | ----------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
523
+ | `string` | `FimoString` | `extends String` — **not** a primitive `string` |
524
+ | `text` | `FimoString` | Multiline plain text with the same source tracking as `string` |
525
+ | `richtext` | `FimoRichText` | Tiptap JSONContent + source metadata |
526
+ | `boolean` | `FimoBoolean` | class; `.valueOf()` → `boolean` |
527
+ | `media` | `FimoMedia` / `FimoMedia[]` | shape + rendering in `references/assets.md` |
528
+ | `number` | `number` | plain — not wrapped. A wrapper would break `<span>{post.views}</span>` (React renders a boxed `String` directly but throws on a boxed `Number`), so it stays untracked and unclickable in the editing surfaces |
529
+ | `json` | `Record<string, any>` | the same shape you wrote, plus a hidden (non-enumerable, symbol-keyed) source tag — render with `<Json>`, see below |
530
+ | `date` | `FimoString` | same wrapper as `string`/`text`, **not** `FimoDate` — see below |
531
+ | `blocks` | array of plain objects | the array/objects themselves are plain; each item's own scalar fields are wrapped by their own field type (a nested `string` is still `FimoString`, a nested `number` stays a plain `number`, …) — see "Blocks" above |
532
+ | `reference` | `FimoReference` / `FimoReference[]` | reference object(s) with target `id`; use `populate` when embedded targets are needed |
530
533
 
531
534
  Rules of thumb:
532
535
 
533
- - **Pass the whole primitive to the matching `fimo/ui` component** — `<Text value={post.title} />`, `<Image value={post.cover} />`, `<RichText value={post.body} />`, `<Boolean value={p.inStock} />`. Don't unwrap first; the component reads the source metadata so the field stays inline-editable in the dashboard.
536
+ - **Pass the whole primitive to the matching `fimo/ui` component** — `<Text value={post.title} />`, `<Image value={post.cover} />`, `<RichText value={post.body} />`, `<Boolean value={p.inStock} />`, `<Date value={post.publishDate} />`, `<Json value={post.metadata} />`. Don't unwrap first; the component reads the source metadata so the field stays inline-editable in the dashboard.
534
537
  - **`FimoString extends String`**, so `typeof post.title === 'object'` and `post.title === 'Hi'` is `false`. It stringifies fine inside JSX and template literals; call `.toString()` only when something genuinely needs a primitive `string`.
538
+ - **`number` fields are the one scalar type left unwrapped** — `post.views` is a plain `number`, so `{post.views}` renders directly in JSX, `typeof`/`===`/arithmetic all behave normally, and there is no `<Number>` component. This is deliberate, not a gap: wrapping it would break direct JSX rendering in every existing site.
539
+ - **`json` fields are a shallow clone of what you wrote**, tagged with a hidden source symbol — not the original object, and not a class instance. Reading it behaves exactly like plain JSON (`JSON.stringify` round-trips it unchanged; `for...in`/`Object.keys` see only your own keys). Render it with `<Json value={post.metadata} />` (default renders as a `<span>`; pass `as="pre"` for a formatted block, or a children render function for specific keys) so it stays inline-editable and live-updates in the dashboard preview like every other field.
535
540
  - **Never hand-construct** a `FimoString` / `FimoMedia` / etc. — that bypasses source tracking. For a literal string use `t()`; for a literal image use `<StaticImage>`.
536
541
  - `t()` also returns a `FimoString` (see `references/labels.md`).
537
542
 
@@ -553,7 +558,7 @@ class FimoBoolean {
553
558
  }
554
559
  ```
555
560
 
556
- > **`FimoDate`:** exported from `fimo/ui` (it's the `<Date>` component's value type), but the generated schema client does **not** wrap `date` fields in it today — they arrive as a raw ISO string. `<Date value={post.someDate} />` accepts that at runtime either way.
561
+ > **`FimoDate`:** exported from `fimo/ui` (it's one of the `<Date>` component's accepted value types), but the generated schema client does **not** wrap `date` fields in it — a `date` field wraps as `FimoString` instead (see the table above), because the generated TypeScript type for a `date` field is `string`, and `FimoString` is what keeps that contract's string methods (`.slice()`, `.includes()`, …) working. `<Date value={post.someDate} />` accepts a `FimoString`, a `FimoDate`, a raw `Date`, or a raw string — all four render correctly.
557
562
 
558
563
  ## UI code pattern
559
564
 
@@ -579,7 +584,7 @@ export function BlogList() {
579
584
  }
580
585
  ```
581
586
 
582
- For the `<Text>` / `<RichText>` / `<Image>` / `<Date>` components and the rules of thumb, see `references/ui.md`.
587
+ For the `<Text>` / `<RichText>` / `<Image>` / `<Date>` / `<Json>` components and the rules of thumb, see `references/ui.md`.
583
588
 
584
589
  ## Read path (published app, no auth)
585
590
 
@@ -21,11 +21,11 @@ In development, the generated app reloads when DB label values change. In produc
21
21
 
22
22
  ## Locale behavior
23
23
 
24
- The default label locale is `i18n.defaultLocale` in `fimo-config.json`, falling back to `en` when it is not set. `fimo validate`, the generated app runtime, and `fimo labels set` without `--locale` all use that default locale.
24
+ The default label locale is `i18n.defaultLocale` in `.fimo/config.json`, falling back to `en` when it is not set. `fimo validate`, the generated app runtime, and `fimo labels set` without `--locale` all use that default locale.
25
25
 
26
26
  For non-default locales, create explicit DB values with `fimo labels set --locale <locale>` or `fimo labels set-many --locale <locale>`. Keep the code shape the same for every locale: `t('hero.title')` declares the key, and the DB decides which locale value is shown.
27
27
 
28
- `fimo-config.json` owns the locale list:
28
+ `.fimo/config.json` owns the locale list:
29
29
 
30
30
  ```json
31
31
  {
@@ -4,7 +4,7 @@ Fimo provides locale utilities that follow the Fimo standard, but they are helpe
4
4
 
5
5
  ## Configuration
6
6
 
7
- `fimo-config.json` owns the locale list and routing strategy. Keep one locale unless the user asks for multilingual or localized output.
7
+ `.fimo/config.json` owns the locale list and routing strategy. Keep one locale unless the user asks for multilingual or localized output.
8
8
 
9
9
  ```jsonc
10
10
  {
@@ -28,7 +28,7 @@ Locale tags should be structurally valid, for example `en`, `es`, `pt-BR`, or `z
28
28
 
29
29
  ## Canonical Routes
30
30
 
31
- Keep `fimo-config.json#routes` canonical and unlocalized:
31
+ Keep `.fimo/config.json#routes` canonical and unlocalized:
32
32
 
33
33
  ```json
34
34
  {
@@ -71,7 +71,7 @@ Copyable examples live in `assets/react-router-locales/routes.ts` and `assets/re
71
71
 
72
72
  Before changing a multilingual app, inspect its locale provider, route table, language switcher, redirects, and current public URLs. Preserve that behavior while migrating.
73
73
 
74
- For React Router projects, prefer converging on one locale contract owned by `fimo-config.json`, `fimoRoutes()`, and `FimoLink`. Move existing providers and language-switcher UI into the framework root instead of replacing them or adding a second locale context. Keep route metadata canonical and reuse page modules across locales.
74
+ For React Router projects, prefer converging on one locale contract owned by `.fimo/config.json`, `fimoRoutes()`, and `FimoLink`. Move existing providers and language-switcher UI into the framework root instead of replacing them or adding a second locale context. Keep route metadata canonical and reuse page modules across locales.
75
75
 
76
76
  If adopting the standard helper would change established public URLs, do not silently rewrite them. Keep the custom router temporarily, pass its resolved locale to `<FimoProviders locale={locale}>`, and ask the user to choose the canonical URLs and redirects before normalizing the route table.
77
77
 
@@ -86,7 +86,7 @@ import { FimoLink } from 'fimo/react-router';
86
86
  <FimoLink to="/pricing" locale="es">Spanish pricing</FimoLink>
87
87
  ```
88
88
 
89
- `FimoLink` localizes absolute internal paths according to `fimo-config.json#i18n.routing`. It leaves relative, hash, query-only, and external URLs alone. Use React Router's raw `Link` only when you intentionally want to bypass Fimo's locale behavior.
89
+ `FimoLink` localizes absolute internal paths according to `.fimo/config.json#i18n.routing`. It leaves relative, hash, query-only, and external URLs alone. Use React Router's raw `Link` only when you intentionally want to bypass Fimo's locale behavior.
90
90
 
91
91
  Read the active locale with `useLocale()` when component logic needs it:
92
92
 
@@ -125,5 +125,5 @@ When using custom routing, also provide localized internal-link helpers in that
125
125
  ## What Not To Do
126
126
 
127
127
  - Do not create `src/pages/__localized/*` copies just for locales.
128
- - Do not duplicate every route in `fimo-config.json` per locale.
128
+ - Do not duplicate every route in `.fimo/config.json` per locale.
129
129
  - Do not use `/es` as a normal canonical route when `es` is an enabled locale.
@@ -85,16 +85,16 @@ Notes:
85
85
  ```
86
86
 
87
87
  The `seo` plugin rewrites `<title>`, og, twitter, canonical tags from
88
- `fimo-config.json#seo` at build time. You can leave a placeholder title in
88
+ `.fimo/config.json#seo` at build time. You can leave a placeholder title in
89
89
  `index.html`; it'll be replaced.
90
90
 
91
91
  ## File: `src/main.tsx`
92
92
 
93
- `FimoProviders` (and the runtime primitives it wraps) require **two** contexts:
94
- a React Router `<Router>` ancestor (it reads `useLocation`/`useNavigate`) and a
95
- `@tanstack/react-query` `<QueryClientProvider>` (its internal
96
- `RefreshContentProvider` calls `useQueryClient`). Mount both around
97
- `<FimoProviders>`:
93
+ `FimoProviders` requires a React Router `<Router>` ancestor (it reads
94
+ `useLocation`/`useNavigate`). It reuses a host app's
95
+ `@tanstack/react-query` client when one exists and supplies a stable fallback
96
+ for adopted SPAs. This recipe still mounts an explicit provider so the app owns
97
+ the shared cache and its configuration:
98
98
 
99
99
  ```tsx
100
100
  import { FimoProviders } from 'fimo/react-router';
@@ -122,8 +122,9 @@ createRoot(document.getElementById('root')!).render(
122
122
 
123
123
  `react-router` and `@tanstack/react-query` are peer dependencies of `fimo`;
124
124
  both are in the install command above. `FimoProviders` is exported only from
125
- the `fimo/react-router` adapter barrel — there is no router-free (or
126
- react-query-free) provider surface in the package today.
125
+ the `fimo/react-router` adapter barrel. Keep the explicit QueryClientProvider
126
+ when the app needs custom query defaults or shared cache access; adopted SPAs
127
+ can omit it.
127
128
 
128
129
  ## File: `src/App.tsx`
129
130
 
@@ -139,7 +140,7 @@ export function App() {
139
140
  }
140
141
  ```
141
142
 
142
- ## File: `fimo-config.json`
143
+ ## File: `.fimo/config.json`
143
144
 
144
145
  ```json
145
146
  {
@@ -164,7 +165,7 @@ this version field. It also never injects the React Router plugin: in a
164
165
  framework-mode project that `reactRouter()` plugin is added by your own
165
166
  `vite.config.ts`, not by `fimo/vite`.
166
167
 
167
- ## File: `.fimo.settings.json`
168
+ ## File: `.fimo/project.json`
168
169
 
169
170
  ```json
170
171
  {
@@ -221,6 +222,6 @@ shows the **deployed** app, not the localhost dev server.
221
222
  ## What to do next
222
223
 
223
224
  - Add a sitemap: pass `fimo({ seo: true, sitemap: true })` and set
224
- `fimo-config.json#seo.url` to your production base URL.
225
+ `.fimo/config.json#seo.url` to your production base URL.
225
226
  - Look up exports: see `references/ui.md`.
226
227
  - Use schema content: see `references/content.md`.
@@ -100,6 +100,11 @@ when to render them, and how.
100
100
 
101
101
  ## File: `src/root.tsx`
102
102
 
103
+ The explicit `QueryClientProvider` below is the canonical template shape so the
104
+ app can configure query defaults such as `staleTime`. Adopted SPAs can omit it:
105
+ `FimoProviders` reuses an ancestor client when present and supplies a stable
106
+ fallback otherwise.
107
+
103
108
  ```tsx
104
109
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
105
110
  import { FimoProviders, FimoScripts, loadFimoMetaData, buildFimoMeta, fimoHtmlProps } from 'fimo/react-router';
@@ -161,7 +166,7 @@ export default fimoRoutes(routes) satisfies RouteConfig;
161
166
  Page filenames are your choice; the scaffold uses PascalCase (e.g. `Index.tsx`,
162
167
  `Privacy.tsx`).
163
168
 
164
- `fimoRoutes()` is Fimo's React Router helper for path-prefix locales. It is a no-op for single-locale projects and expands concrete locale aliases when `fimo-config.json#i18n.locales` contains more locales. Custom routers can ignore this helper and pass their own locale to `<FimoProviders locale={locale}>`; see `references/locales.md`.
169
+ `fimoRoutes()` is Fimo's React Router helper for path-prefix locales. It is a no-op for single-locale projects and expands concrete locale aliases when `.fimo/config.json#i18n.locales` contains more locales. Custom routers can ignore this helper and pass their own locale to `<FimoProviders locale={locale}>`; see `references/locales.md`.
165
170
 
166
171
  ## File: `src/pages/Index.tsx`
167
172
 
@@ -177,7 +182,7 @@ export default function HomePage() {
177
182
  }
178
183
  ```
179
184
 
180
- ## File: `fimo-config.json`
185
+ ## File: `.fimo/config.json`
181
186
 
182
187
  ```json
183
188
  {
@@ -195,7 +200,7 @@ export default function HomePage() {
195
200
  }
196
201
  ```
197
202
 
198
- ## File: `.fimo.settings.json`
203
+ ## File: `.fimo/project.json`
199
204
 
200
205
  ```json
201
206
  {
@@ -263,9 +268,9 @@ changes after a `fimo deploy` (the local dev server is localhost-only).
263
268
  ## What to do next
264
269
 
265
270
  - Add more routes: extend `src/routes.ts`, create matching `src/pages/*.tsx`,
266
- add route entries in `fimo-config.json#routes`.
271
+ add route entries in `.fimo/config.json#routes`.
267
272
  - Add a sitemap: pass `fimo({ sitemap: true })` (opt-in, off by default; the
268
273
  canonical template enables it). To customize the base URL, set
269
- `fimo-config.json#seo.url`.
274
+ `.fimo/config.json#seo.url`.
270
275
  - Override SEO per route: see `references/seo-overrides.md`.
271
276
  - Look up an export: see `references/api.md`.
@@ -17,6 +17,7 @@ Use these to render content-type field values consistently. They carry source me
17
17
  | `<Video>` | Schema `media` video fields | `<Video value={post.heroVideo} />` |
18
18
  | `<Date>` | Schema date fields | `<Date value={post.publishDate} />` |
19
19
  | `<Boolean>` | Schema boolean fields | `<Boolean value={product.inStock} />` |
20
+ | `<Json>` | Schema `json` fields | `<Json value={post.metadata} as="pre" />` |
20
21
  | `` fimo`...` `` | Compose tracked values (mix `t()` + schema text) | ``<Text value={fimo`${t('by')} ${post.author}`} />`` |
21
22
  | `useLabels()` | `t('key')` hook | see `references/labels.md` |
22
23
  | `useLocale()` | Active locale and route locale metadata | see `references/locales.md` |
@@ -26,9 +27,10 @@ Use these to render content-type field values consistently. They carry source me
26
27
  1. **Schema text → `<Text>`**, never `<h1>{post.title}</h1>`.
27
28
  2. **Schema media → `<Image>` / `<Video>`**, never `<img src={post.coverImage.url} />`. Provide `width` / `height` when known so Fimo can optimize and reserve layout space.
28
29
  3. **Non-schema images** (decorative, hard-coded URLs, generated assets referenced directly) → `<StaticImage>`. Never hand-construct a `FimoMedia` to feed `<Image>`.
29
- 4. **Label text → `<Text value={t('key')} />`**, not `<h1>{t(...)}</h1>`. Label values live in the DB for `i18n.defaultLocale` from `fimo-config.json` unless a non-default locale is explicitly targeted. See `references/labels.md`.
30
+ 4. **Label text → `<Text value={t('key')} />`**, not `<h1>{t(...)}</h1>`. Label values live in the DB for `i18n.defaultLocale` from `.fimo/config.json` unless a non-default locale is explicitly targeted. See `references/labels.md`.
30
31
  5. **Mixed schema + translated text** → the `` fimo`...` `` template literal inside `<Text>`.
31
32
  6. **Never hand-roll richtext rendering** — always `<RichText>`. To restyle a node, pass `components={{ heading: ..., link: ..., ... }}`.
33
+ 7. **Schema `json` → `<Json>`**, not a hand-rolled `<pre data-fimo-source={getFimoSource(post.metadata)}>{JSON.stringify(post.metadata)}</pre>`. Default renders as a `<span>`; pass `as="pre"` (with a `whitespace-pre-wrap` class) for a formatted block, or a children render function for custom display of specific keys.
32
34
 
33
35
  ## App code conventions
34
36
 
@@ -78,6 +80,7 @@ The template uses **Vite + React 19 + TypeScript + Tailwind v4 + shadcn/ui + rea
78
80
 
79
81
  - Raw `<a href>` for internal nav → use `<FimoLink>` for locale-aware paths or React Router `<Link>` / `<NavLink>` only when intentionally bypassing Fimo locale helpers.
80
82
  - Raw `<img>` for schema media → use `<Image>` (with width/height).
83
+ - Raw `<pre data-fimo-source={getFimoSource(...)}>` for schema `json` fields → use `<Json>`.
81
84
  - Hardcoded strings in JSX → wrap in `t('key')` and add the DB value with `fimo labels set`.
82
85
  - Calling `t()` with a dynamic first argument → key must be a string literal.
83
86
  - Editing generated `.ts` files under `src/schemas/` or `src/forms/` → regenerate them through `fimo validate` or the matching push command.
@@ -6,7 +6,7 @@ Use this as the phase contract for complete migrations.
6
6
 
7
7
  1. Confirm the target path.
8
8
  2. If the target path is missing, create exactly one Fimo project there.
9
- 3. If it has `.fimo.settings.json`, reuse it.
9
+ 3. If it has `.fimo/project.json` or the legacy `.fimo.settings.json`, reuse it.
10
10
  4. If it is non-empty and not a Fimo project, stop and ask for a target path.
11
11
  5. Never overwrite user work outside generated migration folders without reading
12
12
  the existing files first.
@@ -110,7 +110,7 @@ function buildCanonicalManifest({ projectRoot, urlLedger, urlLedgerPath, sourceL
110
110
  forms,
111
111
  redirects: normalizeItems(sourceLedger?.redirects, 'redirect'),
112
112
  locales: normalizeItems(sourceLedger?.locales, 'locale'),
113
- seo: normalizeSeo(urlLedger),
113
+ seo: normalizeSeo(urlLedger, projectRoot),
114
114
  unsupported: normalizeItems(sourceLedger?.unsupported, 'unsupported'),
115
115
  unresolved: mergeItems([
116
116
  ...normalizeUnresolved(sourceLedger?.unresolved),
@@ -326,14 +326,15 @@ function normalizeUrlForms(forms) {
326
326
  }));
327
327
  }
328
328
 
329
- function normalizeSeo(urlLedger) {
329
+ function normalizeSeo(urlLedger, projectRoot) {
330
+ const configPath = resolveProjectConfigPath(projectRoot);
330
331
  return asArray(urlLedger?.pages).map((page) => ({
331
332
  id: `seo:${page.route}`,
332
333
  status: 'discovered',
333
334
  route: page.route,
334
335
  sourceUrls: compact([page.url]),
335
336
  sourceFiles: compact([page.artifacts?.html]),
336
- targetFiles: ['fimo-config.json'],
337
+ targetFiles: [configPath],
337
338
  confidence: numberOr(page.confidence, 0.7),
338
339
  title: page.seo?.title ?? page.title ?? null,
339
340
  description: page.seo?.description ?? null,
@@ -341,6 +342,34 @@ function normalizeSeo(urlLedger) {
341
342
  }));
342
343
  }
343
344
 
345
+ function resolveProjectConfigPath(projectRoot) {
346
+ if (fs.existsSync(path.join(projectRoot, '.fimo/project.json'))) {
347
+ return '.fimo/config.json';
348
+ }
349
+ if (fs.existsSync(path.join(projectRoot, '.fimo.settings.json'))) {
350
+ if (fs.existsSync(path.join(projectRoot, 'fimo-config.json'))) {
351
+ return 'fimo-config.json';
352
+ }
353
+ if (fs.existsSync(path.join(projectRoot, 'fimo.config.json'))) {
354
+ return 'fimo.config.json';
355
+ }
356
+ return 'fimo-config.json';
357
+ }
358
+ if (
359
+ fs.existsSync(path.join(projectRoot, '.fimo/config.json')) ||
360
+ fs.existsSync(path.join(projectRoot, '.fimo/agents'))
361
+ ) {
362
+ return '.fimo/config.json';
363
+ }
364
+ if (fs.existsSync(path.join(projectRoot, 'fimo-config.json'))) {
365
+ return 'fimo-config.json';
366
+ }
367
+ if (fs.existsSync(path.join(projectRoot, 'fimo.config.json'))) {
368
+ return 'fimo.config.json';
369
+ }
370
+ return '.fimo/config.json';
371
+ }
372
+
344
373
  function normalizeUnresolved(items) {
345
374
  return asArray(items).map((item, index) => {
346
375
  if (typeof item === 'string') {
@@ -9,6 +9,12 @@ The AI chat opens as a floating panel by default. You can dock it to the left or
9
9
  3. Press **Enter** or click the **send button**.
10
10
  4. The AI responds in a stream. You see tool status badges appear as it works, and the preview updates automatically.
11
11
 
12
+ ## Responding to Choices and Forms
13
+
14
+ The AI can place choices, cards, tables, images, and contextual actions directly in its reply. Optional suggestions do not interrupt the conversation.
15
+
16
+ When the AI needs an answer before it can continue, it shows a form in the chat and waits for your response. Complete the form for a structured answer, or reply normally in the chat to answer in your own words.
17
+
12
18
  ## Attaching Context
13
19
 
14
20
  Give the AI more to work with:
@@ -33,6 +39,14 @@ To halt the AI mid-generation, use the **Stop button** in the input bar — whil
33
39
 
34
40
  While the AI works, you see small badges in the chat showing what it is doing. Each badge displays a tool name and its current status. Examples include reading files, writing code, searching your project, or generating images. These badges help you follow along without needing to understand the technical details.
35
41
 
42
+ ## Reviewing Changes That Could Not Merge
43
+
44
+ Chat changes are prepared separately and then applied to the environment you are viewing. Most changes merge automatically.
45
+
46
+ If the project changed in the same place while the AI was working, the response shows a **Review changes** card and an attention banner above the chat input. The banner remains visible when floating chat history is collapsed.
47
+
48
+ Choose **Auto fix** or keep chatting to let Fimo continue in the retained proposal, resolve the conflict, and retry the merge. Choose **Review manually** to inspect and resolve the proposal yourself. Discarding leaves the current environment unchanged and permanently removes the proposal.
49
+
36
50
  ## Tips for Better Results
37
51
 
38
52
  - **Be specific**: Mention colors, layout, text content, and spacing when you can.
@@ -12,7 +12,7 @@ If you're driving Fimo from the terminal, the equivalent commands are `fimo doma
12
12
  ## Adding a Custom Domain
13
13
 
14
14
  1. Open **Settings** from the top navigation bar (gear icon), alongside Preview, Content, Assets, Agents, and Analytics.
15
- 2. In the Settings menu on the left, select **Domains** (globe icon) — listed with General, SEO, and Audit log.
15
+ 2. In the Settings menu on the left, select **Domains** (globe icon) — listed with General and SEO.
16
16
  3. Click the **Add domain** button (+ icon) in the top-right of the panel. (When domain purchase is enabled, a **Buy domain** button with a shopping-cart icon sits next to it.)
17
17
  4. A drawer opens. Type or select a domain — you can enter a subdomain or an apex domain. Domains your organization already owns appear in an autocomplete dropdown, and Fimo checks availability live as you type. For an apex domain, a checkbox lets you also redirect it to the `www` subdomain (on by default). Confirm to add it.
18
18
  5. A DNS table appears showing the record(s) you need to add. For a **subdomain** it's a single CNAME record:
@@ -47,4 +47,4 @@ The preview is one of several workspaces, and only one is shown at a time. Switc
47
47
  - **Alt+4** -- Code
48
48
  - **Alt+5** -- Settings
49
49
 
50
- When the Preview workspace is open, the visual editor and the changes panel can appear alongside it as the preview's side panels.
50
+ When the Preview workspace is open, the visual editor can appear alongside it as a preview side panel.
@@ -14,7 +14,13 @@ Every change you make is automatically saved to your project, but saved changes
14
14
 
15
15
  To push your latest changes live, open the publish panel from the header **Publish** button and click **Publish** inside it again. It redeploys with your latest code and content.
16
16
 
17
- > **Tip:** Before your site has ever been published, the chat shows a one-click **Publish** button that deploys immediately without opening the panel.
17
+ > **Tip:** After completing relevant work, the AI may offer a one-click **Publish** callout in chat. It appears only when publishing is available; the header **Publish** control remains the reliable path at any time.
18
+
19
+ ## Publishing Changes That Need Review
20
+
21
+ If an AI chat change cannot merge automatically, use the response's **Review changes** card first. Resolve the conflicts and merge the proposal into `main`.
22
+
23
+ When the AI requested publication, the review dialog offers **Merge and publish** after the conflicts are resolved. Publishing starts only after the merge succeeds, so unresolved or discarded proposals never reach the live site.
18
24
 
19
25
  ## What You See When You Click Publish
20
26
 
@@ -23,6 +29,7 @@ The header **Publish** button itself only shows the label "Publish" (or a spinne
23
29
  - **"Not published yet"** — Your site has never been published. The **Publish** button inside the panel is ready to click.
24
30
  - **"Publishing"** — Publishing is in progress. A spinner and a **Publishing** status badge show while it builds, and the button is disabled.
25
31
  - **"Published"** — Your site is live. A **Published** status badge appears, your live URL is listed under a **Published site** heading as a clickable link, and a **Last published** date and time is shown.
32
+ - **"Couldn't publish · N issues"** — Project validation found issues that must be fixed first. Choose **Fix with Fimo** to send the safe issue list to the project chat and ask Fimo to repair it.
26
33
 
27
34
  ## Key Concepts
28
35