Breeze RMM v0.98.1 — a runtime extension platform, durable approvals, and a rebuilt quote builder.
This is the release to deploy. v0.98.0 was withdrawn: its web container image failed to build
after the rest of the release had already published, so that version was never deployable. v0.98.1
carries that work plus the build fix and the extension build-time-loading deprecation below.
Everything here covers the full range since v0.97.2.
Summary
- Runtime extension platform — Breeze can now load signed, versioned extensions at runtime: artifacts and operations, web pages with navigation and named slots, a testkit, and a v1 SDK staging contract (#2617, #2633, #2648, #2650).
- Durable action intents & Tier-3 approvals — approval decisions are now durable intents with an outbox, so they survive an API restart instead of being lost mid-flight (#2625, #2628).
- Quote builder overhaul — a document-styled editor, a 30-second undo-send window, and quote duplication (#2623).
- Agent reliability — credential-rotation ordering, PAM deny-gate correctness, and full script stdout/stderr/exit codes (#2647, #2644, #2629).
Added
- Runtime extension artifact & operations (#2617) — the packaging, staging and operations layer for runtime extensions.
- Runtime web pages, navigation & named slots (#2633) — extensions can contribute pages, nav entries and slot content to the web app, served from the extension registry.
- Extension testkit (#2648) — a conformance harness for extension authors.
- Signed bundles staged through the v1 SDK contract (#2650) — extension bundles are staged and validated against the v1 manifest.
- Durable action-intents & Tier-3 approval layer (#2625) — approvals modelled as durable intents with an outbox and immutability trigger.
- Durable approval follow-ups + headless executors (#2628) — Phase 2 Google and Phase 3 M365 headless executors for approved actions.
- Quote builder overhaul (#2623) — document-styled editor, 30-second undo-send window, and quote duplication.
- Helper shell refresh (#2636) — a single header over one main region, chat as a 340px side panel on wide windows, and window size/position that persist across relaunches.
- Client-declared session tools (#2637) — chat sessions may declare client-side tools (validated, capped at 8); calls bridge over SSE and results persist so sessions reload faithfully. Sessions that declare no client tools are byte-identical to before.
- Optional customer M365 Graph-actions (write) executor — gated behind
M365_GRAPH_ACTIONS_TOOLS_ENABLED, disabled by default, and deliberately not deployed by the generic Compose stack.
Improved
- Extension loading (#2658) — build-time extension loading is deprecated in favour of the runtime
path. Extensions are now discovered and loaded at runtime; the build-time route still works but is on
a deprecation timer. Migration guidance:docs/extensions/build-time-transition.md, and SDK support is
documented indocs/extensions/sdk-compatibility.md. - Job scheduling (#2640) — the scan-orgs job now enqueues outside a held DB context, and #1105 tripwire captures are deduplicated.
Fixed
- Agent credential rotation (#2647, #2621) — the agent persists rotated credentials before the server commits the rotation, closing a window where a badly-timed restart could strand a device.
- Script results (#2629, #2474) — stdout, stderr and exit code are carried through the WebSocket command result instead of being dropped.
- PAM deny gate (#2644, #2610) — the deny gate now releases only on proven dismissal, with bounded recovery.
- Linux viewer (#2645, #2614) — the AppImage registers the
breeze://scheme, so viewer links actually connect. - AI tools (#2646, #2603) — repaired the
get_cis_compliancequery. - Migrations (#2627, #2622) — healed the v0.97.0 migration checksums for the eight files edited in place.
- Web container build (#2662) —
apps/web/Dockerfilenow copies the@breeze/extension-web-sdkworkspace manifest, so itszoddependency installs and the Astro build resolves. This is what withdrew v0.98.0; a structural guard for the class is tracked in #2661.
Security
- Extension route namespaces reserved (#2641, #2634, #2635) — seven hijackable route namespaces are now reserved and
CORE_NAMESPACESis auto-derived, so an extension cannot shadow a core/api/v1mount. - AI tool errors sanitized before streaming (#2646) — tool errors are scrubbed before they reach the client stream.
- Approvals permission cleanup — a migration revokes
approvals:decidefrom any non-system organization role named "Org Admin". An earlier revision of the seed granted this to custom roles as well as the built-in one; that revision never shipped in a release, so on an up-to-date deployment this is defensive and will report zero rows. It logs its row count either way. - Non-superuser migration guard in CI (#2626) — migrations are now exercised as an unprivileged role, catching the class of failure that only appears against managed Postgres.
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade. Bump BREEZE_VERSION to 0.98.1, then:
docker compose pull api web && docker compose up -d(If you build from source, run pnpm install first.)
Database — 8 migrations, applied automatically. They auto-apply on API boot via autoMigrate (unless you set AUTO_MIGRATE=false) and are idempotent. No large-table rewrites or backfills: every new column is nullable with no default, both new indexes are partial, and the one new CHECK constraint runs a row-count preflight first. Expect a fast boot.
One migration performs a cleanup DELETE (the approvals:decide revoke described above) and reports its row count as a WARNING in the Postgres log even when zero.
No new required environment variables. Nothing added here will refuse to boot. The release does add an optional customer M365 Graph-actions (write) executor block; it is off by default (M365_GRAPH_ACTIONS_TOOLS_ENABLED=false) and needs no action unless you deliberately enable it. That executor is intentionally not deployed by the generic Compose stack — it expects a separately released, digest-pinned image running with a workload identity, private ingress and controlled egress. Do not expose it through Caddy or point it at a plaintext URL.
If you maintain your own docker-compose.yml rather than tracking the repo's, note that the upstream file gained a secrets: entry for the executor signing key which defaults to /dev/null when unused — harmless, but you will not inherit it automatically.
Behavior changes & feature flags. No defaults changed. Build-time extension loading is deprecated
but still functional — if you build extensions into your API image, nothing breaks in this release; see
docs/extensions/build-time-transition.md before the deprecation completes. The runtime extension platform ships enabled but is inert until you install an extension. Helper chat sessions behave identically unless a client declares session tools.
No breaking changes.
Full Changelog: v0.97.2...v0.98.1
Note: the auto-generated link at the bottom of this page may compare against a different tag. The correct previous deployable release is
v0.97.2— use the link above.
What's Changed
Full set of changes since v0.97.2, the last deployable release.
- ci(migrations): non-superuser migration guard (prevents the v0.97.0 class) by @ToddHebebrand in #2626
- Quote builder overhaul: document-styled editor, 30s undo-send window, duplication by @ToddHebebrand in #2623
- fix(migrations): heal v0.97.0 checksums for the 8 migrations #2622 edited in place (v0.97.2) by @ToddHebebrand in #2627
- feat(approvals): durable action-intents & Tier-3 approval layer (Plan 1) by @ToddHebebrand in #2625
- feat(helper): Workspace Files — finder UI, content preview, and the Workspace Reshape by @ToddHebebrand in #2631
- feat(helper): files-first shell — one header, chat side panel, window-state persistence (W8) by @ToddHebebrand in #2636
- feat(w7): chat over the estate — client-declared session tools, cited RAG answers in helper chat by @ToddHebebrand in #2637
- fix(jobs): scan-orgs enqueues outside held DB context + dedupe #1105 tripwire Sentry captures by @ToddHebebrand in #2640
- feat(extensions): runtime extension artifact & operations (Plan 02) by @ToddHebebrand in #2617
- feat(extensions): runtime web pages, navigation & named slots (Plan 03) by @ToddHebebrand in #2633
- feat(extensions): add extension testkit (Plan 04, Task 1) by @ToddHebebrand in #2648
- fix(extensions): stage signed bundles through the v1 SDK contract by @ToddHebebrand in #2650
- fix(agent): PAM deny gate releases only on proven dismissal + bounded recovery (#2610) by @ToddHebebrand in #2644
- fix(ai): repair get_cis_compliance query + sanitize tool errors before streaming (#2603) by @ToddHebebrand in #2646
- fix(viewer): register breeze:// on Linux so the AppImage actually connects (#2614) by @ToddHebebrand in #2645
- feat(intents): durable approval follow-ups + Phase 2 Google + Phase 3 M365 headless executors by @ToddHebebrand in #2628
- fix(extensions): reserve 7 hijackable route namespaces + auto-derive CORE_NAMESPACES (#2634, #2635) by @ToddHebebrand in #2641
- fix(agent): persist credentials before the server commits rotation (#2621) by @ToddHebebrand in #2647
- fix(agent): carry stdout/stderr/exitCode through the WS command result (#2474) by @bdunncompany in #2629
- refactor(extensions): deprecate build-time loading (Plan 05, Task 6) by @ToddHebebrand in #2658
- ci: publish an edge stock API image from main pushes by @ToddHebebrand in #2660
- docs(extensions): correct the deprecation-gate anchor (v0.98.0 predates the gate) by @ToddHebebrand in #2663
- fix(ci): copy extension-web-sdk manifest into the web Docker deps stage by @ToddHebebrand in #2662
Full Changelog: v0.97.2...v0.98.1