ChaiBuilder Logo

chaipro v0.4.1

Released 2026-09-28. Upgrading from v0.4.0.

A patch release with no breaking API changes. The headline is an opt-in design system for MCP agents: a written set of design rules per site, checks on every block an agent writes, and theme edits that wait for your approval. Around it, custom blocks can group their settings, registered blocks can live in the Library tab, and links an AI writes to your own pages now survive a slug change.

Three behavior changes are worth a look before you deploy: a request middleware that throws now fails the request instead of being skipped, a database error on a public page is now an error instead of a cached 404, and a Button with a link renders as a single <a>. All three are under Changed and in the upgrade notes.

Added

  • A design system for agents. Pass designSystem to mcpPlugin and agents get seven more tools: they draft a written design system for the site with you, run deterministic design checks on every block they write, follow design playbooks (setup, critique, audit, polish, typography, color, layout, motion, copy, bolder, quieter), and propose theme and design token changes that are published only when you approve. designChecks sets what a failed check does on a write: 'warn', 'strict' or 'off'. Nothing changes until the deployment turns the option on and a site enables its own design system. No database migration is needed. See Design System for Agents.
  • Two narrow theme actions. UPDATE_THEME patches the draft theme's fonts, radius and colors, and needs theme:edit. UPDATE_DESIGN_TOKENS restyles existing design tokens only, refuses unknown token ids, and needs design_tokens:edit. Both mark the change as pending publish, like a theme save in the builder.
  • Settings groups for custom blocks. groupProps({ label, properties }) from chaipro/registry collects related props into a collapsible section of the settings panel, with an Expand all / Collapse all toggle at the top. Props stay top-level in the schema and in saved blocks, so grouping needs no content migration. Groups do not nest in this release. See Custom Blocks.
  • Registered blocks in the Library tab. A block config can set showInLibrary: true to move the block from the Add Block panel's Blocks tab into the Library tab, grouped by its group, with preview as the card image. Global search follows the same split, and the Library tab appears even when no UI library is registered.
  • A read-only theme panel. The builder takes themeReadOnly and themeReadOnlyReason. The theme panel's token controls stay visible with their real values but cannot be edited, and the reason shows on hover. The props are presentation only, so enforce the same rule on the server.
  • Panels that render on first open. A block whose attributes carry data-render="on-open" renders its children only once the panel first opens, so a closed header menu adds no HTML or hydration cost to the page.
  • Repeater rows know when they scroll sideways. Rows of a Repeater styled as a horizontal scroller (overflow-x-auto, overflow-x-scroll or snap-x) receive $repeaterScrollsX next to $repeaterIndex, so a custom block can, for example, lazy load every card after the first.

Changed

  • AI-written links to your own pages are stable references. The MCP server and the builder's AI used to write links to site pages as plain slugs, which broke when the target page's slug changed and never reached the page's link index. They now store the same pageType:<type>:<id> reference the link picker stores. External URLs, mailto:, tel:, anchors, bindings and links that match no page are kept as written. The MCP get_pages_list tool returns a link reference for every linkable page, and the builder's AI gets its own page list tool to look them up.
  • A throwing request middleware now fails the request. A middleware that threw used to be logged and skipped, and the next middleware answered in its place. It is now logged and rethrown, so the request fails with a 500 instead of falling through to a 404 that the route could cache.
  • Database errors on a public page are errors, not 404s. A failed query while looking up a page, resolving a page link, looking up a redirect or reading a page's other languages used to read as "not found" or "nothing there", and the result could be cached with no expiry: a live page became a cached 404, every link on a page became #, a redirected slug 404'd, or the language switcher lost its other languages until the next republish. Each lookup now throws its own error with the query error attached, and a thrown error is never cached, so the next request retries. A page that really does not exist still returns a 404.
  • A Button with a link renders as one <a>. It used to render a <button> inside an <a>, which is invalid HTML and splits keyboard and screen reader behavior across two elements. The <button> now renders only when the Button has no link.
  • Theme fonts preload more weights. The rendered page preloads up to four upright font weights across the heading and body fonts, picked from the most commonly used weights, instead of only the first file of each.
  • When a page has no Open Graph image of its own, the fallback reads the global data provider's seo.image before falling back to the site logo.
  • The builder's right panel opens wider (380px) than the left panel.
  • The Image block's quality option reads Default (65), the quality it actually renders at.
  • The npm package description and keywords now describe the built-in MCP server.

Security

  • check_page_design requires ai:read. The design check names any banned words it finds, which are part of the site's AI settings, so a caller with only pages:read could have probed them. It now needs ai:read, like get_design_system.

Fixed

  • A deleted page no longer holds on to its slug. Deleting a page and then creating or moving another page onto the same slug failed with "Slug is already in use". Pages in the trash are skipped by the slug check, and restoring or permanently deleting them still works.
  • Metadata-only edits show up in the publish dialog. An edit that changed only a page's metadata never appeared as a change to publish.
  • Page type tracking defaults reach the builder. A page type's default tracking settings were never sent to the client, so the Tracking panel's reset, new pages and the MCP get_page_tracking tool all saw nothing.
  • Sites whose default language is not English get the right language from server helpers outside the page render. The MCP get_pages_list tool labelled every primary page on a French default site as English, and resolved links to the wrong slug.
  • Accessible names on Button, Form Button and Link. An empty aria-label is never rendered, a Button takes its label from its text only when it has no child blocks, and a Link no longer copies its default text into aria-label. The icon is hidden from screen readers only when the button has a name.
  • The font selector no longer swaps an unregistered font. Opening the Theme panel silently replaced a stored font that was not registered with the first registered font, and saved the draft. The stored font now shows as a disabled item and nothing is written until someone picks a font.
  • A gradient direction with no color stops no longer hides a solid background. A style such as bg-gradient-to-r without from-* or to-* could evict the element's bg-* color and leave it invisible.
  • A Box with the style tag renders its CSS. Text inside it was printed as [object Object] on the server, and HTML import no longer wraps CSS text in <span> tags.
  • Select options that share a value stay distinct instead of dropping options.
  • Parallel design system saves from an agent no longer overwrite each other.
  • The design check runs on edits that only remove blocks, and get_design_system on a site with no design system yet returns the theme, fonts and tokens the setup starts from.
  • With drag and drop off, a Library card for a registered block is disabled where the target would reject it, and a failed UI library load shows its error and a Retry button.

Upgrade notes

  1. Upgrade the package.

    pnpm up chaipro@^0.4.1
    

    No database migration is needed.

  2. Check your request middleware. A middleware that throws now fails the request with a 500 instead of being skipped. Catch the errors you expect inside the middleware and return normally, and let only real failures throw.

  3. Watch for errors where you used to see 404s. A database outage on a public page now surfaces as a server error and is retried on the next request, instead of being cached as a 404. If your monitoring alerts on 5xx responses, expect these to show up there.

  4. Check CSS that targets a button inside a link. A linked Button is now a single <a>, so selectors such as a > button no longer match it.

  5. The design system is opt in. Nothing changes until you pass designSystem to mcpPlugin and a site enables its design system. Follow Design System for Agents when you are ready.

© ChaiBuilder. All rights reserved.