Breeze RMM v0.128.0: customer portal sign-up options (portal access from Contacts, an access-request queue, per-organization sign-in rules, Sign in with Microsoft and customer domain verification), Wisp check-ins that wait for an event and standing instructions Wisp keeps to, installer uploads to partner-wide software packages, and an authenticator app as a backup beside a passkey.
⚠️ Breaking change: breeze-agent enroll --site-id is removed. A hand-written install script that still passes the flag now fails. Drop the flag. Installers generated by Breeze are not affected. See Self-Hosting / Upgrade Notes.
Summary
- ⚠️
breeze-agent enroll --site-idis removed (#11543). The flag has been ignored since v0.123.0, because the site comes from the enrollment key. Passing it now stops the enrollment with--site-id was removed: the site now comes from the enrollment key, so drop the flag from your script. - Customer portal sign-up options, first release (#11377: #11405, #11408, #11528, #11523, #11557, #11568, #11577, #11576).
- Portal access from Contacts. The organization Contacts tab has a Portal column, Give portal access and Resend invite row actions, a bulk "Give portal access (N)" action, and a checkbox on the create form. The portal login is bound to the contact.
- Sign-in & registration rules. Set a partner default in Partner settings → Customer portal and override it per organization on the organization's Customer Portal tab. A blank field inherits and shows where the value comes from.
- Access requests. A queue above the portal users list shows people waiting for portal access. Approve or deny them one at a time or in bulk; the requester gets an email either way.
- Sign in with Microsoft, where configured. Customers can sign in to the portal with their Microsoft work account once the server has a portal Entra app (
PORTAL_ENTRA_CLIENT_IDandPORTAL_ENTRA_CLIENT_SECRET) and the organization's Microsoft tenant is proven. An organization can set a session length for Microsoft sign-ins and can turn passwords off; the save shows which accounts could not sign in afterwards and asks for confirmation. - Customer domain verification. The new Organization → Domains tab is the one place for a customer's email domains. Verify a domain with a DNS TXT record, the organization's proven Microsoft tenant or its Google Workspace directory. Breeze re-checks each proof about once a day. Ticketing → Email now shows a read-only summary with a link to this tab.
- Still to come: self-registration by verified email domain, Sign in with Google, and directory-driven provisioning. Nothing acts on a verified domain yet.
- Wisp check-ins, event waits and standing instructions (Breeze Cloud only,
BREEZE_WISP_ENABLED; #11489, #10991: #11312, #11525, #11571, #11524, #11570).- Check-ins on the thread. The thread shows the check-ins Wisp has scheduled, with Cancel, and a fired check-in has Run now.
- Wait for an event. A check-in can fire when a device comes online, a script or device command finishes, or an agent run settles. Each has a deadline (24 hours by default, 7 days at most). If the event has not happened by then, the check-in fires anyway and says so.
- Check on its own. A check-in can be scheduled to run one read-only assessment of one organization when it fires and post what it found. Scheduling one always asks for approval, because it spends the grant's budget while nobody is watching.
- Standing instructions. When a chat message gives a standing instruction such as "don't reboot PC-01", a chip under the reply offers Keep, Keep for everyone at <org> and Forget. Once kept, Wisp refuses to propose an action that breaks an unconditional "don't" on a named device. An instruction with a condition, or one not kept yet, shows a red banner on the approval card and always asks for approval.
- Upload installers to partner-wide software packages (#11412: #11462, #11484). A full-partner admin uploads an installer once to a partner-wide package, including the built-in SentinelOne package, and every organization can use it. A version saved with blank install arguments on a built-in integration package gets the package's own template.
- Authenticator app as a backup beside a passkey (#11420: #11471, #11486). An account whose main second factor is a passkey can add an authenticator app in Settings → Profile → Multi-factor authentication, sign in with it when the passkey is not to hand, use it to add or remove passkeys, and remove it again. The passkey stays the main factor and recovery codes are not changed.
Added
- New remote access tool alerts (#11331). When a device's management scan finds a known remote access or RMM tool that its previous scan did not have, Breeze raises a built-in alert on the device (New remote access tool on HOST: …, medium, or New RMM agent on HOST: …, info). A device's first scan is the baseline and raises nothing. Each tool gets its own rule per organization under Alerts → Monitors → Built-in alerts; switch a rule off for a tool you use. The agent also detects six more remote support tools. See Behaviour changes.
- Pick a remote tool from Connect Desktop (#11261). The Connect Desktop button is now a split button. The main part does what it did before; the arrow lists the other remote tools enabled for the device, plus the built-in viewer.
- Pax8 suggested matches and bulk review (#11511). Unmapped Pax8 companies show a suggested organization from a name matcher that ignores case, accents, punctuation and legal suffixes such as Inc, LLC and GmbH. Review and map up to 200 in one step.
- UniFi (#11520): every site mapping change and controller registration is written to the audit log, the sync history shows an Unmapped sites count, and the self-hosted controller picker is relabelled Collector agent location with help text.
- Connection Health: Sync stalled for DNS filter integrations and Microsoft 365 tenant sync. An integration whose sync stopped advancing no longer reads as healthy (#11537).
- Trend Micro is recognised as an antivirus provider (Apex One, Worry-Free, Vision One) instead of showing as "other". Needs the 0.128.0 agent. Not lab-verified; see Known gaps (#11435).
- Wisp (Breeze Cloud only): the grant's daily budget now counts chat as well as background work, and the spend meter shows both (#11512). The chat shows "Waiting for your approval", including when the request went to your phone or to another approver (#11530). Wisp's standing state is refreshed during a chat (#11521). "Go through the open alerts" from chat starts a real assessment (#11522). Similar device concerns in one organization are grouped (#11519). Wisp can start a Fleet Design run under a grant; apply and rollback stay refused (#11517). A reply that promises something Wisp did not dispatch is caught (#11574).
- Billing API:
POST /invoices/:id/paymentsaccepts anIdempotency-Keyheader (oridempotencyKeyin the body), so a retried manual payment lands once (#11409). - Vendor updates (Dell, Surface, HP, Lenovo): still switched off. A
Vendor update: run failingbuilt-in alert rule, a faster fleet view, and device-page states that use the Patches tab's names (#11275, #11468, #11268, #11337).
Improved
- AI approval mode has its own home. Partner → AI Approvals (renamed from "AI Approval Timeout") now holds Approval Mode next to the timeout, instead of inside the AI budget settings (#10988).
- AI chat:
- A chat starts faster, because the tool definitions are built once per process instead of once per session (#11045).
- A chat that has been idle for 2 hours, or is older than 24 hours, now shows as expired when you open it instead of failing on the first message; a 15-minute sweep retires the rest (#11466).
- A patch install across several organizations is refused with the list of organizations to split by (#11340).
- A write with no clear owner is refused with the fix, before an approval card is filed (#11465).
- Two read actions that were wrongly refused now work (#11437).
- Ten paper cuts across AI, Wisp and MCP (#11341).
- Wisp (Breeze Cloud only) spends less and says less that is stale. It skips a scheduled look at an organization where nothing changed (#11472) and runs a watch only when its results change (#11473). Concerns close when their alert resolves (#11463). The morning brief counts open high-severity concerns as needing you (#11469). The readiness note is re-checked on every run (#11518). Metric anomalies reach the assessment (#11470). Wisp is offered only the tools its grant allows (#11342).
- Backup:
- Snapshot listings include empty folders and symlinks (#11467).
- Browsing is at full speed straight after a large file list is built (#11352).
- Storage cleanup and the reconcile job now read snapshot manifests over 200 MiB instead of skipping them (#11330).
- The agent reads a snapshot manifest as a stream on restore and verify, so a very large snapshot no longer needs the whole manifest in memory (#11339).
- Backup verification and test restore run on their own lane in the agent, so a long verification no longer holds up scripts and monitors (#11359).
- Backup page paper cuts (#11334). The Cove credential form matches what the connection needs, and credentials can be rotated at any time (#11343).
- Ticket workspace: status, SLA and internal-note text meets WCAG AA contrast in both themes, and the ticket queue works from the keyboard (
j/kto move,xto select) (#11567). - Security pages say why. Isolation refusals, the Microsoft 365 mailbox card, EDR and coverage statuses now give the reason (#11336).
- Partner settings: a field that can lock organizations reads Locks orgs when set until a partner value is saved (#11534).
- Migrations at boot:
- A starting API waits for the migration lock for 5 minutes by default (
MIGRATION_LOCK_TIMEOUT_MS), logs which database session holds it, then exits so the container restarts. Before, it waited forever with nothing in the log (#11388). - The whole migration set applies on a database owned by a role that is neither a superuser nor
BYPASSRLS(#11345).
- A starting API waits for the migration lock for 5 minutes by default (
- Boot check: with
TRUST_PROXY_HEADERSon, the API logs one[proxy-trust]warning when noTRUSTED_PROXY_CIDRSentry overlaps a network it is attached to. It never stops startup (#11585). - Worker split and multi-process groundwork: the optional
workerservice can be scaled (--scale worker=N); command relay, cache invalidation and command-result tracking now work across processes (#11366, #11390, #11516, #11373, #11361, #11356). A large number of agents disconnecting at once no longer pushes the API into load shedding (#11351). The shipped Compose files still run one API. - Monitoring overlay: the images in
docker-compose.monitoring.ymlare updated and pinned by digest. See Behaviour changes (#11355).
Fixed
- More built-in alerts send notifications (#11346, #11372). Log correlation alerts, DNS threat alerts, two AI agent attention alerts, automation and flow Create alert actions and metric anomaly alerts appeared on the Alerts page but could miss notification channels, routing rules and escalations. They now send like every other alert. See Behaviour changes.
- Remote desktop (Windows agent):
- The Windows sign-in screen is captured instead of a black frame (#9583, #11407).
- A session starts on the Windows built-in H.264 encoder when OpenH264 cannot load, instead of being refused, and the picture stays current on a static screen (#11399, #11636).
- Held Shift, Ctrl and Alt keys are no longer left stuck, and Release stuck keys works (#9687).
- Copied images reach the viewer (#11391).
- Agent (Windows): Breeze Assist is started directly, so the agent tracks the real Assist process (#11545). The watchdog reports its own edition, so it is offered the right update (#11371).
- Network Proxy host mode: the device page loads in the dashboard frame (#11403), and a device's own login form no longer gets
403 Cross-site request blocked(#11536). - Reports:
- Portal report PDF downloads, scheduled report delivery and fleet-design documents no longer fail with a 500 (#11191).
- The Excel download of a stored SLA performance run includes the Breaches and Notes sheets. This was the known issue in v0.127.0 (#11304).
- The staff SLA performance CSV has labelled headers (#11338).
- Editing a saved custom report keeps its columns, filters and chart instead of saving defaults over them (#11533).
- The SLA performance template no longer opens on a notice about a choice you cannot make (#11474).
- Billing: the overdue sweep no longer marks an invoice overdue after it was paid or voided (#11402). Checkout refuses a balance the invoice currency cannot express, with
409 BALANCE_NOT_REPRESENTABLE(#11410). - Patching: installed updates show their install date where the operating system records one (Windows Update, Apple, winget, Chocolatey), and a later scan no longer clears it. Needs the 0.128.0 agent (#11539).
- UniFi, self-hosted controllers: a device or client on a controller site that is not mapped to a Breeze site is no longer filed under the collector agent's organization. The same client MAC at two sites of one controller is now two rows. See Behaviour changes (#11514).
- Microsoft 365 sign-in events sync returns its first page and recovers from Graph timeouts (#11546).
- MCP and OAuth clients: two processes sharing one stored credential no longer lose the connection when both refresh at the same moment (#11547).
- Enrollment: a device enrolling while its first inventory arrives no longer fails on a database deadlock (#11347).
- Configuration policies: saving the Backup tab keeps a custom retention instead of filling the missing fields from the Standard preset (#11324).
- Event logs: one event with a very long source name no longer loses the rest of its batch (#11322).
- Errors: more best-effort database steps give their intended answer instead of a 500 or a failed job. A restore that could not be dispatched is now marked failed, with a fixed message (#11260).
- Self-hosted
BINARY_SOURCE=localwith the official manifest staged: agent upgrades no longer stall on the backup component, and Breeze Assist updates are no longer refused (#11305). - Portal: a mixed-case email address is treated as the same login by both invite paths (#11540).
- Web: pages no longer trip the content security policy when building form validators (#11544). Software rule label, New folder name validation, slug error and trend timestamps (#11335). Seventeen small fixes from the pre-release sweep, including the Software Library version form on built-in packages and toasts that hid a partly failed bulk invite (#11608).
- Other: fix-memory outcomes are corrected when a late result arrives (#11360). A malformed stored setting is logged once an hour instead of on every read (#11362). Two command paths no longer hold database row locks while waiting on Redis (#11357, #11369).
Security
Security — hardening
This release has no security advisory. Routine hardening:
- customer portal accounts: invite and password-reset links are single use and tied to their purpose and to the account's current state, a failed sign-in gets one uniform answer, and a reset is refused for a disabled account (#11408). Both invite paths compare email addresses the same way (#11540);
- multi-factor authentication cannot be switched off while a passkey remains on the account, and no unused authenticator secret is kept when it is switched off (#11471);
- software upload sessions are authorised against the session's own owner (#11462);
- AI: a write with no clear owner is refused before an approval is filed (#11465), and a Wisp session is offered only the tools its grant allows (#11342);
- UniFi: inventory from a self-hosted controller is filed only under sites that are mapped (#11514);
- deployment: the migration set runs as a non-superuser owner without
BYPASSRLS(#11345), and the API warns at boot about a proxy trust setting that matches no attached network (#11585); - supply chain: monitoring overlay images are pinned by digest (#11355), the Stripe library is pinned to an exact version (#11401), and advisory exceptions for the
ziplibrary are removed now that the updater uses a fixed version (#11365).
Self-hosters are encouraged to upgrade.
Self-Hosting / Upgrade Notes
Upgrade command. Check how your install pins its images: grep '^BREEZE_API_IMAGE_REF=' .env.
- Digest-pinned (the value ends in
@sha256:…, which is everyguided-setup.shinstall from v0.112.0): fetch the currentguided-setup.shfrommain, then runbash guided-setup.sh --upgrade 0.128.0. It verifies the signed image inventory and updatesBREEZE_VERSIONand all four image digests together, then pulls and restarts. - Tag-form (the value ends in
:${BREEZE_VERSION}): setBREEZE_VERSION=0.128.0, then rundocker compose pull api web portal && docker compose up -d(andpnpm installif you build from source). If you run the optionalworkercontainer, pull and restart it too. - Do not edit only
BREEZE_VERSIONon a digest-pinned install. That re-pulls the images you already run. - If you roll services one at a time, update the API before the web and portal containers. The new Contacts, Customer portal, Domains and Software Library screens call routes the old API does not have.
- If you run the optional
workercontainer, update it together with the API. While one runs the old build and the other the new one, commands relayed between them fail; this ends when both run v0.128.0 (#11390). --upgradedoes not change yourdocker-compose.yml. To pick up this release's new Compose mappings (listed under Environment variables), take the v0.128.0docker-compose.yml/deploy/docker-compose.prod.yml, or add the lines to the service'senvironment:block yourself. A value that is only in.envdoes not reach the container.- See the Upgrade Guide.
⚠️ Breaking change.
breeze-agent enroll --site-idis removed (#11543).- What breaks:
breeze-agent enrollexits with--site-id was removed: the site now comes from the enrollment key, so drop the flag from your script. - Who is affected: anyone with a hand-written install or deployment script (RMM migration script, GPO, Intune, shell wrapper) that passes
--site-idto the 0.128.0 agent. Installers and commands generated by Breeze stopped passing it in v0.123.0. - What to do: remove the flag. The site comes from the enrollment key, as it has since v0.123.0. There is no opt-out.
- What breaks:
No other breaking changes for an install on default settings. If you integrate with the API, check these before you upgrade:
- Portal sign-in and invites (#11408). Portal login no longer answers
400 Multiple portal accounts found; every failed sign-in is401 Invalid email or password. Accept-invite answers400 Invalid or expired invitefor a disabled or already-set-up account. Setting an invited portal user toactivethroughPATCH …/portal-users/:idanswers 409, because only accepting the invite activates it. Newcodevalues appear on existing 409s (PORTAL_USER_IDENTITY_MANAGED,PORTAL_ACCOUNT_TRANSITION_REFUSED). POST /orgs/organizations/:id/portal-users/inviteaccepts an optionalcontactId. The invite email must match the contact's (PORTAL_INVITE_EMAIL_MISMATCH), and a login bound to another contact is not re-pointed (PORTAL_INVITE_CONTACT_CONFLICT). NewPOST …/portal-users/invite-contactsinvites up to 100 contacts and returns one outcome per contact (#11405)./mfa/disableanswers 409 while the account still has a passkey (#11471).- Software upload sessions: a session the caller cannot see answers 404 where a forbidden
?orgIdused to answer 403. Upload sessions on a partner-wide package ignore?orgId, and partner users with selected-organization access get 403 (#11462). GET /ai/sessions/:idcan now returnstatus: 'expired'for an idle session (#11466). Theapproval_requiredstream event gains two optional fields,pushedToPhoneandwaitingOn(#11530).- Database and VM restore dispatch failures return a fixed message instead of the raw error text (#11260).
- Checkout can answer
409 BALANCE_NOT_REPRESENTABLE(#11410). - Remote launch accepts an optional
providerId, which only selects among the providers already enabled (#11261).
Database.
- 21 migrations. They are idempotent and apply automatically on first API boot via
autoMigrate, unlessAUTO_MIGRATE=false. Expect[auto-migrate] Applied 21 migration(s)from v0.127.0. The set was verified to apply as a non-superuser role. No shipped migration was modified, renamed or removed. - None touches the large device or audit tables. Three are worth knowing about:
2027-01-22-230200-portal-account-foundations(#11408) backfills every row ofportal_users, a small table. A portal user whose status is not one of invited, active or disabled is set to disabled and their sessions are ended. It also createsportal_user_identitiesand copies existing Microsoft identities into it.2027-01-22-233400-wisp-standing-instruction-capture(#11524) replaces a CHECK constraint on the AI egress events table (llm_egress_events). That is one scan of the table under an exclusive lock. On an install with a long AI history, expect AI requests to wait for a moment during the upgrade.2027-01-22-231400-unifi-clients-site-identity(#11514) adds a column tounifi_clientsand builds a unique index on it withoutCONCURRENTLY, then drops the old index. Until the old API process is replaced, its UniFi client writes fail; the cost is at most one telemetry poll per collector, and the job is retried.
- New tables enable and force row-level security in the file that creates them:
portal_user_identities,portal_access_policies,portal_access_requestsanddevice_oem_policy_side. - Other additions are new nullable columns, columns with a constant default, CHECK constraints on small tables and ordinary indexes:
wisp_check_ins(seven columns over two files; existing rows become time-basednotifycheck-ins),wisp_watches,software_upload_sessions.partner_id,invoice_payments.idempotency_key,oauth_refresh_tokens,devices.watchdog_edition,backup_snapshot_files.kind,unifi_sync_runs.sites_unmapped,customer_email_domainsandclient_ai_tenant_mappings. Every file that writes rows elects system scope first. - One-way changes: the
security_providerenum gainstrend_micro(#11435), and the oldunifi_clientsunique index is dropped (#11514). - Ownership.
ALTER TYPE … ADD VALUEneeds the migration role to own the type. It does on a standard install. - Rollback. Take a backup, or note a PITR point, before you upgrade. Rolling back to v0.127.0 keeps the new schema. With the old
unifi_clientsindex gone, the v0.127.0 API cannot write UniFi client rows, so restore the backup if you roll back and use UniFi. Rollback was not tested.
Environment variables.
- Required: none. No new required environment variables. The config validator refuses to boot only when one of the optional variables below is set to a malformed value.
- New, optional (api service), mapped in both shipped Compose files:
PORTAL_ENTRA_CLIENT_IDandPORTAL_ENTRA_CLIENT_SECRET: the customer portal's own multi-tenant Entra app registration. Portal Sign in with Microsoft and Microsoft tenant proof stay off, and their settings stay hidden, unless both are set (#11557, #11568).PORTAL_ENTRA_CALLBACK_BASE_URL: optional origin (scheme, host and port, no path) for the two redirect URIs. Empty uses the origin ofPUBLIC_URL. With the Entra app configured, a malformed value stops the API at boot. Register<base>/api/v1/portal/auth/oidc/entra/callbackand<base>/api/v1/portal/auth/oidc/entra/consent-returnas Web redirect URIs on the app.OAUTH_REFRESH_ROTATION_GRACE_MS(10000, at most 30000,0turns it off): how long the same client may present a refresh token it has just rotated and get the new token back instead of having the connection revoked (#11547).MIGRATION_LOCK_TIMEOUT_MS(300000): how long a starting API waits for another process's migration lock before it exits and restarts. Raise it if a large migration routinely runs longer. A value that is not a positive whole number of milliseconds stops the API at boot (#11388).
- Newly mapped in Compose (web service):
TUNNEL_ORIGIN_TEMPLATE. It is an existing variable that was passed only to the API. Network Proxy host mode needs it on the web container too, or the browser blocks the device frame (#11403). - New, optional, not in
.env.exampleor the shipped Compose files. To use one, add it to the service'senvironment:block yourself:BACKUP_GC_LIVE_SET_MAX_BYTES: memory budget for backup storage cleanup's set of live keys (api, orworkerwhen split). Leave it unset unless cleanup reports that the set is over its budget (#11330).M365_SYNC_SIGNIN_EVENTS_PAGE_SIZE(100, from 10 to 1000): page size for the Microsoft 365 sign-in events sync, read by the Microsoft Graph read executor (#11546).
- Monitoring overlay only:
PROMETHEUS_IMAGE_REF,GRAFANA_IMAGE_REF,ALERTMANAGER_IMAGE_REF,LOKI_IMAGE_REF,PROMTAIL_IMAGE_REF,REDIS_EXPORTER_IMAGE_REFandPOSTGRES_EXPORTER_IMAGE_REFoverride one image each. Empty uses the pinned default (#11355).
Behaviour changes and feature flags.
- New remote access tool alerts are on by default (#11331). Every organization starts with each rule on, and a rule is created the first time its tool appears. A device's first management scan is its baseline, and a tool it has already reported raises nothing; a tool that appears later does. The six tools that only the 0.128.0 agent detects (UltraViewer, Zoho Assist, DWService, Supremo, Ammyy Admin, Chrome Remote Desktop) can raise an alert the first time that agent reports them, even where they were installed earlier. If you use a remote tool across your fleet, switch its rule off per organization under Alerts → Monitors → Built-in alerts. There is no partner-wide switch yet.
- More built-in alerts start sending notifications (#11346, #11372): log correlation, DNS threat, AI agent attention alerts, automation and flow Create alert actions, and metric anomaly alerts. Only alerts raised after the upgrade send. Review routing if you use these.
- UniFi, self-hosted controllers are mapped-only (#11514). Devices and clients on a controller site that is not mapped to a Breeze site are no longer filed under the collector agent's organization, and rows already filed there are removed the next time the controller reports them. Map the controller's sites in Integrations → UniFi to keep their inventory. Unmapped sites still appear there for mapping. The worker logs
unifi.reconcile.unmappedwith the counts. Cloud-console collectors are unchanged. - Migration lock wait is bounded (#11388). An API that cannot get the migration lock in 5 minutes exits non-zero and the restart policy tries again. It used to wait forever.
- Worker split: the
workercontainer no longer has the fixed namebreeze-worker(#11366). Scripts that calldocker logs breeze-workerordocker exec breeze-workershould usedocker compose logs workeranddocker compose exec worker. - Monitoring overlay images move up one to three major versions (#11355): Prometheus 2 to 3, Grafana 10 to 13, Loki and Promtail 2.9 to 3.6, plus Alertmanager and the two exporters. This applies only if you run
docker-compose.monitoring.ymland take the new file. Read the upstream upgrade notes for Prometheus, Grafana and Loki first, and back up their volumes; to stay where you are, set the*_IMAGE_REFvariables to your current images. - Customer portal (#11408, #11528, #11557). With no policy saved, sign-in works as before. Microsoft logins created by the AI for Office add-in with no password now read Active instead of Pending setup in the portal users list, and add-in sessions end after 12 hours. Bulk invite no longer touches those logins.
- Sign in with Microsoft is off until
PORTAL_ENTRA_CLIENT_IDandPORTAL_ENTRA_CLIENT_SECRETare both set. The Google Workspace domain verification method needsGOOGLE_WORKSPACE_ENABLEDand a Workspace connection; the Microsoft method needs the portal Entra app and a proven tenant. DNS verification needs nothing extra. - OAuth refresh tokens (#11547): the same client re-presenting a token within 10 seconds of rotating it gets the new token. A later presentation, or one by a different client, is still treated as reuse and revokes the connection.
- Microsoft 365 sign-in events: a first sync reads 1 day of history instead of 7 (#11546).
- Backup storage cleanup reads manifests more strictly (#11330). A snapshot the agent wrote with no files is now handled instead of stopping cleanup for that destination. A manifest with a repeated or missing
fileskey, or naming another snapshot, stops cleanup for that destination rather than being treated as empty. - AI chat sessions: a sweep every 15 minutes marks chats idle for 2 hours, or older than 24 hours, as expired. The limits are unchanged; they used to be applied only on the next message (#11466).
- Wisp (Breeze Cloud only): a grant's daily budget now counts chat. A chat-heavy day can use up the budget and pause background checks until 00:00 UTC; chat itself is never refused by the grant budget (#11512). Reading a standing instruction from a chat message is one small model call, at most 20 per grant per day (#11524).
- Vendor updates stays off.
BREEZE_OEM_UPDATES_ENABLEDdefaults tofalse; leave it unset. - No flag in this release has to be turned on.
Known gaps.
- Trend Micro recognition (#11435) is not lab-verified. No Trend Micro installation was available; it is covered by unit tests only.
- macOS upgrade-in-place was not verified on Apple Silicon. There was no Apple Silicon lab host for this release.
- Intel macOS upgrade-in-place from 0.127.0 was verified on the signed release candidate: no permission prompt, the helper loaded within seconds of the install, existing Screen Recording and Accessibility grants were kept unchanged, and a remote desktop session connected. Apple Silicon was not verified (no lab host).
- Built-in H.264 encoder fallback: the picture can stay blocky after a burst of change on an otherwise static screen until the screen changes again (#11639). This only affects Windows hosts with no hardware encoder where OpenH264 cannot load; those hosts could not start a session before this release.
- The RDP-session preference of the sign-in screen capture (#9583) was not lab-verified. Capture of the console sign-in screen was.
- S3 backup transport was not exercised in the lab for the new verification lane and manifest streaming (#11359, #11339). Both were verified on the local storage provider.
- Portal Sign in with Microsoft (#11557, #11568) needs a real Entra app and tenant, and was not exercised end to end in the pre-release sweep.
- Command relay across more than one API process (#11390, #11516, #11373) was exercised on a single API instance only.
Full Changelog: v0.127.0...v0.128.0
What's Changed
- docs(testing): v0.127.0-rc.1 lab legs — Windows/Linux, macOS Intel, Apple Silicon results by @ToddHebebrand in #11299
- docs(release-notes): clear the next-release draft after v0.127.0 by @ToddHebebrand in #11302
- fix(reports): import jspdf-autotable by named export so server-side PDFs render by @ToddHebebrand in #11191
- docs: v0.127.0 release docs by @ToddHebebrand in #11303
- fix(binaries): register backup from the official manifest and resolve helper assets by canonical name in local mode by @ToddHebebrand in #11305
- fix(reports): SLA performance Excel downloads of stored runs include the breaches and notes sheets by @ToddHebebrand in #11304
- ci(gate): shadow thin selection from anchors and verified PR results (#10746) by @ToddHebebrand in #11276
- feat(oem-updates): alert when a device is still Failing past its last night (#11247) by @ToddHebebrand in #11275
- fix(web): device vendor-updates states use the Patches tab vocabulary (#11248) by @ToddHebebrand in #11268
- fix(ai-tools): classify portal Customer view route as permanent staff_ui_render exemption (#11129) by @ToddHebebrand in #11258
- feat(remote): pick a remote tool from a split Connect Desktop button (#10922) by @ToddHebebrand in #11261
- fix(viewer,agent): stop stranding held modifiers; make Release stuck keys work (#9595) by @ToddHebebrand in #9687
- docs(spec): native System Health admin tab (#10764) by @fabicarvano in #10808
- docs(remote-access): Physical keys punctuation fix shipped in v0.127.0 by @ToddHebebrand in #11308
- docs(spec): Wisp on device — care loop and support in Breeze Assist by @ToddHebebrand in #11309
- fix(agents): truncate event-log source to varchar(255) (#11279) by @ToddHebebrand in #11322
- docs(plan): OEM W09 follow-ups — fleet state query and export trigger cost (#11242 #11259) by @ToddHebebrand in #11323
- fix(config-policy): keep a custom backup retention through a Backup tab save (#11278) by @ToddHebebrand in #11324
- feat(trust): auto-restrict on card testing and recidivist endpoints, close open checkouts (#11307, #10123) by @ToddHebebrand in #11329
- fix(web/settings): AI approval mode gets its own home by @ToddHebebrand in #10988
- fix(ai): cache the static tool surface and time pre-stream phases (#11004) by @ToddHebebrand in #11045
- fix(backup): GC and reconcile stream snapshot manifests over 200 MiB (#11232, #11233) by @ToddHebebrand in #11330
- feat(alerts): alert partners when a remote access tool appears on a device (#11306) by @ToddHebebrand in #11331
- test(helper): isolate tests from host-installed Breeze Helper (#11285) by @ToddHebebrand in #11333
- fix(api): remaining caught queries survive a failed statement (#11225) by @ToddHebebrand in #11260
- fix(backup): UI paper cuts — explainer, running size, cooldown reason, index error redaction (#11280) by @ToddHebebrand in #11334
- fix(web): vendor updates UI paper cuts (#11281) by @ToddHebebrand in #11337
- fix(ai-tools): split_by_org for manage_patches install across orgs (#10431) by @ToddHebebrand in #11340
- fix(web/backup): Cove credential form matches adapter schema; rotate reachable anytime (#11291) by @ToddHebebrand in #11343
- feat(wisp): check-in routes, Run now, scheduled chip and cancel on the thread (#10996) by @ToddHebebrand in #11312
- test(backup): pin the snapshot row lock between result persistence and file-index hydration (#11178) by @ToddHebebrand in #11344
- docs(migrations): record accepted out-of-order #9760 migrations (#9886) by @ToddHebebrand in #11354
- fix(migrations): apply the shipped set as a non-superuser, non-BYPASSRLS owner (#8991) by @ToddHebebrand in #11345
- fix(alerts): four built-in producers publish alert.triggered via createSourcedAlert (#11328) by @ToddHebebrand in #11346
- fix(admission): a mass socket close no longer escalates W08 to level 3 (#9520) by @ToddHebebrand in #11351
- fix(reports): staff SLA performance CSV uses labelled headers (#11282) by @ToddHebebrand in #11338
- fix(ci): osv-scanner install survives a GitHub release-download outage (#11367) by @ToddHebebrand in #11370
- fix(agent/backup): stream the snapshot manifest on restore and verify (#11234) by @ToddHebebrand in #11339
- fix(cluster-cache): publish timeout outcome, reject any keys, per-site writer ratchet (#8640) by @ToddHebebrand in #11356
- docs(plan): partner-wide installer upload for built-in packages (#9246) by @ToddHebebrand in #11363
- fix(agent): run backup verifications on their own lane (#6106) by @ToddHebebrand in #11359
- fix(fix-memory): outcome-accuracy follow-ups (#7279) by @ToddHebebrand in #11360
- fix: misc paper cuts — software rule label, New folder validation, slug error, trends timestamps (#11284) by @ToddHebebrand in #11335
- fix(backup): analyze the file index table after a large hydration publish (#11209) by @ToddHebebrand in #11352
- fix(web): stop PsaConnectionsPage and M365 ARC-sealer tests flaking under load (#11350) by @ToddHebebrand in #11353
- fix(agent-ws): keep orphaned-result expectations in Redis (#4135) by @ToddHebebrand in #11373
- chore(helper): migrate apps/helper to Tailwind 4 (#10017) by @ToddHebebrand in #11364
- chore(security): drop zip audit/trivy ignores now that the updater uses zip 9 (#8910) by @ToddHebebrand in #11365
- fix(agents): persist the watchdog's own edition for the artifact-edition gate (#4297) by @ToddHebebrand in #11371
- fix(security): say why in isolation, M365 mailbox, EDR and coverage statuses (#11283) by @ToddHebebrand in #11336
- fix(alerts): create_alert and metric anomaly alerts publish alert.triggered after COMMIT (#11348) by @ToddHebebrand in #11372
- fix(wisp): offer a Wisp session only the tools its grant ceiling admits (#10430) by @ToddHebebrand in #11342
- fix(api): dedupe/journal invalid stored settings; own skip reason for restore-point policy failure (#8585) by @ToddHebebrand in #11362
- fix(api): start the cluster cache bus in the worker role (#8639) by @ToddHebebrand in #11361
- fix(ai,wisp,mcp): AI, Wisp and MCP paper cuts (#11287) by @ToddHebebrand in #11341
- fix(commands): resolve topology poll authority version before the claim locks rows (#7268) by @ToddHebebrand in #11357
- fix(compose): worker scale-out + dev/local-build overrides (#4144) by @ToddHebebrand in #11366
- fix(topology): resolve diagnostic requester authority version before the claim locks rows (#11358) by @ToddHebebrand in #11369
- docs(plan): amend W05 D8 — workers now subscribe to the cluster-cache bus (#11375) by @ToddHebebrand in #11376
- fix(agent): read Windows clipboard images through the user helper (#8393) by @ToddHebebrand in #11391
- docs(plan): Wisp on device implementation plan (W01–W07) by @ToddHebebrand in #11313
- docs(spec): customer portal registration options (contacts, self-registration, Microsoft, Google, SCIM) by @ToddHebebrand in #11326
- fix(db): bound the migration advisory-lock wait (#4144) by @ToddHebebrand in #11388
- fix(agent): capture the Winlogon sign-in screen via a DIB section on a dedicated desktop-attached thread (#8434) by @ToddHebebrand in #9583
- fix(api): shard the agent command relay per API instance (#4134) by @ToddHebebrand in #11390
- docs(plan): EDR W05 Sophos Central adapter + W07 detection signatures (#8169 #8171) by @ToddHebebrand in #11404
- docs(plan): CI throughput W06 shepherd + W07 refinements (#10750 #10751) by @ToddHebebrand in #11406
- fix(deps): pin stripe exactly and keep optional-peer overrides armed through a fresh resolve (#3690) by @ToddHebebrand in #11401
- fix(web): allow the Network Proxy tunnel origin in the dashboard frame-src (#11300) by @ToddHebebrand in #11403
- fix(billing): overdue sweep no longer stamps paid/voided invoices; drop dead refund writer (#3803) by @ToddHebebrand in #11402
- feat(portal): invite from contacts — contactId on invite, batch invite-contacts, Portal column (#11378) by @ToddHebebrand in #11405
- fix(agent): surface unconfirmed-desktop frames and back off capture-thread recycling (#8434) by @ToddHebebrand in #11407
- fix(deploy): bump and digest-pin monitoring compose images (#7812) by @ToddHebebrand in #11355
- fix(billing): a retried manual payment lands once via an idempotency key (#3803) by @ToddHebebrand in #11409
- ci(integration): balance shards by recorded timing + named suite map, no selection change (#10751) by @ToddHebebrand in #11482
- ci(shepherd): classify merge-queue failures from run evidence (#10750) by @ToddHebebrand in #11461
- fix(wisp): morning brief counts open HIGH concerns as needing you, drops readiness from "open", cuts items at a word (#11428) by @ToddHebebrand in #11469
- feat(auth): authenticator app as a backup beside a primary passkey (#11421) by @ToddHebebrand in #11471
- fix(reports): drop the can't-fan-out notice from the template modal (#11282) by @ToddHebebrand in #11474
- docs(ci): plan for W05 — thin merge-queue run enforced (#10749) by @ToddHebebrand in #11477
- docs(plan): UniFi multi-org matching + Pax8 name matching (#10358) by @ToddHebebrand in #11478
- docs(spec): retention windows for high-volume tables + client-AI transcript carve-out (#4342) by @ToddHebebrand in #11479
- docs(plan): Wisp self-knowledge and closed loops, W01–W10 (#10425) by @ToddHebebrand in #11480
- fix(billing): Checkout refuses non-representable balances; invoice events publish after commit (#3803) by @ToddHebebrand in #11410
- docs(plan): dispatch facade full pass over the agentWs importer set (#4142) by @ToddHebebrand in #11481
- fix(wisp): skip tick and watch assessments when nothing changed (#11423) by @ToddHebebrand in #11472
- test(api): make the relay-shard conflict test deterministic (#11483) by @ToddHebebrand in #11485
- fix(ai): map monitor-definitions describe + ticket list_work_types in RBAC map (#11431) by @ToddHebebrand in #11437
- feat(portal): account foundations — status CHECK, browser_access, state machine, purpose-bound tokens, uniform login, identities release A (#11379) by @ToddHebebrand in #11408
- feat(software): partner-wide installer upload — API (#11413) by @ToddHebebrand in #11462
- fix(ai): refuse owner-less partner-wide writes before filing; Wisp focus org as write default (#11432) by @ToddHebebrand in #11465
- docs(plans): tracking_issue for #11489 #11500 #11505 by @ToddHebebrand in #11509
- fix(ai): expire idle chat sessions on read and on a 15-min sweep; Wisp rolls a 410 to a fresh session (#11430) by @ToddHebebrand in #11466
- fix(wisp): concerns close — outcome implies resolved, alert auto-close, nudge follow-up (#11427) by @ToddHebebrand in #11463
- fix(wisp): carry the anomaly incident id into assessments and show metric anomalies (#11425) by @ToddHebebrand in #11470
- ci(postgres): Postgres 18 smoke on every PR + scheduled 17/18 suite (#11417) by @ToddHebebrand in #11475
- feat(integrations): shared org-name matcher + Pax8 suggested matches and bulk review (#11245) by @ToddHebebrand in #11511
- feat(wisp): grant budget meter counts chat; chat warns, never blocks (#10414) by @ToddHebebrand in #11512
- perf(api): vendor updates fleet view in two statements over a materialised policy side (#11242) by @ToddHebebrand in #11468
- docs(plan): portal registration W3 — access policy, access-request queue, sign-in card (#11380) by @ToddHebebrand in #11515
- fix(agent,api): recognise Trend Micro as an AV provider (#8171) by @ToddHebebrand in #11435
- fix(relay): command dispatch onto the relay facade; flip 27 workers global (#11506) by @ToddHebebrand in #11516
- ci(gate): W05a — gate publishes its queue selection (#10749) by @ToddHebebrand in #11487
- fix(wisp): Fleet Design run delegable under a Wisp grant; apply/rollback stay refused (#11433) by @ToddHebebrand in #11517
- fix(wisp): evaluate watches in code, launch a run only when the hit-set changes (#11424) by @ToddHebebrand in #11473
- feat(web/software): upload installers to partner-wide packages (#11414) by @ToddHebebrand in #11484
- ci(integration): compute named-suite selection on PR runs, shadow (#10751) by @ToddHebebrand in #11488
- fix(unifi): unmapped self-hosted sites are discovery-only + unifi_clients site identity (#11504) by @ToddHebebrand in #11514
- fix(wisp): re-evaluate the readiness note every run and stop touching it (#11429) by @ToddHebebrand in #11518
- fix(backup): list empty folders and symlinks in hydrated snapshot indexes (#11235) by @ToddHebebrand in #11467
- feat(web): authenticator app as a backup beside a primary passkey (#11422) by @ToddHebebrand in #11486
- feat(wisp): standing state on every turn; status answers from the picture first (#10426, #10429) by @ToddHebebrand in #11521
- feat(wisp): same-org rollup of model-raised device concerns by pattern (#11426) by @ToddHebebrand in #11519
- feat(wisp): on-demand Wisp assessment from chat (#10406) by @ToddHebebrand in #11522
- feat(wisp): approval-wait signal — cards say where they wait, chat shows it, Wisp hears how long (#10416) by @ToddHebebrand in #11530
- feat(unifi): mapping/controller audit, collector-location copy, unmapped-site counter (#11502) by @ToddHebebrand in #11520
- docs(software): partner-wide installer upload (#9246) by @ToddHebebrand in #11531
- ci: W05b — CI consumes the published queue selection, inert until CI_THIN_QUEUE=enforce (#10749) by @ToddHebebrand in #11527
- fix(web/reports): restore saved builder state when editing a custom report (#9728) by @ToddHebebrand in #11533
- docs(plan): portal registration W04 — Entra tenant proof, Sign in with Microsoft, OIDC layer (#11381) by @ToddHebebrand in #11535
- fix(web): partner 'Locks orgs' badge only claims a lock once set (#11411) by @ToddHebebrand in #11534
- test(alerts): make the re-arm closed-index plan check deterministic (#11532) by @ToddHebebrand in #11538
- fix(patching): report and keep patch install dates (#9723) by @ToddHebebrand in #11539
- feat(portal): access policy, access-request queue and identities read switch — API (#11380) by @ToddHebebrand in #11528
- fix(network-proxy): admit same-origin Origin: null and forward tunnel Referer in host mode (#11458) by @ToddHebebrand in #11536
- fix(docker): clear stale astro dev lock in web/portal dev images (#11184) by @ToddHebebrand in #11542
- fix(agent): remove the deprecated enroll --site-id flag (#8493) by @ToddHebebrand in #11543
- fix(web,portal): set zod jitless for every browser entry (#9972) by @ToddHebebrand in #11544
- fix(agent): launch session spawn targets directly, not via cmd /c start (#6923) by @ToddHebebrand in #11545
- feat(web): portal sign-in & registration card, partner Customer portal tab, access-request queue (#11380) by @ToddHebebrand in #11523
- fix(m365): sign-in events sync returns a first page and recovers from Graph timeouts (#9394) by @ToddHebebrand in #11546
- fix(oauth): refresh-rotation grace window keyed on the new token (#10301) by @ToddHebebrand in #11547
- fix(portal): one case-insensitive login-email comparison for both invite paths (#11529) by @ToddHebebrand in #11540
- feat(wisp): event check-ins — fire on a device, script, command or run, with a deadline (#10410) by @ToddHebebrand in #11525
- fix(connection-health): stale arm for dns_filter and m365_sync sources (#10021) by @ToddHebebrand in #11537
- feat(wisp): capture standing instructions from chat, with a keep/forget chip (#10428) by @ToddHebebrand in #11524
- feat(portal): Entra tenant proof, Sign in with Microsoft API, OIDC layer, session caps, sso_only (W04a, #11381) by @ToddHebebrand in #11557
- feat(wisp): enforce kept standing instructions in chat, proposals and release (#10428) by @ToddHebebrand in #11570
- feat(portal): Sign in with Microsoft UI, tenant proof panel, session cap, sso_only confirmation (W04b, #11381) by @ToddHebebrand in #11568
- feat(wisp): run-mode check-ins check on their own and post the result (#10410) by @ToddHebebrand in #11571
- fix(web): make the ticket workspace readable and keyboard-operable by @ToddHebebrand in #11567
- docs(plan): portal registration W05 — domain verification + Organization › Domains (#11382) by @ToddHebebrand in #11573
- feat(wisp): dispatch evidence and the post-turn promise linter (W08, #10427) by @ToddHebebrand in #11574
- test(wisp): replay regression suite, scorer and five defect-class fixtures (W09, #10432) by @ToddHebebrand in #11578
- test(portal): pin the clock in AgreementDetailView so the expiry assertion is date-independent by @ToddHebebrand in #11579
- feat(portal): domain verification API — DNS / Entra tenant / Google directory (W05a, #11382) by @ToddHebebrand in #11577
- feat(web): Organization › Domains and customer domain verification UI (W05b, #11382) by @ToddHebebrand in #11576
- docs(plan): high-volume table retention windows (#4342) by @ToddHebebrand in #11510
- docs(plan): portal registration W6 — self-registration by verified email domain (#11383) by @ToddHebebrand in #11584
- fix(api): warn at boot when TRUSTED_PROXY_CIDRS overlaps no attached subnet (#2987) by @ToddHebebrand in #11585
- fix(web): pre-release sweep v0.127.0 → main — tracking doc and small fixes by @ToddHebebrand in #11608
- feat(api): report-first retention runner (#4342 W0) by @ToddHebebrand in #11595
- fix(agent): fall back to the MFT encoder when OpenH264 cannot load (#11392) by @ToddHebebrand in #11399
- fix(enrollment): take the org export lock before the devices write, retry lost lock races (#9521) by @ToddHebebrand in #11347
- docs(qa): pre-release sweep follow-up — Wisp pass, lab legs, known gaps by @ToddHebebrand in #11616
- chore(release): What's New entry for 0.128.0 and mobile store version 1.0.4 by @ToddHebebrand in #11617
- docs(qa): pre-release sweep — release-candidate lab legs and the #11622 fix by @ToddHebebrand in #11637
- fix(agent): keep the software MFT fallback current on a static desktop (#11622) by @ToddHebebrand in #11636
Full Changelog: v0.127.0...v0.128.0