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
designSystemtomcpPluginand 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.designCheckssets 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_THEMEpatches the draft theme's fonts, radius and colors, and needstheme:edit.UPDATE_DESIGN_TOKENSrestyles existing design tokens only, refuses unknown token ids, and needsdesign_tokens:edit. Both mark the change as pending publish, like a theme save in the builder. - Settings groups for custom blocks.
groupProps({ label, properties })fromchaipro/registrycollects 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: trueto move the block from the Add Block panel's Blocks tab into the Library tab, grouped by itsgroup, withpreviewas 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
themeReadOnlyandthemeReadOnlyReason. 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-scrollorsnap-x) receive$repeaterScrollsXnext 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 MCPget_pages_listtool 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.imagebefore 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_designrequiresai:read. The design check names any banned words it finds, which are part of the site's AI settings, so a caller with onlypages:readcould have probed them. It now needsai:read, likeget_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_trackingtool 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_listtool 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-labelis 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 intoaria-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-rwithoutfrom-*orto-*could evict the element'sbg-*color and leave it invisible. - A Box with the
styletag 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_systemon 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
Upgrade the package.
pnpm up chaipro@^0.4.1No database migration is needed.
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.
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.
Check CSS that targets a button inside a link. A linked Button is now a single
<a>, so selectors such asa > buttonno longer match it.The design system is opt in. Nothing changes until you pass
designSystemtomcpPluginand a site enables its design system. Follow Design System for Agents when you are ready.
Related
- Design System for Agents - enable the design tools, checks and playbooks.
- MCP Server Setup - the
designSystemoption and the full tool list. - Custom Blocks - block config and the props schema.
- chaipro v0.4.0 - the previous release.
- chaipro Changelog - all releases.

