Releases: LanternOps/breeze
Release list
v0.92.0
Breeze RMM v0.92.0 — a big quotes/deposits release: up-front deposit invoicing, a reworked quote editor, a fleet-wide vulnerability triage queue, permanent alert dismissal, and headless third-party (winget) patching.
Summary
- Quotes — charge an up-front deposit at acceptance (a percentage, or the total of specific selected lines) and invoice the balance afterward, plus a substantial quote-editor UX overhaul with two-way markup pricing, line images, quote titles, and AI-styled catalog copy (#2245, #2227).
- Vulnerabilities — the
/vulnerabilitiesfleet page becomes a fix-first triage queue: findings grouped by remediation unit, clickable stat cards, and per-finding ticket linking (#2225). - Alerts — a new terminal
dismissedstatus that makes an alert go away for good and is honored by the warranty-expiry evaluator, so the same condition is never re-alerted (#2226). - Patching — third-party (winget) patching now works on servers, logged-out, and headless machines via a SYSTEM-context machine-scope path, plus a wave of ring/scan/reboot correctness fixes (#2224, #2223, #2222, #2221, #2220).
- MCP / AI — the Breeze MCP server is now self-describing (server instructions + five guided workflow prompts), and partner-owned ("all orgs") config policies are finally visible to AI/MCP tools (#2214, #2213).
Added
- Quote deposits — charge a deposit up front at quote acceptance, computed as either a percentage of the quote or the total of specific selected lines, with the balance invoiced afterward (deposit-first invoicing). Percent deposits that round to zero cents are rejected; a per-category breakdown shows what the deposit covers (#2245)
- Quote editor overhaul — two-way markup pricing on the add-line form (cost + markup → price, or price + cost → markup, whichever you typed last stays authoritative), visible labels on every field, auto-fill-from-web that also prices the line, line images, quote titles, moving lines between pricing panels, and AI-styled catalog copy per partner (#2227)
- Vulnerabilities fleet triage UI — the read-only
/vulnerabilitiespage becomes a work queue: findings grouped by remediation unit (one Chrome update is one row, not 30 identical CVE rows), four clickable stat cards (Critical open · KEV exposure · Patch ready · Accepted), fleet-level triage (previously per-device only), and linking a finding to a ticket (#2225) - Billing tab in org settings — the per-org tax identity + billing address page (previously reachable only by typing the URL) now has a proper Billing tab in the Organization settings nav (#2228)
- MCP server instructions + guided prompts — the MCP server advertises
instructionsoninitialize(tenant hierarchy, tool-selection strategy, safety guardrails) and apromptscapability with five argument-templated MSP workflows (fleet triage, etc.) so connecting clients (Claude, ChatGPT) are oriented automatically (#2214)
Improved
- Permanent alert dismissal — a terminal
dismissedstatus, distinct fromresolved, valid from any status (including already-resolved). Dismissed alerts are hidden from list views by default and honored by the warranty-expiry evaluator, so a "make this go away for good" action actually sticks instead of the synthetic alert being re-created (#2226) - Compliance table reboot state — a stale "pending reboot" flag on an offline device is now qualified as stale instead of shown as an active pending-reboot (#2220)
Fixed
- Headless third-party (winget) patching — third-party scanning and installs previously only worked when a user-helper session was connected, so servers, logged-out workstations, and headless boxes never scanned or patched. Winget now runs in SYSTEM context at machine scope with proper WindowsApps path resolution (#2224)
- Patch-ring correctness — ring auto-approve now actually approves third-party patches (#2222); the ring patches endpoint reports correct per-source counts and derived OS (#2221); full-scan tombstoning is scoped to only the sources the scan actually covered, so a partial scan no longer tombstones patches from sources it didn't see (#2223)
- Partner-owned config policies in AI/MCP tools —
list_configuration_policies(and the other config-policy AI/MCP tools) filtered on the org axis only, so a partner-owned ("all orgs",org_id NULL) policy was invisible to a partner-scoped MCP caller. Now uses the shared dual-axis reader, matching the HTTP routes and web UI (#2213) - Passkey MFA metadata persistence —
POST /auth/mfa/passkey/verifywrote the WebAuthn signature counter +last_used_atwith a bare DB call that silently matched 0 rows under forced RLS (passkey MFA runs before the user is authenticated). "Last used" stayed "Never" and the signature counter never advanced; both now persist under a system DB context (#2211)
Security
- Passkey signature counter — the WebAuthn authenticator signature counter now advances correctly (it was silently frozen), restoring clone/replay detection for passkey MFA (#2211).
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade. Bump BREEZE_VERSION to 0.92.0, then:
docker compose pull api web && docker compose up -d
(If you build from source, run pnpm install first.)
Database — 7 migrations, idempotent, auto-apply on boot via autoMigrate (unless AUTO_MIGRATE=false). All are lightweight DDL — no table rewrites or large backfills, no long stall on boot:
- Quote deposits:
deposit_type/deposit_percent/deposit_amountonquotes,deposit_eligible/item_typeonquote_lines,deposit_dueoninvoices, plus a follow-up CHECK-constraint migration (NOT NULL DEFAULTadds are metadata-only) (#2245), - Quote editor: nullable
titleonquotes,image_idFK + index onquote_lines, andcatalog_ai_styleonpartners(#2227), - Vulnerabilities: nullable
ticket_id+ index ondevice_vulnerabilities(#2225), - Alerts:
dismissed_at/dismissed_bycolumns onalertsplus a newdismissedenum value (added in its own transaction) (#2226).
No new required environment variables.
Behavior changes.
- Alerts can now be permanently dismissed. Dismissed alerts are hidden from the default alert list and are no longer re-created by the warranty-expiry evaluator — this is the durable opt-out for recurring synthetic alerts. Nothing changes for existing alerts until a technician dismisses one (#2226).
- Third-party (winget) patching now runs on headless/server/logged-out machines. Devices that previously never scanned for third-party patches (no user-helper session) will begin scanning and can be patched via the machine-scope SYSTEM path. If you rely on third-party patch approvals, expect these devices to start reporting findings after upgrade (#2224).
No breaking changes.
Full Changelog: v0.91.0...v0.92.0
What's Changed
- docs: sync technical docs for v0.91.0 by @ToddHebebrand in #2212
- fix(auth): persist passkey MFA metadata under system DB context (#2210) by @bdunncompany in #2211
- fix(mcp): surface partner-owned config policies in AI/MCP tools by @ToddHebebrand in #2213
- feat(mcp): server instructions + guided workflow prompts by @ToddHebebrand in #2214
- fix(web): qualify stale pending-reboot on compliance table for offline devices (#2219) by @ToddHebebrand in #2220
- fix(patches): ring view source counts + derived os in ring patches endpoint (#2215) by @ToddHebebrand in #2221
- fix(patches): let ring auto-approve actually approve third-party patches (#2218) by @ToddHebebrand in #2222
- fix(patching): scope full-scan tombstoning to sources the scan covered (#2217) by @ToddHebebrand in #2223
- fix(agent): SYSTEM-context machine-scope winget patching with WindowsApps path resolution (#2216) by @ToddHebebrand in #2224
- feat(alerts): permanent 'dismissed' status + warranty re-alert suppression by @ToddHebebrand in #2226
- chore(dev): drop stale tailwind.config.mjs bind-mounts from dev compose override by @ToddHebebrand in #2208
- feat(web): vulnerabilities fleet triage UI by @ToddHebebrand in #2225
- chore(deps): bump @types/node from 26.0.1 to 26.1.0 in /e2e-tests by @dependabot[bot] in #2231
- chore(deps): bump tsx from 4.22.4 to 4.23.0 in /e2e-tests by @dependabot[bot] in #2233
- chore(deps): bump @anthropic-ai/sdk from 0.106.0 to 0.110.0 in /e2e-tests by @dependabot[bot] in #2234
- chore(deps): bump the typescript-tooling group with 2 updates by @dependabot[bot] in #2237
- chore(deps): bump the hono group with 2 updates by @dependabot[bot] in #2240
- chore(deps): bump nodemailer from 9.0.1 to 9.0.3 by @dependabot[bot] in #2242
- feat(web): add clickable Billing tab to org settings by @ToddHebebrand in #2228
- fix(deps): repair broken pnpm-lock.yaml (duplicate hono key) blocking all CI (#2246) by @bdunncompany in #2247
- feat(quotes): editor UX overhaul + move lines between pricing panels by @ToddHebebrand in #2227
- feat(quotes): deposits — percent or selected-lin...
v0.91.0
Breeze RMM v0.91.0 — partner-scope SSO for MSP technicians with login-page branding, agent/watchdog version pinning, VPN presence telemetry, and an SSO/agent-policy fixes wave.
Summary
- Auth / SSO — MSP technicians can now sign in to the partner dashboard via a partner-axis SSO provider, and single-partner self-hosted instances can brand the login page (#2194, #2202). Org SSO login — which was silently broken on production-shaped (
breeze_app/RLS) deployments — is fixed and hardened (#2206). - Agents — partners and orgs can pin the agent and watchdog to a specific version with inherit-with-override semantics (#2187), and the heartbeat update gate now honors the effective (partner + org) update policy instead of silently ignoring locked partner settings (#2184).
- Devices — active VPN client presence telemetry from the agent heartbeat (#2185).
- Enrollment keys — expired keys are now auto-purged, with a manual "Delete expired" action and a readable short-code column (#2203).
Added
- Partner-scope SSO + login-page branding — MSP technicians can SSO into the partner dashboard via a partner-axis OIDC provider (separate from customer/org SSO), and single-partner self-hosted instances can show partner branding and an SSO button on the login page (#2194, follow-ups #2202)
- Agent/watchdog version pins — pin the agent and watchdog to a specific version (or "latest") at partner or org level; org pins override partner pins, letting you hold a known-good version fleet-wide or stage a rollout to one org. If a pinned build doesn't exist for a device's platform/arch, the upgrade fails closed rather than falling back to latest (#2187)
- Active VPN client presence telemetry — devices report which VPN clients are present and active, surfaced on the device (#2185)
- Enrollment key auto-purge — expired enrollment keys are purged automatically after a grace period (default 7 days), plus a manual "Delete expired" action and a short-code column replacing the always-"Hidden" KEY column (#2203)
Improved
- Settings navigation — Partner Settings gets a grouped sidebar nav (matching Organization Settings), and both pages get honest save contracts: no fabricated "Saved at" status, confirmation before discarding unsaved edits on tab switch, and failed saves no longer wipe the page (#2204)
- MCP OAuth — new opt-in anonymous Dynamic Client Registration posture (
OAUTH_DCR_ALLOW_ANONYMOUS) so OAuth clients without initial-access-token support — Claude Desktop / claude.ai / ChatGPT — can connect to the Breeze MCP server (#2193)
Fixed
- Org SSO under RLS — org SSO initiation, the
/sso/checkprobe, and the callback identity lookup read through bare DB calls that returned 0 rows under forced RLS, so org SSO login didn't work on production-shaped deployments; returning logins also inserted duplicate identity rows instead of updating. All fixed, with a unique index preventing identity-linking races and SSO tables wired into tenant-delete cascades (#2206) - Agent update policy enforcement — a partner's locked Agent Update Policy / Maintenance Window was shown as locked in the UI but ignored by the heartbeat update gate; the gate now resolves the same effective partner+org merge used everywhere else, and fails closed if the policy lookup errors (#2184)
- API duplicate-key handling — duplicate-SKU catalog imports (and nine other request paths) now return the intended 409 instead of a raw 500; distributor catalog imports no longer hold a pooled DB connection through multi-second AI enrichment calls (#2192)
- Discovery — clearing an asset's Display Name and saving no longer fails with a literal
[object Object]error (#2200)
Security
- SSO hardening — password reset now respects a partner-axis
enforceSSOflag (previously partner staff could bypass SSO enforcement via password reset) (#2202); IP-level rate limiting on SSO login initiation and a unique index against identity-linking races (#2206) - Agents — version-pin resolution and the update gate fail closed on lookup errors instead of falling through to permissive defaults (#2184, #2187)
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade. Bump BREEZE_VERSION to 0.91.0, then:
docker compose pull api web && docker compose up -d
(If you build from source, run pnpm install first.)
Database — 4 migrations, idempotent, auto-apply on boot via autoMigrate (unless AUTO_MIGRATE=false):
sso_providersgains a partner axis (nullablepartner_id,org_idbecomes nullable, XOR check) and a new smallpartner_login_brandingtable, both with RLS,- a tiny cleanup + CHECK constraint on
partner_login_branding.accent_color, - a dedupe + unique index on
user_sso_identities(bounded by user count; removes duplicate rows created by the returning-login bug, keeping the freshest per provider/external-id — any dedupes are logged with row counts), devices.active_vpnsnullablejsonbcolumn (metadata-only ADD COLUMN, no rewrite).
No table rewrites or large backfills — no long stall on boot.
No new required environment variables. Three new optional variables:
ENROLLMENT_KEY_PURGE_AFTER_DAYS(default7) — days after expiry before an enrollment key is auto-purged,ENROLLMENT_KEY_CLEANUP_ENABLED(default on) — kill switch for the auto-purge worker,OAUTH_DCR_ALLOW_ANONYMOUS(defaultfalse) — only relevant if you run the MCP OAuth server withOAUTH_DCR_ENABLED=true; allows anonymous DCR so Claude/ChatGPT-style clients can register. If you set any of these, remember Docker Compose only interpolates variables explicitly mapped in theapiserviceenvironment:block —.envalone isn't enough.
Behavior changes.
- Expired enrollment keys are now auto-purged 7 days after expiry by default (cascading their bootstrap tokens and deployment invites). Keys with no expiry are never touched. Opt out with the
ENROLLMENT_KEY_CLEANUP_ENABLEDkill switch (#2203). - Locked partner agent-update policies are now actually enforced at the heartbeat gate. An org under a partner with a locked
Manualpolicy or a restricted maintenance window that was previously (incorrectly) receiving automatic agent updates will stop receiving them after upgrade (#2184). - Org SSO logins that were silently failing on RLS-enforced deployments now work; duplicate SSO identity rows are deduped once at migration time (#2206).
- Login page — when a partner enforces SSO, the password form collapses behind a "Sign in with password instead" toggle for partner-axis users; org users are unaffected (#2202).
No breaking changes.
Full Changelog: v0.90.0...v0.91.0
What's Changed
- docs: sync technical docs for v0.90.0 by @ToddHebebrand in #2188
- fix(agents): heartbeat update gate honors effective (partner+org) update policy (#2123) by @ToddHebebrand in #2184
- feat(devices): active VPN client presence telemetry (#2139) by @ToddHebebrand in #2185
- ci: raise Integration Tests timeout 40 -> 55 min by @ToddHebebrand in #2191
- fix(api): duplicate-key 409s no longer clobbered into 500s; distributor import enrichment runs outside the held transaction by @ToddHebebrand in #2192
- fix(mcp-oauth): allow anonymous DCR so Claude/ChatGPT can connect by @ToddHebebrand in #2193
- feat(agents): partner + org agent/watchdog version pins (#2124) by @ToddHebebrand in #2187
- feat(auth): partner-scope SSO for MSP technicians + login-page branding by @ToddHebebrand in #2194
- fix(sso): post-merge review follow-ups for partner SSO + login branding (#2194) by @ToddHebebrand in #2202
- fix(discovery): Asset Info save fails with "[object Object]" on empty Display Name by @ToddHebebrand in #2200
- feat(enrollment-keys): auto-purge expired keys, delete-expired action, short-code column by @ToddHebebrand in #2203
- feat(web): grouped sidebar nav for Partner + Org settings, honest save contracts by @ToddHebebrand in #2204
- fix(sso): org SSO under RLS on public routes + identity/cascade hardening (#2195) by @ToddHebebrand in #2206
- fix(web): bump no-silent-mutations targeted-set count to 58 by @ToddHebebrand in #2209
Full Changelog: v0.90.0...v0.91.0
v0.90.0
Breeze RMM v0.90.0 — live per-device automation progress, portable-device battery telemetry, and a broad reliability/security fixes wave.
Summary
- Automations — automation runs now record a structured per-device result (pass/fail/pending/skipped) with timing and output, and the UI shows it updating live as the run executes instead of only a final aggregate count (#2023).
- Devices — portable devices now report battery and power status (percent, charging state, plugged-in, time remaining) from the agent heartbeat (#2142).
- Software detection — new file-version (
>=) detection rule for identifying installed software by on-disk file version (#2089). - Reliability & security hardening — agent heartbeat now fails closed when its update-policy lookup fails (#2125), uptime scoring credits boot spans and stops a recovered-self double-dip (#2166), and the Windows MSI bootstrap token finally honors the device-enrollment limit set at build time (#2161).
Added
- Per-device automation results with live progress — each automation run seeds a row per targeted device and updates it running → success/failed/skipped as the concurrency loop finishes, giving a consolidated per-device breakdown with timing and captured output that a polling UI watches live (#2023)
- Battery & power status for portable devices — the agent heartbeat reports a power snapshot (present, percent, charging state, plugged-in, time-remaining) surfaced on the device (#2142)
- File-version (
>=) software detection rule — detect installed software by comparing an on-disk file version with a>=operator (#2089)
Improved
- Billing lists — shared list chrome and pill-role layering across billing surfaces, with follow-up test coverage (#2151)
Fixed
- Auth — a passkey is now accepted as an alternate MFA method when an authenticator app is the primary factor, instead of being rejected (#2153)
- Reliability scoring — boot spans are credited as uptime and a recovered-self credit double-dip is removed; fleet scores may shift after upgrade as new data accrues (#2166)
- Patching — update-ring category include/exclude filters are enforced at approval time, not just at scan time (#2117)
- Remote — Scheduled Tasks — the Scheduled Tasks tool is now theme-aware (#2136)
- Remote terminal — a manual Disconnect no longer triggers auto-reconnect (#2137)
- Web — idle logout — the partner's effective session-timeout is honored when logging out idle sessions (#2147)
- Web — device action bar — gated on
status !== 'online'rather than== 'offline', so actions render correctly for transitional states (#2078) - Config policies — org ownership badge + locked org-assignment target (#2167); org-only feature tabs are gated on partner-wide policies (#2101)
- Installer — the Windows MSI filename-bootstrap token honors the device-enrollment limit set when the installer was built; a multi-use token now enrolls up to its limit instead of silently 404-ing after the first machine (#2161)
Security
- Agents — fail closed on heartbeat update-policy lookup — if an agent's update-policy can't be resolved, the heartbeat no longer proceeds with a permissive default (#2125)
- Auth — fixed token lifetimes — the deliberate 15-minute access / 7-day refresh token design is unchanged; the phantom
JWT_EXPIRES_IN/REFRESH_TOKEN_EXPIRES_INvariables that falsely implied a tunable knob are removed so config no longer advertises a control that does nothing (#2146)
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade. Bump BREEZE_VERSION to 0.90.0, then:
docker compose pull api web && docker compose up -d
(If you build from source, run pnpm install first.)
Database — 3 migrations, idempotent, auto-apply on boot via autoMigrate (unless AUTO_MIGRATE=false):
- new
automation_run_device_resultstable (per-device automation results, org-scoped RLS on the device's org), devices.battery_statusnullablejsonbcolumn,installer_bootstrap_tokens.consumed_countinteger with a small guarded backfill of already-consumed tokens.
No table rewrites or large backfills — no long stall on boot.
No new required environment variables. Two variables are removed from the shipped compose/.env examples: JWT_EXPIRES_IN and REFRESH_TOKEN_EXPIRES_IN. They were never read by any code path (access/refresh TTLs are hardcoded at 15m/7d by design), so setting them never did anything — you can safely delete them from your .env and compose. No behavior change.
Behavior changes.
- Agent heartbeat now fails closed when the update-policy lookup fails (#2125) — an agent that can't resolve its update policy no longer falls through to a permissive default.
- Reliability scores may shift after upgrade — devices affected by the boot-span uptime credit or the recovered-self double-dip will re-score as new heartbeat data accrues (#2166).
- Remote terminal no longer auto-reconnects after you click Disconnect (#2137).
No breaking changes.
Full Changelog: v0.89.0...v0.90.0
What's Changed
- chore(skills): commit /release skill (sanitized) so worktree sessions load it by @ToddHebebrand in #2164
- docs: sync technical docs for v0.89.0 by @ToddHebebrand in #2165
- fix(config-policies): gate org-only feature tabs on partner-wide policies (#2101) by @ToddHebebrand in #2169
- Config policies: org ownership badge + locked org assignment target by @ToddHebebrand in #2167
- fix(web): gate device action bar on status!=='online' not =='offline' (#2078) by @ToddHebebrand in #2170
- fix(web): honor partner effective session timeout in idle logout (#2147) by @ToddHebebrand in #2171
- fix(remote-terminal): stop auto-reconnect after manual Disconnect (#2137) by @ToddHebebrand in #2172
- fix(config): remove phantom JWT_EXPIRES_IN / REFRESH_TOKEN_EXPIRES_IN env vars (#2146) by @ToddHebebrand in #2173
- fix(remote): make Scheduled Tasks tool theme-aware (#2136) by @ToddHebebrand in #2174
- fix(patch): enforce ring category include/exclude filters at approval time (#2117) by @ToddHebebrand in #2176
- fix(reliability): credit boot spans as uptime, stop recovered-self credit double-dip by @ToddHebebrand in #2166
- refactor(billing): shared list chrome, pill-role layering, plus follow-up tests (#2151) by @ToddHebebrand in #2177
- feat(software): file-version (>=) detection rule (#2089) by @ToddHebebrand in #2178
- feat(devices): battery and power status for portable devices (#2142) by @ToddHebebrand in #2180
- fix(agents): fail closed when heartbeat update-policy lookup fails (#2125) by @ToddHebebrand in #2181
- fix(auth): allow passkey as alternate MFA when authenticator is primary (#2153) by @ToddHebebrand in #2175
- feat(automations): per-device execution results with live progress (#2023) by @ToddHebebrand in #2179
- fix(installer): honor device-enrollment-limit on Windows MSI bootstrap token (#2161) by @ToddHebebrand in #2182
Full Changelog: v0.89.0...v0.90.0
v0.89.0
Breeze RMM v0.89.0 — partner-wide everything: define a policy once, apply it to every org — plus scheduled report delivery and a faster Windows remote desktop.
Summary
- Partner-wide first (epic #2135) — the config surfaces MSP techs define once now apply across ALL their orgs, not one at a time: software & security policies (#2143), compliance rule sets, sensitive-data, peripheral-control policies & maintenance windows (#2149), alert notification channels, routing rules & escalation policies (#2156), and standalone automations (#2162) are all dual-ownership (org-scoped or partner-wide), with isolation enforced by database row-level security, not just app code. Patching's artificial org-first restrictions are gone too (#2143).
- Reports — saved reports now actually run on their schedule and email recipients, with branded PDF attachments, an exec-summary cover, trend deltas vs the prior period, and next-run visibility in the UI (#2148, #2152).
- Remote desktop (Windows) — encode pipeline rebuilt: async Media Foundation transforms, zero-copy texture path, adaptive slow-start; noticeably lower latency on busy hosts (#2145).
- Billing & AI — the AI/MCP surface gains full write coverage over billing and ticketing (quotes, invoices, contracts, tickets) and the six broken billing read tools are repaired with a contract test against registry drift (#2122). Quotes/Invoices/Contracts get a shared UI kit and editor parity (#2150).
Added
- Partner-wide ("All orgs") ownership for software policies, security policies (#2143); compliance rule sets, sensitive-data policies, peripheral-control policies, maintenance windows (#2149); notification channels, routing rules, escalation policies (#2156); automations (#2162). Create-time scope selector + "All orgs" badge in each list; partner-wide evaluation fans out per device org (results, alerts, and findings always land on the device's own org).
- Partner-wide patching unblocked — update rings are partner-axis; a partner-wide patch policy now resolves and schedules end-to-end (#2143)
- Scheduled report execution — daily/weekly/monthly saved reports run per-org-timezone and email recipients; PDF-format reports attach branded PDFs with exec-summary cover and trend deltas (#2148, #2152)
- Ticket soft-delete + admin restore — clear out test/spam/duplicate tickets reversibly instead of parking them in Closed (#2144)
- Billing & ticketing AI/MCP write tools — create/update quotes, invoices, contracts, and tickets from the AI agent and MCP clients; broken billing read tools repaired (#2122)
Improved
- Quotes/Invoices/Contracts — shared status/loading/save UI kit and editor parity across the three surfaces (#2150)
- Windows remote desktop — async MFT encode, zero-copy capture→encoder path, adaptive slow-start bitrate ramp (#2145)
- Reliability score card — self-explaining factor rows for all five factors; devices no longer bounce to a mystery score (#2159)
Fixed
- Reliability scoring — VSS software events no longer count as memory/disk hardware errors (bare event-ID matches now require a hardware source), and a device's own failure events no longer double-penalize its score; fleet scores may shift (mostly upward) after upgrade (#2159)
- Remote viewer — session stats survive auto-reconnect, so adaptive bitrate no longer freezes after a network blip (#2158)
- UniFi (self-hosted controller) — deep-telemetry collector upsert now matches its partial unique index, fixing a 500 (#2141)
Security
- Tenant isolation — every table converted to partner-wide ownership ships a dual-axis row-level-security policy plus a database CHECK enforcing exactly-one-owner (org XOR partner), covered by per-table cross-tenant forge tests against real Postgres (#2143, #2149, #2156, #2162)
- MCP — the
breeze://scriptsresource read now applies dual-ownership scoping (previously org-only) (#2162)
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade command. Bump BREEZE_VERSION=0.89.0 in your .env, then:
docker compose pull api web && docker compose up -d(If you build from source, run pnpm install first.)
Database — 10 migrations, idempotent, auto-apply on boot via autoMigrate (unless AUTO_MIGRATE=false). All are DDL-only on small config tables: nullable partner_id columns, org_id NOT NULL relaxations, exactly-one-owner CHECK constraints, partner indexes, RLS policy swaps (org-only → dual-axis), and ticket soft-delete columns. No backfills or table rewrites — no long stall on boot.
No new required environment variables.
Behavior changes.
- Ticket delete is now a soft-delete with admin restore; deleted tickets leave the default lists but remain restorable (#2144).
- Reliability scores may shift after upgrade — devices previously penalized by VSS event misclassification or self-failure double-counting will score higher as new data accrues (#2159).
- Partner-wide features are additive — existing org-scoped policies, channels, and automations behave exactly as before. Creating "All orgs" objects requires a partner admin with all-organizations access.
No breaking changes.
Full Changelog: v0.88.0...v0.89.0
What's Changed
- docs: sync technical docs for v0.88.0 by @ToddHebebrand in #2121
- Partner-wide first: patch enablement, capability gate, and dual-ownership software + security policies by @ToddHebebrand in #2143
- perf(agent): Windows remote-desktop encode pipeline — async MFT, zero-copy, adaptive slow-start by @ToddHebebrand in #2145
- Quotes/Invoices/Contracts polishing round 2: shared billing kit + editor parity by @ToddHebebrand in #2150
- Ship scheduled report execution and posture report polish by @ToddHebebrand in #2148
- Reports: PDF email attachments, exec-summary cover, trend deltas, next-run visibility by @ToddHebebrand in #2152
- feat(ai): billing & ticketing AI/MCP write tools + repair broken read tools by @ToddHebebrand in #2122
- fix(unifi): match partial unique index in cloud collector upsert (deep telemetry 500) by @ToddHebebrand in #2141
- feat(tickets): soft-delete + admin restore for tickets (#2140) by @ToddHebebrand in #2144
- chore(deps): bump tauri from 2.11.3 to 2.11.5 in /apps/helper/src-tauri by @dependabot[bot] in #2154
- chore(deps): bump tauri from 2.11.3 to 2.11.5 in /apps/viewer/src-tauri by @dependabot[bot] in #2155
- Partner-wide first phase 2: compliance, sensitive-data, peripheral, and maintenance dual-ownership by @ToddHebebrand in #2149
- fix(viewer): viewer_stats survive auto-reconnect — adaptive bitrate no longer freezes by @ToddHebebrand in #2158
- Partner-wide first phase 3: alert delivery rails dual-ownership (channels, routing, escalation) by @ToddHebebrand in #2156
- docs(partner-wide): backup template/binding design (#2132) + automations conversion mapping (#2133) by @ToddHebebrand in #2157
- fix(reliability): bare-ID hardware gate, self-failure exclusion, self-explaining score card by @ToddHebebrand in #2159
- Partner-wide first phase 4: automations dual-ownership (org XOR partner) by @ToddHebebrand in #2162
Full Changelog: v0.88.0...v0.89.0
v0.88.0
Breeze RMM v0.88.0 — self-hosted UniFi controllers, EDR-aware incident response, and exclusive Windows Update control.
Summary
- Networking — Breeze can now manage a self-hosted UniFi Network controller (one VM serving many customer sites) entirely through an on-LAN agent, with no UniFi cloud key, and fans that one controller out to many orgs for inventory and telemetry (#2097). Network-discovered devices get a native detail page (#1998), and DNS Security gains a Pi-hole v6 client (#2069).
- Patch management — a Configuration Policy toggle lets you manage Windows Update exclusively through Breeze, suppressing the OS's native auto-install channel so updates only flow through your approval rings (#2079). Windows Update scanning is more accurate: correct category classification, populated release dates, and firmware/driver-only sources now fail loud instead of silently doing nothing (#2118, #2114, #2116, #2119).
- Incident response — the Incidents page is now EDR-aware, rendering a unified feed that unions live EDR detections with tracked incident records, with deep links back to the originating EDR console (#2095).
- MSP workflows — Security & Compliance Posture report in the UI (#2087), partner-wide ("all orgs") config-policy ownership (#2064), maintenance-window reboots for pending-reboot devices (#2096), plus billing/contracts and ticketing polish.
Added
- Self-hosted UniFi controller support — agent-mediated, no cloud key; one controller → many customer orgs for inventory and deep telemetry (#2097)
- EDR-aware Incidents page — new
GET /incidents/feedunions live EDR detections with tracked incidents, severity-ranked, with EDR console link-out (#2095) - Exclusive Windows Update source — Patches-tab toggle "Manage Windows Update exclusively through Breeze" so updates flow only through Breeze's rings (#2079)
- Native detail page for network-discovered devices — richer view for assets found via network discovery (#1998)
- Pi-hole v6 DNS Security client — REST API integration for Pi-hole v6 (#2069)
- Security & Compliance Posture report — now exposed in the UI (#2087)
- Software detection rules for
.exe/.msideployments, plus a reboot-code fix (#2088) - Maintenance-window reboots — optionally reboot devices with a pending reboot during their maintenance window (#2096)
- Ticketing: drop-unknown-sender & DMARC-fail drop — new
dropmode for unmatched senders and a drop-on-verification-failure toggle; inbound review queue moved into the Tickets tab (#2105) - Catalog AI enrichment on distributor imports plus a "Polish with AI" helper (#2081)
- Partner-wide config-policy ownership — "all orgs" owner option when creating a config policy (#2064)
- Elastic Defend recognized as an antivirus provider (#2068)
- PAM signer thumbprint pinning — match by certificate thumbprint, not just subject CN (#2080)
- Contracts — prefill the Pax8 sell price in the subscription-link modal (#2084)
- Billing — full-width, expandable line-description boxes for quotes and invoices (#2072)
Improved
- Ticketing — partner-level SLAs surfaced in Priorities settings, with a corrected precedence note (#2076)
- Agent update policy — mode labels relabeled to match actual behavior (#2086)
- Inbound email — trust real Mailgun inbound MX authserv-ids and scan all
Authentication-Resultsheaders (#2099) - Network inventory —
interface_namewidened fromvarchar(100)totextfor long interface names (#2065)
Fixed
- AI patch tooling —
manage_patcheslistis now scoped to the tenant/device instead of the global catalog (#2115) - Patch categories — reconcile ring
definitioncategory with the agent'sdefinitions, and classify Windows Update categories from all WUA categories (#2119, #2118) - Alerts — resolved alerts are no longer un-muteable; added a "Forever" suppression option and an expiry reaper (#2110)
- MCP org-scoped keys — resolve the owning partner under system context, and resolve a membership-less Partner Admin role (#2108, #2109, #2104)
- Config policy — ownership reconciled with the Assignments tab, and web
FeatureTypeparity enforced against the canonical list (#2107, #2070) - UniFi (cloud) — corrected Site Manager API integration: parsing, paths, mapping UX, and a safe replace-all (#2103)
- Reports —
GET /reports/templatesimplemented (was 500ing via a/:iduuid cast) (#2102) - Devices — Connect Desktop & Power actions disabled for offline devices (#2077)
- Security providers — match Bitdefender before Defender in provider detection (#2085)
- API keys — API-key auth can now write device custom-field values (#2071)
Security
- PAM — pin certificate thumbprint for signer matching, hardening rule evaluation against subject-CN spoofing (#2080)
- Tenant isolation — AI
manage_patcheslistscoped to tenant/device rather than the global catalog (#2115) - Dependencies — bump
anyhowto 1.0.103 (RUSTSEC-2026-0190) (#2073)
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade command. Bump BREEZE_VERSION=0.88.0 in your .env, then:
docker compose pull api web && docker compose up -d(If you build from source, run pnpm install first.)
Database — 12 migrations, idempotent, auto-apply on boot via autoMigrate (unless AUTO_MIGRATE=false). All are additive and fast: ADD COLUMN IF NOT EXISTS (metadata-only defaults), two varchar(100)→text widenings (no table rewrite in Postgres), one new RLS-protected table (unifi_controller_sites), and one small partial index on suppressed alerts. No backfills or full-table rewrites — no long stall on boot.
No new required environment variables. The config validator is unchanged this release.
Behavior changes & feature flags.
- Exclusive Windows Update (#2079) — gated behind a new Configuration Policy toggle, "Manage Windows Update exclusively through Breeze," which defaults OFF. Existing policies are unaffected (grandfathered). When enabled, the Windows agent sets
NoAutoUpdate=1underHKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AUto suppress the OS auto-install channel; Breeze's own ring-based installs continue as normal. - Ticketing unknown-sender handling (#2105) — the default remains
quarantine(review queue), so behavior is unchanged unless you opt into the newdropmode. The newdropUnverifiedSenders(SPF/DKIM/DMARC-fail drop) toggle also defaults off.
No breaking changes.
Full Changelog: v0.87.0...v0.88.0
What's Changed
- docs: sync technical docs for v0.87.0 by @ToddHebebrand in #2063
- chore(addins,viewer): migrate Office add-ins + viewer to Tailwind 4 (#2057) by @ToddHebebrand in #2067
- fix(security): bump anyhow to 1.0.103 (RUSTSEC-2026-0190) by @ToddHebebrand in #2073
- fix(docs): upgrade docs site to Astro 7 (fixes Cloudflare Pages build) by @ToddHebebrand in #2074
- feat(dns-security): add Pi-hole v6 REST API client (#2017) by @ToddHebebrand in #2069
- fix(api): allow API-key auth to write device custom-field values (#2066) by @ToddHebebrand in #2071
- feat(pam): pin cert thumbprint for signer matching, not just subject CN (#1776) by @ToddHebebrand in #2080
- fix(api): widen interface_name from varchar(100) to text (#2006) by @ToddHebebrand in #2065
- feat(security): recognize Elastic Defend as an antivirus provider (#2018) by @ToddHebebrand in #2068
- fix(agent): match bitdefender before defender in providerFromName (#2075) by @ToddHebebrand in #2085
- chore(deps): bump cloud.google.com/go/storage from 1.62.3 to 1.63.0 in /agent by @dependabot[bot] in #2094
- chore(deps): bump github.com/pion/webrtc/v4 from 4.2.15 to 4.2.16 in /agent by @dependabot[bot] in #2093
- chore(deps): bump the aws-sdk group in /agent with 4 updates by @dependabot[bot] in #2091
- feat(web): native detail page for network-discovered devices — #1424 slice 2 of 4 by @ToddHebebrand in #1998
- fix(web): relabel agent update policy modes to match actual behavior (#1962) by @ToddHebebrand in #2086
- feat(reports): expose Security & Compliance Posture report in the UI by @ToddHebebrand in #2087
- feat(software): detection rules for .exe/.msi deploys + reboot-code fix (#2022) by @ToddHebebrand in #2088
- fix(config): enforce web FeatureType parity with canonical CONFIG_FEATURE_TYPES (#2004) by @ToddHebebrand in #2070
- feat(web): partner-wide ("all orgs") owner option on config policy create by @ToddHebebrand in #2064
- fix(web): disable Connect Desktop & Power for offline devices (#2013) by @ToddHebebrand in #2077
- fix(tickets): surface partner-level SLAs in Priorities settings + correct precedence note by @ToddHebebrand in #2076
- feat(billing): full-width, expandable line description boxes for quotes & invoices by @ToddHebebrand in #2072
- feat(contracts): prefill Pax8 sell price in subscription-link modal by @ToddHebebrand in https://github.com/LanternOps/breeze/pul...
v0.87.0
Breeze RMM 0.87.0 — UniFi network integration, downloadable + branded reports, M365 email-to-ticket, distributor catalog import, and the BE-16 vulnerability correlation job — plus invoice/contract polish and a batch of correctness + hardening fixes.
A feature-heavy release (286 files) that's still a light upgrade for operators: 10 idempotent migrations (all new-table creates + cheap metadata-only column changes — no large-table rewrites or backfills), no new required environment variables, and no breaking changes.
Summary
- UniFi network integration — connect a partner's UniFi Site Manager cloud account to map UniFi sites → Breeze sites and reconcile UniFi devices as discovered assets, with an optional agent-side read-only deep-telemetry collector. Opt-in per partner; off until you connect an account (#2040).
- Reports — persisted, downloadable report runs and a new client-facing Security & Compliance Posture report with a partner-branded PDF (logo, scorecard, per-device tables) for insurance/vetting (#2058).
- Email-to-ticket (M365) — connect a Microsoft 365 shared mailbox so customer email becomes tickets and replies send back from that mailbox, with no MX/forwarding changes (#2045). Inbound alias is now editable independently of the partner slug (#2060).
- Billing / distributors — import hardware & subscriptions from TD SYNNEX and Pax8 into the catalog, then quote/contract them with internal unit cost, markup, SKU/part-number, and margin tracking (kept off customer-facing documents); plus a QuickBooks customer import that creates Organizations + default Sites (#2025, #2048, #2044).
- Vulnerability management — the BE-16 correlation step is now wired into a daily job, gated per-org behind a new
vulnerabilityconfig-policy feature (default OFF) (#2050). - Fixes & hardening — self-hosted email-to-ticket / Stripe webhooks reaching their handlers again, MSI bootstrap enrollment, one-click alert suppress, MCP partner-role resolution, and a UniFi GDPR-cascade gap (#2054, #2049, #2020, #2019, #2052/#2055).
Added
- UniFi network integration — connect a partner's UniFi Site Manager cloud account (encrypted API key), map UniFi sites to Breeze sites, and reconcile UniFi devices into discovered assets. An optional agent-side, read-only deep-telemetry collector polls the local UniFi Network controller for richer device/client data. A BullMQ sync worker runs on a 30-minute scheduler. Opt-in: nothing happens until a partner connects an account. (#2040)
- Downloadable report runs + Security & Compliance Posture report — report runs are now persisted and downloadable, and there's a new client-facing Security & Compliance Posture report (for insurance/vetting) rendered as a partner-branded PDF (logo, scorecard, per-device tables). CSV/Excel exports retain full per-row data; the PDF is the polished client deliverable. (#2058)
- M365 shared-mailbox email-to-ticket — connect a Microsoft 365 shared mailbox (admin-consent flow) so customer email becomes tickets and replies are sent back from that mailbox via Microsoft Graph — no MX or forwarding changes. On first connect only new mail is ticketed (no historical backfill). Optional; see upgrade notes for the Azure app + env vars. (#2045)
- QuickBooks customer import — browse, select, and import QuickBooks customers as Breeze Organizations, each with a default Site carrying contact/address. MFA-gated and idempotent on re-import. (#2048)
- Distributor catalog import + line cost & margin — import hardware and subscriptions from TD SYNNEX and Pax8 into the catalog, then quote and contract them with internal unit cost, markup, SKU/part-number, and margin tracking. Cost and SKU are snapshotted on the line and kept off customer-facing documents. (#2025)
Improved
- Editable inbound email alias — partner admins can set a custom inbound email local-part, decoupled from the partner slug, so an awkward auto-generated
tickets@…address can be changed without DB access. Ships dark (defaults to the slug); the original slug address keeps working forever. (#2060) - Editable organization type — Org Type (Customer vs Internal) is now editable on Settings → Organization → General, not just at create time. (#2061)
- Vulnerability correlation daily job — the previously-uncalled BE-16 correlation step now runs daily (13:00 UTC), gated behind a new
vulnerabilityconfig-policy feature ({ enabled }, default OFF). Enable Vulnerability Scanning on a policy and assign it to an org to populate findings. (#2050) - Invoice polish + internal margin panel — payments are gated to issued (non-draft) invoices, the document header dedupes when no seller is named, operator hints surface (taxable-but-no-tax-rate, no billing contact), and a new internal "Margin" summary panel appears on the invoice editor/detail rails (gated on
invoices:read, never shown on customer documents). (#2044) - Contracts list/detail UX — the bulk bar keeps selected rows visible, "Delete drafts" is only offered when a draft is selected, empty states split into first-run vs filtered-empty, the redundant Organization column is dropped in org-locked embeds, and date inputs render correctly in dark mode. (#2024)
- Device list & sidebar quality-of-life — the device list Columns dropdown gains a "Reset to defaults" button (restores column visibility + order), and the sidebar gains a "Collapse all" button that collapses every section except the one holding the active page. (#2015)
Fixed
- Self-hosted email-to-ticket & Stripe webhooks reaching their handlers — a wildcard
authMiddlewareon the webhook-CRUD router blanketed the entire/webhooks/*subtree, 401'ing the public signature-gated inbound-email, Stripe, and Stripe Connect webhooks before their HMAC handlers ran (broke self-hosted email-to-ticket, #2053). Auth is now applied per-route. (#2054) - MSI bootstrap CA enrollment token — MSI installs succeeded but agents never enrolled ("no bootstrap token present") because a deferred EXE custom action couldn't read
[CustomActionData]. Fixed by referencing[OriginalDatabase]directly. Takes effect in this release's signed MSI; the immediate workaround remains a property-based silent install (SERVER_URL=… ENROLLMENT_KEY=…). (#2049) - One-click alert suppress — single-alert Suppress sent no request body, so the API's required
{ until }always returned 400 and suppress never worked. Adds a duration picker (default 24h) and surfaces the server's specific error. (#2020) - Confirm contract cancel — the terminal Cancel action on a contract (irreversible; stops all future invoicing) previously fired on a single unconfirmed click and now routes through a confirmation dialog. Pause/resume stay immediate. (#2024)
- MCP owning-partner resolution + SSE public URL — org-scoped (manual) API keys reached MCP
tools/callwith no partner, causing "Insufficient permissions: no role assigned" for partner-admin users; the key's owning partner is now resolved for role resolution only (RLS visibility unchanged). The SSEendpointevent also now advertises the configured public base URL instead of a barehttp://URL behind an HTTPS proxy. (#2019) - UniFi org data now included in GDPR erasure — the five new
org_idUniFi tables weren't registered in the org-deletion cascade, which would have orphaned UniFi data on org delete; both are now enrolled inORG_CASCADE_DELETE_ORDER. (#2052, #2055)
Security
- Per-route auth on
/webhooks(defense-in-depth) — replacing the/webhooks/*wildcardauthMiddlewarewith per-route auth ensures the public, HMAC-verified webhook endpoints (inbound email, Stripe, Stripe Connect) are reached and validated by their own signature checks instead of being blanket-401'd. Requires a new build to take effect. (#2054)
Self-Hosting / Upgrade Notes
No breaking changes. Existing orgs are unaffected by the new feature gates below — UniFi, M365 email-to-ticket, and vulnerability scanning are all opt-in and stay off until you turn them on.
- Upgrade command. Bump
BREEZE_VERSION=0.87.0in.env, thendocker compose pull api web && docker compose up -d. If you build from source, runpnpm installafter pulling. Node pin is unchanged (v22.20.0). - Database — 10 idempotent migrations, auto-applied on boot via
autoMigrate(unlessAUTO_MIGRATE=false). They are all new-table creates (UniFi ×2, ticket mailbox connections, report runs, report type) with RLS enabled inline, plus cheap metadata-only column changes (quote_lines/invoice_linesdescriptionDROP NOT NULL, new accounting/cost/SKU/inbound-local-part columns) and indexes on the new empty tables. No large-table rewrites or backfills — boot is fast. - No new required environment variables. The M365 email-to-ticket feature adds three optional vars —
TICKET_MAILBOX_M365_CLIENT_ID,TICKET_MAILBOX_M365_CLIENT_SECRET(API) andPUBLIC_TICKET_MAILBOX_APP_ID(web). Unset = the feature is disabled and nothing breaks at boot. To enable it, register a separate multi-tenant Azure app with Graph application permissionsMail.ReadWrite+Mail.Send, redirect URI<PUBLIC_URL>/api/v1/tickets/mailbox/callback, set those three vars, and map them in theapi/webenvironment:blocks of your compose (a value in.envalone isn't enough). If you reverse-proxy over HTTPS, make surePUBLIC_API_URLis set to your external URL so the MCP SSE endpoint advertises the right scheme (#2019). - Behavior changes & feature flags.
vulnerabilityconfig-policy feature — default OFF. A new per-org policy gate; the daily BE-16 correlation job (13:00 UTC) only populates findings for orgs whose assigned policy enables scanning. No existing org is opted in. (#2050)- UniFi integration — opt-in. No sync runs until a partner connects a UniFi Site Manager account; the agent teleme...
v0.86.0
Breeze RMM 0.86.0 — Astro 7 / Tailwind 4 / Vite 8 frontend modernization, plus quotes & invoices polish and a batch of correctness fixes.
This is a large frontend build-toolchain release (494 files) but a light upgrade for operators: no database migrations, no new required environment variables, no feature flags, and no runtime breaking changes.
Summary
- Frontend stack — both
apps/webandapps/portalmigrated to Tailwind 4 and upgraded to Astro 7 + Vite 8 (Rolldown). Build-time only; prod images and runtime behavior unchanged (#1991, #1995, #2008). - Quotes & invoices — totals now compute from one shared source of truth so the editor, line totals, and live-totals rail can't disagree; plus optimistic reordering and accessibility polish (#2011).
- Reliability scoring — the #1967 event-classification de-junk is now complete for macOS and Linux, with a server-side hardware-error gate so stale/old-agent junk can no longer depress hardware scores (#2005).
- Fixes — self-hosted Windows short-link installer 500s, Site address/contact persistence, and the device Effective Config tab now showing warranty (and other) feature cards (#2002, #2001, #2003).
- Hardening — silent 0-row writes on four update/delete endpoints now surface as real errors instead of fake success (#2001).
Improved
- Quotes & invoices polish — Quote totals are computed from a single shared
computeQuoteTotalshelper, so the optimistic editing UI, per-line totals, and the right-rail "Live totals" can no longer disagree with each other or with the next server load, even at sub-cent rounding. Adds optimistic block/line reordering (debounced, with a duplicate-id guard protectingsort_order), a unified save/dirty-state model, and accessibility improvements (live regions, focus management, WCAG target sizing). No schema changes. (#2011)
Fixed
- Reliability scoring de-junk for macOS & Linux — extends the 0.85.0 Windows-only event-classification fix (#1967) to macOS and Linux: macOS IOKit/App Store chatter and
JetsamEventreports, and routine Linux kernel chatter (USB/ACPI), are no longer misclassified as hardware faults or device crashes. A server-sideisGenuineHardwareErrorgate at the scoring and offenders chokepoints means junk from historical data and from devices still on old agent binaries can't depress the hardware factor. Per-app crashes now count as a downweightedapp_crash— crash tiles still show every crash, but per-app crashes weight well below a BSOD/kernel panic in the score. Scores self-heal within hours via the existing recompute automation; no operator action required. (#2005) - Effective Config tab now shows warranty (and other) feature cards — the device Effective Configuration tab previously rendered a hardcoded list of 8 feature types and silently dropped the rest, so a device with a
warrantypolicy showed no warranty card (hiding the source of unexpected warranty alerts). It now renderswarrantyplus other baseline types; enforced features get full cards, and unassigned baselines collapse into a single "Not enforced — using Breeze Defaults" chip strip. Web device-detail page only. (#2003) - Public Windows short-link installer 500s (self-hosted) — on self-hosted 0.85.0, public Windows installer short links (
/s/<code>) returned HTTP 500 for every request: the public path creates a child enrollment key withcreatedBy: nulland the installer helper coerced it to"", invalid for the nullableuuidforeign key. Now passesnullthrough cleanly. Dashboard Direct Download and macOS short links were never affected. Self-hosters on 0.85.0 hitting this should upgrade. (#2002) - Site address & contact now persist — editing a customer Site (Settings → Organizations → site → Details) and clicking Save silently discarded the address/contact fields, because the page sent a flat field shape while the API stores nested JSONB and Zod stripped the unknown keys. Now maps flat ↔ nested on read and write. (#2001)
Security
- Silent 0-row write guards (defense-in-depth) — added explicit failure responses to update/delete handlers that previously returned
200 + nullon a 0-row write (an RLS rejection or post-SELECT race), which read to clients as a fake success:PATCH /orgs/sites/:id,PATCH /discovery/profiles/:id,POST /discovery/assets/:id/link,DELETE /monitors/:id. These tables already have RLS forced, so cross-tenant writes were already prevented — this converts a silent fake-success into a real error. (#2001)
Self-Hosting / Upgrade Notes
No breaking changes at runtime. The Astro 7 / Tailwind 4 / Vite 8 change is build-time only — production Docker images, the upgrade command, and runtime behavior are unchanged.
- Upgrade command. Bump
BREEZE_VERSION=0.86.0in.env, thendocker compose pull api web && docker compose up -d. If you build from source, run a freshpnpm installafter pulling — dependencies changed substantially (drops@astrojs/tailwind/postcss/autoprefixer; adds@tailwindcss/vite+tailwindcss@4; Astro/Vite/adapter major bumps). Build commands are unchanged (astro build/astro previewwork as before). Node pin is unchanged (v22.20.0). - Database — nothing required. No migrations in this release.
- No new required environment variables.
- Behavior changes & feature flags. No feature flags added. Two server-side scoring/UI behaviors changed, both self-applying with no per-org opt-in or grandfathering: reliability scores recompute to exclude misclassified macOS/Linux events (self-heals within hours, #2005), and the Effective Config tab's layout/counts changed to surface all enforced feature types (#2003).
Full Changelog: v0.85.0...v0.86.0
What's Changed
- docs: sync technical docs for v0.85.0 by @ToddHebebrand in #2000
- fix(web): persist site address & contact on the Site Detail page (+ silent-write hardening) by @ToddHebebrand in #2001
- fix(api): public Windows short-link installer 500s on null-creator child key by @ToddHebebrand in #2002
- fix(web): render warranty (and other) feature cards on device Effective Config tab by @ToddHebebrand in #2003
- fix(reliability): finish #1967 de-junk — macOS/Linux classifier + server-side hardware gate + weak app-crash signal by @ToddHebebrand in #2005
- build(portal): migrate to Tailwind 4 by @ToddHebebrand in #1991
- build(web): migrate to Tailwind 4 by @ToddHebebrand in #1995
- build: upgrade to Astro 7 + Vite 8 (both apps) by @ToddHebebrand in #2008
- docs: Astro 7 / Tailwind 4 / Vite 8 visual regression baseline by @ToddHebebrand in #2009
- Polishing quotes & invoices (rebased onto Tailwind 4) by @ToddHebebrand in #2011
Full Changelog: v0.85.0...v0.86.0
v0.85.0
Breeze RMM v0.85.0 — a feature release: one-click Huntress & SentinelOne EDR deployment, a Software Deployment automation action, a "Breeze Defaults" config-policy baseline, billing/catalog polish (markup defaults, catalog images, quote line editing, tax precision), and a substantial reliability-scoring overhaul that makes fault scores actually discriminate between healthy and unhealthy devices.
Summary
- EDR deployment — built-in Huntress & SentinelOne deployment packages: push the EDR agent to a device from Breeze instead of hand-rolling an installer (#1957).
- Automations — a new Software Deployment action type, so automations can install software as a step (#1981).
- Config policy — a virtual "Breeze Defaults" baseline that every policy inherits from, so you can see and override the shipped defaults (#1725).
- Billing & catalog — partner markup defaults, catalog item images, inline quote-line editing, and a tax-rate precision fix (#1960).
- Reliability — fault scoring is now rate-normalized by observed up-days and no longer saturates, plus the agent correctly classifies Windows events instead of mislabeling DCOM timeouts as crashes and the whole System log as "hardware" (#1989, #1967).
- Alerting — metric alerts average across the window instead of requiring every sample, and config-policy offline rules honor their per-rule duration (#1988, #1992).
Added
- Built-in Huntress & SentinelOne deployment packages — deploy the EDR agent to devices directly from Breeze (#1957)
- Software Deployment automation action — install software as an automation step (#1981)
- Config-policy "Breeze Defaults" baseline — a virtual baseline policy showing the shipped defaults, inheritable and overridable (#1725)
- Billing/catalog: partner markup defaults, catalog item images, inline quote-line editing (#1960)
- Agent self-heal: an AI tool that restarts a wedged agent via the watchdog (#1966)
- Devices: a unified default sort for the merged Devices list (#1424)
Improved
- Reliability scoring is far more accurate — scores are rate-normalized by observed up-days and de-saturated, so a device with 14 faults no longer scores the same as one with 1,400; and the agent now classifies Windows events correctly (DCOM timeouts are no longer counted as crashes, and the System log is no longer blanket-tagged "hardware") (#1989, #1967) — scores will shift once the new agent is promoted; see upgrade notes
- Metric alerts average across the evaluation window instead of firing only when every sample breaches (#1988)
- Config-policy offline alert rules honor their per-rule duration and cap it at the re-eval horizon (#1992, #1996)
- Agent-update maintenance window is now a structured, validated field instead of free text (#1963)
- Patches page tab state moved to
#hash— back button and shareable links work (#1977)
Fixed
- Tax-rate precision: tax rates are stored at
numeric(8,5)so fractional rates round-trip correctly (#1960) - Onboarding: the "add your first site" nag is suppressed once an org already has a site (#1978)
- Auth:
/auth#signupis gated on the runtime registration flag (#1979) - Billing: corrected tooltip on the disabled Record payment button (#1975)
- Installer: MSI filename-bootstrap token uses parentheses, not brackets, so it survives MSI's Formatted-field parsing (#1956)
- Self-hosting compose:
CLIENT_AI_ENTRA_CLIENT_IDis mapped into theapiservice; removed a stalepostcss.config.mjsbind mount from the dev stacks (#1972, #1999)
Security & Privacy
- Scrubbed real customer device data from tracked files (#1968); suppressed documented pnpm install-time CVEs in Trivy with rationale (#1970); enabled the
DB_CONTEXTLESS_WRITE_STRICTcheck suite-wide to catch un-scoped DB writes in CI (#1828).
Self-Hosting / Upgrade Notes
Standard upgrade — bump BREEZE_VERSION, then docker compose pull api web && docker compose up -d (run pnpm install if you build from source).
- Database — applies automatically, nothing required. 8 new idempotent migrations apply on boot (
autoMigrate, unlessAUTO_MIGRATE=false): software-catalog partner axis + built-in-catalog partner-read RLS, S1 org-mappings registration token, Huntress deploy account key (stored encrypted, not an env var), partner auto-tax/hardware + default markup, catalog item images, and a tax-rate precision change (ALTER COLUMN … TYPE numeric(8,5)on the small tax-rate tables — instant, no large-table rewrite or backfill). - No new required environment variables. If you run Breeze AI for Office, note that
CLIENT_AI_ENTRA_CLIENT_IDis now mapped into theapiservice in the compose file (#1972) — set it in.envif you use that feature; it's optional and defaults to empty otherwise. - Behavior change — reliability scores will move (#1967, #1989). Once you promote the new agent, Windows event classification and the scoring formula both change, so device reliability scores will look different (generally more spread out and more accurate). This is expected — it's a correctness fix, not a regression. Until the agent is promoted, behavior is unchanged.
- No breaking changes.
Full Changelog: v0.84.0...v0.85.0
What's Changed
- fix(installer): use parens for MSI filename-bootstrap token, not brackets (#1956) by @ToddHebebrand in #1959
- docs: sync technical docs for v0.84.0 by @ToddHebebrand in #1955
- feat(billing): markup defaults, tax precision fix, catalog images, quote editing by @ToddHebebrand in #1960
- feat(config-policy): virtual "Breeze Defaults" baseline (#1725) by @ToddHebebrand in #1958
- feat(agent): AI tool to restart a wedged agent via the watchdog by @ToddHebebrand in #1966
- feat: built-in Huntress & SentinelOne deployment packages by @ToddHebebrand in #1957
- fix(reliability): correct agent event classification + de-saturate the score by @ToddHebebrand in #1967
- chore(security): suppress pnpm install-time CVEs in Trivy (documented) by @ToddHebebrand in #1970
- chore(privacy): scrub real customer device data from tracked files by @ToddHebebrand in #1968
- chore(ci): enable DB_CONTEXTLESS_WRITE_STRICT suite-wide (#1828) by @ToddHebebrand in #1929
- fix(compose): map CLIENT_AI_ENTRA_CLIENT_ID into api service (#1972) by @ToddHebebrand in #1974
- docs(testing): salvage 2026-06-15 UI QA sweep records by @ToddHebebrand in #1973
- test(web): cover org-scope toggle on DeviceStatusChart + MonitoringIntegration by @ToddHebebrand in #1971
- fix(alerts): average metric window instead of requiring every sample (#1980) by @ToddHebebrand in #1988
- fix(alerts): honor per-rule duration for config-policy offline rules (#1982) by @ToddHebebrand in #1992
- feat(reliability): rate-normalize fault scoring by observed up-days (#1908 a+b) by @ToddHebebrand in #1989
- fix(alerts): cap config-policy offline-rule duration at the re-eval horizon (#1982 follow-up) by @ToddHebebrand in #1996
- fix(web): structured, validated agent-update maintenance window (#1963) by @ToddHebebrand in #1990
- feat(automations): Software Deployment action type (#1981) by @ToddHebebrand in #1997
- test(web): pin #1976 — partner-settings save surfaces Zod field message by @ToddHebebrand in #1987
- test(web): lock single-emit toast invariant; #1301 verified dev-only (#1301) by @ToddHebebrand in #1993
- fix(web): tooltip on disabled Record payment button (#1975) by @ToddHebebrand in #1983
- fix(web): gate /auth#signup on runtime registration flag (#1979) by @ToddHebebrand in #1985
- fix(web): migrate Patches page tab state to #hash (#1977) by @ToddHebebrand in #1984
- feat(web): unified default sort for the merged Devices list (#1424) by @ToddHebebrand in #1994
- fix(web): suppress "add first site" nag when org already has a site (#1978) by @ToddHebebrand in #1986
- fix(compose): drop non-existent postcss.config.mjs bind mount from dev stacks by @ToddHebebrand in #1999
Full Changelog: v0.84.0...v0.85.0
v0.84.0
Breeze RMM v0.84.0 — a feature release: catalog/quoting gets distributor + Pax8 + AI assists, billing gains bulk actions, an EDR operations surface (SentinelOne + Huntress) lands behind a flag, native ticket auto-replies & canned responses, a working HTTP network proxy, plus reliability, patching, and broad API security hardening.
Summary
- Quoting & catalog — inline TD SYNNEX EC Express price/availability lookup in the quote editor (#1922), a Pax8 subscription → contract-line picker (#1924), and AI auto-fill for new catalog items from a product name or SKU (#1942).
- Billing — bulk actions across quotes, invoices, and contracts, plus draft delete from the detail view (#1926).
- EDR operations (preview) — SentinelOne + Huntress threat/incident surfacing across the fleet, behind a feature flag (#1946).
- Ticketing — customizable auto-reply and reusable canned responses (#1931).
- Networking — a working HTTP reverse Network Proxy with a reworked discovery asset modal (#1913), and per-session TLS verification for the tunnel proxy (#1916).
- Endpoint management — Windows USB blocking enforcement with no kernel driver (#1871), MSI filename-bootstrap enrollment for Windows parity (#1902), and per-device config-policy compliance shown on the device detail page (#1895).
- Reliability & patching — saner reliability scoring (capped counts, age-aware windows, offender drill-down, de-duplicated events) and patch-list/update-ring fixes.
- Security hardening — a cluster of API authorization, session-revocation, and secrets-at-rest improvements.
Added
- Inline TD SYNNEX EC Express price & availability lookup by SKU inside the quote editor (#1922)
- Pax8 subscription → contract-line picker: link, change, pause, and unlink (#1924)
- AI catalog auto-fill — draft a new catalog item's fields from a product name or SKU (#1942)
- Stripe payment keys now live in Integrations → Payments instead of buried in billing settings (#1954)
- Billing bulk actions on quotes / invoices / contracts, plus draft delete on the detail view (#1926)
- EDR operations (preview) — SentinelOne + Huntress threats/incidents across the fleet, behind a feature flag (#1946)
- Ticket auto-reply + canned responses — customizable templated replies with merge variables (#1931)
- Network Proxy — working HTTP reverse proxy, with a reworked discovery asset modal (#1913)
- Windows USB blocking enforcement — no kernel driver required (#1871)
- Per-device config-policy compliance section on the device detail page (#1895)
- MSI filename-bootstrap enrollment for Windows installer parity (#1902)
- Reliability card: offender drill-down with age-aware windows and capped alarming counts (#1907, #1921)
- Viewer: interactive update prompt instead of a silent auto-close (#1909)
Improved
- PAM: UAC interception now defaults to opt-in for new orgs; existing active orgs are grandfathered to their current behavior (#1914) — see upgrade notes
- Remote Tools shows all services and has reliable Close / Back navigation (#1911)
- Tunnel proxy now does per-session TLS verification with an explicit scheme (#1916)
- Software Library loads correctly in "All Orgs" mode (aggregates across accessible orgs) (#1938)
- Network Changes has a clearer empty state that points to creating a discovery profile (#1940)
- Background sync/scheduler work split out of DB transactions to reduce connection pressure during S1 sync and patch scheduling (#1919)
Fixed
- Patches: selecting an update ring no longer collapses the patch list to 50 items (#1897)
- Patches: duplicate identical "Default" update rings are de-duplicated (#1939)
- Reliability: stopped ~1.37× count inflation from events double-counted across the window (#1904, #1905); agent now persists its reliability send cadence across restarts (#1912)
- Config Policy: Monitoring tab rendering fixed (no more invalid nested controls) (#1937)
- Catalog: the item drawer blocks saving a bundle when the detail load fails (prevents wiping components) (#1944, #1947); enrichment attributes are shape-validated on create (#1945, #1948)
- Peripherals: stop shipping an empty policy set on an enqueue-before-commit race (#1882)
- Database: partner-scope ring/approval migrations are now safe to re-run (#1941)
Security
- Hardening across the API: additional authorization/authentication gates (RBAC, step-up, signing capabilities), fail-closed mid-session revocation for the tunnel and event WebSockets, tighter cross-org/partner access boundaries, and webhook URLs encrypted at rest and masked on read (#1887, #1888, #1890, #1891, #1892, #1893). Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Standard upgrade — bump BREEZE_VERSION, then docker compose pull api web && docker compose up -d (run pnpm install if you build from source).
- Database — nothing required. 7 new idempotent migrations apply automatically on boot (
autoMigrate, unlessAUTO_MIGRATE=false): ticket response templates, tunnel per-session TLS verification, the partner-scope update-ring/approval guards + default-ring de-dup, installer bootstrap-token platform column, and the PAM UAC opt-in grandfathering. No large-table rewrites or backfills. - Behavior change — PAM UAC interception (#1914): new organizations default to opt-in for UAC interception. Organizations already active keep their existing behavior (grandfathered). If you rely on UAC interception for a newly-created org, enable it explicitly.
- EDR operations is a preview behind a flag. It's gated by the web build-time flag
PUBLIC_ENABLE_EDR_INTEGRATIONS(off by default). With it off, the fleet EDR pages and dashboard summary are hidden. No server env vars are required for the rest of the release. - No new required environment variables.
Full Changelog: v0.83.3...v0.84.0
What's Changed
- fix(api): block cross-tenant destructive DR command injection by @ToddHebebrand in #1888
- fix(api): close cross-org/partner app-layer allowlist gaps by @ToddHebebrand in #1887
- fix(api): add missing authz/authn gates (security RBAC, step-up, signing caps) by @ToddHebebrand in #1890
- fix(api): fail-closed mid-session revocation for tunnel + event WS by @ToddHebebrand in #1891
- fix(api,secrets): encrypt webhook URLs at rest + mask on read by @ToddHebebrand in #1893
- fix(api,ai): AI approval arg-match, device-memory site auth/injection, notif encryption by @ToddHebebrand in #1892
- fix(api): enforce app-layer site axis on reads + PAM rule writes by @ToddHebebrand in #1889
- feat(policies): per-device config-policy compliance route + device-detail section (#1876) by @ToddHebebrand in #1895
- test(api): raise timeout on flaky mcpServer effectiveTier site-axis test by @ToddHebebrand in #1900
- fix(test): treat file-level use('*', requirePermission) as a live perms source by @ToddHebebrand in #1901
- fix(patches): stop ring selection collapsing the patch list to 50 by @ToddHebebrand in #1897
- test(api): raise timeout on flaky mcpServer C4 site-axis alerts test by @ToddHebebrand in #1903
- fix(reliability): dedup events across window to stop ~1.37× count inflation (#1904) by @ToddHebebrand in #1905
- feat(viewer): interactive update prompt instead of silent auto-close by @ToddHebebrand in #1909
- fix(agent): persist reliability send cadence across restarts (#1906) by @ToddHebebrand in #1912
- fix(peripheral): stop shipping empty policies[] on enqueue-before-commit race (#1879) by @ToddHebebrand in #1882
- docs(billing): spec QuickBooks Online accounting integration (Xero follow-on) by @ToddHebebrand in #1885
- feat(agent): Windows USB blocking enforcement (no kernel driver) by @ToddHebebrand in #1871
- test(api): fix userDeleteResurrect 403 after #1887 partner-mgmt gate by @ToddHebebrand in #1915
- fix(pam): default UAC interception to opt-in; grandfather active orgs by @ToddHebebrand in #1914
- perf(agent): cut redundant Windows collection — batch hardware WMI, daily hardware/patch scans by @ToddHebebrand in #1910
- fix(web): show all services + reliable Close/Back in Remote Tools by @ToddHebebrand in #1911
- feat: working Network Proxy (HTTP reverse proxy) + discovery asset-modal UX rework by @ToddHebebrand in #1913
- fix(api): phase-split s1Sync + patchScheduler conn-holds (#1896) by @ToddHebebrand in #1919
- docs(issue-to-pr): prevent duplicate PRs when fanning out issue-fixers by @ToddHebebrand in #1920
- docs: sync technical docs for v0.83.1–v0.83.3 by @ToddHebebrand in #1899
- feat(installer): MSI filename-bootstrap enrollment (Windows parity) by @ToddHebebrand in #1902
- feat(reliability): cap alarming counts, age-aware windows, offender drill-down (#1907) by @ToddHebebrand in https://github.com/Lanter...
v0.83.3
Breeze RMM v0.83.3 — the current stable hotfix. It fixes the root cause of database connection-hold during patch/deploy, trims Sentry quota/noise, and repairs auto-update of the Windows user-helper for self-hosted servers.
Summary
- Patch/deploy connection-hold root cause fixed (#1894) — continues the #1105 work; reduces database connection pressure during patch and deploy runs, plus Sentry quota/noise reduction.
- Windows user-helper auto-update repaired (#1881, #1884) —
breeze-user-helpernow ships with anasInvokermanifest and is served from a server-relative download URL, fixing a regression where the helper couldn't update. - Tickets — selectable & editable requester, with a clickable device link. (#1883)
- Devices — the reboot-pending dot no longer wraps under the "Down" pill. (#1886)
Self-Hosting / Upgrade Notes
Standard upgrade — bump BREEZE_VERSION, then docker compose pull api web && docker compose up -d. No new migrations, no new environment variables, and no compose changes. Recommended for everyone on the v0.83.x line.
- Patch/deploy connection pressure (#1894). Root-cause fix for connection-hold during patch/deploy operations — the last major piece of the #1105 connection-exhaustion work. Worth taking if you run patching at scale or have seen "too many clients" during deploys.
- Self-hosted user-helper auto-update (#1881, #1884). Earlier builds served
breeze-user-helperfrom an absolutegithub.comdownload URL thatdownloadFromURLrejected on self-hosted servers, so the helper couldn't update; it now has its own server-relative/download/user-helperroute and ships with anasInvokermanifest. If you self-host and saw user-helper update failures, this fixes them. (This is the user-helper sibling of the agent download-URL fix — not the Tauri Helper desktop app.)
What's Changed
- fix(agent,windows): ship breeze-user-helper with asInvoker manifest (#949 regression) by @ToddHebebrand in #1881
- feat(tickets): selectable + editable requester, clickable device link by @ToddHebebrand in #1883
- fix(api): serve breeze-user-helper from a server-relative download URL (#1878) by @ToddHebebrand in #1884
- fix(devices): stop reboot-pending dot wrapping under Down pill by @ToddHebebrand in #1886
- fix(api): patch/deploy conn-hold root cause + Sentry quota/noise fixes (0.83.3) by @ToddHebebrand in #1894
Full Changelog: v0.83.2...v0.83.3