Changelog
July 13, 2026
Patch Changes
- e2f902c: Render the Ask AI trigger from the shared header instead of wiring it up per page. Custom pages built on
PageLayout(a landing page, most of all) never passed the header’saskslot, so the Ask AI button — and the search modal’s hand-off to it — silently went missing on them while the generated docs, changelog, and reference pages had it. The header now owns the trigger and reads whether Ask AI is on from the config, so every page gets it; passaskEnabled={false}to opt a page out. - 66b721b: Move the MCP server config under
aiinblume.config.ts, alongside the other agent-facing features. Renamemcp: { … }toai: { mcp: { … } }— the shape of the block is unchanged. - c8ae77e: Fix
ERR_MODULE_NOT_FOUNDin a deployed server function. Surfacing an adapter’s deploy bundle out of.blumeresolved every traced dependency’s symlink against the source dir, so the links pointed into a directory the same step then deleted — the function died on its first external import (Cannot find package '@orama/orama'with Ask AI or the MCP server enabled). The bundle is now copied verbatim, leaving those links relative and internal to it.
July 13, 2026
Patch Changes
-
d62dbd0: Harden the pre-paint inline scripts and the route-normalizing regexes against the issues CodeQL flagged.
The theme and banner scripts in
<head>used to be built by interpolating config values into JavaScript source withJSON.stringify. JSON escaping isn’t a code-context escape —</script>and U+2028/U+2029 pass straight through it — so a craftedbanner.idor theme value could break out of the script. Both scripts are now constants and take their values fromdata-*attributes on their own<script>tag, which Astro HTML-escapes.ReferenceLayouthad drifted to its own inline copies of both scripts; it now shares the same module asRootLayoutandPageLayout.Route and slug normalization used
/^\/+|\/+$/-style patterns to trim leading and trailing separators. Those take quadratic time on a long run of the trimmed character, and they run on values that come from outside Blume (configured routes, OpenAPI spec URLs, the site origin), so a pathological config could hang the build. They’re replaced by linear trimming helpers incore/trim.ts; behavior is unchanged.
July 13, 2026
Patch Changes
- 6afb56a: Declare the
blumebin asbin/blume.mjsinstead of./bin/blume.mjs. The leading./is redundant and some package managers normalize it away when linking the binary; dropping it keeps the published manifest consistent with what installers actually write.
July 13, 2026
Major Changes
- 7372fe8: Blume v1.
Patch Changes
-
e922ff5: Stop “Clear conversation” from resurrecting an orphaned answer bubble while a reply is still streaming. Clearing mid-answer emptied the panel, but the in-flight stream kept re-appending its assistant message to the cleared conversation — a growing answer with no question above it. Clearing now aborts the in-flight request and revokes the stream’s right to write into the conversation, and asking a new question right after a clear works as before.
-
e922ff5: Match locale folders and dot suffixes case-insensitively, the way BCP 47 codes are defined. A configured
pt-BRwith the conventional lowercasept-br/folder (or anintro.pt-br.mdxsuffix under thedotparser) previously fell through as default-locale content at a literal/pt-br/…route — and the unconfigured-locale warning, which already compared case-insensitively, stayed silent about it. Those files now route as the configured locale, with the configured casing in routes and labels. -
e922ff5: The generated changelog index’s heading, page title, and meta description now come from the translatable
changelog.titleandchangelog.descriptionUI strings (translated in every built-in pack), joining the reveal button the template already localized. Previously the page rendered a hardcoded English “Changelog” heading, an English “ changelog“ title suffix, and an English description even on non-English default locales. -
1e5446f: Lengthen the default changelog description. “Product updates and release notes.” is 34 characters — under the 50-character floor search engines want from a meta description, and the generated
/changelogpage uses it for both its meta tag and its on-page subtitle. It now reads “Product updates, new features, and fixes from every release.” Sites that setui.changelog.descriptionare unaffected. -
e922ff5: The syntax docs now label callouts and
package-installblocks as MDX-only, matching the existing notes on diagrams and math. Previously a reader following the page could write:::noteor apackage-installfence in a.mdfile and get literal text or a plain code fence with no hint why. -
e922ff5: Apply the js-yaml 4-safe YAML engine to
matter.readas well. The front-matter wrapper previously exposed gray-matter’s ownreadhelper unwrapped, so reading a file through it would parse with the removedsafeLoaddefault and crash with “Function yaml.safeLoad is removed in js-yaml 4” — the exact failure the wrapper exists to prevent formatter()andmatter.stringify(). -
68520af: Exclude Vite’s pre-bundled dep cache (
node_modules/.vite/) from @vitejs/plugin-react. Astro’s react() replaces the plugin’s defaultnode_modulesexclude, so Babel (carrying the React Compiler) was re-parsing every 500KB+ optimized dep chunk in dev — the source of the “[BABEL] Note: The code generator has deoptimised the styling” messages. Blume’s own components stay covered by the compiler. -
e922ff5: Serve image-path icons from under
deployment.base.<Icon>emitted an image icon’s path (/brand/mark.png) as-is, so on a site deployed under a base path the request went to the domain root and 404’d while<Card img>, the logo, and every other image emitter were correctly rebased. Image icons now get the samewithBasetreatment; external URLs, data URIs, and relative paths are untouched. -
e922ff5:
@astrojs/vueand@astrojs/svelteare now declared as optional peer dependencies, matching@astrojs/netlifyand@astrojs/cloudflare. Projects using Vue or Svelte islands must install the matching integration themselves, and package managers now surface and satisfy that requirement instead of the build relying on an undeclared package. -
e922ff5:
blume build --isolatednow reports the build’s actual output directory on success. Aserveroutput build with the Vercel adapter lands its deploy bundle at.blume-verify/.vercel/output(it is never surfaced to the project root), but the message previously pointed at.blume-verify/dist, which that build never populates. -
e922ff5: The breadcrumb and pagination
<nav>landmark labels are now translatable via the newnav.breadcrumbandpage.paginationUI strings, with translations in every built-in language pack. Previously both were hardcoded English (“Breadcrumb”, “Pagination”) while the sibling chrome landmarks were dictionary-driven, so screen readers announced English landmark names on localized sites. -
e922ff5: Fix
ai.markdownComponentscrashing config validation in projects that resolve Zod 4. The schema used the single-argumentz.record(...)form, which Zod 4 rejects at schema-construction time, so any config parse failed before your settings were even read; it now uses the dual-compatible two-argument form. -
e922ff5: The MCP
get_pagetool’s description — shipped user-facing intools/listand the server card — no longer claims to return a page’s original Markdown source. The tool serves the agent variant (components downleveled to plain Markdown,<Visibility>resolved for agents), and the description now says so. -
e922ff5: The sidebar’s panel-stack back arrow and drill-in chevrons now mirror under RTL locales (
rtl:-scale-x-100), matching the pagination arrows and the panel slide animation, which already flipped direction. Previously the arrows pointed against the reading direction on RTL sites. -
d9590fc: Emit a complete Open Graph card in the page head, so crawlers and social validators stop flagging the metadata as incomplete:
og:url— the page’s canonical URL (rendered only whendeployment.siteis set, or a page overridesseo.canonical).og:type—articleon blog posts and changelog entries,websiteeverywhere else. Article pages also emitarticle:published_timeandarticle:modified_time.og:site_name— the sitetitle.og:image:width,og:image:height,og:image:type, andog:image:alton Blume’s generated OG card, so a crawler can lay it out without fetching the image. Anseo.imageyou supply yourself declares none of these, since its dimensions and format are unknown.
-
1e5446f: Give every generated OpenAPI page its own meta description. Operation and overview pages set no
description, so all of them fell back to the site-wide default — a spec with twenty operations shipped twenty pages carrying one identical description, which search engines treat as duplicate content. Each operation page now derives a description from the spec’s own prose (its description, or its summary) followed by the endpoint it documents, and the overview page uses the spec description. These land inseo.description, so they feed the meta tag without also printing as a visible subtitle above the body prose. -
80eb252: Emit X (Twitter) card tags, and add
seo.xfor account attribution:seo: { x: { handle: "@acme", creator: "@jane" }, }handlebecomestwitter:siteandcreatorbecomestwitter:creator— the one piece of X card metadata with no Open Graph equivalent to fall back to. A page can credit its own author withseo.x.creatorfrontmatter, which is what a guest post wants. The@is optional in both places.Every page also now emits
twitter:card,twitter:title,twitter:description, andtwitter:image:alton the generated card.twitter:cardpreviously rendered only when a page had an image; a page without one now gets the compactsummarycard instead of sharing as a bare link. -
e922ff5: The Scalar API reference shell now sets
<html lang>anddirfrom the default locale, mirroring the changelog index’s locale wiring, and renders the same localized skip-to-content link as the other layouts. Previously it hardcodedlang="en"with nodir— so RTL default locales rendered LTR chrome — and offered keyboard users no way to skip past the navbar. -
e922ff5: The search dialog’s section-filter “All” pill is now translatable via the new
search.allUI string, with translations in every built-in language pack. Previously it rendered hardcoded English inside an otherwise fully localized dialog. -
e922ff5: ⌘K / Ctrl+K now toggles the search dialog: pressing it while the dialog is open closes it, matching how ⌘I toggles the Ask AI panel. Previously the shortcut unconditionally re-opened, calling
showModal()on an already-open dialog — a silent no-op on evergreen browsers but anInvalidStateErroron older engines. The/shortcut stays open-only, andopen()itself now guards against an already-open dialog. -
e922ff5: Reject a
tocconfig whoseminHeadingLevelexceeds itsmaxHeadingLevel. An inverted range (including an explicit min above the default max of 3) previously validated fine and silently rendered an empty table of contents on every page; it now fails config validation with a clear message. -
e922ff5: Internal-error stack traces now relativize
.blume/runtime frames on Windows too. The remap previously matched only POSIX absolute paths, so drive-letter frames likeC:\...\.blume\...printed the full machine path instead of the project-relative.blume\...form tagged(generated).