@bettercms-ai/mcp 0.83.0 → 0.83.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 (40) hide show
  1. package/README.md +86 -86
  2. package/SKILL.md +160 -160
  3. package/dist/index.js +38 -9
  4. package/dist/index.js.map +1 -1
  5. package/dist/kit-catalog.json +1509 -1509
  6. package/dist/skills/bettercms/SKILL.md +206 -206
  7. package/dist/skills/bettercms/references/accessibility.md +171 -171
  8. package/dist/skills/bettercms/references/animation.md +296 -296
  9. package/dist/skills/bettercms/references/astro.md +148 -148
  10. package/dist/skills/bettercms/references/bindings.md +366 -366
  11. package/dist/skills/bettercms/references/componentize.md +185 -185
  12. package/dist/skills/bettercms/references/components.md +415 -415
  13. package/dist/skills/bettercms/references/content-experiments.md +62 -62
  14. package/dist/skills/bettercms/references/content-modeling.md +382 -382
  15. package/dist/skills/bettercms/references/detection.md +465 -465
  16. package/dist/skills/bettercms/references/dock-input.md +121 -121
  17. package/dist/skills/bettercms/references/editor-chrome.md +92 -92
  18. package/dist/skills/bettercms/references/external-content.md +78 -78
  19. package/dist/skills/bettercms/references/finish-site.md +377 -377
  20. package/dist/skills/bettercms/references/forms-and-interactions.md +245 -245
  21. package/dist/skills/bettercms/references/frameworks.md +159 -159
  22. package/dist/skills/bettercms/references/getting-started.md +156 -156
  23. package/dist/skills/bettercms/references/integrations.md +364 -364
  24. package/dist/skills/bettercms/references/kit-catalog.md +3259 -3259
  25. package/dist/skills/bettercms/references/kit-scenarios.md +712 -712
  26. package/dist/skills/bettercms/references/localization.md +85 -85
  27. package/dist/skills/bettercms/references/media-and-brand.md +181 -181
  28. package/dist/skills/bettercms/references/next.md +189 -189
  29. package/dist/skills/bettercms/references/other-frameworks.md +85 -85
  30. package/dist/skills/bettercms/references/portable-text.md +213 -213
  31. package/dist/skills/bettercms/references/programmatic-seo.md +98 -98
  32. package/dist/skills/bettercms/references/publishing.md +289 -289
  33. package/dist/skills/bettercms/references/seo.md +357 -357
  34. package/dist/skills/bettercms/references/shopify-headless.md +52 -52
  35. package/dist/skills/bettercms/references/site-blueprints.md +895 -895
  36. package/dist/skills/bettercms/references/site-review.md +74 -74
  37. package/dist/skills/bettercms/references/worked-examples-advanced.md +509 -509
  38. package/dist/skills/bettercms/references/worked-examples.md +885 -885
  39. package/dist/skills/bettercms/references/write-limits.md +217 -217
  40. package/package.json +1 -1
@@ -1,206 +1,206 @@
1
- ---
2
- name: bettercms
3
- description: "BetterCMS: build, convert, import, edit, publish and verify BetterCMS sites. Use whenever the user names BetterCMS or its MCP, or the repo has @bettercms-ai/* packages, data-bcms- attributes, bcms-content.json or bcms-rebuild.yml, even when they only say 'make it editable', 'import my site', 'convert this repo', 'add a section', 'fix the schema' or 'publish'. Covers setup, the finish-site workflow, content modeling, components, click-to-edit bindings, Portable Text, media, forms, SEO and launch review. Moving off another CMS: bettercms-migrate. ABM campaigns: bettercms-abm."
4
- license: MIT
5
- metadata:
6
- author: bettercms
7
- version: "0.3.0"
8
- ---
9
-
10
- # BetterCMS
11
-
12
- The BetterCMS MCP serves its own doctrine, so this skill carries only what the server cannot see:
13
- your repo's framework wiring, binding attributes, env names, stored value shapes and the traps
14
- that only show up in code. Read doctrine from the MCP, never from memory:
15
-
16
- - Schema, sections, variants, publish order: resource `bettercms://playbook/schema` (§1–§14).
17
- - Content sidebar organisation: resource `bettercms://playbook/structure`.
18
- - Section patterns (149 worked kit entries by category and edge tag): resource `bettercms://kit`.
19
- - Guided flows: the `studio` prompt routes to the rest (`convert_site` prompt,
20
- `build_site` prompt, `componentize_site` prompt, `propose_schema` prompt, `new_page` prompt,
21
- `new_component` prompt, `new_form` prompt, `seo_optimize` prompt, `import-site` prompt,
22
- `field-ui` prompt, `edit_layout` prompt for the Global Layout, `generate_landing_pages` prompt
23
- for page families from data).
24
- - Import and modelling rule ids: `CM-01`…`CM-83` in the content-modeling standard.
25
-
26
- ## Start here
27
-
28
- Setting up a project, or asked to "Continue BetterCMS setup"? Read
29
- [references/getting-started.md](references/getting-started.md) first: it owns the setup phases
30
- and the resume check. For any other task, read the one reference the table below names.
31
-
32
- ## Connecting (before your first MCP call)
33
-
34
- Listing tools needs no sign-in; the first tool **call** does.
35
-
36
- 1. **A 401 on the first call is the sign-in, not an error.** The client opens a browser sign-in
37
- from the `WWW-Authenticate` header. Tell the user to approve it, then retry that same call.
38
- 2. **If `list_projects` lacks the project id you were given, stop and say so.** Consent binds to
39
- the workspace the dashboard had active; ask the user to re-authenticate in the right one.
40
- Never continue in whichever project IS listed: that writes into someone else's site.
41
- 3. **Pass `projectId` on every project tool, and never ask the user to re-scope.** A
42
- workspace-wide connection reaches every project by naming it per call.
43
- 4. **A refusal for access: call `whoami` first.** It names the principal, the workspace, the
44
- scope (project or workspace) and, where visible, the grants (publish, code and deploy,
45
- sidebar schema), so you can tell the user which one is missing.
46
- 5. **"Invalid tool parameters" is the client, not BetterCMS.** A client with tool search (Claude
47
- Code) lists most of the 150 tools by name and loads a schema on demand; a call to a tool whose
48
- schema it has not loaded is refused before it is sent. Load the tool with the client's tool
49
- search, every tool the step needs in one search, then make the same call again. Never change
50
- the arguments because of it. The tools a setup starts with are always loaded.
51
- 6. **Unsure how a feature works: `search_docs` before guessing.** A tool that fails oddly, a
52
- capability you needed and did not have, or docs that misled you: `give_feedback`, and tell the
53
- user you sent it.
54
-
55
- ## Invariants
56
-
57
- These hold on every task. The reference in brackets has the detail and the codes.
58
-
59
- 1. **Confirm the bound project before any write**: §9 of the schema playbook, then `get_project`.
60
- Its `authoringPreference` defaults to components (recorded by a deploy, a promote or setup)
61
- and is never asked; the owner can switch it to fields.
62
- 2. **Never create SEO fields** (§5b). Page and entry meta are native columns. [seo.md]
63
- 3. **A page is a list of sections**, never loose top-level blocks, and never a nav, footer or
64
- modal: chrome is the Layout. A call to action is one `button` field, never a text field
65
- beside a link field. [components.md, content-modeling.md]
66
- 4. **Nothing is live until it is published, and a page is not its content.** A draft form,
67
- component or entry renders nothing live. Read `warnings` on every write: `ENTRY_STILL_DRAFT`
68
- and `ENTRY_SEED_FAILED` mean content did not ship. An answer that leads with `held`, and a
69
- publish reading `outcome.status: "partial"`, did not reach the site: do the action it names
70
- before you report it.
71
- [publishing.md]
72
- 5. **Name the folder system every time you say "folder"**: Content sidebar folders never touch a
73
- URL, URL page folders are part of the path, media folders organise assets.
74
- [content-modeling.md]
75
- 6. **Headless projects are built by their host.** Never `deploy_project`, `deploy_to_host` or
76
- `create_deploy_upload` there, never add `bcms-rebuild.yml`; deploy with
77
- `npx @bettercms-ai/cli@latest deploy --to <host>`, or push to the repo the host builds.
78
- Done = `receipt.frontEnd` closed. [getting-started.md]
79
- 7. **Every refusal has a code. Report it; do not retry blind.** The same call returns the same
80
- code. Change the input or stop.
81
- 8. **Media is served by the backend that owns the asset ids.** `mediaUrl` is `mediaBaseUrl` from
82
- `get_project`; never hardcode, re-point or re-host media, and never read a bucket or key.
83
- [frameworks.md]
84
- 9. **Bind the leaf that renders the value, one address per element.** Attribute values ride
85
- `data-bcms-props`; `data-bcms-kind` declares the container, and the MODEL picks the editor.
86
- Inside an instance the address is `<instanceId>__overrides.<key>`; chrome uses
87
- `data-bcms-layout-field`. [bindings.md]
88
- 10. **Declared mode is a switch you flip** with `set_binding_mode` after the stamped build reports
89
- clean: push, release, report clean, flip, release again. [bindings.md]
90
- 11. **A field is not editable because it exists.** It is editable when its value renders from the
91
- CMS on a bound leaf and an edit shows in preview and after publish.
92
- 12. **Bulk work runs as code, not as a chain of tool calls.** Propose the mapping and dry-run it
93
- before a high-volume write; use the MCP for state, targeted fixes and reports.
94
- 13. **A build makes a site live, not editable.** It brings in SEO and meta, media, the brand and
95
- the models `bcms-content.json` declares. Pages, collections, forms, bindings and components
96
- are `editor_setup`'s: run it after an import or a rebuild (`get_deploy_status` `editorSetup`
97
- `never` or `stale`). It also fills missing meta, merges identical components and adopts
98
- declared bindings when proven; do only what get_next_steps still lists. [getting-started.md]
99
-
100
- ## What you do, and what only the owner does
101
-
102
- The MCP acts as the signed-in person. Some decisions are theirs by design: no tool makes them,
103
- and saying you made one is a false report. Name each as an action in your final message.
104
-
105
- | Only the owner | Where |
106
- |---|---|
107
- | Authoring preference and media delivery answers | you ask; `set_authoring_preference`, `set_media_delivery` |
108
- | Visual Approval of a component, CI (GitHub Actions) validation | dashboard |
109
- | Approving a generated job or a flagged ABM entry | the user's explicit yes before `approve_ai_job` / `approve_campaign_entries` |
110
- | Brand colours and typography; URL page folders; unpublishing a form | dashboard |
111
- | Hosting **Run as a server app**; form integrations; the Turnstile secret | dashboard |
112
- | `llms.txt` and Markdown twin switches | dashboard, SEO permission |
113
- | Publishing to production | the user's authorization, then the tools |
114
-
115
- Secrets never go in a tool call, a `PUBLIC_` variable or a client bundle. A 403
116
- `SCHEMA_ACCESS_REQUIRED` means the person lacks Admin or Developer access: stop and tell them.
117
-
118
- ## Which reference to read
119
-
120
- Read one reference per phase. Each is self-contained; a second one is needed only when the task
121
- crosses into its topic. When this skill is not installed, the MCP serves the same files as
122
- resources: `bettercms://skill/bettercms` for this file, and each reference under its file stem
123
- (`bettercms://skill/seo` for seo.md).
124
-
125
- | Task | Reference | Read when | Keywords |
126
- |---|---|---|---|
127
- | Set up or resume a project | [getting-started.md](references/getting-started.md) | first contact, or "Continue BetterCMS setup" | setup, resume, onboarding, connect, import my site, headless, own front end, SDK, CLI |
128
- | Finish an imported or converted site | [finish-site.md](references/finish-site.md) | a convert or build job; "make it fully editable"; the gap ledger | make it editable, finish, gap ledger, convert |
129
- | Move content out of another CMS (Cosmic, Contentful, Sanity, Strapi, Prismic, WordPress…) | [external-content.md](references/external-content.md) | a CMS SDK in package.json; `envWarning` on import; pages that render empty without a third-party key | Contentful, Sanity, Strapi, envWarning, missing key, empty pages |
130
- | Read a source site before modelling it | [detection.md](references/detection.md) | converting from a URL or built HTML; deciding what a band, a repeat or a value is | detect, classify, section, repeat, global, carousel clone, hidden state |
131
- | Pages vs collections, folders, fields, schema changes | [content-modeling.md](references/content-modeling.md) | modelling a route family; a model write returns 409 | schema, model, collection, field, folder, rename, remove field, listing, filter, locked field |
132
- | Dock layout: groups, rows, tabs, icons, item names, showIf order | [editor-chrome.md](references/editor-chrome.md) | after any import, convert, componentize or extract (the gate's `dock` row); a `dock-*` rule; the `field-ui` prompt | dock, fieldset, tab, group, itemLabel, showIf, field-ui |
133
- | A custom input for one field in the dock: when, the user's approval, the contract | [dock-input.md](references/dock-input.md) | `get_next_steps` lists `dock-input-candidate`; a 409 `input_needs_confirmation` | custom input, ui.input, dock input, confirmed, swatch |
134
- | What the server does and does not check on a write | [write-limits.md](references/write-limits.md) | before relying on a limit; reading a refused write; a bulk load or re-run | validation, maxLength, unique, 400, refused write, dry run, externalKey, upsert, re-run |
135
- | Plan a site by business type | [site-blueprints.md](references/site-blueprints.md) | the IA of a known site type, with its collections, forms and structured data | new site, IA, portfolio, agency, corporate, SaaS, ecommerce, directory, blog, docs, restaurant, events, course, jobs, real estate, nonprofit, multi-brand |
136
- | Components, props, variants, component publish codes | [components.md](references/components.md) | creating, swapping, publishing or validating a component | component, prop, variant, sectionType, publish component |
137
- | Which kit pattern fits a section, and its shape and pitfalls, by category and edge tag | [kit-scenarios.md](references/kit-scenarios.md) | before designing any section's fields or props; a band detection.md classified | kit, pattern, scenario, edge tag, events, locations, calculator, map, chart, docs, team, bento, slots, personalization, localized |
138
- | One section, source HTML to bound template: hero, feature grid, pricing table, testimonials, FAQ, bento | [worked-examples.md](references/worked-examples.md) | you want the whole path for one section in production shapes | example, hero, pricing, FAQ, testimonial, source to schema |
139
- | The same for an article entry, navigation in the Global Layout, tabs holding columns | [worked-examples-advanced.md](references/worked-examples-advanced.md) | a collection entry with a body, site chrome, or nested blocks | example, blog post, document body, mega menu, tabs, columns |
140
- | The modelled section closest to the one you are building: schema, HTML signals, mcp steps, pitfalls | [kit-catalog.md](references/kit-catalog.md) | before designing a section or its props; matching source HTML to a known pattern | kit, catalogue, edge tag, section pattern, bento, localized, personalization, a11y, responsive |
141
- | Componentize a derived site | [componentize.md](references/componentize.md) | `get_site_composition` shows pages made of fields only | componentize, sections, fields-only, get_componentize_plan, BcmsSections, --sections |
142
- | Click-to-edit attributes, addresses, declared mode | [bindings.md](references/bindings.md) | `grep -rl "data-bcms-" src` finds files; a value the editor cannot select | data-bcms-field, click to edit, binding report, stega, declared |
143
- | Animated sites: GSAP, ScrollTrigger, split text, Motion, Lenis, Locomotive, three.js and WebGL, marquees, carousels, Lottie, hydrated islands, and what must stand down in the editor's canvas (`inEditor()`) | [animation.md](references/animation.md) | `package.json` lists `gsap`, `lenis`, `locomotive-scroll`, `framer-motion` or `motion`, `three`, `swiper` or a text splitter; a publish refused with `SPLIT_PATTERN_UNKNOWN` or `ISLAND_PROPS_UNMATCHED`; a `client-only-island` gate exception | animation, GSAP, ScrollTrigger, SplitText, Lenis, Framer Motion, marquee, Swiper, Lottie, island, client:only, data-bcms-split |
144
- | Wiring, env, hosting modes, media host, snapshots | [frameworks.md](references/frameworks.md) | `package.json` lists an adapter; `bcms-content.json` exists | hosting, headless, env, codegen, types, revalidate, snapshot |
145
- | Astro adapter | [astro.md](references/astro.md) | the repo has `astro.config.*` | astro.config, Astro, BcmsBlocks, getStaticPaths |
146
- | Next.js adapter | [next.md](references/next.md) | the repo has `next.config.*` | next.config, Next.js, App Router, ISR, notFound, static export |
147
- | Nuxt, SvelteKit, React Router, Vite: no adapter | [other-frameworks.md](references/other-frameworks.md) | neither `astro.config.*` nor `next.config.*`; `nuxt.config.*`, `svelte.config.*`, `react-router.config.*` | Nuxt, SvelteKit, React Router, Vite, createClient |
148
- | Rich text and field types | [portable-text.md](references/portable-text.md) | writing a richtext value; converting HTML or Markdown | rich text, Portable Text, richtext, HTML, Markdown |
149
- | Brand kit, tokens, fonts, logo, images, icons | [media-and-brand.md](references/media-and-brand.md) | design fidelity, alt text, a logo or favicon change | brand, tokens, fonts, logo, image, alt text, favicon |
150
- | Connect a vendor with a public API (jobs board, store, CRM, video): declare, approve, call, recipes | [integrations.md](references/integrations.md) | the user names Greenhouse, JobDiva, Shopify, HubSpot, Zoom, Apollo or any API; a 409 `integration_not_approved` | integration, API key, Greenhouse, JobDiva, Shopify, HubSpot, Zoom, Apollo, sync, vendor, token |
151
- | Forms, menus, accordions, modals, consent | [forms-and-interactions.md](references/forms-and-interactions.md) | attaching or verifying a form; an interactive section | form, submission, Turnstile, modal, accordion, menu |
152
- | Languages, locale prefixes, translation, hreflang | [localization.md](references/localization.md) | the build serves `/fr`-style prefixes; `locale-unvarianted` in a binding report | language, locale, /fr, translate, hreflang, i18n |
153
- | SEO and AEO | [seo.md](references/seo.md) | meta, JSON-LD, sitemap, robots, redirects, AI crawlers, `list_seo_issues` | SEO, meta, JSON-LD, schema.org, sitemap, robots, OG image, redirect, 410, llms.txt |
154
- | Accessibility: alt text, form labels, contrast, the audit codes and the manual checks | [accessibility.md](references/accessibility.md) | writing alt text; building a form; before reporting a site done | accessibility, WCAG, alt text, decorative, label, contrast, captions |
155
- | Page families from data | [programmatic-seo.md](references/programmatic-seo.md) | a keyword list or CSV should become pages | programmatic SEO, CSV, dataset, landing pages, glossary |
156
- | Publish, deploy, roll back, reconcile a re-import; add a section to a page or set its spacing | [publishing.md](references/publishing.md) | a release; a code push that conflicts with CMS edits; "add a section here", "more padding on this section"; a write that answers `held` or a publish that reads `partial` | publish, deploy, rollback, sync, webhook, schedule, automation, add section, insertSection, sectionStyle, spacing, padding, margin, held, partial |
157
- | Read-only launch review | [site-review.md](references/site-review.md) | "is this ready to launch?" without fixing | launch review, audit, is it ready, QA |
158
- | A/B tests on section variants | [content-experiments.md](references/content-experiments.md) | an experiment plan or readout | A/B test, experiment, variant test |
159
- | Headless Shopify storefront | [shopify-headless.md](references/shopify-headless.md) | Shopify owns commerce, BetterCMS the editorial | Shopify, Hydrogen, storefront, product |
160
-
161
- Other sites move into BetterCMS with the `bettercms-migrate` skill; per-account campaign pages
162
- are the `bettercms-abm` skill.
163
-
164
- ## Context budget
165
-
166
- A whole-site job outlives one context window. Spend it on the site, not on re-reading.
167
-
168
- - Start from the receipt: `get_next_steps` returns `receipt.done`, `receipt.missing` and
169
- `receipt.nextAction`. Plan the session from it, not from re-reading the site.
170
- - Hold SKILL.md plus only the ONE reference the current phase needs; drop it when the phase ends.
171
- - Ask the MCP for summaries before reading files: `get_site_composition`, `get_binding_report`
172
- and `get_next_steps` answer "what is left" in a few hundred tokens, where built HTML or a whole
173
- repo costs tens of thousands.
174
- - Run bulk edits through the codemod (`npx @bettercms-ai/convert`), not file-by-file hand edits
175
- in context; read its receipt, not the diff.
176
- - Keep the gap ledger in `.bettercms/ledger.json` in the repo (shape in finish-site.md) and
177
- re-read it after a reset instead of carrying it in chat.
178
- - Where your agent supports subagents, fan out per-route verification and have each return only
179
- its verdict and the failing evidence.
180
- - Pass the `projectId` you already have; never re-list projects to find it again.
181
- - After a reset, say "Continue BetterCMS setup": the resume check rebuilds state from the MCP and
182
- the ledger.
183
-
184
- ## Verify loop (after every change, before you say "done")
185
-
186
- Stop at the first step that is not clean, fix, then restart. A report that does not exist yet is
187
- "not yet generated", which is not the same as dirty; say which.
188
-
189
- 1. **Fetch the live URL**, cache-busted: a 200 whose body contains copy you just published. The
190
- steps below read the control plane, and all of them can be green on a site that answers 404.
191
- 2. `get_binding_report` for every route you touched: `unaddressable` under 2%, and, where the
192
- source declares its bindings, `coverage.pending` empty and `mode: "declared"`. `refreshReason: "never-generated"` means no BetterCMS
193
- release wrote one (on headless none ever will, so step 1 is the proof); `"outdated"` means
194
- the next release rewrites it.
195
- 3. `get_site_composition`: every page you touched is made of sections, with the intended
196
- components.
197
- 4. `list_seo_issues`: no issue on a page you created or edited.
198
- 5. `get_next_steps`: `receipt.complete` is `true`. While it is `false`, run
199
- `receipt.gate.nextAction` and read again after each batch; nothing else ends an imported
200
- site's setup, and an exception is recorded only for a reason that is true. The gate, its bars and the exceptions it accepts are in
201
- [finish-site.md](references/finish-site.md). Suggestions still in `missing` after that, and
202
- owner actions, go in your final message by name.
203
-
204
- "Done" means the loop is clean and the gate reads complete, not that a tool call returned 200.
205
- `bettercms init` reads the gate again when you exit and prints its numbers per page, so the
206
- user sees them whatever your last message said.
1
+ ---
2
+ name: bettercms
3
+ description: "BetterCMS: build, convert, import, edit, publish and verify BetterCMS sites. Use whenever the user names BetterCMS or its MCP, or the repo has @bettercms-ai/* packages, data-bcms- attributes, bcms-content.json or bcms-rebuild.yml, even when they only say 'make it editable', 'import my site', 'convert this repo', 'add a section', 'fix the schema' or 'publish'. Covers setup, the finish-site workflow, content modeling, components, click-to-edit bindings, Portable Text, media, forms, SEO and launch review. Moving off another CMS: bettercms-migrate. ABM campaigns: bettercms-abm."
4
+ license: MIT
5
+ metadata:
6
+ author: bettercms
7
+ version: "0.3.0"
8
+ ---
9
+
10
+ # BetterCMS
11
+
12
+ The BetterCMS MCP serves its own doctrine, so this skill carries only what the server cannot see:
13
+ your repo's framework wiring, binding attributes, env names, stored value shapes and the traps
14
+ that only show up in code. Read doctrine from the MCP, never from memory:
15
+
16
+ - Schema, sections, variants, publish order: resource `bettercms://playbook/schema` (§1–§14).
17
+ - Content sidebar organisation: resource `bettercms://playbook/structure`.
18
+ - Section patterns (149 worked kit entries by category and edge tag): resource `bettercms://kit`.
19
+ - Guided flows: the `studio` prompt routes to the rest (`convert_site` prompt,
20
+ `build_site` prompt, `componentize_site` prompt, `propose_schema` prompt, `new_page` prompt,
21
+ `new_component` prompt, `new_form` prompt, `seo_optimize` prompt, `import-site` prompt,
22
+ `field-ui` prompt, `edit_layout` prompt for the Global Layout, `generate_landing_pages` prompt
23
+ for page families from data).
24
+ - Import and modelling rule ids: `CM-01`…`CM-83` in the content-modeling standard.
25
+
26
+ ## Start here
27
+
28
+ Setting up a project, or asked to "Continue BetterCMS setup"? Read
29
+ [references/getting-started.md](references/getting-started.md) first: it owns the setup phases
30
+ and the resume check. For any other task, read the one reference the table below names.
31
+
32
+ ## Connecting (before your first MCP call)
33
+
34
+ Listing tools needs no sign-in; the first tool **call** does.
35
+
36
+ 1. **A 401 on the first call is the sign-in, not an error.** The client opens a browser sign-in
37
+ from the `WWW-Authenticate` header. Tell the user to approve it, then retry that same call.
38
+ 2. **If `list_projects` lacks the project id you were given, stop and say so.** Consent binds to
39
+ the workspace the dashboard had active; ask the user to re-authenticate in the right one.
40
+ Never continue in whichever project IS listed: that writes into someone else's site.
41
+ 3. **Pass `projectId` on every project tool, and never ask the user to re-scope.** A
42
+ workspace-wide connection reaches every project by naming it per call.
43
+ 4. **A refusal for access: call `whoami` first.** It names the principal, the workspace, the
44
+ scope (project or workspace) and, where visible, the grants (publish, code and deploy,
45
+ sidebar schema), so you can tell the user which one is missing.
46
+ 5. **"Invalid tool parameters" is the client, not BetterCMS.** A client with tool search (Claude
47
+ Code) lists most of the 150 tools by name and loads a schema on demand; a call to a tool whose
48
+ schema it has not loaded is refused before it is sent. Load the tool with the client's tool
49
+ search, every tool the step needs in one search, then make the same call again. Never change
50
+ the arguments because of it. The tools a setup starts with are always loaded.
51
+ 6. **Unsure how a feature works: `search_docs` before guessing.** A tool that fails oddly, a
52
+ capability you needed and did not have, or docs that misled you: `give_feedback`, and tell the
53
+ user you sent it.
54
+
55
+ ## Invariants
56
+
57
+ These hold on every task. The reference in brackets has the detail and the codes.
58
+
59
+ 1. **Confirm the bound project before any write**: §9 of the schema playbook, then `get_project`.
60
+ Its `authoringPreference` defaults to components (recorded by a deploy, a promote or setup)
61
+ and is never asked; the owner can switch it to fields.
62
+ 2. **Never create SEO fields** (§5b). Page and entry meta are native columns. [seo.md]
63
+ 3. **A page is a list of sections**, never loose top-level blocks, and never a nav, footer or
64
+ modal: chrome is the Layout. A call to action is one `button` field, never a text field
65
+ beside a link field. [components.md, content-modeling.md]
66
+ 4. **Nothing is live until it is published, and a page is not its content.** A draft form,
67
+ component or entry renders nothing live. Read `warnings` on every write: `ENTRY_STILL_DRAFT`
68
+ and `ENTRY_SEED_FAILED` mean content did not ship. An answer that leads with `held`, and a
69
+ publish reading `outcome.status: "partial"`, did not reach the site: do the action it names
70
+ before you report it.
71
+ [publishing.md]
72
+ 5. **Name the folder system every time you say "folder"**: Content sidebar folders never touch a
73
+ URL, URL page folders are part of the path, media folders organise assets.
74
+ [content-modeling.md]
75
+ 6. **Headless projects are built by their host.** Never `deploy_project`, `deploy_to_host` or
76
+ `create_deploy_upload` there, never add `bcms-rebuild.yml`; deploy with
77
+ `npx @bettercms-ai/cli@latest deploy --to <host>`, or push to the repo the host builds.
78
+ Done = `receipt.frontEnd` closed. [getting-started.md]
79
+ 7. **Every refusal has a code. Report it; do not retry blind.** The same call returns the same
80
+ code. Change the input or stop.
81
+ 8. **Media is served by the backend that owns the asset ids.** `mediaUrl` is `mediaBaseUrl` from
82
+ `get_project`; never hardcode, re-point or re-host media, and never read a bucket or key.
83
+ [frameworks.md]
84
+ 9. **Bind the leaf that renders the value, one address per element.** Attribute values ride
85
+ `data-bcms-props`; `data-bcms-kind` declares the container, and the MODEL picks the editor.
86
+ Inside an instance the address is `<instanceId>__overrides.<key>`; chrome uses
87
+ `data-bcms-layout-field`. [bindings.md]
88
+ 10. **Declared mode is a switch you flip** with `set_binding_mode` after the stamped build reports
89
+ clean: push, release, report clean, flip, release again. [bindings.md]
90
+ 11. **A field is not editable because it exists.** It is editable when its value renders from the
91
+ CMS on a bound leaf and an edit shows in preview and after publish.
92
+ 12. **Bulk work runs as code, not as a chain of tool calls.** Propose the mapping and dry-run it
93
+ before a high-volume write; use the MCP for state, targeted fixes and reports.
94
+ 13. **A build makes a site live, not editable.** It brings in SEO and meta, media, the brand and
95
+ the models `bcms-content.json` declares. Pages, collections, forms, bindings and components
96
+ are `editor_setup`'s: run it after an import or a rebuild (`get_deploy_status` `editorSetup`
97
+ `never` or `stale`). It also fills missing meta, merges identical components and adopts
98
+ declared bindings when proven; do only what get_next_steps still lists. [getting-started.md]
99
+
100
+ ## What you do, and what only the owner does
101
+
102
+ The MCP acts as the signed-in person. Some decisions are theirs by design: no tool makes them,
103
+ and saying you made one is a false report. Name each as an action in your final message.
104
+
105
+ | Only the owner | Where |
106
+ |---|---|
107
+ | Authoring preference and media delivery answers | you ask; `set_authoring_preference`, `set_media_delivery` |
108
+ | Visual Approval of a component, CI (GitHub Actions) validation | dashboard |
109
+ | Approving a generated job or a flagged ABM entry | the user's explicit yes before `approve_ai_job` / `approve_campaign_entries` |
110
+ | Brand colours and typography; URL page folders; unpublishing a form | dashboard |
111
+ | Hosting **Run as a server app**; form integrations; the Turnstile secret | dashboard |
112
+ | `llms.txt` and Markdown twin switches | dashboard, SEO permission |
113
+ | Publishing to production | the user's authorization, then the tools |
114
+
115
+ Secrets never go in a tool call, a `PUBLIC_` variable or a client bundle. A 403
116
+ `SCHEMA_ACCESS_REQUIRED` means the person lacks Admin or Developer access: stop and tell them.
117
+
118
+ ## Which reference to read
119
+
120
+ Read one reference per phase. Each is self-contained; a second one is needed only when the task
121
+ crosses into its topic. When this skill is not installed, the MCP serves the same files as
122
+ resources: `bettercms://skill/bettercms` for this file, and each reference under its file stem
123
+ (`bettercms://skill/seo` for seo.md).
124
+
125
+ | Task | Reference | Read when | Keywords |
126
+ |---|---|---|---|
127
+ | Set up or resume a project | [getting-started.md](references/getting-started.md) | first contact, or "Continue BetterCMS setup" | setup, resume, onboarding, connect, import my site, headless, own front end, SDK, CLI |
128
+ | Finish an imported or converted site | [finish-site.md](references/finish-site.md) | a convert or build job; "make it fully editable"; the gap ledger | make it editable, finish, gap ledger, convert |
129
+ | Move content out of another CMS (Cosmic, Contentful, Sanity, Strapi, Prismic, WordPress…) | [external-content.md](references/external-content.md) | a CMS SDK in package.json; `envWarning` on import; pages that render empty without a third-party key | Contentful, Sanity, Strapi, envWarning, missing key, empty pages |
130
+ | Read a source site before modelling it | [detection.md](references/detection.md) | converting from a URL or built HTML; deciding what a band, a repeat or a value is | detect, classify, section, repeat, global, carousel clone, hidden state |
131
+ | Pages vs collections, folders, fields, schema changes | [content-modeling.md](references/content-modeling.md) | modelling a route family; a model write returns 409 | schema, model, collection, field, folder, rename, remove field, listing, filter, locked field |
132
+ | Dock layout: groups, rows, tabs, icons, item names, showIf order | [editor-chrome.md](references/editor-chrome.md) | after any import, convert, componentize or extract (the gate's `dock` row); a `dock-*` rule; the `field-ui` prompt | dock, fieldset, tab, group, itemLabel, showIf, field-ui |
133
+ | A custom input for one field in the dock: when, the user's approval, the contract | [dock-input.md](references/dock-input.md) | `get_next_steps` lists `dock-input-candidate`; a 409 `input_needs_confirmation` | custom input, ui.input, dock input, confirmed, swatch |
134
+ | What the server does and does not check on a write | [write-limits.md](references/write-limits.md) | before relying on a limit; reading a refused write; a bulk load or re-run | validation, maxLength, unique, 400, refused write, dry run, externalKey, upsert, re-run |
135
+ | Plan a site by business type | [site-blueprints.md](references/site-blueprints.md) | the IA of a known site type, with its collections, forms and structured data | new site, IA, portfolio, agency, corporate, SaaS, ecommerce, directory, blog, docs, restaurant, events, course, jobs, real estate, nonprofit, multi-brand |
136
+ | Components, props, variants, component publish codes | [components.md](references/components.md) | creating, swapping, publishing or validating a component | component, prop, variant, sectionType, publish component |
137
+ | Which kit pattern fits a section, and its shape and pitfalls, by category and edge tag | [kit-scenarios.md](references/kit-scenarios.md) | before designing any section's fields or props; a band detection.md classified | kit, pattern, scenario, edge tag, events, locations, calculator, map, chart, docs, team, bento, slots, personalization, localized |
138
+ | One section, source HTML to bound template: hero, feature grid, pricing table, testimonials, FAQ, bento | [worked-examples.md](references/worked-examples.md) | you want the whole path for one section in production shapes | example, hero, pricing, FAQ, testimonial, source to schema |
139
+ | The same for an article entry, navigation in the Global Layout, tabs holding columns | [worked-examples-advanced.md](references/worked-examples-advanced.md) | a collection entry with a body, site chrome, or nested blocks | example, blog post, document body, mega menu, tabs, columns |
140
+ | The modelled section closest to the one you are building: schema, HTML signals, mcp steps, pitfalls | [kit-catalog.md](references/kit-catalog.md) | before designing a section or its props; matching source HTML to a known pattern | kit, catalogue, edge tag, section pattern, bento, localized, personalization, a11y, responsive |
141
+ | Componentize a derived site | [componentize.md](references/componentize.md) | `get_site_composition` shows pages made of fields only | componentize, sections, fields-only, get_componentize_plan, BcmsSections, --sections |
142
+ | Click-to-edit attributes, addresses, declared mode | [bindings.md](references/bindings.md) | `grep -rl "data-bcms-" src` finds files; a value the editor cannot select | data-bcms-field, click to edit, binding report, stega, declared |
143
+ | Animated sites: GSAP, ScrollTrigger, split text, Motion, Lenis, Locomotive, three.js and WebGL, marquees, carousels, Lottie, hydrated islands, and what must stand down in the editor's canvas (`inEditor()`) | [animation.md](references/animation.md) | `package.json` lists `gsap`, `lenis`, `locomotive-scroll`, `framer-motion` or `motion`, `three`, `swiper` or a text splitter; a publish refused with `SPLIT_PATTERN_UNKNOWN` or `ISLAND_PROPS_UNMATCHED`; a `client-only-island` gate exception | animation, GSAP, ScrollTrigger, SplitText, Lenis, Framer Motion, marquee, Swiper, Lottie, island, client:only, data-bcms-split |
144
+ | Wiring, env, hosting modes, media host, snapshots | [frameworks.md](references/frameworks.md) | `package.json` lists an adapter; `bcms-content.json` exists | hosting, headless, env, codegen, types, revalidate, snapshot |
145
+ | Astro adapter | [astro.md](references/astro.md) | the repo has `astro.config.*` | astro.config, Astro, BcmsBlocks, getStaticPaths |
146
+ | Next.js adapter | [next.md](references/next.md) | the repo has `next.config.*` | next.config, Next.js, App Router, ISR, notFound, static export |
147
+ | Nuxt, SvelteKit, React Router, Vite: no adapter | [other-frameworks.md](references/other-frameworks.md) | neither `astro.config.*` nor `next.config.*`; `nuxt.config.*`, `svelte.config.*`, `react-router.config.*` | Nuxt, SvelteKit, React Router, Vite, createClient |
148
+ | Rich text and field types | [portable-text.md](references/portable-text.md) | writing a richtext value; converting HTML or Markdown | rich text, Portable Text, richtext, HTML, Markdown |
149
+ | Brand kit, tokens, fonts, logo, images, icons | [media-and-brand.md](references/media-and-brand.md) | design fidelity, alt text, a logo or favicon change | brand, tokens, fonts, logo, image, alt text, favicon |
150
+ | Connect a vendor with a public API (jobs board, store, CRM, video): declare, approve, call, recipes | [integrations.md](references/integrations.md) | the user names Greenhouse, JobDiva, Shopify, HubSpot, Zoom, Apollo or any API; a 409 `integration_not_approved` | integration, API key, Greenhouse, JobDiva, Shopify, HubSpot, Zoom, Apollo, sync, vendor, token |
151
+ | Forms, menus, accordions, modals, consent | [forms-and-interactions.md](references/forms-and-interactions.md) | attaching or verifying a form; an interactive section | form, submission, Turnstile, modal, accordion, menu |
152
+ | Languages, locale prefixes, translation, hreflang | [localization.md](references/localization.md) | the build serves `/fr`-style prefixes; `locale-unvarianted` in a binding report | language, locale, /fr, translate, hreflang, i18n |
153
+ | SEO and AEO | [seo.md](references/seo.md) | meta, JSON-LD, sitemap, robots, redirects, AI crawlers, `list_seo_issues` | SEO, meta, JSON-LD, schema.org, sitemap, robots, OG image, redirect, 410, llms.txt |
154
+ | Accessibility: alt text, form labels, contrast, the audit codes and the manual checks | [accessibility.md](references/accessibility.md) | writing alt text; building a form; before reporting a site done | accessibility, WCAG, alt text, decorative, label, contrast, captions |
155
+ | Page families from data | [programmatic-seo.md](references/programmatic-seo.md) | a keyword list or CSV should become pages | programmatic SEO, CSV, dataset, landing pages, glossary |
156
+ | Publish, deploy, roll back, reconcile a re-import; add a section to a page or set its spacing | [publishing.md](references/publishing.md) | a release; a code push that conflicts with CMS edits; "add a section here", "more padding on this section"; a write that answers `held` or a publish that reads `partial` | publish, deploy, rollback, sync, webhook, schedule, automation, add section, insertSection, sectionStyle, spacing, padding, margin, held, partial |
157
+ | Read-only launch review | [site-review.md](references/site-review.md) | "is this ready to launch?" without fixing | launch review, audit, is it ready, QA |
158
+ | A/B tests on section variants | [content-experiments.md](references/content-experiments.md) | an experiment plan or readout | A/B test, experiment, variant test |
159
+ | Headless Shopify storefront | [shopify-headless.md](references/shopify-headless.md) | Shopify owns commerce, BetterCMS the editorial | Shopify, Hydrogen, storefront, product |
160
+
161
+ Other sites move into BetterCMS with the `bettercms-migrate` skill; per-account campaign pages
162
+ are the `bettercms-abm` skill.
163
+
164
+ ## Context budget
165
+
166
+ A whole-site job outlives one context window. Spend it on the site, not on re-reading.
167
+
168
+ - Start from the receipt: `get_next_steps` returns `receipt.done`, `receipt.missing` and
169
+ `receipt.nextAction`. Plan the session from it, not from re-reading the site.
170
+ - Hold SKILL.md plus only the ONE reference the current phase needs; drop it when the phase ends.
171
+ - Ask the MCP for summaries before reading files: `get_site_composition`, `get_binding_report`
172
+ and `get_next_steps` answer "what is left" in a few hundred tokens, where built HTML or a whole
173
+ repo costs tens of thousands.
174
+ - Run bulk edits through the codemod (`npx @bettercms-ai/convert`), not file-by-file hand edits
175
+ in context; read its receipt, not the diff.
176
+ - Keep the gap ledger in `.bettercms/ledger.json` in the repo (shape in finish-site.md) and
177
+ re-read it after a reset instead of carrying it in chat.
178
+ - Where your agent supports subagents, fan out per-route verification and have each return only
179
+ its verdict and the failing evidence.
180
+ - Pass the `projectId` you already have; never re-list projects to find it again.
181
+ - After a reset, say "Continue BetterCMS setup": the resume check rebuilds state from the MCP and
182
+ the ledger.
183
+
184
+ ## Verify loop (after every change, before you say "done")
185
+
186
+ Stop at the first step that is not clean, fix, then restart. A report that does not exist yet is
187
+ "not yet generated", which is not the same as dirty; say which.
188
+
189
+ 1. **Fetch the live URL**, cache-busted: a 200 whose body contains copy you just published. The
190
+ steps below read the control plane, and all of them can be green on a site that answers 404.
191
+ 2. `get_binding_report` for every route you touched: `unaddressable` under 2%, and, where the
192
+ source declares its bindings, `coverage.pending` empty and `mode: "declared"`. `refreshReason: "never-generated"` means no BetterCMS
193
+ release wrote one (on headless none ever will, so step 1 is the proof); `"outdated"` means
194
+ the next release rewrites it.
195
+ 3. `get_site_composition`: every page you touched is made of sections, with the intended
196
+ components.
197
+ 4. `list_seo_issues`: no issue on a page you created or edited.
198
+ 5. `get_next_steps`: `receipt.complete` is `true`. While it is `false`, run
199
+ `receipt.gate.nextAction` and read again after each batch; nothing else ends an imported
200
+ site's setup, and an exception is recorded only for a reason that is true. The gate, its bars and the exceptions it accepts are in
201
+ [finish-site.md](references/finish-site.md). Suggestions still in `missing` after that, and
202
+ owner actions, go in your final message by name.
203
+
204
+ "Done" means the loop is clean and the gate reads complete, not that a tool call returned 200.
205
+ `bettercms init` reads the gate again when you exit and prints its numbers per page, so the
206
+ user sees them whatever your last message said.