github LanternOps/breeze v0.129.0

50 minutes ago

Breeze RMM v0.129.0: a ticket triage board with an in-place focus view, notices when a backup destination keeps failing, a tool profile and context window for each AI model, a System Health tab for platform administrators, customer portal self-registration by verified email domain, and security hardening across sign-in, backup and remote access.

⚠️ This release needs action on upgrade. Local backup destinations must now be private to the agent, and network shares are no longer supported as local destinations. Read Action required on upgrade under Self-Hosting / Upgrade Notes before you update the server or promote the agent.

Summary

  • ⚠️ Action required on upgrade. Several changes in this release are deliberately strict. Read Action required on upgrade before you update the server or promote the agent.
  • Ticket workspace: a triage board and a focus view (#11575).
    • Triage board. /tickets is a full-width board with two-line rows: number and subject, then organization, requester and device. Owner, SLA ("8h 14m left", Breached) and age are on the right. Priority and type chips are neutral, so red on the board means a breach.
    • Focus view. Opening a ticket shows it in place, with an "All open · 3 of 9" strip. j/k step between tickets; Esc or Back returns to the board with the row and scroll position restored. The conversation gets the room, the composer is pinned, and a recipient line says who a public reply emails.
    • Situation column. The right column leads with the requester and the linked device's live state (online, signed-in user, active alerts, Remote in), then SLA, linked alerts and the checklist. Below 1024px the view becomes Conversation and Details tabs.
    • Unsent drafts are kept per ticket while you move between tickets.
  • Backup: notices when a destination keeps failing (#11777, #11770, #11771).
    • A failing backup destination opens one Connection health incident, sends one in-app notice to the partner's backup admins, and appears in the daily digest. It is on by default and has no setting.
    • The backup dashboard shows one critical destination failing item when two or more devices on one destination fail for a reason that belongs to the destination.
    • Failed jobs name a specific cause (store access denied, not found, clock skew, storage operation failed, upload session ended, helper stopped, and others) in the job list, the device tab and the overview.
    • A run that the destination refuses now ends, and the failure names the store's error code (for example AccessDenied).
  • AI models: tool profile and context window (#11393: #11680, #11786, #11761, #11795, #11801).
    • Tools and context. Under AI Providers & Models → Models → (model) → Tools and context, a partner can set a model's tool profile (Auto, Full, Standard, Minimal, Custom) and, on OpenAI-compatible endpoint models, a context window override.
    • Auto uses the model's real window. Breeze learns an OpenAI-compatible model's context window from the endpoint's model list, or from a context-length rejection, and Auto picks a smaller tool set and a shorter prompt when the full set does not fit. Platform, Anthropic bring-your-own-key and catalog models are not changed.
    • Per-feature verify. Verify on an OpenAI-compatible model now runs a round trip for each feature the model is assigned to, with stand-in tools. The drawer shows each result. Verify is real traffic billed by the partner's provider.
    • A profile only changes which tools are offered to the model. Permissions, approvals and guardrails are unchanged. See Behaviour changes.
  • System Health tab (#10958: #11561). Platform administrators get a Health tab at Administration → System. It shows the connection-health reconciler and digest, each per-kind heartbeat, and the queue counts for connection health, alerts and event dispatch. It reads Redis only, so it works without the monitoring overlay, and it refreshes only when asked.
  • Customer portal: self-registration by verified email domain (#11383: #11679, #11746). This completes the item listed as still to come in v0.128.0.
    • A person with an address at one of an organization's verified email domains can ask for portal access at /request-access. They confirm a single-use link sent to that mailbox, valid for 30 minutes.
    • In approval mode the request joins the organization's access-request queue, which now shows whether the requester's domain is still verified. In instant mode the account is created and the person sets it up from an invite.
    • Off for every organization until an MSP turns it on. The login page shows Request access only on a verified custom portal domain whose organization has self-registration on and at least one verified email domain. On the shared portal host the page is reached by its URL.
    • Still to come: Sign in with Google (in this release, switched off; see Added) and directory-driven provisioning.

Added

  • Sign in with Google for the customer portal: in this release, switched off (#11384: #11791, #11796). The API, the MSP settings row, the portal buttons and the docs are in place, and nothing appears until a server sets PORTAL_GOOGLE_CLIENT_ID and PORTAL_GOOGLE_CLIENT_SECRET. Leave them unset until Google sign-in is announced as supported. See Environment variables and Known gaps.
  • Portal: a notice when sign-in falls back to password (#11594). When an organization's proven Microsoft tenant is lost while Microsoft sign-in was on, Breeze writes an organization.portal_sign_in.password_fallback audit event and shows a notice on the Sign-in & registration card and on Organization → Domains, with the cause, the date, Re-run the tenant proof and Dismiss. The fallback itself is unchanged.
  • AI transcript retention settings, report-only (#4342: #11775, #11789). The partner and organization AI data-policy cards have a technician AI transcript window (365 days by default), and the AI for Office policy editor shows its own. Each field previews how many conversations are past the window. Nothing is removed in this release unless a server sets AI_TRANSCRIPT_RETENTION_ENFORCE=true. See Behaviour changes.
  • Report-only retention jobs for high-volume tables (#4342: #11663, #11665, #11703, #11707, #11775). Five nightly jobs count the rows that are past their window in device commands, filesystem snapshots, network monitor results, device sessions, closed alerts, script executions, AI transcripts and eleven run and access history tables. They log a REPORT-ONLY line, set the breeze_retention_rows_eligible metric, and delete nothing. See Environment variables.
  • Possible reinstall detection (#8318: #10918). When a newly enrolled device matches an older record in the same partner by SMBIOS system UUID, by serial number and manufacturer, or by hostname, Breeze flags the new record as a probable reinstall and emits a device.reinstall_suspected event. A built-in Possible Device Reinstall alert template is added; no rule is created, so alerting is opt-in. Nothing is reattached yet, and there is no screen for it yet. Hardware matching needs the 0.129.0 agent.
  • Agent: groundwork for reattaching a reinstalled machine (#8318: #10122). The agent can now carry out a signed, bounded identity rebind. Nothing uses it in this release: the server sends no directive until the reattach action ships.
  • Breeze Assist branding and localization (#11204). Breeze Assist renders the configured locale (English and Brazilian Portuguese) and partner branding in its identity text: product name, welcome text, "Provided by", support and portal labels, window titles and the tray. The Helper tab of the Configuration Policies editor has the eight branding fields; blank inherits. Consent, elevation, approval and security text is localized only and cannot be replaced by branding. With no branding configured, Breeze Assist stays Breeze. See Known gaps.
  • Sign-in welcome (#10272). After a successful sign-in the dashboard shows a short personalized welcome with the user's avatar instead of the credential form.
  • Ticket import: Zammad 7.2.x module (#11296). GET /ticket-imports/modules now lists zammad. API only; there is no screen for ticket import yet. See Known gaps.
  • Portal API: GET /portal/network/sites/health returns network health per site, behind the existing network visibility setting. The portal screen for it is not in this release (#11215).
  • API start on a read-only database (#11738). /health/ready reports dbReadOnly and a single reason field. See Behaviour changes.
  • Metrics: breeze_retention_rows_eligible{job_name} (#11663) and breeze_agent_eventlog_noise_dropped_total{event_id} (#11739).

Improved

  • AI approval cards say what will happen (#11701). A ticket reply or note shows the ticket number and subject, who a public reply emails, and the message as plain text above Approve and Deny. A memory write shows what will be remembered and for whom. Approval requests name the ticket number and the device instead of ID fragments.
  • Remote desktop: a missing permission is explained (#11666). A user whose role lacks remote:access now sees why Connect Desktop is not available instead of "Connection failed". No role gains a permission.
  • Permanent device delete gives an actionable error. A deadlock, serialization failure or statement timeout answers a retryable 409, and other failures carry code: DEVICE_PURGE_FAILED with a message the dashboard shows (#11657).
  • Windows Security event log volume (#11739). The API drops five high-volume Windows Security audit records (5038, 5157, 5152, 4957, 5061) before they are stored, and the 0.129.0 Windows agent collects a fixed list of audit events instead of every audit failure. Failed logons (4625), Kerberos pre-authentication failures (4771) and audit policy changes (4719) are kept. See Behaviour changes.
  • Billing switched off for a partner is now honoured by background work: the contract billing sweep, hour-block close, scheduled quote sends, autopay and the autopay notices. Receipts, failure notices, reminders and overdue notices are still sent. There is no screen for the switch yet (#11124).
  • Worker split: suspending, archiving, merging or offboarding a tenant, ending a Quick Support session and tearing down a remote session now close the agent's socket on whichever API instance holds it. Sixteen more background workers can run on the worker service (#11526).
  • Wisp (Breeze Cloud only): Wisp's standing state now carries what the user did to its check-ins and concerns in the last 24 hours, so it can say "you cancelled that check-in at 14:05" (#11759). The memory page marks a standing instruction that has passed its end date as Expired (#11700).
  • Audit Trail uses the shared resource-type labels and UniFi action labels (#11696).
  • Translations: original copy is restored for 95 strings that had been replaced by a humanized key, and placeholder strings have real copy across the 8 locales. The non-English text for 51 of them is machine-drafted (#11654, #11724).
  • Mobile (Android): the build no longer asks for the overlay and storage-read permissions, which the app does not use (#11569). The store version is 1.0.5 (#11851).
  • Agent build: the Go toolchain is 1.26.11 (#11708).

Fixed

  • Custom roles: Inherit From now takes effect (#10641). A custom role's Inherit From parent grants its permissions at runtime, and every reader of privilege (approver lists, notification recipients, report access, access reviews) uses the same lookup. Removing an inherited grant ends live remote sessions and event sockets of the affected members. Members of a custom role that has a parent gain the parent's permissions on upgrade. See Behaviour changes.
  • Backup:
    • A multipart backup write to an S3-compatible store that sends an unparseable x-amz-abort-date header (seen with Wasabi) no longer fails with 502 storage_error (#11767).
    • A run whose destination refuses the request, or whose upload session has died, now ends instead of continuing (#11771).
  • Remote desktop (macOS agent): a double-click from the viewer arrives as a double-click. Before, Finder treated it as two single clicks and started a rename. Needs the 0.129.0 agent. See Known gaps (#11670).
  • Viewer (Linux): session windows now turn on WebRTC in the webview. This does not yet make the Linux viewer connect to devices whose agent runs as a service, which includes every Windows device: the WebKitGTK library that Ubuntu ships is built without WebRTC (#11642).
  • Agent (Windows, security scans): quick, full and custom scans skip the agent's own compiled YARA rule cache, so a scan no longer reports its own rule files as threats. Needs the 0.129.0 agent. See Known gaps (#11748).
  • Breeze Assist: "Using ..." lines settle to done or failed when the tool finishes instead of spinning (#11750).
  • Microsoft 365: the Admin actions consent button now goes to Microsoft's approval screen instead of back to the dashboard (#11669).
  • Customer portal:
    • Login, forgot-password, the inbound-email sender lookup and the Outlook add-in sender lookup match a login's email address without regard to case. Where two logins differ only by case, each path refuses instead of choosing one (#11658).
    • The Contacts list refreshes Roles after portal access is given, and removing the login removes the portal role (#11667).
  • Sign-in: an SSO-only account with no passkey or authenticator app can now register an approver device after an SSO re-authentication (#11656).
  • Billing: changing an organization's billing contact requires billing:manage (#11683).
  • Quotes and tickets: catalog item ownership is validated on manual quote lines and ticket parts (#11682).
  • Reports: decommissioned devices are no longer counted in report device populations (#11653).
  • Alerts: patch failure details are kept up to 4,000 characters (#10965).
  • Tickets:
    • The device Tickets tab lists the device's tickets whichever organization the switcher is on (#11650).
    • In the composer, an attachment that failed for a permanent reason no longer offers Retry, and a restored draft warns about attachments it could not restore (#11723).
  • UniFi: partner-wide pickers list every organization the user can reach (#11695).
  • Configuration policies: a tab whose Save was blocked now says why (#11661).
  • Software Library: the Add Version form is validated on submit (#11660).
  • AI chat: the typed message is kept when the session was closed elsewhere (#11668).
  • Web: the organization switcher no longer overlaps at phone width, and the domain verification panel is no longer cut off (#11651). The AI Approvals legend lists Locks orgs (#11652).
  • Wisp (Breeze Cloud only):
    • A finished specialist's result reaches the next chat turn (#11752).
    • Opening the Wisp pane on another page continues the thread's live session instead of starting a second one (#11751).
    • A standing instruction is kept once per thread (#11742), and one that has passed its end date is no longer loaded into the session (#11700).
    • "Tell me when this device is back online" schedules a check-in, not a watch (#11699).
    • A check-in that should run an assessment is refused when no Triage agent can run it, and the post says why (#11662).
    • Credentials are scrubbed from memory content before it is stored (#11697).

Security

Security — hardening

This release tightens checks across sign-in and account lifecycle, the Partner API, backup and recovery, remote tunnels, inbound email, the Outlook add-in and the agent. Self-hosters are encouraged to upgrade. Several of these changes are deliberately strict and need action on upgrade; read Action required on upgrade below before you update the server or promote the agent. (#11784, #11785, #11787, #11790, #11802, #11804, #11805, #11806, #11807, #11809, #11810, #11814, #11815, #11827, #11828, #11829, #11830, #11831, #11832, #11834, #11842)

Self-Hosting / Upgrade Notes

Action required on upgrade

Before you update agents

  • Local backup destinations and local vaults must be private to the agent's service account. Earlier agents created local destinations, including the default <data directory>/backups (/var/lib/breeze/backups on Linux), with mode 0755. After the agent update, backup, restore, listing, retention, vault and bare-metal recovery operations against such a destination stop with "local backup store is not private" until it is migrated. The agent does not change the permissions of an existing destination. Migrate before updating agents: see "Local destination permissions" in the backup storage docs. The Windows default store under the Breeze data directory already meets the rule. (#11828)
  • Network shares are no longer supported as local destinations or vaults. UNC paths, mapped network drives and SMB or NAS shares are refused, and the SMB share vault type can no longer be created. A vault saved on a share can still be deactivated or deleted. Move these to a dedicated directory on an attached disk, or to S3-compatible storage. The path must be a dedicated directory, not a drive or filesystem root, with no link or reparse point in it. (#11828)
  • If you redirect an old server hostname to a new one, update server_url on the agents first. Agents now follow a redirect only to the same scheme, host and port (an http to https upgrade on the same host is still followed). (#11785)
  • Update agents in stages. With AGENT_AUTO_PROMOTE=false, a new agent release is registered but not promoted, so you can update a few devices, check their backups, and then promote. See "Controlled agent fleet rollout" in the upgrade docs.

Before you update the server

  • Deploy the web app and the API together. The signup confirmation page now sends the password chosen at signup. (#11802)
  • Deploy the API and the Outlook add-in together, so the add-in shows the new messages. (#11831)
  • Do not start disaster recovery executions during the upgrade. Executions queued or running at upgrade stop with execution_definition_unavailable; review them, because commands already sent are not recalled. Approvals granted but not yet carried out must be requested again. (#11805)
  • BACKUP_LOCAL_ROOT (new, optional, self-hosted only). Server-side features for local backup destinations (connection test, file browse, verification, storage sweep, recovery downloads, recovery media) now read only from <BACKUP_LOCAL_ROOT>/<organization id>/<storage configuration id>/. Without it, those features pause for local destinations: the sweep skips them with a warning and deletes nothing, verification stays pending, and the connection test reports "Not tested here". Agents are unaffected. See the backup storage docs for setup steps, which move no data. (#11806)

After the upgrade, check

  • Platform admins listed in BREEZE_PLATFORM_ADMINS. An account is now promoted at API start only when it is active, its address is verified, it is a partner-level account and no other account shares the address. Accounts that already have platform-admin status keep it. Read the startup log warnings, and verify the address of any listed account that is not verified yet (POST /api/v1/auth/resend-verification while signed in; needs a configured mail service). (#11834)
  • Partner API keys. A key whose owner has since been removed, deactivated, moved to a narrower role or limited to selected organizations is refused with 401 Invalid partner API credentials until an admin who holds the needed access re-issues it or the owner's access is restored. (#11815)
  • Tunnel allowlist rules. A source rule written as a single address with no prefix length now matches only that address; widen it to the intended CIDR if users can no longer open tunnels. Stored IPv6 rules now apply. An IPv6 rule written with a host address and a short prefix (for example 2001:db8::5/32) stays inactive until it is rewritten. Agents that have not updated still ignore IPv6 rules, so IPv6 targets are refused on them. (#11787)
  • The inbound email review queue. Inbound mail is now attributed to the From header address, and a passing authentication verdict counts only when it is for the From domain. Expect more mail held for review (or dropped, where Drop mail that fails sender authentication is on) in the first days. Mailbox jobs queued before the upgrade are held for review, never dropped. For a ticket created from Mailgun mail whose recorded submitter differs from the customer's From address, a reply may no longer match the ticket by its subject token. (#11830)

Behaviour changes

  • Custom roles and recovery credentials. Generating a bare-metal recovery token, creating a bare-metal recovery and reissuing a recovery code now need devices:execute as well as backup:write. Built-in roles are unchanged. Grant devices:execute to a custom role that should keep this. (#11832)
  • Resending invites. An admin can resend a pending invite only for a role and sites they could invite; otherwise the request returns 403. (#11842)
  • Site-restricted users can no longer create or control deployments, or change AI for Office mappings, policy and templates; they can still view deployments in their sites and retry their own failed devices. Deployment control buttons may still be shown to them and return 403. Patch package options and install-failure counts cover only devices in their sites. (#11790)
  • Script Builder sessions are private to the user who started them. Mobile search returns only the result groups the caller has permission to open. (#11784)
  • Sign-in lockout counts every password attempt before the password is checked, including attempts sent at the same moment. A member of a role can no longer turn off that role's MFA requirement. Pending email changes are cancelled by password reset or change, sign-out, removal and similar account events. (#11802)
  • Outlook add-in linking follows the same rules as sign-in: lockout, the partner's SSO requirement and IP allowlist. Technicians at a partner that requires SSO, or outside the partner's IP allowlist, can no longer link the add-in with a password. Refusals return 401 invalid_credentials; the audit log records the reason. (#11831)
  • Removed accounts. Re-inviting a removed account, or setting it back to active or invited, starts it without platform-admin status and with its address unverified. This also applies to an account that never had a password (for example, SSO-only) when it is disabled and re-enabled. (#11834)
  • Linux bare-metal recovery. The rebuild keeps the restored GRUB configuration and initramfs and no longer runs boot tools from the restored system. A restore onto different hardware may not boot if its initramfs lacks a needed storage driver. grub-efi is no longer a required tool on the rebuild host. The new --restored-boot-tools flags are accepted but always refused in this release. (#11829)
  • MSSQL restore under a new database name builds one statement with a MOVE clause per database file. A database with many files (around 37 or more, depending on name and path lengths) fails with "sqlcmd: query is too long for one command line" and no database is created. Same-name restores are unaffected. Backup file paths with control characters are refused. (#11827)
  • Windows helper sessions are named after their verified account, as DOMAIN\user. Message receipts and chat replies record that form. Notifications or script runs addressed to SYSTEM by name no longer reach a helper. While a domain controller is unreachable, only domain-qualified names are matched. (#11804)
  • Device file operations and scans accept only absolute local paths. UNC paths, device namespaces and relative paths are refused. Secure delete and encrypt refuse a file with other hard links. (#11814)
  • Tunnels. The VNC tunnel type reaches only the local VNC endpoint. Under partner-trust enforce mode, a restriction ends open tunnels at their next check. (#11787)
  • Huntress webhook. Every failure before the signature verifies now returns one 401 Webhook authentication failed; the reason is in the API log. Deliveries are limited to 600 per minute per source address. (#11810)
  • Selective restore can answer 503 index_query_timeout on a very large index; nothing is created. (#11810)
  • Images. PNG logos, quote images and signed-copy certificates over the size limits, or animated, are not decoded: a report shows the company name, a quote PDF leaves the image out, and a signed-copy download falls back to the original file. (#11807)
  • Flows. For partner-wide flows, the active and running run limits now apply to each organization separately; monthly limits stay partner-wide. (#11807)

Upgrade command

Check how your install pins its images: grep '^BREEZE_API_IMAGE_REF=' .env.

  • Digest-pinned (the value ends in @sha256:…, which is every guided-setup.sh install from v0.112.0): fetch the current guided-setup.sh from main, then run bash guided-setup.sh --upgrade 0.129.0. It verifies the signed image inventory and updates BREEZE_VERSION and all four image digests together, then pulls and restarts.
  • Tag-form (the value ends in :${BREEZE_VERSION}): set BREEZE_VERSION=0.129.0, then run docker compose pull api web portal && docker compose up -d (and pnpm install if you build from source). If you run the optional worker container, pull and restart it too.
  • Do not edit only BREEZE_VERSION on a digest-pinned install. That re-pulls the images you already run.
  • Update the API, web and portal containers together. The new ticket board, the model drawer, the System Health tab and the portal request-access pages call routes the old API does not have. If you run the optional worker container, update it with the API.
  • --upgrade does not change your docker-compose.yml. To pick up this release's new Compose mappings (listed under Environment variables), take the v0.129.0 docker-compose.yml / deploy/docker-compose.prod.yml, or add the lines to the api service's environment: block yourself. A value that is only in .env does not reach the container.
  • See the Upgrade Guide.

Breaking changes

  • ⚠️ Local backup destinations and network shares. See the first two items of Action required on upgrade above for what stops, who is affected and what to do.
  • ⚠️ Do not roll the API back to v0.128.0 after this upgrade without restoring your backup. The upgrade drops the unused patch_compliance_snapshots table. A v0.128.0 API on the upgraded database fails organization erasure and organization merge, and the AI patch agent's evidence read fails. Recovery is to roll forward again (#11725).
  • No other change removes a feature on an install with default settings. Read Action required on upgrade, Behaviour changes and Other behaviour changes and feature flags for the changes that are strict by design.

Database

  • 19 migrations. They are idempotent and apply automatically on first API boot via autoMigrate, unless AUTO_MIGRATE=false. Expect [auto-migrate] Applied 19 migration(s) from v0.128.0. No shipped migration was modified, renamed or removed. The set was verified to apply as a non-superuser role.
  • No table is rewritten and no large table is backfilled. Two things are worth planning for:
    • Index builds on large tables. Seven files build 18 indexes with CREATE INDEX CONCURRENTLY, on device_commands, network_monitor_results, device_sessions, alerts, script_executions, ai_agent_runs, patch_job_results, automation_runs, report_runs, user_notifications, remote_sessions, sessions, backup_jobs, ai_sessions and device_hardware. Reads and writes continue during a build. Each build reads its table twice, so on an install with a long history the first boot can take from seconds to a few minutes per table; patch_job_results is likely the largest (#11663, #11665, #11703, #11707, #11775, #11777, #10918).
    • If a build is interrupted (for example the container is stopped mid-boot), it can leave an index marked INVALID. The next boot stops with a message that names it. Run DROP INDEX CONCURRENTLY public.<name> and start the API again.
  • One table is dropped. 2027-01-24-150000-drop-patch-compliance-snapshots drops patch_compliance_snapshots. Nothing in Breeze ever wrote to it. The migration logs a warning with the row count if it finds any rows. This is one-way; see Breaking changes (#11725).
  • Short locks on busy tables. Two files take a brief exclusive lock under a 5-second lock timeout. If a long transaction holds a conflicting lock, the migration fails, the API exits, and the file runs cleanly on the next start:
    • 2027-01-23-090000-device-possible-replacement-reason adds two columns, a CHECK and a trigger to devices, and fills the two columns on rows that already carry a possible-reinstall link (#10918).
    • 2027-01-23-102000-alert-retention-fk-set-null changes two foreign keys into alerts (from log_correlations and network_change_events) to ON DELETE SET NULL, then validates each with one scan that does not block writes (#11665).
  • Rows written. 2027-01-24-120000-ai-transcript-retention-columns sets the new technician transcript window to 365 days on every existing partner AI data-policy row; it has no effect while transcript retention is report-only (#11775). 2027-01-23-090300 adds the built-in Possible Device Reinstall alert template and creates no alert rule (#10918).
  • Other additions are nullable columns, columns with a constant default and CHECK constraints: partner_ai_models (tool profile, allow-list and context window columns), ai_invocations (tool profile and exposure fingerprint), device_hardware.system_uuid, script_executions.output_purged_at, ai_sessions.transcript_purged_at, wisp_check_ins.cancelled_by, and portal_access_requests.google_hosted_domain with its CHECK. 2027-01-23-235000-role-inheritance-permissions-epoch replaces two trigger functions and writes no rows (#11680, #11761, #10918, #11703, #11775, #11759, #11791, #10641).
  • Rollback. Take a backup, or note a PITR point, before you upgrade. Rolling back to v0.128.0 keeps the new schema, and patch_compliance_snapshots stays dropped, so restore the backup if you roll back. 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, in .env.example and mapped in both Compose files (api, and worker when split):
    • BACKUP_LOCAL_ROOT: see Before you update the server above (#11806).
    • PORTAL_GOOGLE_CLIENT_ID, PORTAL_GOOGLE_CLIENT_SECRET and PORTAL_GOOGLE_CALLBACK_BASE_URL (optional; falls back to PUBLIC_URL, PUBLIC_APP_URL, PUBLIC_API_URL): the customer portal's Google OAuth client. With them unset nothing changes: no Google row, button or copy appears and every Google route answers 404. Leave them unset until Google sign-in is announced as supported. Once the client is set, boot also needs a valid callback base. The only redirect URI to register is https://<your-breeze-domain>/api/v1/portal/auth/oidc/google/callback. The client id must be lower-case and end in .apps.googleusercontent.com; a malformed value stops the API at boot (#11384).
    • PORTAL_SELF_REGISTRATION_ENABLED (true): set it to false to turn customer-portal self-registration off for every organization. Unset or empty means on; a value that is not true, 1, false or 0 stops the API at boot. Self-registration also needs a configured mail service (#11679).
  • New, optional, mapped in both Compose files but not in .env.example. These 54 belong to the report-only retention jobs. Leaving them out keeps the default. Each job counts and deletes nothing until its _ENFORCE variable is true or 1. See "Report-only retention jobs" in the environment docs for each window.
    • Device telemetry (#11663): DEVICE_COMMAND_RETENTION_* (120 days), FILESYSTEM_SNAPSHOT_RETENTION_* (7), NETWORK_MONITOR_RESULT_RETENTION_* (30) and DEVICE_SESSION_RETENTION_* (365), each with _DAYS, _BATCH_SIZE, _MAX_BATCHES and _ENFORCE.
    • Closed alerts (#11665): ALERT_RETENTION_DAYS (365), ALERT_RETENTION_BATCH_SIZE, ALERT_RETENTION_MAX_BATCHES and ALERT_RETENTION_ENFORCE.
    • Script executions (#11703): SCRIPT_EXECUTION_OUTPUT_RETENTION_DAYS (90), SCRIPT_EXECUTION_RETENTION_DAYS (365), SCRIPT_EXECUTION_RETENTION_BATCH_SIZE, SCRIPT_EXECUTION_RETENTION_MAX_BATCHES and SCRIPT_EXECUTION_RETENTION_ENFORCE.
    • AI transcripts (#11775): AI_TRANSCRIPT_RETENTION_BATCH_SIZE, AI_TRANSCRIPT_RETENTION_MAX_BATCHES and AI_TRANSCRIPT_RETENTION_ENFORCE. The windows are set in the AI data-policy settings, not here.
    • Run and access history (#11707): HISTORY_RETENTION_BATCH_SIZE, HISTORY_RETENTION_MAX_BATCHES, and a _DAYS and _ENFORCE pair for each of AI_AGENT_RUN_RETENTION_* (400), PATCH_JOB_RESULT_RETENTION_* (365), SECURITY_POSTURE_SNAPSHOT_RETENTION_* (365), CIS_BASELINE_RESULT_RETENTION_* (365), AUTOMATION_RUN_RETENTION_* (180), REPORT_RUN_RETENTION_* (365), USER_NOTIFICATION_READ_RETENTION_* (90), USER_NOTIFICATION_RETENTION_* (365), REMOTE_SESSION_RETENTION_* (365), SUPPORT_SESSION_RETENTION_* (365), AUTH_SESSION_RETENTION_* (30) and NETWORK_CHANGE_EVENT_RETENTION_* (90).
  • Changed meaning, no new name: BREEZE_PLATFORM_ADMINS (see After the upgrade, check above, #11834).
  • Compose: docker-compose.yml and deploy/docker-compose.prod.yml each gain the same 66 lines in the shared api environment block: the 54 retention mappings, BACKUP_LOCAL_ROOT, the three PORTAL_GOOGLE_* variables and PORTAL_SELF_REGISTRATION_ENABLED, plus comments. No mapping was removed and no service was added.

Other behaviour changes and feature flags

  • Custom roles with an Inherit From parent gain the parent's permissions (#10641). On upgrade, members of such a role get the parent's permissions, and they start to appear in approver lists, notification recipients, report access and access reviews. The role editor already showed these permissions as held. To see which roles widen before you upgrade, run the read-only report scripts/ops/role-inheritance-gain-report.sql against your database: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -P pager=off -f scripts/ops/role-inheritance-gain-report.sql. It returns one row per role that has a parent. A parent chain is followed for at most 8 levels, and creating or editing a role past that depth is refused.
  • AI tool profiles: Auto can narrow OpenAI-compatible models with no action from you (#11786). After the first model discovery sync (daily at 06:48 UTC, or a manual sync), a model whose endpoint states a context window gets the tool set that fits it. For example, chat on a 128k model moves to the Standard set, and an 8k model gets Minimal everywhere. A model whose window is too small for Breeze chat tools is refused at the start of the conversation with 409 context_window_too_small, where before the first request failed. The first request's max_tokens is capped from the known window. To keep the full set on a model, set its profile to Full in the model drawer. Platform, Anthropic bring-your-own-key and catalog models are not affected.
  • AI tool profiles: a saved change restarts open conversations on that model at their next message; the user is asked to resend (#11801). A write that would take a required tool away from a feature the model serves is refused with 422 tool_profile_underpowered.
  • AI model Verify can now refuse one feature for a model (#11795). Only after an admin re-verifies an OpenAI-compatible model that is explicitly assigned to that feature, and it fails that feature's round trip. Existing verification records refuse nothing.
  • Backup destination notices are on by default (#11777). Partners' backup admins (backup:write) start to receive one in-app notice per failing destination, and the incident appears in Connection health and the daily digest. Only failures on the destination's current storage settings in the last 72 hours count.
  • Retention is report-only (#4342). Every _ENFORCE variable defaults to false. Review the nightly REPORT-ONLY log lines or the breeze_retention_rows_eligible metric before you turn one on. With SCRIPT_EXECUTION_RETENTION_ENFORCE on, script output is removed after 90 days and the dashboard shows "Output removed after the retention window". With AI_TRANSCRIPT_RETENTION_ENFORCE on, conversations past their window are emptied to a stub and flagged conversations are held.
  • Customer portal self-registration (#11746). PORTAL_SELF_REGISTRATION_ENABLED defaults to on, and each organization's self-registration mode defaults to off, so nothing is offered until an MSP turns it on for an organization that has a verified email domain. The /request-access page answers on any host and gives every address the same reply. MSP approval of a request re-checks that the requester's domain is still verified and answers 409 PORTAL_ACCESS_REQUEST_DOMAIN_NOT_VERIFIED if it is not (#11679).
  • Conflicting portal access requests (#11384). A Microsoft (or Google) portal sign-in in approval mode at an address that already has a pending request for a different identity (another account, another provider, or a pending self-registration) is now refused instead of silently keeping the first request. The portal tells the person a request for their address is already waiting (/login?sso=request_pending) instead of the generic failure. The MSP denies the pending request, then the person signs in again.
  • Sign in with Google is off until PORTAL_GOOGLE_CLIENT_ID and PORTAL_GOOGLE_CLIENT_SECRET are both set. Leave them unset.
  • Windows Security events (#11739). Records 5038, 5157, 5152, 4957 and 5061 are no longer stored, shown in the Events view, matched by event_log monitors or forwarded to a SIEM. The response to the agent's upload reports the count as noiseDropped. Once a Windows device runs the 0.129.0 agent, it collects only the audit events on its list; NTLM credential-validation failures (4776) are not on it.
  • /health/ready on a read-only database (#11738). It answers 503 with "dbReadOnly": true and "reason": "db-read-only"; /health stays 200. With no migration pending, the API now starts against a read-only database instead of restarting in a loop, and with BINARY_SOURCE=local it reports "binarySyncPending": true until the database accepts writes. With a migration pending it stops with an error that names the read-only condition. The API's 503 body now carries one reason value (shutting-down, db, db-read-only, redis or workers-pending).
  • Reports: decommissioned devices are no longer in report device populations, so device counts in reports can go down (#11653).
  • Ticket queue age is measured from when the ticket was created; the tooltip shows created and updated. The #caller-verification hash on /tickets/[id] is gone (#11575).
  • Billing contact: changing an organization's billing contact needs billing:manage (#11683).
  • Billing switched off for a partner: organization-scoped callers of the invoice and autopay routes are now refused while the partner's billing is off (#11124).
  • Linux devices that reported a placeholder serial number (for example "To Be Filled By O.E.M.") record one serial-number change when they update to the 0.129.0 agent (#10918).
  • API changes to check if you integrate:
    • POST /authenticator/register-grant accepts ssoReauthGrantId, and a rejected proof answers 400 instead of 401 (#11656).
    • PATCH /ai/models/offerings/:id accepts toolProfile, toolAllowlist and contextWindowOverride (#11801). Model records carry contextWindow and toolProfile (#11786, #11801).
    • Session starts can answer 409 context_window_too_small or 409 tool_profile_underpowered (#11786, #11680).
    • GET /tickets rows include submitterName (#11575).
    • Backup job and dashboard routes return failureCause beside failureCategory (#11770).
    • GET /portal/auth/methods returns requestAccess (#11679) and google (#11796).
    • Script execution reads return outputPurgedAt, and AI session reads return transcriptPurgedAt (#11703, #11775, #11789).
    • The AI data-policy routes carry transcriptRetentionDays, and three …/transcript-retention-preview routes are added (#11775).
  • Wisp (Breeze Cloud only, BREEZE_WISP_ENABLED): no default changed.
  • No flag in this release has to be turned on.

Known gaps

Verification gaps in this release. Stage your own rollout if one of these applies to you.

  • macOS on Apple Silicon: the upgrade-in-place check (no permission prompt, helper reloaded, remote desktop working) was run on an Intel Mac on macOS 15 only. It was not run on Apple Silicon or on a second macOS version.
  • MSSQL backup and restore (#11827): verified against SQL Server Express before merge; not re-run on the release build.
  • Linux bare-metal recovery (#11829): a full rebuild and first boot was not run on lab hardware for this release. Test a recovery on your own hardware before you rely on it.
  • Agent redirect handling (#11785): ordinary operation was checked on Linux and Windows agents; a redirecting proxy in front of the server was not.
  • Not exercised for want of an external account or device: inbound email through a mail provider (#11830), Outlook add-in linking (#11831), Portal Sign in with Google (#11384; it stays switched off), Zammad ticket import against a live instance (#11296), the UniFi integration change (#11695).
  • Tool profiles (#11393): the lab leg against a real small-context model was not run.
  • The macOS Local Network prompt for the agent (#11311) was not lab-verified.
  • The RDP-session preference of the Windows sign-in screen capture (#9583) is still not lab-verified.
  • Breeze Assist branding and localization (#11204) was not checked on Windows. The Brazilian Portuguese strings of the System Health tab (#11561) are machine-drafted.

Known issues

  • Breeze Assist on macOS stays in English when the system language is Portuguese (Brazil) (#11204).
  • A partner API key that is refused because of its owner's access returns the general 401 Invalid partner API credentials message (#11815).
  • Built-in H.264 encoder fallback: the picture can stay blocky after a burst of change on an otherwise static screen (#11639, still open).
  • Linux viewer: it still cannot connect to devices whose agent runs as a service (#11642).
  • Found during release testing, and older than this release: #11854, #11856, #11857, #11858.

What's Changed

Full Changelog: v0.128.0...v0.129.0

Don't miss a new breeze release

NewReleases is sending notifications on new releases.