@bettercms-ai/mcp 0.63.2 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +1 -0
  2. package/SKILL.md +1 -1
  3. package/dist/index.js +908 -487
  4. package/dist/index.js.map +1 -1
  5. package/dist/skills/bettercms/SKILL.md +175 -0
  6. package/dist/skills/bettercms/references/astro.md +67 -0
  7. package/dist/skills/bettercms/references/bindings.md +201 -0
  8. package/dist/skills/bettercms/references/componentize.md +106 -0
  9. package/dist/skills/bettercms/references/components.md +228 -0
  10. package/dist/skills/bettercms/references/content-experiments.md +62 -0
  11. package/dist/skills/bettercms/references/content-modeling.md +185 -0
  12. package/dist/skills/bettercms/references/editor-chrome.md +88 -0
  13. package/dist/skills/bettercms/references/external-content.md +78 -0
  14. package/dist/skills/bettercms/references/finish-site.md +123 -0
  15. package/dist/skills/bettercms/references/forms-and-interactions.md +203 -0
  16. package/dist/skills/bettercms/references/frameworks.md +149 -0
  17. package/dist/skills/bettercms/references/getting-started.md +106 -0
  18. package/dist/skills/bettercms/references/localization.md +81 -0
  19. package/dist/skills/bettercms/references/media-and-brand.md +142 -0
  20. package/dist/skills/bettercms/references/next.md +93 -0
  21. package/dist/skills/bettercms/references/other-frameworks.md +66 -0
  22. package/dist/skills/bettercms/references/portable-text.md +206 -0
  23. package/dist/skills/bettercms/references/programmatic-seo.md +98 -0
  24. package/dist/skills/bettercms/references/publishing.md +146 -0
  25. package/dist/skills/bettercms/references/seo.md +156 -0
  26. package/dist/skills/bettercms/references/shopify-headless.md +52 -0
  27. package/dist/skills/bettercms/references/site-blueprints.md +250 -0
  28. package/dist/skills/bettercms/references/site-review.md +73 -0
  29. package/dist/skills/bettercms/references/write-limits.md +84 -0
  30. package/package.json +2 -2
@@ -0,0 +1,250 @@
1
+ ---
2
+ title: "Site blueprints"
3
+ description: "Route, collection and section plans per business type: portfolio, agency, corporate, SaaS/AI and ecommerce."
4
+ ---
5
+
6
+ # Site blueprints by business type
7
+
8
+ A route and content model that fits the business, while editor folders, public URLs and reusable
9
+ components stay separate. A blueprint is a starting hypothesis, not permission to replace a
10
+ working site's taxonomy. The platform rules behind each layer are in
11
+ [content-modeling.md](content-modeling.md).
12
+
13
+ ## Contents
14
+
15
+ - [Common decision process](#common-decision-process)
16
+ - [Starter rules](#starter-rules)
17
+ - [Deliverables](#deliverables)
18
+ - Catalogs, read only the one that matches (a mixed site can use two, but give each page family
19
+ one route owner):
20
+ - [Portfolio](#portfolio-website): a person or studio presents selected work, services and a
21
+ contact path
22
+ - [Agency](#agency-website): services, sectors, proof and lead generation drive the site
23
+ - [Corporate](#corporate-website): several business units, regions, audiences, governance or
24
+ regulated content coexist
25
+ - [SaaS, AI, enterprise tech](#saas-ai-and-enterprise-technology-website): product,
26
+ solutions, industries, integrations, trust and education need separate models
27
+ - [Large ecommerce](#large-ecommerce-website): catalog, categories, products and shopping
28
+ journeys dominate; a Shopify-backed store also reads [shopify-headless.md](shopify-headless.md)
29
+
30
+ Data-generated page families (glossary, integrations, locations): [programmatic-seo.md](programmatic-seo.md).
31
+
32
+ ## Common decision process
33
+
34
+ 1. Inventory existing public URLs, navigation, templates, source content, business goals,
35
+ locales, owners, analytics and design tokens. Keep established URLs and brand rules unless a
36
+ change is in scope.
37
+ 2. Give each family a **source of truth**: a BetterCMS page, a collection entry, an external
38
+ system (commerce, ATS, docs), or application runtime. Name its editorial owner and publishing
39
+ gate. Record capabilities BetterCMS does not have as gaps; never invent fields that imply
40
+ them.
41
+ 3. Produce a route matrix: pattern, purpose, static / list / detail, content source, template,
42
+ canonical, indexability, sitemap eligibility, and the redirect it replaces. A collection's
43
+ list is a page; its entries render through one dynamic detail page.
44
+ 4. Produce a model matrix: fields and groups, references, taxonomy, reusable sections, global
45
+ nav/footer, labels, and variants. Components for reusable presentation, collections for
46
+ entities with their own lifecycle. Whether bands become components or fields follows
47
+ `authoringPreference` from `get_project`, which only the owner answers.
48
+ 5. Propose **Content sidebar** folders for editor tasks, **component groups** for definitions,
49
+ and **media folders** for assets. None of these changes a URL. **URL page folders** do change
50
+ paths, and renaming one 301s its pages, so they need explicit review. Sidebar doctrine:
51
+ `bettercms://playbook/structure`.
52
+ 6. Define per-family SEO policy: one canonical target, real indexable content, native SEO
53
+ metadata (never modelled fields, §5b of `bettercms://playbook/schema`), structured data only
54
+ where visible facts support it, and the treatment of filters, search, pagination, drafts,
55
+ gated pages and deleted records. Pages marked noindex are left out of the generated sitemap.
56
+ 7. Validate one representative route per family and the edge cases: empty collection, long
57
+ title, unpublished detail, duplicate slug, moved URL, mobile nav, optional section, locale,
58
+ no-result state. Confirm edit, preview and public render, then the build and binding reports.
59
+
60
+ ## Starter rules
61
+
62
+ - Reference page lists illustrate common shapes; do not create pages the business does not have.
63
+ - Prefer a few stable, human-readable route patterns. The best URL is often the existing one.
64
+ - Keep a slug unique within its route namespace; check static against dynamic paths and locales.
65
+ When a published URL changes, add a redirect (`create_redirect`).
66
+ - Keep a dedicated 404 and access/error pages. Leave drafts, private areas, internal search,
67
+ parameter duplicates and 404s out of the sitemap.
68
+ - Sitemaps hold absolute, canonical, indexable URLs; Google documents a limit of 50,000 URLs /
69
+ 50 MB uncompressed per file. [Google sitemap guide](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap)
70
+ - Content sidebar folders are navigation for editors. Public hierarchy comes from routes and
71
+ internal links, never from folder labels. [Google ecommerce site structure](https://developers.google.com/search/docs/specialty/ecommerce/help-google-understand-your-ecommerce-site-structure)
72
+ - With locale variants, keep explicit equivalent-page mappings and one `hreflang`
73
+ implementation, verified in the rendered head. [Google localized versions](https://developers.google.com/search/docs/specialty/international/localized-versions)
74
+
75
+ ## Deliverables
76
+
77
+ Return a route tree, route matrix, content and model matrix, folder plan, component inventory,
78
+ sitemap and redirect policy, open ownership decisions, and a phased implementation plan. On a
79
+ live project, implement only the scope the user asked for and verify the routes you touched.
80
+
81
+ ## Portfolio website
82
+
83
+ Use this when the primary job is to show selected work and make an individual or small studio credible. First determine whether the work is private, client-approved, dated, or still under embargo.
84
+
85
+ ### Route and model starter
86
+
87
+ | Family | Example path | BetterCMS model | Index and sitemap |
88
+ |---|---|---|---|
89
+ | Home | `/` | Static page with selected projects and clear contact action | Yes |
90
+ | Work index | `/work/` | Static index page querying Projects | Yes if substantive |
91
+ | Project detail | `/work/{slug}/` | Projects collection + one dynamic template | Published, approved projects only |
92
+ | About / services | `/about/`, `/services/` | Static pages unless services need independent owners and detail pages | If public and useful |
93
+ | Writing / speaking | `/writing/`, `/writing/{slug}/` | Optional collection and index | Published articles only |
94
+ | Contact | `/contact/` | Static page + form | Usually yes |
95
+ | Password/preview case study | Existing route | Other page or protected runtime route | No |
96
+
97
+ Keep the existing work prefix if it is `/projects/`, `/case-studies/`, or another established route; route changes need a redirect map.
98
+
99
+ ### Editor structure
100
+
101
+ Content sidebar: `Start here` (Home, About, Contact), `Portfolio` (Work index, Projects), `Writing` if used, `Site essentials` (legal/other). Component groups: `Globals`, `Portfolio` (project hero, gallery, outcomes), `Shared sections` (CTA, quote, logo strip). Media folders may separate approved client work, self-initiated work, portraits, and downloadable files. These folders do not determine URLs.
102
+
103
+ Project entry fields: display title, slug, client display name, service/category references, summary, role, dates when relevant, hero image plus alt text, ordered gallery items with captions/alt, challenge, approach, verified outcomes, credits, related projects, SEO, approval/visibility state. Do not require a public client name, metric, or testimonial when consent is absent. Support anonymous case studies without accidentally exposing the original client in image filenames, alt text, schema, or social previews.
104
+
105
+ Use repeatable gallery items rather than a long list of `image1` fields. Give each item a meaningful editor label and image metadata. Keep project-specific storytelling sections as instances; make hero/gallery/quote layouts reusable definitions with instance overrides.
106
+
107
+ ### Validation
108
+
109
+ Check case-study consent, working gallery at different aspect ratios, captions, full-size media performance, downloadable file links, contact submission, related-work references, archived projects, and redirect behavior for renamed slugs. A portfolio with only a few projects does not need auto-generated service × industry pages.
110
+
111
+ ## Agency website
112
+
113
+ Use when the site must explain services, prove results, and convert qualified leads. The key distinction from a portfolio is a durable offer taxonomy and repeatable proof linked to each offer.
114
+
115
+ ### Route and model starter
116
+
117
+ | Family | Example path | Model and purpose |
118
+ |---|---|---|
119
+ | Home | `/` | Static overview, positioning, primary CTA |
120
+ | Services index/detail | `/services/`, `/services/{slug}/` | Static index + Services collection only if multiple services have owners, proof, and maintained detail content; otherwise static pages |
121
+ | Industries | `/industries/`, `/industries/{slug}/` | Optional collection; publish only distinct industry expertise |
122
+ | Work index/detail | `/work/`, `/work/{slug}/` | Case studies collection and dynamic detail template |
123
+ | Insights | `/insights/`, `/insights/{slug}/` | Editorial collection, authors, categories |
124
+ | Agency | `/about/`, `/team/`, `/careers/` | Static or collection by update cadence |
125
+ | Contact | `/contact/` | Form with routing/consent behavior |
126
+
127
+ Use the established `/case-studies/`, `/blog/`, etc. when the current site already has them. A service × industry matrix should be created only for combinations with distinct evidence, offer, and maintenance owner; otherwise link the existing service and industry pages instead of generating thin duplicates.
128
+
129
+ ### Content relationships and components
130
+
131
+ Cases reference services, industries, client permission state, outcome evidence, and optional quotes. Service pages reference relevant cases, deliverables, process, FAQ, and CTA. Industry pages reference services/cases and sector-specific language. Avoid duplicating client logos or metrics across pages: maintain permission and source context on the case/client record.
132
+
133
+ Component groups: `Globals` (nav/footer), `Proof` (case card, metrics, testimonial), `Offers` (service card, process), `Conversion` (CTA, contact form), `Editorial`. Reuse definitions with page-specific props, and allow section order to vary by page. Editors should see grouped fields such as `Primary button → Label, Link`, `Proof item → Metric, Context, Source`.
134
+
135
+ Content sidebar folders should match editor work: `Core pages`, `Services`, `Industries`, `Case studies`, `Insights`, `Company`. These are dashboard folders, not paths.
136
+
137
+ ### Validation
138
+
139
+ Review lead form destination, attribution and consent, internal links from every offer to relevant proof, case-study rights, schema claims, duplicate service routes, old URL redirects, and mobile CTA visibility. Keep draft or client-confidential work out of sitemaps and public data feeds.
140
+
141
+ ## Corporate website
142
+
143
+ Use for multiple audiences, brands, regions, business units, approval chains, or regulated statements. The main modeling problem is ownership: who can update a statement, which sites reuse it, and when it expires.
144
+
145
+ ### Route and model starter
146
+
147
+ | Family | Example path | Owner and model |
148
+ |---|---|---|
149
+ | Corporate home | `/` | Global communications; static page |
150
+ | Business units | `/businesses/{slug}/` | Collection if units share a template and lifecycle |
151
+ | Products/services | Existing taxonomy | Collection or static pages by unit ownership |
152
+ | Newsroom | `/news/`, `/news/{slug}/` | News collection, media contact, publish date |
153
+ | Leadership | `/leadership/`, `/leadership/{slug}/` | People collection if profiles recur |
154
+ | Careers | `/careers/` | Landing page; job details may remain in an ATS |
155
+ | Investor / governance | `/investors/`, `/governance/` | Gated approval; files with version/date |
156
+ | Policies and legal | `/privacy/`, `/terms/` | Static pages with accountable owner |
157
+ | Contact / locations | `/contact/`, `/locations/{slug}/` | Form plus locations collection when needed |
158
+
159
+ Do not copy ATS jobs, stock prices, investor filings, or regulated data into BetterCMS unless BetterCMS is deliberately the system of record. Preserve external systems and public links.
160
+
161
+ ### Governance and editor structure
162
+
163
+ Record owner, reviewer, source of claim, effective date, review date, and version where these matter. Separate draft, legal-reviewed, approved, and published states with the project's own editorial board: read its stages and which one is the publish gate with `get_workflow_board` before `move_stage`, because stage keys are per project. Do not claim an approval stage exists if the board has none. Scope access and publishing by the product's real permissions. High-risk copy (financial figures, certifications, compliance claims, regulated products) needs a verified source and designated reviewer.
164
+
165
+ Content sidebar: `Corporate pages`, `Business units`, `Newsroom`, `People`, `Investors`, `Legal`, `Regions` if used. Component groups: `Globals`, `Corporate identity`, `Business unit`, `Newsroom`, `Data/proof`. Distinguish sitewide global identity from unit-specific branding and local navigation. A shared global component should not overwrite an independently branded unit page.
166
+
167
+ ### Regions and languages
168
+
169
+ Choose a deliberate URL strategy, such as `/{locale}/...` or regional domains. Keep locale-to-locale equivalent-page IDs, fallback behavior, canonical target, and language switcher destinations. Check what the connected project models for locales before planning; implement and verify `hreflang` output in the frontend, where the rendered head is decided. Do not auto-redirect by IP or index machine placeholders. Follow [Google's localized-page guidance](https://developers.google.com/search/docs/specialty/international/localized-versions).
170
+
171
+ ### Validation
172
+
173
+ Test unit-specific nav/footers, ownership permissions, embargoed news, expiring files, superseded legal pages, regional links, localization fallbacks, 404/redirects, accessibility, and the published head for every major template. Separate search visibility from access control: `noindex` does not protect private information.
174
+
175
+ ## SaaS, AI, and enterprise technology website
176
+
177
+ Use when a product site must explain a platform to multiple buyers and evaluators. Distinguish product truth, marketing interpretation, developer documentation, and live application behavior.
178
+
179
+ ### Route and model starter
180
+
181
+ | Family | Example path | Suggested ownership |
182
+ |---|---|---|
183
+ | Home | `/` | Static marketing composition |
184
+ | Product/platform | `/product/`, `/features/{slug}/` | Static overview; Features collection only if repeated and maintained |
185
+ | Solutions | `/solutions/{slug}/` | Collection for distinct jobs-to-be-done/use cases |
186
+ | Industries | `/industries/{slug}/` | Collection where sector-specific workflows/proof exist |
187
+ | Integrations | `/integrations/{slug}/` | Collection with provider status, auth, capability, owner |
188
+ | Customers | `/customers/{slug}/` | Case studies with approvals and proof sources |
189
+ | Pricing | `/pricing/` | Static page or runtime-driven product data; one owner for actual pricing |
190
+ | Resources | `/resources/{slug}/`, `/blog/{slug}/` | Editorial collections and their list pages |
191
+ | Glossary | `/glossary/{term}/` | Definition collection with editorial gates |
192
+ | Comparisons / alternatives | `/compare/{slug}/` | Dedicated reviewed model, never blind competitor templating |
193
+ | Trust and legal | `/security/`, `/privacy/`, `/trust/` | Static pages or external trust center |
194
+ | Docs / API | `/docs/...` | Often a separate docs system/repository; link rather than duplicate |
195
+ | Conversion | `/demo/`, `/contact/` | Forms with routing, consent, and success states |
196
+
197
+ These are options, not required pages. Keep existing routes and product naming. For a large enterprise site, consider ownership by product line/market and a shared navigation contract; avoid separate page schemas for identical layouts.
198
+
199
+ ### Model and section kit
200
+
201
+ Entities: Solutions, Industries, Features, Integrations, Cases, Resources, Glossary Terms, and optional Comparisons. Use references across them so an integration or proof item updates once. Each entry needs an owner, lifecycle, canonical URL, native SEO metadata, and sufficient unique content. Integration entries need a clear status (live, beta, planned) and must never imply a planned connector is available.
202
+
203
+ Shared sections: product hero, outcome grid, workflow steps, feature visual, integration grid, proof strip, case excerpt, FAQ, security/trust callout, pricing CTA. Keep a single component definition per visual family and use variants/instance overrides. Give buttons and media grouped editor controls. Expose only supported rich-text headings; a hero title may be plain text rendered as H1 while an article body may allow H2/H3, links, lists, and code if the renderer supports them.
204
+
205
+ Content sidebar: `Core pages`, `Product`, `Solutions`, `Industries`, `Integrations`, `Customers`, `Resources`, `Trust`, `Other`. Component groups should reflect role, not route.
206
+
207
+ ### Search and AEO
208
+
209
+ Build topic hubs and link related solution, industry, integration, case, and glossary pages. Only publish a specific solution × industry page when it adds differentiated workflow, evidence, and value. Answer questions directly with verifiable facts and useful context; do not fabricate FAQ, schema, or “AI answer” pages. Use [programmatic-seo.md](programmatic-seo.md) for generated page families and [Google's AI-search guidance](https://developers.google.com/search/docs/fundamentals/ai-optimization-guide) for the current search-policy boundary.
210
+
211
+ ### Validation
212
+
213
+ Verify product claims against shipped capability, integration statuses, pricing consistency, demo form routing, docs links, internal topic paths, glossary duplicates, comparison accuracy, rendering of code/rich text, and desktop/mobile navigation. Noindex preview, gated assets, and incomplete pages.
214
+
215
+ ## Large ecommerce website
216
+
217
+ Use for a catalog-heavy site regardless of commerce engine. The core choice is the boundary between **commerce facts** and **editorial merchandising**.
218
+
219
+ ### Source-of-truth contract
220
+
221
+ Products, variants, SKUs, price, availability, tax, orders, checkout, customer accounts, and fulfillment normally belong to the commerce platform. BetterCMS owns editorial landing pages, category storytelling, buying guides, banners, proof, and selected product-page content blocks. A CMS reference to a product uses a stable external ID plus a verified lookup; don't silently duplicate transactional fields into editable CMS text.
222
+
223
+ ### Route and model starter
224
+
225
+ | Family | Example path | Index policy |
226
+ |---|---|---|
227
+ | Home and campaigns | `/`, `/campaigns/{slug}/` | Public, unique campaigns |
228
+ | Catalog root / category | `/shop/`, `/collections/{slug}/` | Curated category pages with products and links |
229
+ | Product | `/products/{slug}/` | Available public products; decide retired-product policy |
230
+ | Brand | `/brands/{slug}/` | Only substantive brand pages |
231
+ | Buying guides | `/guides/{slug}/` | Unique advice with product references |
232
+ | Editorial | `/stories/{slug}/` | Published articles |
233
+ | Search, cart, account, checkout | Runtime routes | Usually excluded from sitemap; private data protected |
234
+ | Filters and sort | Parameters on category routes | Explicit crawl/index policy; avoid unbounded URL combinations |
235
+
236
+ Keep existing paths if the store already uses another taxonomy. Decide whether unavailable products stay indexable, redirect to a successor, or return 404/410 based on permanence and user value. Do not redirect every missing product to the homepage.
237
+
238
+ ### Editor model and reuse
239
+
240
+ Models: Campaigns, Buying Guides, optional Brand and Category editorial records, plus product references. Category merchandising groups can include hero, intro, featured products, editorial cards, filters, and FAQs. Components: global store nav, search, promo bar, product card, variant selector, add-to-cart, category hero, recommendation rail, cart feedback. Commerce controls remain functional code tied to live data; an editor can change allowed presentation and copy but must not create an unfulfillable cart action.
241
+
242
+ Content sidebar: `Campaigns`, `Collections`, `Guides`, `Stories`, `Store pages`; group media by campaigns/editorial needs. Content sidebar folders never change a URL; URL page folders do, and renaming one 301s its pages, so do not turn category folders into URL folders unless a route change is intended.
243
+
244
+ ### Crawl and scale
245
+
246
+ Provide crawlable category → subcategory → product links and paginated result URLs. Decide which facet combinations deserve dedicated curated landing pages; keep the rest out of the index/crawl space by an intentional policy. Do not rely on canonical alone to control a near-infinite faceted URL space. Keep canonical, internal link, and sitemap URLs consistent. Sitemaps should include only eligible canonical pages and split before protocol limits. Product price/availability markup must match the current displayed commerce data; validate variant markup against Google's current `ProductGroup` guidance. [Google ecommerce structure](https://developers.google.com/search/docs/specialty/ecommerce/help-google-understand-your-ecommerce-site-structure) · [Faceted navigation](https://developers.google.com/crawling/docs/faceted-navigation) · [Product variants](https://developers.google.com/search/docs/appearance/structured-data/product-variants)
247
+
248
+ ### Validation
249
+
250
+ Test a product with several variants, a sold-out product, missing image, empty category, deep pagination, filter combinations, mobile search, currency/market change, cart handoff, and changed price after cache expiry. Verify that sitemap counts match eligible catalog records and that deleted routes/redirects do not strand internal links.
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: "Site review"
3
+ description: "A read-only launch review: what to check per route and how to report findings without fixing them."
4
+ ---
5
+
6
+ # Read-only site review
7
+
8
+ **Outcome.** An evidence-backed issue list, scoped to the actual project and revision, that a
9
+ developer can reproduce and prioritise. Change no data or code during a review unless the user
10
+ separately asks for repairs.
11
+
12
+ ## Establish a baseline
13
+
14
+ Identify the project, source commit, import or release revision, hosting mode (`get_project`),
15
+ public or staging URL, and expected route inventory. Then read the control plane and record when
16
+ each report was generated:
17
+
18
+ | Read | Tells you |
19
+ |---|---|
20
+ | `get_site_composition` | Which pages are made of sections, and which components they use |
21
+ | `get_binding_report` | Per route: `mode` (`declared` or `text-match`), `coverage.pending`, and `refreshReason` when there is no current report |
22
+ | `list_seo_issues` | Native SEO problems per page |
23
+ | `get_component_readiness` | Per component: validation and Output state |
24
+ | `list_forms` | Which forms exist and whether each is published |
25
+ | `get_deploy_status` | The last build and release |
26
+ | `get_next_steps` | What the platform itself still counts as unfinished |
27
+
28
+ A binding report is created only by a BetterCMS release (a content apply later updates its Layout
29
+ rows), so a headless site may never have one; `never-generated` is missing evidence, not a clean
30
+ result. A green control plane cannot prove a route answers:
31
+ fetch rendered pages too, cache-busted.
32
+
33
+ Sample every **route class** (static, list, collection detail, 404 or protected, locale) and
34
+ every **component family**. Include two instances of a reused component, one variant, one nested
35
+ slot, the global nav and footer, long and empty content, and a custom Portable Text block when
36
+ present. Widen the sample when a failure looks systematic.
37
+
38
+ ## Review dimensions
39
+
40
+ | Dimension | Evidence to collect |
41
+ |---|---|
42
+ | Structure | Page / collection / entry classification, which of the four folder systems is used for what, route and redirect integrity |
43
+ | Reuse | Definition, default, variant and instance ownership; override isolation; global chrome; slot limits |
44
+ | Editability | Schema, stored value, reader, prop, bound leaf or attribute, preview, published output; intended fields against verified bindings |
45
+ | Editor UX | Field types, allowed Portable Text controls, labels, grouping, defaults, required states, repeatable-item previews |
46
+ | Design and media | Brand tokens, font loading, logo roles, asset delivery from the project's media origin, alt / caption / crop, desktop and mobile fidelity |
47
+ | Behaviour | Forms and their destinations, keyboard and focus, navigation, accordion / modal / consent logic, custom code |
48
+ | Discoverability | Native SEO, canonical and noindex, structured data matching visible content, sitemap and robots, internal links |
49
+ | Delivery | Build, cache and revalidation, live status and content, draft isolation, secrets and the server/client boundary |
50
+
51
+ Use automated checks where they answer a concrete question, and manual visual or editor checks
52
+ where automation cannot show intent. Never edit production as a test. If an edit-to-render test
53
+ needs a write, mark it unverified in a read-only review, or get the user's authorisation for a
54
+ safe draft test.
55
+
56
+ Useful anchors while reviewing: a draft form refuses public submissions (403), so a form that
57
+ renders but is not published cannot take a lead; a headless project is never built by BetterCMS,
58
+ so its proof is the external host's public response; a Content sidebar folder never changes a
59
+ URL, while renaming a URL page folder 301s its pages.
60
+
61
+ ## Issue format and decision
62
+
63
+ For each issue record severity (blocker, high, medium, low), the route / component / field,
64
+ expected against observed, exact reproduction, evidence (link, screenshot, report time), likely
65
+ owner, and a specific acceptance check. Separate a verified defect from an inference or missing
66
+ evidence. Summarise coverage as verified intended editable fields divided by discovered intended
67
+ editable fields, with exclusions listed separately.
68
+
69
+ Recommend **ready**, **ready with named exceptions**, or **not ready**. A blocker includes a
70
+ broken public route, lost content or reference, an unbound core editorial value, a form sending
71
+ to the wrong destination, an exposed secret, or a live state that contradicts what the user
72
+ intended. For each, give the smallest repair path and whether it belongs to code, CMS data, a
73
+ platform capability, or a user decision.
@@ -0,0 +1,84 @@
1
+ ---
2
+ title: "Write limits"
3
+ description: "What the server checks on a content write (lengths, patterns, uniqueness, references, body size) and what it does not."
4
+ ---
5
+
6
+ # Write limits: what the server checks on a content write
7
+
8
+ Use this before you rely on a limit. "Exists" means the server refuses a bad value. "Does not
9
+ exist" means the value is stored, so you are the check.
10
+
11
+ ## The write path
12
+
13
+ Entry writes from the MCP and the Management API run `createEntry` / `updateEntry` in
14
+ `src/lib/content/entry-write.ts`:
15
+
16
+ 1. Request schema (Zod). Failure: 400 with `{ errors }`, keyed by field, no `code`.
17
+ 2. Value normalisation (shapes below). Failure: a validation result with `errors`.
18
+ 3. Per-field value checks against the model. Failure: a validation result with `errors`.
19
+ 4. Uniqueness, inside the insert transaction. Failure: `kind: "unique_conflict"` with `conflicts`.
20
+
21
+ The batch route reports the same two outcomes as `code: "UNIQUE_CONFLICT"` or `"VALIDATION"`.
22
+
23
+ Rule: read `errors` by field key, fix exactly those fields, write again once.
24
+
25
+ `update_content_entry` `data` REPLACES the entry's whole value object: an optional field left out
26
+ is deleted. Send `merge: true` to lay `data` over the stored value by top-level key (a group or
27
+ repeater you send still replaces that whole key). Pass `ifMatch` (the `optimisticVersion` from
28
+ `get_content_entry`) so a 409 tells you someone wrote since your read; with `merge` it defaults to
29
+ the version the merge read.
30
+
31
+ ## Limits that exist
32
+
33
+ | Limit | Behaviour |
34
+ |---|---|
35
+ | `maxLength` / `minLength` in text field config | Counted in characters. An empty value is left to `required` |
36
+ | `pattern` in text field config | Tested against every non-empty value |
37
+ | Numeric limit config (`maxLength`, `minLength`, `min`, `max`, `step`) on model save | A numeric string (`"60"`) is stored as a number; an impossible value (`"abc"`, a negative length, `step: 0`, `min` above `max`, a pattern that does not compile) is refused with `FIELD_CONFIG_INVALID`, naming the field and the fix |
38
+ | Repeater `maxItems` | Enforced when a number |
39
+ | `select` value | Must be one of the field's options |
40
+ | Rich text top-level `_type` | A name nothing renders is refused, naming `_type` and `_key`. Top level only — a foreign mark keeps its text unmarked, a foreign inline child renders nothing |
41
+ | Request body | 260 MB for the whole server |
42
+
43
+ ## Limits that do not exist (you hold them)
44
+
45
+ | Missing check | Rule for the agent |
46
+ |---|---|
47
+ | Limit config saved as a string before the model-save check existed | Write every numeric config value as a JSON number; re-save a model you find with string limits |
48
+ | Modular (block) field `blockSlugs`, `minItems`, `maxItems` | Check the block list against the field config yourself before writing |
49
+ | Reference existence on draft save and publish (shape only) | Read each referenced entry id before you write the reference |
50
+ | Component `overrides` (any keys, any types; required props not enforced) | Write only declared prop keys with the declared type; fill every prop the component needs |
51
+ | Size or depth of text, richtext and JSON values | Keep values to what the page renders; never paste whole documents into one field |
52
+ | Publish re-validation (publish copies the draft to live) | Only publish a draft you wrote through the write path above |
53
+ | Version restore re-validation (restore writes the stored snapshot) | After a restore, read the entry and write it back through `update_content_entry` so checks run |
54
+
55
+ ## Normaliser output shapes
56
+
57
+ What you read back after a write:
58
+
59
+ | Field | Stored shape |
60
+ |---|---|
61
+ | richtext | `{ format, value, html }` envelope |
62
+ | image | `{ id, url, name, altText }`. An asset id or media URL resolves to its asset; a site-relative path resolves to the asset the build adopted; an external URL on a project-scoped write is fetched and stored as a new asset. Only when none of that works (fetch refused or failed, no project scope) is it kept as `{ url }` (plus `altText` if given) |
63
+ | group / repeater (zoned) | Zone envelopes `{ nonRepeatable, repeatable }`, walked field by field |
64
+ | repeater given a bare array | Wrapped as `{ repeatable: [...] }` |
65
+
66
+ Rich text written as HTML or markdown may be stored in the older Lexical format depending on a
67
+ server flag. Portable Text arrays are always stored as Portable Text
68
+ ([portable-text.md](portable-text.md)).
69
+
70
+ A stored value of `{ html }` is the shape starter templates and `bcms-content.json` seed. Writes
71
+ accept it and store the full envelope, so sending an entry's data back unchanged works. Do not
72
+ write new rich text in that shape.
73
+
74
+ ## Other refusal codes that exist today
75
+
76
+ | Area | Codes | Where described |
77
+ |---|---|---|
78
+ | Content sidebar structure | `NAV_SYSTEM_FOLDER`, `NAV_TYPE_MISMATCH`, `NAV_KIND_MISMATCH`, `NAV_PAGE_BOUND_MODEL`, `SCHEMA_ACCESS_REQUIRED` | the folder tool descriptions |
79
+ | Hosting | `HEADLESS_NO_BUILD`, `HEADLESS_NEEDS_CUSTOM_HOST`, `HEADLESS_ARTIFACT_TARGET` | [frameworks.md](frameworks.md) |
80
+ | Components | `COMPONENT_*` publish codes | [components.md](components.md) §4 |
81
+ | Content models | `FIELD_CONFIG_INVALID` | this file |
82
+ | Forms | `FORM_FIELD_INVALID`, `FORM_DEFINITION_INVALID`, `FORMS_WORKER_NOT_CONFIGURED`, `FORMS_WORKER_SECRET_UNSET`, `FORM_SUBMISSION_NOT_FOUND`, `FORM_SECRET_DASHBOARD_ONLY` | [forms-and-interactions.md](forms-and-interactions.md) |
83
+
84
+ `SCHEMA_ACCESS_REQUIRED` (403): see the owner boundary in SKILL.md.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/mcp",
3
- "version": "0.63.2",
3
+ "version": "0.64.0",
4
4
  "type": "module",
5
5
  "description": "BetterCMS MCP server — schema, content, forms + components authoring tools over the Management API, authed via OAuth device-code.",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@bettercms-ai/device-auth": "^0.2.0",
35
- "@bettercms-ai/sdk": "^1.24.0",
35
+ "@bettercms-ai/sdk": "^1.25.0",
36
36
  "@modelcontextprotocol/sdk": "^1.30.0",
37
37
  "zod": "^4.3.6"
38
38
  },