Breeze RMM v0.122.1: remote desktop clipboard v2, AI suggested fixes that research and remember, administrator-approved diagnostic file access, Partner API ticket read and write, customer portal read APIs for hardware and performance data, restores that check snapshot integrity, and a large cut in database work per agent heartbeat.
v0.122.0 was never released. Its tag and container images exist, but a database migration in it fails on installations that have security policy links. Upgrade from v0.121.x straight to v0.122.1, and don't deploy 0.122.0. If you already started v0.122.0 and the API is restarting with
cannot ALTER TABLE "config_policy_feature_links" because it has pending trigger events, move to 0.122.1: the failed migration rolled back, and 0.122.1 applies the corrected file (#8396).
⚠️ Removed in this release (announced in v0.121): /api/v1/ai/provider now returns 404, and requests that still send the retired AI model fields (reviewerModel, allowedModels, agent model) are rejected with 400. The AI model registry (/api/v1/ai/models) replaces them. Details under Self-Hosting / Upgrade Notes (#7867).
⚠️ Restores need a v0.120.0 or later backup helper. Restores are refused for devices whose backup helper cannot check snapshot attestations, and recovery media older than v0.120.0 are refused. Update agents and rebuild recovery media before upgrading the server (#8047, #8302).
⚠️ Partner API tickets:* grants take effect now. Service principals that already hold tickets:read or tickets:write can use the new ticket routes as soon as you upgrade. Review those grants first (#8037, #8235).
⚠️ Some roles lose webhook visibility. Viewing webhooks now needs the new webhooks:read permission. A custom role with organizations:read but not organizations:write, and the built-in Partner Viewer and Partner Security Approver, no longer see webhooks until you add it (#8285).
⚠️ Roll forward only for installers. Installer bootstrap tokens are stored hashed from the first start. Rolling back afterwards breaks every installer issued since the upgrade and the tokens hashed at boot; re-issue installers if you roll back (#7978).
⚠️ Avoid deploying during a database backup window. Three migrations briefly take ACCESS EXCLUSIVE locks on busy tables and give up after 5 s if a long reader holds one; the API then fails to boot and re-applies cleanly on the next restart. Details under Database (#8011).
Security — hardening
This release includes security hardening across:
- partner service principal key ownership, scope delegation and MCP access;
- permission checks for webhooks, AI for Office templates, tunnels, DNS filtering policies, CIS baselines and IOC auto-quarantine, fleet findings, audit baselines, site-restricted users and partner-scope audit data;
- second-factor confirmation for charging a client, changing payment settings, approving audit baselines and restoring unattested backups;
- backup restore integrity, device purge and org erasure handling of backup storage;
- command delivery checks over WebSocket and queued org merges;
- installer bootstrap token storage and lifetime;
- the agent's own data directory on Windows file tools;
- diagnostic file access, which never grants credential material;
- endpoint URLs shown in alerts, tickets, monitor results and logs, and outbound request handling;
- customer portal responses for draft invoices;
- dependency updates.
Before upgrading: have each partner service principal's owner rotate any of its keys that another admin issued, and review the scopes granted before the upgrade beyond tickets:*. Scopes granted before this release are not re-checked against the granting admin's own permissions.
Self-hosters are encouraged to upgrade. (#7907, #7908, #7916, #7920, #7954, #7956, #7957, #7958, #7959, #7978, #7979, #8008, #8010, #8012, #8039, #8042, #8045, #8047, #8060, #8088, #8097, #8108, #8118, #8253, #8255, #8267, #8279, #8280, #8285, #8286, #8302, #8327, #8328, #8332, #8358, #8363)
Summary
- Remote desktop clipboard v2 (#8262, #8266, #8263). Large text copies in both directions, and PNG/JPEG images too, except that images copied on a Windows device do not yet reach the viewer (see Known gaps, #8393). A status chip shows what policy allows in each direction and offers copy and send actions. A paste that can't be delivered is cancelled instead of pasting stale content, and connecting no longer overwrites the technician's clipboard. Each session writes one audit entry summarising its clipboard activity (never the content). Needs this release's agent and viewer.
- Remote input fixes (#8244, #8251, #7848). Keys and mouse buttons are released when the viewer loses focus or the session drops, so nothing stays stuck down on the remote. German and French keyboards type the right letters on Windows and Linux remotes.
- AI suggested fixes research and remember (#7939, #7946). The suggestions panel on an alert groups Proven, AI suggestions and Similar fixes. A research agent proposes fixes from the catalog, built-in actions or manual steps, and a new Fix memory page lists what worked. Triage runs check fix memory first.
- Diagnostic file access (#7406, #8327). The AI assistant can ask to list and read files in named folders on one device, read-only and time-boxed, after an administrator approves. Credential material is never grantable, and file content is redacted for secrets before the assistant sees it.
- Partner API: tickets, device status and MCP (#8037, #8235, #8303, #7586, #8090). Service principals can read a ticket change feed and create, update, assign and comment on tickets. Ticket webhooks gain
ticket.updatedandticket.assigned. An opt-indevice-status:readscope adds a live device-status feed, and service principal keys can authenticate MCP at partner scope. - Customer portal visibility APIs (#7797, #8119, #8175, #8357, #8101). Per-organization toggles open read-only portal APIs for hardware health, hardware inventory and performance metrics, all off by default; a software inventory read API sits behind its own toggle. The portal has no pages for this data yet, so customers don't see it in the portal UI in this release.
- Restores check snapshot integrity (#8047, #8302). Restores proceed automatically for verified snapshots. Restoring an unattested snapshot needs a technician's second-factor confirmation, and restore wizards show a Verified / Not verified badge.
- Topology overview (#7892, #7845, #7882, #7883, #7846, #7843, #7847). Cards zoom out to summary panels, members are grouped by role, VPN and overlay networks are classified by interface type, and stale or decommissioned devices no longer read as online.
- Who's connected (#7461). The device page shows a banner naming colleagues with a live Desktop, Terminal or VNC session on that device.
- Reliability baseline markers (#8319, #8323). Mark a device reimaged, remediated or hardware-replaced, and its reliability score restarts from that point with a before/after comparison.
- Lighter heartbeats (#8128, #8222, #8264, #8055, #8054, #8282). A steady agent heartbeat now runs 14 database statements in 2 transactions (v0.121: 9 transactions), policy resolution is one read, and requests queue fairly for database connections under load.
Added
- Diagnostic file access for the AI assistant: requests name the device, paths, list/read, a purpose and a duration (5–1440 minutes); administrators decide in the Approvals inbox or the mobile app; grants are read-only and revocable. Diagnostic reads need this release's agent; older agents return
agent_update_required(#7406, #8327). - AI suggested fixes: Generate and "Research deeper" on an alert, built-in actions (reboot, restart service, kill process, disk cleanup) runnable from a suggestion, "Draft a script" into the script builder, and the Fix memory page with Retire (#7939). Triage verdict and full alert runs consult fix memory first, behind
ml.remediation_suggestions.enabled(#7946). - Partner API tickets:
GET /api/v1/partner-api/tickets(signed change feed with tombstones),/tickets/ids,/tickets/:id,/tickets/:id/commentsfortickets:read(#8037);POST /tickets,PATCH /tickets/:id,POST /tickets/:id/status,/assign,/commentsfortickets:write, withX-Idempotency-Keysupport and external ticket references (#8235, #8304). - Ticket webhooks:
ticket.updated(with changed field names) andticket.assigned; existing ticket events carry more ids, including the comment's origin so a mirror can skip its own comments (#8303). Customer email replies now fireticket.commented(#8344). - Partner API device-status feed (
GET /api/v1/partner-api/device-status) behind the opt-indevice-status:readscope (#7586). - Partner service principal keys on MCP at partner scope, with opt-in
ai:read,ai:write,ai:executeandai:execute_adminscopes.MCP_UNATTENDED_TIER3_PRINCIPALSacceptspartner_sp:<principal id>(#8090). - Remote desktop clipboard v2 in the agent and Breeze Viewer, and one
session_clipboard_summaryaudit entry per session (#8262, #8266, #8263). - Who's connected banner on the device page (
GET /remote/devices/:deviceId/active-sessions) (#7461). - Customer portal: hardware health (#7797), per-device hardware inventory (#8119) and performance metrics (#8175) toggles, each off by default and included in Enable all. They open read-only portal APIs; there are no portal pages for this data yet. Also a Site filter on the Network assets table (#8101).
- Customer portal software inventory (API only):
GET /portal/software/summaryandGET /portal/software/devices/:deviceId, behind the newenableSoftwareInventorytoggle. It is off by default and not turned on by Enable all; switch it on individually per organization. The portal has no software page yet, so the toggle only opens the read API (#8357). - Reliability baseline markers: "Mark work done" on the device reliability panel, provisional scoring for 14 days, before/after comparison and marker history; a completed bare-metal recovery places a
reimagedmarker automatically (#8319, #8323). - Physical placement (room, rack, rack unit, height) for devices and discovered assets, API only (
/devices/:id/placement,/discovery/assets/:id/placement) (#8348). - Site location pins:
POST /api/v1/orgs/sites/:id/locationpins a site's coordinate and optional 50–1000 m geofence radius from the field; it requires the newsites:set_locationpermission and deliberately no MFA.PATCH /orgs/sites/:idalso acceptslatitude/longitude/geofenceRadiusM(still MFA-gated; both coordinates or neither). Only the site's coordinate is stored, never a technician position. Audited assite.location_set(#8223). - Time entries carry an org and site without a ticket:
POST /api/v1/time-entries/startandPOST /api/v1/time-entriesaccept optionalorgId,siteIdandsource. A ticket's org always wins; a mismatch is422 ORG_MISMATCH, a site outside the org is422 SITE_ORG_MISMATCH.GET /time-entriesreturnssiteIdand filters by it (#8223). - Location suggestions (partner setting, off by default): Ticketing settings → Time Tracking gains a toggle and a default arrival radius (
timeTracking.locationSuggestions).GET /api/v1/time-entries/location-sitesreturns the flag, the default radius, whether the caller may pin sites, and the caller's sites (capped at 2000 with atruncatedflag) for the mobile app's arrival prompt. The mobile prompt itself ships later (#8223). - EDR integrations (read path): a provider framework with Bitdefender GravityZone as the first provider. Partner admins connect an API key, map GravityZone companies to organizations, and endpoints are linked to devices by hostname; detections sync in the background. API only under
/api/v1/edr(#8220, #8259). - Hosted partner sign-in page at
/login/<partner-slug>, shown on the Login Branding card (#8070). - Pushover for ticket assignments to the assignee's own Pushover key, set on the profile page; an optional partner fallback to the default key is off by default (#8080).
- Default assignee for new inbound tickets, per partner, on the Inbound email card (#8106).
- Staff forward routing: with the new partner switch on, a customer email forwarded by your staff into a connected Gmail mailbox is filed under the original sender's organization. Off by default (#7961).
- Gmail mailboxes can label and archive mail that became a ticket. Off until a label is set; needs the
gmail.modifyscope on the domain-wide delegation grant (#7950). - Delete time entries from the ticket's Time & Billing rail and from the timesheet (#8135).
- Quote Sign & pay: a customer signing a quote with money due now goes straight to Stripe checkout (#8249).
- Payment reminders for every unpaid invoice (upcoming, repeat and overdue), configured under Billing → Payments. Off by default and independent of automatic payments (#7866).
- Automatic payments (enrollment, charging, retries, processing fee, client pages and emails). Ships switched off for every partner behind the per-partner rollout switch (#7822, #7877, #7893, #7987, #7983, #7986).
- Access reviews: reviewers can't decide their own access, except in a single-admin setup, where the decision is flagged "Self-decided" (#7878). "Notify reviewer" sends the email from the server (#7851).
- Organization column on the Custom Fields page for partner-level users (#8100).
- Agent display branding (build time): operators building their own agent can set the display name, description and publisher of the agent and watchdog (#8061).
- Windows recovery console groundwork: the
breeze-backuprecovery console runs on WinPE. Building Windows recovery media is not part of this release (#7926).
Improved
- Heartbeat database work: a steady beat now runs 14 statements in 2 transactions, down from 9 transactions in v0.121. UniFi collector polls make no database calls for devices without collectors, and permanent agent auth rejections are cached for 60 s (#8128, #8222, #8264, #8055, #8054).
- Database connections under load: requests queue fairly for a pool slot and fail cleanly after a bounded wait, timed-out transactions always roll back, and short event-loop stalls no longer cause false timeouts (#8243, #8282).
- Restores download files in parallel (up to 8 at a time) while installing in manifest order (#7417).
- Fewer noisy metric anomaly episodes: three consecutive 5-minute buckets, and RAM growth only on a new 7-day high (#7815).
- Quote PDFs match the web proposal and use partner branding, with an optional contents list (#7713). Quote parts orders include only lines with a SKU or part number, and the editor and send dialog say so (#8248).
- Topology: neighbor-cache corroboration places phones and printers and splits conflicting gateways (#7845); summary cards, role sections and a compact toolbar (#7892).
- Microsoft 365 admin consent signs the administrator in first, shows a confirm-tenant screen, and pins consent to the verified tenant (#7933, #7938). Consent failures name the cause, for example a Conditional Access block (#7915).
- Ticket-assigned email includes a facts table, the first 1,200 characters of the message and an "Open ticket" link (#7952).
- Customer email sender name: customer-facing mail is sent as your company name instead of "Company via Breeze" (#6574).
- AI chat: read-only Windows event log queries against
SystemorSetuprun without an approval tap in interactive chat (#7917); the assistant sees longer validation errors (#7836); monitor creation explains valid kinds and conditions (#7840, #8103). - macOS agent updates download the installer package from your own server first, then fall back to the GitHub release; the package must still match the signed checksum (#8107).
- Breeze Assist starts hidden in the tray when the agent starts it; launching it yourself still opens the window (#8213).
- AI connections: adding an OpenAI-compatible connection reports whether discovery was queued (#8099); a refused Base URL shows on the field (#8271); env-managed offerings lock name and price (#8098).
FORCE_HTTPSrejections return a reason code and link to the TLS docs (#8093).- Sign-in page partner logo renders larger (#7929).
- Scoped contact responsibilities (backend): caller verification, account readiness, billing contact resolution and report recipients read from a new
contact_rolesmodel, back-filled from existing contact roles. No UI change in this release (#8226). - 65 more operator settings (retention windows, agent ingest quotas, rate limits, screenshot and log-forwarding caps,
DB_POOL_MAX) are passed from.envinto the API container by both Compose files (#7858).
Fixed
- Time Tracking settings show the stored values. Settings → Ticketing → Time Tracking always displayed both suggestion toggles as off, with default thresholds, and saving the card wrote those defaults back over the stored settings (since v0.109). It now loads and keeps the stored values. If you saved that card on an earlier version, re-check "Suggest time entries from remote sessions" and its thresholds (#8387).
- AI
run_scriptand other tools that wait on a device no longer report failure when the device takes longer than a minute (#7928). Tool results are matched to the right call in chat and in AI agent runs (#7932, #8214). - AI chat shows the provider error when a turn fails before any output (#8273); an aborted chat no longer puts the model on cooldown (#8177); OpenAI-compatible gateways such as Ollama no longer refuse every tool call (#8091).
- Moved devices pick up their new organization and site on the agent through a signed identity update (#8320).
- Device control (peripheral policy v2) applies to devices that aren't in any device group (#8322).
- Agent command results finishing during shutdown are kept and delivered on the next connect (#8379).
- Windows service monitoring no longer reports protected services such as
WinDefendasnot_found(#8038). - Antivirus and firewall: a failed collection reports Unknown instead of off, without the unprotected penalty or alerts (#8043, #8272). N-able is no longer detected from any process named
agent(#8085). - macOS: the desktop helper no longer re-raises the screen recording prompt after a restart (#8154); reinstalling right after uninstalling works (#7876); a
breezegroup without a GID is repaired (#7833); long group member lists are read correctly (#7972). - Windows: restore point descriptions keep their first characters (#8069); the Storage Spaces collector no longer flaps on hosts without pools (#8150); the agent's own service restart no longer counts against reliability (#8227); the Migrate Agent Edition script no longer stops itself midway, and automatic edition migration canaries one device per org (#7336).
- Windows installs with object storage install the watchdog again, and the install one-liner enrolls before installing the service (#7585).
- Add Device install command uses the API's configured public URL on split deployments (#8124).
- Linux patches on update rings with a deferral are no longer held forever; the deferral starts from when the device first reported the patch (#7930).
- Bare-metal recovery: a failed attempt no longer consumes the recovery token (#7411); a snapshot from a changed destination is refused up front (#7410).
- Backup: a backup is stopped if the device moves org or its config changes mid-send; verifications of a failed snapshot fail immediately (#8044). The policy Backup tab offers "New destination" in its empty state and lists the policy owner's destinations (#8314, #8336).
- Org erasure completes for an organization that is in use, and partner staff whose home org is erased are kept (#8011).
- Moving a device to another org no longer times out after 30 s in the dashboard (#8025).
- Scripts queued by partner technicians for offline devices are delivered when the device comes online (#7964).
- Scheduled network discovery jobs no longer stick in
scheduled(#7945); discovery no longer overwrites an agent-detected device role (#8034). - DNS filtering: policy changes sync to the provider again (#8337); Cloudflare Gateway event sync and list edits use the real Cloudflare APIs (#7619); a private-address integration host shows a clear sync error (#8073).
- Network proxy loads device stylesheets and scripts in Firefox and for
crossoriginresources (#8110). - Microsoft 365 ticket mailboxes keep polling through transient Graph errors (#8300); converting a quarantined email keeps its body and sender (#8316).
- Ticket assignment notifications are no longer lost when the worker runs first (#8040).
- Patch compliance Export downloads the CSV (#8315).
- Security recommendations can be completed or dismissed by partner users across organizations (#8094).
- Step-up prompts work when enabling the AI unattended script lane and the partner script-authoring ceiling with
ENABLE_2FAon (#8095, #8115). - Service principal edits no longer shift the expiry by the browser's time zone (#8383).
- Audit Trail shows partner-level events to partner users and records partner-level and document writes that were dropped before (#7808, #8009); filtering by user no longer returns 500 (#8374).
- Webhook delivery Retry no longer returns 404 (#8336).
- AI tools:
manage_tagsadd and C2C item restore work again (#8298);manage_patchesdevice actions resolve the device's own org (#7839);get_device_detailskeeps core fields when compacted (#8064); monitor updates keep the stored URL (#7955). - Service and process monitor alert titles show the name instead of
{{serviceName}}(#8063). - Org branding logo saves correctly (#8062); redirects are never cached by browsers (#8048); long dashboard pages are no longer cut off (#8018).
- Agent change reports with a NUL character no longer fail the whole batch (#8026).
- Helper screenshots are removed from disk when their records are deleted (#8216, #8116).
- Guided setup boot helper recreates Caddy reliably after a reboot (#7962).
- pt-BR no longer translates vendor names (#7728).
- Smaller fixes from the pre-release sweeps (#8114, #8336, #8374, #7834, #7837, #7838, #7849, #7859, #7860, #7871, #7835, #8105, #8178, #8212, #8027, #8036, #8270).
Known gaps in this release
- Clipboard images from Windows devices don't reach the viewer (#8393). Text copies work in both directions, including large ones, but an image copied on a Windows device isn't sent to the viewer. The desktop session runs as SYSTEM and can't read the user's copied image formats. Images pasted into a Windows device aren't affected by this. Planned for a follow-up release.
- Identity sync after a device move needs a deployment signing key (#8320). A key exists when the server registers its own agent binaries (
BINARY_SOURCE=local) or has issued an agent rollback directive. On the defaultBINARY_SOURCE=github, the server has no key, so a moved agent keeps its enrolled organization and site, as before this release, and the API logs a one-time warning. - Checked before the release: live Windows and Linux agents for identity sync, clipboard text, Breeze Assist start-hidden, Storage Spaces, diagnostic file access and the AI event-log query, and real Stripe test mode for Charge now, the consent cap, payment-settings step-up, quote Sign & pay, and partner suspension. Not lab-run: macOS agent rows (#8154, Breeze Assist Dock reopen), the viewer's clipboard status chip and image paste (#8266), and held-key release on disconnect (#8251).
Self-Hosting / Upgrade Notes
Upgrade command. Check how your install pins its images: grep '^BREEZE_API_IMAGE_REF=' .env.
- Digest-pinned (value ends in
@sha256:…, everyguided-setup.shinstall from v0.112.0): fetch the currentguided-setup.shfrommain, then runbash guided-setup.sh --upgrade 0.122.1. It verifies the signed image inventory, updatesBREEZE_VERSIONand all four image digests, then pulls and restarts. - Tag-form (value ends in
:${BREEZE_VERSION}): setBREEZE_VERSION=0.122.1, then rundocker compose pull api web portal && docker compose up -d. - Do not edit only
BREEZE_VERSIONon a digest-pinned install. It re-pulls the images you already run. --upgradedoes not change yourdocker-compose.yml. To set any of this release's new optional variables, add their lines to theapiservice'senvironment:block (or take the v0.122.1docker-compose.yml); a value only in.envdoes not reach the API.- See the Upgrade Guide.
Breaking changes and required actions.
- Legacy AI model settings removed (#7867). The AI model registry (Settings → AI Providers & Models) is now the only AI model configuration.
/api/v1/ai/provideris gone (404). Use/api/v1/ai/models:POST /ai/models/connections,POST /ai/models/connections/:id/key,POST /ai/models/connections/:id/endpoint,DELETE /ai/models/connections/:id, andPUT /ai/models/assignmentsfor per-feature defaults.- Requests that still send
reviewerModel(script policy),allowedModels(AI for Office org policy) ormodel(AI agent create/update/preview; sendofferingId) are rejected with HTTP 400 naming the replacement. These fields were already ignored; GET responses no longer include them. BREEZE_AI_SCRIPT_REVIEWER_MODELandWORKSPACE_CONTENT_LLM_MODELare no longer read; remove them from.env. New partners start every AI feature on the platform default model.- Upgrading straight from a release older than v0.121.0: each partner is set up from the platform default; a partner with its own Anthropic key keeps using it, but its legacy per-feature model choices are not carried over.
- No database change for this in this release; the legacy table and columns are archived and dropped in the next release.
- Restores now require a v0.120.0 or later backup helper (#8047, #8302). Restores that write, import or boot a backup (file, SQL Server, Hyper-V, restore as VM, instant boot, bare-metal recovery and rebuild) are refused for devices whose backup helper does not check restores against snapshot attestations, with "Update the Breeze agent on this device, then try again." Recovery media and recovery tools older than v0.120.0 are refused at code exchange and authentication. Verification and test restore are unchanged. Update agents and rebuild recovery media before upgrading the server.
- Backups without an attestation restore after a two-factor confirmation. Snapshots taken before attestations existed are labelled "Not verified"; restoring one requires a technician's two-factor confirmation (an explicit confirmation when
ENABLE_2FA=false; a technician without a second factor must set one up first, and SMS-only accounts need an authenticator app or passkey), recorded in the newbackup_restore_authorizationstable and the audit log (backup.restore.unattested_override). AI tools and DR plans refuse such snapshots.breeze_backup_restore_integrity_totalgainsstatus="override"andstatus="refused".
- Backups without an attestation restore after a two-factor confirmation. Snapshots taken before attestations existed are labelled "Not verified"; restoring one requires a technician's two-factor confirmation (an explicit confirmation when
tickets:*grants on partner service principals take effect in this release (#8037, #8235). v0.121.x already let admins granttickets:readandtickets:writeto a partner service principal, but the Partner API ticket routes were not live, so those grants did nothing. This release adds the routes (/api/v1/partner-api/tickets*), and any principal that already holds those scopes can use them immediately:tickets:readreads every ticket and every comment, including internal notes, in every organization the principal reaches, andtickets:writecreates and updates tickets and posts comments, including customer-visible replies that email the requester. Before upgrading, review which partner service principals holdtickets:*(Settings → Partner Service Principals) and remove the scopes from any that should not have them. Scopes granted before this upgrade are not re-checked against the granting admin's role, so include principals whose scopes were granted by an admin who does not hold them.submitterEmailon ticket writes is not verified.- Partner service principal keys are issued by the principal's owner and end with the owner's sign-in credential (#8332). Only the admin who created a partner service principal can issue or rotate its keys, re-enable it, add a scope, or remove or extend its expiry or source-CIDR restriction; other partner-wide admins get
403(SERVICE_PRINCIPAL_OWNER_REQUIRED) but can still revoke keys, disable the principal, remove scopes and rename it. Every scope is now a delegation the granter must hold, not only the MCPai:*scopes: for exampletickets:read/tickets:writeneedtickets.read/tickets.write,contracts:writeneedscontracts.writeandalerts:readneedsalerts.read(the full list is under "Who can manage a partner service principal" in the API keys reference).- Keys are bound to the owner's credential state like a person's own API keys: the owner's password change or reset, an administrator changing the owner's account status (including disabling it), a change to the owner's MFA factors, or removing the owner from the partner stops the principal's keys on both the Partner API and MCP; signing out does not. Existing keys are bound to their owner's current state on upgrade and keep working.
- Over MCP, a key that another admin issued on someone else's principal is refused; the owner rotates it to restore access (the Partner API keeps accepting it). Have principal owners rotate such keys before upgrading.
- Plan for owner off-boarding: an integration whose principal belongs to a departing admin stops when that admin is disabled or removed, so create a replacement principal under another admin first.
- Organization API keys: only a key's creator can rotate it now (
403,API_KEY_CREATOR_REQUIRED, for anyone else, who can still revoke it), and rotating re-binds the key to the creator's current sign-in. - Rolling deploys: API containers still on v0.121 cannot issue or rotate service principal keys once the migration has run, until they are replaced.
- New
webhooks:readpermission (#8285, #7956). Viewing webhooks and their delivery history (the Webhooks tab under Integrations,GET /webhooks,GET /webhooks/:id,GET /webhooks/:id/deliveriesand the AI assistant'squery_webhookstool) now requireswebhooks:readinstead oforganizations:read. Managing webhooks still requiresorganizations:write. The built-in Org Admin, Org Technician and Partner Technician roles receive it on upgrade (Partner Admin already holds everything), and so does any custom role that holdsorganizations:write(or a wildcard grant covering it). Viewer, billing and security-approver roles do not, so Partner Viewer and Partner Security Approver, which could see webhooks throughorganizations:read, no longer can.- A custom role that holds
organizations:readbut notorganizations:writeloses access to webhooks and their delivery history until an administrator addswebhooks:readto it under Settings → Roles. The upgrade log lists those roles: the migration writes awebhooks-read-permission:warning with their count and up to 20 names. - In the dashboard, the Webhooks tab is hidden for users without
webhooks:read, and users withwebhooks:readbut notorganizations:writesee webhooks and their delivery history without the create, edit, delete, test, pause/resume or retry controls. - API contract change: the delivery list no longer returns delivery
payloadorresponseBody.
- A custom role that holds
- Roll forward only for installers (#7978). Installer bootstrap tokens are stored as a keyed hash (
ENROLLMENT_KEY_PEPPER), and a background sweep at first start hashes existing tokens, logging[startup] Installer bootstrap tokens hashed: X/Y token(s) (Z changed concurrently, F failed). A rollback strands every installer issued after the upgrade, and the pre-upgrade tokens hashed by the sweep stop working on the old version too: re-issue installers after a rollback. RotatingENROLLMENT_KEY_PEPPERnow invalidates every outstanding installer link and every downloaded installer that has not enrolled yet.
Other behaviour changes.
- Bootstrap tokens embedded in downloaded installers now default to 7 days and last at most 30 days (#8280). The previous default was 30 days in code and 1 day under the bundled compose files (
1440).INSTALLER_BOOTSTRAP_TOKEN_TTL_MINUTESnow defaults to10080in code and in both compose files. A value above43200(30 days) is clamped, with a warning at API startup. Set the variable to keep a different value up to 30 days.- The installer download (
GET /enrollment-keys/:id/installer/:platform) andPOST /enrollment-keys/:id/bootstrap-tokennow reject an explicitttlMinutesabove43200with400. The child enrollment key embedded in the legacy macOS zip is held to the same 30 days. - The Add Device modal's Installer tab offers expiries up to 30 days (it previously offered 90 days and 1 year); a longer partner/org default preselects 30 days there. That picker also sizes links generated from the tab. The CLI tab is unchanged.
- The installer-link API (
POST /enrollment-keys/:id/installer-link) and enrollment keys still accept lifetimes up to a year; each installer downloaded from a link carries a token of at most 30 days. - Installers already downloaded keep their original expiry.
- The installer download (
- Patch compliance report files are kept for 30 days (#8284). A generated compliance report CSV can be downloaded for 30 days after it completes; after that a daily job removes the file and the report shows as
expired(download returns 410 — generate a new report). SetPATCH_REPORT_RETENTION_DAYSto change the window (minimum 1). Report files are also removed when their organization is erased, and stray report files with no report record are cleaned up fromPATCH_REPORT_STORAGE_PATHonce they are an hour old (PATCH_REPORT_ORPHAN_MIN_AGE_MS). On the first run after upgrading, existing reports older than the window are expired. - Diagnostic file access: credential material is never grantable, and self-approval needs a fresh second factor (#7406, #8327). Browser secrets, credential stores, private keys and stored tokens can never be requested or granted: requests naming them are refused, listings of approved folders leave them out, and the agent refuses them on its own (
E_DIAG_CREDENTIAL_MATERIAL); therequest_diagnostic_accesstool takes no sensitive-class option. File content read under a grant is passed through secret redaction before the assistant sees it, over a window with 16 KiB of context on each side so a read cannot start inside a secret (contentRedacted: truewhen anything was replaced; one read returns at most 992 KiB). A sole operator approving their own request must sign that approval with a hardware-backed factor (passkey or Breeze Authenticator, L3 or higher; a reused step-up does not count), and adiagnostic_access.self_approvalaudit record is written before the grant activates; if it cannot be written the approval returns 503audit_unavailableand can be retried. Diagnostic reads need agents from this release. See Diagnostic File Access. - Approving an audit baseline apply request now requires MFA and checks its target devices (#8279). On deployments with MFA enabled (
ENABLE_2FA), approving a request returns 403MFA_REQUIREDunless the approver's session has completed MFA. API keys cannot approve apply requests when MFA is enabled. Rejecting a request does not need MFA. Approving is also refused with 409 ("One or more target devices no longer exist in this organization; ask the requester to submit a new apply request") when any device in the request has since been decommissioned, deleted or moved to another organization. Applying an approved request runs the same check and leaves the approval unconsumed. When two decisions on the same request race, or a decision races the request's expiry, the later one returns 409 ("Apply request was already decided") instead of overwriting the first. Pending requests refused this way can be rejected and resubmitted. - Deleting a role that an access review covered now returns 409 ("Role is referenced by access reviews") instead of a server error, so review evidence is kept. Deleting a notification channel keeps the alert delivery history it produced (shown without a channel name), and deleting a maintenance window removes all of its occurrences (#8011).
- AI for Office prompt templates have their own permissions (#8286). Two new permissions,
client_ai_templates:readandclient_ai_templates:write, replaceorganizations:read/organizations:writeon the AI for Office template manager. On upgrade, every role that holdsorganizations:read(built-in and custom) receivesclient_ai_templates:read, and every role that holdsorganizations:writereceivesclient_ai_templates:write. Partner Technician, Partner Viewer and Partner Security Approver get read. The built-in Org Admin gets read and write, which is new access for that role. Partner Admin is covered by its wildcard. Org Technician and Org Viewer get neither. Creating, editing and deleting a template now also requires MFA when your MFA policy requires it. The Templates tab and its edit controls are hidden from users without the matching permission. - CIS hardening and IOC auto-quarantine run under an approving user (#7979, #8008). Editing CIS baselines or remediations and turning on IOC auto-quarantine need
devices:executeand MFA. Existing schedules keep running under the user who created them while that user is active and holdsdevices:execute; otherwise a schedule pauses with "Needs re-approval", an IOC scan runs detect-only, and a remediation returns to pending approval until someone withdevices:executeand MFA saves it again. Approved CIS remediations not dispatched within 7 days return to pending approval. - Automatic payments run only for active partners; resetting an invoice link also resets its automatic-payment links (#8328). When a partner is suspended, churned, offboarding, pending or deleted, automatic payments stop for all of its clients, even with the rollout switch on: enroll and update-method links stop working, setup creates no Stripe customer or Checkout session, a setup that finishes saves no payment method and does not turn automatic payments on, due charges and retries are deferred (and end after the usual grace, as when automatic payments are switched off), reconciliation creates or confirms no payment (an unconfirmed one is cancelled), card-expiry emails stop, and cancelled charging notices are no longer re-planned. Stop and skip links keep working for clients. Payments already in progress at Stripe are still recorded. Reactivating the partner resumes charges that were already scheduled or awaiting a retry. Invoices whose charging notice was cancelled while the partner was inactive are not rescheduled on reactivation; collect those through the invoice's pay link. Separately, an invoice's Reset link now also revokes the skip, confirm-payment and update-method links sent for that invoice, and a revoked automatic-payment link no longer offers the invoice's pay link.
- Charging a client now and changing payment settings ask for a second-factor confirmation; the consent cap is checked before a payment is started (#8358, #8363). Charge now on an invoice, saving the partner Billing settings → Payments tab, saving an organization's own payment settings (its Billing tab, or
PUT /orgs/:orgId/billing/payment-settings) when a value actually changes, and sending a client's automatic-payment request to an address other than its billing contact now ask for a fresh authenticator-app code or passkey, bound to that invoice, those settings or that recipient, and only from a signed-in user session (API keys cannot do these). Whether an organization's payment settings change is decided by the server against the stored values: an organization save that changes none of them needs no confirmation and writes nothing, and the organization Billing tab no longer sends them at all when only other fields (such as the tax ID or address) were edited. Deployments running withENABLE_2FA=falseare not asked. Separately, an invoice over the automatic-payment limit (the one the client authorized, or a lower one you set later) is now refused before anything is created at Stripe, instead of a payment being started and then cancelled; the schedule ends and the client is told the planned charge will not happen, as before. - Device purge and org erasure keep backup objects in storage (#8215, #7980). Purging a device or erasing an organization no longer lets storage cleanup delete its backup files later; the objects stay, including ones past retention, until an explicit deletion feature ships. Storage is not reclaimed on purge or erasure. Legal holds set on a backup policy or configuration policy now block purge and erasure (
409 BACKUP_PROTECTED). - Helper screenshot cleanup catches up (#8216). The first retention run after the upgrade deletes expired screenshots and orphaned files that accumulated before. Screenshot storage is local disk, so with several API containers each sweeps only its own files.
- DNS policy changes reach providers (#8337). Pending DNS filtering policy changes are pushed to providers for the first time after the upgrade. Sending-domain auto-suspension now runs; on self-host it is on only if you set an
EMAIL_DOMAINS_AUTOSUSPEND_*variable. - Linux patches on deferred rings start auto-approving (#7930) once first-seen plus the deferral period has passed. Windows and macOS patches with no release date still wait for manual approval.
- Metric anomaly episodes:
METRIC_ANOMALY_EPISODE_MIN_BUCKETSdefaults to 3 (was 2); the variable still overrides it (#7815). - Policy assignment ties: when two configuration policy assignments tie on every ranking key, the earliest-created now wins. A device decided by an exact tie may change once after the upgrade (#8264).
- Several API instances: some org and partner values (agent update policy, version pins, topology flags, helper settings, policy probe, PAM fallback) are cached per API process for up to 60 s, the remote-management relay setting for up to 180 s. The instance that handled a change applies it immediately (#8128, #8222). A reinstated device or tenant can take up to 60 s to be accepted again (#8054).
- Database pool waits are bounded (#8243, #8282). A request queued behind a saturated pool used to wait indefinitely; it now fails after
DB_POOL_ACQUIRE_TIMEOUT_MS(default 10000,0restores the unbounded wait) withDbPoolAcquireTimeoutError, logged as[db-pool-acquire]. Workers may show more job retries under saturation. WithDB_POOL_MAXbelow 3 a warning is logged at startup. - Moved devices restart their agent once (#8320) after a random 0–60 s delay, when the new signed identity is applied. Deployments that have never created an agent deployment signing key send no identity update until one exists; agents with
BREEZE_ORG_ID/BREEZE_SITE_IDin their environment cannot take the new identity. - Helper (Breeze Assist) API returns 403
helper_disabledfor a device whose effective Helper setting is off (the agent already stops the Helper in that state) (#7959). Breeze Assist's tray menu loses Exit, and theshowTrayIconpolicy option is removed; the tray icon always shows (#8213). - Breeze Viewer shortcuts move to a prefix chord: Ctrl+Alt+Shift+F/V/R on Windows/Linux and ⌃⌥⌘F/V/R on macOS (fullscreen, paste as keystrokes, release stuck keys), so Ctrl/Cmd+Shift+V and +F reach the remote (#8244).
- Windows install one-liner on Add Device enrolls before installing the service and no longer ends with
service start. With object storage configured, watchdog downloads stream through the API instead of redirecting (#7585). - Split deployments: the Add Device command uses
PUBLIC_API_URL(elseAPI_URL) from the API; setPUBLIC_API_URLon the API if the dashboard and API are on different hosts (#8124). - Cloudflare Gateway DNS Security tokens now also need Account Analytics: Read (#7619).
- Microsoft 365 Customer Graph executors you run yourself: deploy executor images that serve
POST /v1/verify-identity(read and actions) before this API version, or onboarding fails asexecutor_unavailable. A consent in progress during the upgrade must be restarted. On Azure Container Apps, executors can setBIND_HOST=127.0.0.1(#7933, #7938, #7682). - Email: customer-facing mail uses your company name as the display name when
EMAIL_FROMis a bare address; anEMAIL_FROMwith its own display name is sent unchanged (#6574). Every transactional email now renders in a sans-serif font (#7987). - Webhooks and automations receive
ticket.commentedfor customer email replies (#8344). The assignee notification for a new ticket arrives on the next outbox pass, about 5 s later (#8303, #8040). - Remote tunnels: closing one needs
devices:execute,remote:accessand MFA (#7907). DNS filtering policy writes refuse site- or device-restricted users (#8118). Fleet findings status changes require MFA (#8045). Opening the live event stream requiresdevices:read(#8012). - Enrollment keys with an
expiresAtin the past are refused with 400; discovery profiles with a subnet larger than /16 needdeepScan(#8374). - Quotes: hardware lines without a SKU or part number are left out of the parts order (#8248). Quotes use the partner's Settings → Branding logo and colors, and contract PDFs generated from now on may paginate slightly differently (#7713).
- Self-hosted
docker/Caddyfile.prodcopies: a new@webBillingAutopaymatcher routes/billing/autopay*to the web app; carry it over if you maintain your own copy (#7822). - Building the agent from source now needs Go 1.26.9. The agent module and the release builds move from Go 1.26.6 to 1.26.9, and
golang.org/x/netfrom v0.59.0 to v0.60.0, picking up the upstreamnet/httpand HTTP/2 fixes in those releases. With the defaultGOTOOLCHAIN=auto,go buildfetches 1.26.9 on its own; withGOTOOLCHAIN=local, install Go 1.26.9 first. Pre-built agent binaries need no action (#8305).
Database.
- 76 migrations (idempotent; applied automatically on boot via
autoMigrateunlessAUTO_MIGRATE=false). Expect[auto-migrate] Applied 76 migration(s). A 77th new file,migrations/preflight/2026-11-28-100000-ai-model-registry-legacy-drop-preflight.sql, is a read-only check for the next release's legacy AI drop and is never applied byautoMigrate. - Mostly additive DDL: new tables for diagnostic access grants, backup restore authorizations and erasure fences, partner API idempotency keys, EDR providers, device ownership history, reliability baselines, physical placements, device workloads, contract hour periods, ticket approval settings and requests, contact roles and fix memory; new columns on
sites,time_entries,tickets,portal_branding,audit_logs,installer_bootstrap_tokens,partner_service_principal_keysand others; new permissions (webhooks:read,client_ai_templates:read/:write,sites:set_location,tickets:record_approval) granted to roles as described above; and RLS policy updates. - Brief exclusive locks on busy tables — avoid a backup window (#8011). The
2026-12-13-110000/110100/110200migrations redefine foreign keys on child tables ofusers,devices,alerts,tickets,rolesand others. Each swap briefly takes an ACCESS EXCLUSIVE lock on the child and the parent table, and waits at most 5 s for it (lock_timeout). If a long-running reader holds one of those tables (a large report, apg_dump/backup window), the migration stops, the API fails to boot with a lock-timeout error, and it re-applies cleanly on the next restart. Avoid deploying this release during a database backup window. No data is rewritten; the new constraints are validated afterwards without blocking writes. Thetime_entries,tickets/ticket_partsandsitescolumn migrations (2026-12-17-100300,2026-12-20-200300,2026-12-20-220000) use the same 5 s lock timeout and validate without blocking writes. audit_logsindex and validation scan at boot (#7808).2026-12-05-110100-audit-logs-partner-scope-index.sqlruns outside a transaction: it buildsaudit_logs_partner_scope_idxwithCREATE INDEX CONCURRENTLY, then runsVALIDATE CONSTRAINTunder SHARE UPDATE EXCLUSIVE. Audit writes continue, but on a largeaudit_logstable both steps scan it and can add minutes to the first boot. If the build is interrupted, the next start refuses with an "INVALID index" message: runDROP INDEX CONCURRENTLY audit_logs_partner_scope_idx;and restart the API. Partner-level events recorded before the upgrade stay hidden (no backfill).- Other concurrent index builds: on
remote_sessions/tunnel_sessions,tickets(partner feed),time_entriesandsites. Each waits for long-running transactions, does not block writes, and refuses the next start with an "INVALID index" message naming the index if interrupted; drop it withDROP INDEX CONCURRENTLY <name>;and restart. - Network-monitor alerts backfill (#7954).
2026-12-07-110000-network-monitor-alert-endpoint-display.sqlscansalertsand rewritesmessage,context.targetandcontext.erroron network-monitor alerts so endpoints show as scheme + host. On a large alerts table this adds time to the first boot. Each rewritten alert is re-delivered once on the Partner API alerts feed. - Other backfills: one ownership row per existing device, in batches of 5,000 followed by a validation scan of
devices(#8219); report run ownership copied from each report, holding SHARE ROW EXCLUSIVE onreport_runsandreportsuntil it commits, so report generation waits briefly on installs with a large report history (#8255);contact_rolesback-filled from existing contacts (#8226); existing partner service principal keys bound to their owner's current state (#8332); grandfathered CIS and IOC approvals, with counts logged (#7979). backup_configs.encryption_keyis dropped (#7977). The column has no writer; the migration refuses, and the API does not boot, if any row still holds a value (refusing to drop backup_configs.encryption_key: N row(s) still hold a non-null value). Review and clear those rows, then restart.- New enum values:
expiredreport status,awaiting_approvalbilling status,hour_blockcontract line type and theresearchAI agent kind.
Environment variables.
-
Required: none. No new required environment variables; the config validator gains no new boot-refused variable, and neither Compose file adds a new
:?guard. -
New, optional:
PATCH_REPORT_RETENTION_DAYS(default 30, minimum 1) andPATCH_REPORT_ORPHAN_MIN_AGE_MS(default 1 hour, never below 10 minutes) (#8284).DB_POOL_ACQUIRE_TIMEOUT_MS(default 10000;0disables) andDB_TIMER_LAG_GRACE_MS(default 2000;0disables) (#8243, #8282).PARTNER_API_TICKET_WRITE_RATE_LIMIT_PER_HOUR(default 1200),PARTNER_API_TICKET_WRITE_PARTNER_RATE_LIMIT_PER_HOUR(default 6000),PARTNER_API_IDEMPOTENCY_RETENTION_ENABLED(default true) andPARTNER_API_IDEMPOTENCY_RETENTION_DAYS(default 7) (#8235).
All are mapped in the root
docker-compose.yml. The fourPARTNER_API_*variables are not yet indeploy/docker-compose.prod.yml; if you run that file and need them, add them to theapiservice'senvironment:block. -
Changed default:
INSTALLER_BOOTSTRAP_TOKEN_TTL_MINUTESis now10080(7 days), capped at43200(above). -
Changed meaning:
MCP_UNATTENDED_TIER3_PRINCIPALSalso acceptspartner_sp:<partner service principal id>(#8090).METRIC_ANOMALY_EPISODE_MIN_BUCKETSdefault is now 3. -
No longer read:
BREEZE_AI_SCRIPT_REVIEWER_MODEL,WORKSPACE_CONTENT_LLM_MODEL(#7867). -
65 more variables passed to the API by both Compose files (#7858): retention windows, agent ingest quotas and rate limits, screenshot and log-forwarding caps,
DB_POOL_MAX, the offboarding drain window, the public download key TTL and login lockout. Every one is passed as${VAR:-}, so unset keeps the built-in default, but a value already in your.envthat Compose used to ignore now takes effect. Check.envfor stale entries before upgrading.
Agents. Agents, Breeze Assist and Breeze Viewer update to 0.122.1 through your normal update channel. Agent-side changes: clipboard v2 and the per-session clipboard summary (#8262, #8263); key and button release on disconnect (#8251); signed org/site identity sync after a device move (#8320); diagnostic file access commands (#7406, #8327); command results kept across shutdown, with a new outbox/inflight/ directory (#8379); macOS update package from your own server first (#8107); macOS install, uninstall, group and screen-capture fixes (#7876, #7833, #7972, #8154); Windows service monitoring, antivirus/firewall unknown state, Storage Spaces, System Restore and agent-data-directory path checks (#8038, #8043, #8150, #8069, #8108, #8010); N-able detection (#8085); peripheral policy for ungrouped devices (#8322); interface types for topology (#7846); parallel restore downloads (#7417); WinPE recovery console groundwork (#7926); build-time display branding (#8061). Breeze Assist starts hidden in the tray (#8213). Breeze Viewer: clipboard v2, input and focus fixes, QWERTZ/AZERTY letters and the new shortcut chord (#8266, #8244, #7848).
Feature flags.
- Automatic payments ship switched off for every partner (per-partner rollout switch). Payment reminders are off until configured under Billing → Payments.
- Customer portal toggles
enableHardwareHealth,enableHardwareInventory,enablePerformanceMetricsandenableSoftwareInventorydefault off for every organization. Enable all turns on the first three, notenableSoftwareInventory, which only opens the read API. - Location suggestions (
timeTracking.locationSuggestions), staff forward routing, the default inbound assignee, Gmail labelling and the Pushover fallback are all off by default. - Customer approval of ticket work (settings API only) defaults to
enabled = false; workload inventory enumeration is off by default; EDR has no UI yet. - AI suggested fixes fix-memory consultation in triage is behind
ml.remediation_suggestions.enabled.
What's Changed
- chore(security): time-boxed npm audit exceptions with reachability evidence (#7861) by @ToddHebebrand in #7864
- fix(installers): serve self-host installers for releases pinned before the edition field (#7830) by @ToddHebebrand in #7838
- fix(patches): read patch_approvals on the request connection when the context covers the partner (#7663) by @ToddHebebrand in #7835
- fix(topology): project VPN half-default route pairs as a default route (#7820) by @ToddHebebrand in #7843
- fix(ai-tools): manage_patches device actions resolve the device's own org (#7827) by @ToddHebebrand in #7839
- fix(ai): manage_monitor_definitions describe action exposes monitor kinds + conditions (#7826) by @ToddHebebrand in #7840
- fix(ai): log scrubbed returned tool errors, keep long validation errors (#7825) by @ToddHebebrand in #7836
- fix(web): billing Rates tab read-only without partner-wide access (#7597) by @ToddHebebrand in #7834
- fix(org-merge): preview counts Fleet Design definitions in reports would-drop (#7615) by @ToddHebebrand in #7837
- chore(security): document the provably-unused-path bar for audit exceptions by @ToddHebebrand in #7865
- fix(agent/macos): repair a breeze group without a GID so agent.sock gets its group (#7829) by @ToddHebebrand in #7833
- fix(authenticator): accept bodyless approver-device revoke (#7811) by @ToddHebebrand in #7849
- fix(portal): disable Pay while an autopay collection is processing (#7824) by @ToddHebebrand in #7860
- fix(ai): show approved event_logs_query result on handoff read-back (#7828) by @ToddHebebrand in #7859
- fix(compose): map 65 retention/quota/rate-limit env vars into the api container (#7640) by @ToddHebebrand in #7858
- feat(topology): corroborate grouped placement and gateway MACs from neighbor caches by @ToddHebebrand in #7845
- fix(access-reviews): email reviewers via server notify route (#7805) by @ToddHebebrand in #7851
- test(topology): fix collection-gap flake at a 5-minute bucket boundary by @ToddHebebrand in #7852
- chore(release): clear the next-release draft after v0.121.0 by @ToddHebebrand in #7869
- docs: v0.121.0 sweep — upgrade notes (+ missing v0.119.0), AI model registry API, API key rules, Quick Support by @ToddHebebrand in #7870
- fix(web): billing profile drawer scrolls with pinned Save footer (#7804) by @ToddHebebrand in #7871
- fix(viewer): send typed letters, not US positions, on QWERTZ/AZERTY (#7809) by @ToddHebebrand in #7848
- test(inbound-email): collision-free fixture ticket numbers (#7868) by @ToddHebebrand in #7874
- feat(quotes): quote PDF matches the web proposal — partner branding, keep-with-next headings, contents by @ToddHebebrand in #7713
- fix(agent/macos): survive a disabled launchd label on install; sweep both bin dirs on uninstall (#7831) by @ToddHebebrand in #7876
- feat(autopay): W02 enrollment — request, client setup, consent, pause/stop, portal payment methods (#7745) by @ToddHebebrand in #7822
- fix(topology): classify tunnel/overlay networks by interface kind, not CIDR (#7819) by @ToddHebebrand in #7846
- feat(ai): model registry W08a — retire legacy AI config paths (code only) (#7606) by @ToddHebebrand in #7867
- feat(autopay): W03 payment reminders for all invoices (#7746) by @ToddHebebrand in #7866
- fix(topology): group-scoped expansion claims for grouped-overview cards (#7818) by @ToddHebebrand in #7847
- fix(topology): truthful grouped overview — scan presence, orphans, freshness, decommissioned (#7879) by @ToddHebebrand in #7883
- ci(security): Trivy ignores for braces + http-cache-semantics (aliases of excepted GHSAs) by @ToddHebebrand in #7889
- test(topology): synthetic large-site topology demo seed (local QA fixture) by @ToddHebebrand in #7890
- fix(topology): grid-pack card members over legacy pins, clean load state, IP order, cross-org links (#7880) by @ToddHebebrand in #7882
- feat(topology): legible overview — summary cards, role sections, site header, compact toolbar by @ToddHebebrand in #7892
- feat(autopay): W04 charging — notice, collection engine, retries, ACH returns, Charge now (#7747) by @ToddHebebrand in #7877
- feat(autopay): W05 processing fee — card % / ACH flat, attestation, disclosure, consent ceiling, reversal allocation, accounting entry (#7748) by @ToddHebebrand in #7893
- feat(remote): show who is already connected on the device page by @aayush-ashok in #7461
- docs(topology): site assignment vs observed location — design spec + 3-wave plan (#7884) by @ToddHebebrand in #7888
- fix(backup): a failed BMR recovery attempt no longer consumes the recovery token (#5408) by @ToddHebebrand in #7411
- docs(readme): refresh contributors gallery by @ToddHebebrand in #7905
- chore: use fictional names in test fixtures and docs by @ToddHebebrand in #7903
- fix(bmr): verify pinned storage identity for self-contained snapshots and every token download (#6490) by @ToddHebebrand in #7410
- fix(m365): let executors bind loopback for sidecar ingress (ACA) by @ToddHebebrand in #7682
- docs(m365): plan identity-first admin consent by @ToddHebebrand in #7909
- docs(backup): W07 plan — Windows WinPE recovery media by @ToddHebebrand in #7904
- feat(m365): executor verify-identity endpoint for identity-first consent (W01) by @ToddHebebrand in #7921
- chore(deps): Bump @types/node from 26.6.2 to 26.6.3 in /e2e-tests by @dependabot[bot] in #7855
- chore(deps): Bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.23.1 to 1.23.2 in /agent in the go-minor-patch group across 1 directory by @dependabot[bot] in #7853
- fix(ai): run_script and device-waiting tools never hold a DB transaction across the device wait (#7918) by @ToddHebebrand in #7928
- fix(ai): pair tool results with tool calls by the SDK tool_use id (#7931) by @ToddHebebrand in #7932
- fix(m365): surface Microsoft consent errors instead of state mismatch by @ToddHebebrand in #7915
- feat(m365): identity-first admin consent — API reversal (W02) by @ToddHebebrand in #7933
- feat(m365): confirm tenant before admin consent + identity-first docs (W03) by @ToddHebebrand in #7938
- fix(api): give every safeFetch request its own pinned connection by @ToddHebebrand in #7908
- fix(monitors): tool results, alerts and stored check errors show monitor endpoints as scheme + host by @ToddHebebrand in #7920
- fix(notifications): push notification policies follow the alert's organization by @ToddHebebrand in #7916
- fix(commands): claim checks partner trust on its own connection by @ToddHebebrand in #7919
- feat(access-reviews): reviewers can't decide their own access (single-admin exception recorded) by @ToddHebebrand in #7878
- fix(tunnels): require remote-access permission to close a tunnel by @ToddHebebrand in #7907
- feat(ai): suggested fixes W2 — research agent, submit_suggestions, panel redesign, fix memory list (#7142) by @ToddHebebrand in #7939
- test(rls): require a parent org check on child tables whose policies admit by user identity by @ToddHebebrand in #7934
- test(api): require a permission gate on every write route by @ToddHebebrand in #7937
- feat(ai): suggested fixes W3 — triage verdict and full runs consult fix memory first (#7143) by @ToddHebebrand in #7946
- chore(security): renew braces and http-cache-semantics audit exceptions to 2026-11-01 by @ToddHebebrand in #7953
- test(ai): stored credentials under generic column names never reach tool results by @ToddHebebrand in #7935
- fix(ai): updating a monitor with its displayed endpoint keeps the stored URL by @ToddHebebrand in #7955
- fix(webhooks): webhook reads require webhook read permission and return the fields the UI uses by @ToddHebebrand in #7956
- fix(settings): launcher password must be re-entered when the launcher URL host changes by @ToddHebebrand in #7958
- fix(tickets): tickets created from monitor alerts show endpoints as scheme + host by @ToddHebebrand in #7954
- fix(commands): WebSocket delivery applies the same claim checks as heartbeat delivery by @ToddHebebrand in #7957
- fix(scripts): scripts queued by partner technicians are delivered when the device comes online by @ToddHebebrand in #7964
- fix(helper): a Helper disabled by policy stops authenticating and /helper/config reports it by @ToddHebebrand in #7959
- chore(backup): drop the unused backup_configs.encryption_key column by @ToddHebebrand in #7977
- feat(installer): bootstrap tokens are stored hashed by @ToddHebebrand in #7978
- docs(spec): add agent display branding Phase 1 design by @fabicarvano in #7841
- fix(guided-setup): stop grep -q SIGPIPE from hiding caddy at boot (#7960) by @bdunncompany in #7962
- fix(agent): install-darwin.sh group check no longer misses members of a long list by @bdunncompany in #7972
- fix(discovery): enqueue scan dispatch after commit and re-dispatch lost scheduled jobs by @bdunncompany in #7945
- fix(backup): org erasure keeps backup storage objects and records them; storage cleanup never reclaims them by @ToddHebebrand in #7980
- fix(autopay): never charge beyond consent, never mislead or strand the client (lab + cross-wave review fixes) by @ToddHebebrand in #7983
- fix(cis): hardening schedules require execute permission and MFA; existing schedules keep running under their creator by @ToddHebebrand in #7979
- fix(autopay): one saved method per client, exact bank-pay amounts, and truthful client notices (follow-ups) by @ToddHebebrand in #7986
- fix(orgs): re-check the merge requester when the queued merge runs by @ToddHebebrand in #8008
- fix(audit): record partner-level and body-targeted writes in the audit log by @ToddHebebrand in #8009
- fix(api): permission-consistency fixes across five small routes by @ToddHebebrand in #8012
- fix(web,api): stop translating vendor names in pt-BR; use ERROR_CODES.RE_ENROLLMENT_REQUIRED by @fabicarvano in #7728
- feat(api,web): adopt ERROR_CODES for tickets routes (E3a) by @fabicarvano in #7881
- fix(devices): move-org no longer times out at 30s or rewrites child rows twice (#7988) by @ToddHebebrand in #8025
- chore(deps): Bump the tauri group across 1 directory with 3 updates by @dependabot[bot] in #7924
- chore(deps): Bump @radix-ui/react-dropdown-menu from 2.1.20 to 2.1.24 by @dependabot[bot] in #8003
- chore(deps): Bump @tanstack/react-query from 5.103.2 to 5.104.1 in the tanstack group by @dependabot[bot] in #7997
- chore(deps): Bump @astrojs/starlight from 0.42.4 to 0.42.5 in the astro group by @dependabot[bot] in #7996
- chore(deps): Bump react-native-safe-area-context from 5.10.0 to 5.10.1 in the mobile group by @dependabot[bot] in #7994
- chore(deps): Bump babel-preset-expo from 57.0.5 to 57.0.13 by @dependabot[bot] in #8004
- chore(deps): Bump marked from 18.0.5 to 18.0.14 by @dependabot[bot] in #8005
- chore(deps): Bump @network-utils/vendor-lookup from 1.0.12 to 1.0.14 by @dependabot[bot] in #8006
- chore(deps): Bump vitest from 5.0.2 to 5.0.3 in /e2e-tests by @dependabot[bot] in #7992
- chore(deps): Bump dotenv from 18.0.3 to 18.0.5 in /e2e-tests by @dependabot[bot] in #7989
- chore(deps): Bump pg from 8.23.0 to 8.23.1 in /e2e-tests by @dependabot[bot] in #7990
- chore(deps): Bump the tauri group with 5 updates by @dependabot[bot] in #8000
- fix(migrations): catalog model pin and report series guards work under a non-bypass migration role by @ToddHebebrand in #8036
- chore(deps): Bump @types/node from 26.6.3 to 26.6.4 in /e2e-tests by @dependabot[bot] in #7991
- fix(file-browser): refuse every Windows spelling of the agent data directory by @ToddHebebrand in #8010
- fix(api): consistent site-restricted access for user-risk policy, patches, AI agents, peripheral policies by @ToddHebebrand in #8042
- feat(autopay): client pages and emails that are clear, styled and never contradict the money (redesign) by @ToddHebebrand in #7987
- chore(deps): Bump the typescript-tooling group across 1 directory with 2 updates by @dependabot[bot] in #8046
- perf(agent-auth): negative-cache terminal agent auth rejections (#8050) by @ToddHebebrand in #8054
- perf(db): one set_config statement per access context + drop unused drizzle schema (#8052) by @ToddHebebrand in #8055
- chore(deps): Bump the hono group across 1 directory with 2 updates by @dependabot[bot] in #7998
- fix(api): cap image URL downloads, trim TLS/discovery error detail, rate-limit model verify by @ToddHebebrand in #8039
- fix(api): fleet findings and RCA suggestions respect the caller's device scope by @ToddHebebrand in #8045
- fix(erasure): org erasure completes for an in-use org and keeps partner identities by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8011
- chore(deps): Bump @react-navigation/native from 7.3.8 to 7.5.0 by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8007
- fix(discovery): never overwrite an agent-detected device role with a port-scan guess (#7971) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8034
- docs(spec): self-hosted instance backup design by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8035
- fix(tickets): queue ticket.assigned only after the assignment commits (#7963) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8040
- fix(deps): bump source-map-js to 1.2.2 (GHSA-68fv-2mgg-jv7q) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8060
- fix(billing): page Stripe reversal operator review on entry, not every sweep (#8021) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8027
- fix(api): strip NUL characters from agent change reports (#8020) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8026
- fix(web): stop off-screen sr-only content from stretching the dashboard page by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8018
- fix(web): render partner sign-in logo larger (#7899) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7929
- docs(spec): Windows deep diagnostics — crashes, leaks, permission failures, hangs by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7923
- feat(backup): W07a — recovery console on WinPE by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7926
- docs(partner-api): state the schemaVersion compatibility rule by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7814
- fix(anomalies): 3-bucket persistence gate, 7-day new-high growth gate, percent peak (#6650) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7815
- fix(audit): show partner-scoped events in the Audit Trail (#7696) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7808
- fix(backup): download restore files concurrently, install in manifest order (#5623) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7417
- feat(tickets): richer ticket-assigned email by @bdunncompany in https://github.com/LanternOps/breeze/pull/7952
- chore(deps): Bump oidc-provider and @types/oidc-provider by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8001
- fix(backup): dispatch ownership re-check after send, settle verifications of failed snapshots, unreported integrity protocol by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8044
- feat(api,web): adopt ERROR_CODES for orgs routes (E4a) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8057
- fix(web): org branding logo persists data URI, not blob: URL (#8017) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8062
- fix(api): get_device_details keeps core device fields through compaction (#7968) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8064
- feat(api): partner API tickets read surface — feed, get, ids, comments (wave 2) by @lennonflima in https://github.com/LanternOps/breeze/pull/8037
- fix(web): never let browsers cache redirects (refs #7985) by @bdunncompany in https://github.com/LanternOps/breeze/pull/8048
- docs: macOS desktop-helper restart step + fix agent version command by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8059
- fix(api): service/process monitor alert titles show the name, not {{serviceName}} (#7966) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8063
- feat: administrator-approved read-only diagnostic file access by @bdunncompany in https://github.com/LanternOps/breeze/pull/7406
- test(portal): stop autopay/payment-methods waitFor flakes under CI load (#8033) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8072
- fix(api): subscribe to session events before pushing the turn (#7783) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8074
- test(topology): deterministic row order in device-deletion snapshot (#8056) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8075
- chore(billing): remove deprecated quickbooksRecordUntouched alias (#7298) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8076
- fix(api): DNS sync records SSRF-blocked host as integration error, not Sentry exception (#8023) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8073
- chore(deps): Bump pg and @types/pg by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8002
- chore: tidy code comments by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8041
- chore(deps): Bump the expo-sdk group across 1 directory with 4 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/7993
- fix(deps): bump shell-quote, sharp and @modelcontextprotocol/sdk for today's advisories by @bdunncompany in https://github.com/LanternOps/breeze/pull/8088
- chore(deps): Bump the aws-sdk group in /agent with 2 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8082
- chore(deps): Bump the go-minor-patch group in /agent with 4 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8083
- docs: refresh the Claude Code contributor guide by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8089
- fix(ai-gateway): send bare tool names and resolve wrapped names back (#8081) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8091
- docs(skills): feature-testing example URLs point at a local stack by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8092
- feat(inbound-email): route staff forwards by the original sender by @bdunncompany in https://github.com/LanternOps/breeze/pull/7961
- fix(api): FORCE_HTTPS non-canonical-Host 400 returns a reason code and logs it (#7875) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8093
- fix(api): hash short code in installer link audit details (#7974) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8097
- fix(ai): event_log app-presence hint for manage_monitor_definitions (#7060) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8103
- fix(web): bind the script-lane enable grant to the values the save arms (#7873) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8095
- fix(agent): N-able detection no longer matches any process named agent (#8084) by @bdunncompany in https://github.com/LanternOps/breeze/pull/8085
- fix(web): lock name and price for env-managed offerings in the drawer (#7780) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8098
- feat(portal): site filter on Network assets table (#7025) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8101
- chore(deps): Bump the anthropic group across 1 directory with 2 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/7999
- ci: require check-migrations green when api changed (#7032) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8102
- feat(portal): hardware health visibility flag and read-only routes (#7731) by @fabicarvano in https://github.com/LanternOps/breeze/pull/7797
- feat(ticket-mailbox): optionally label and archive Gmail mail that became a ticket by @bdunncompany in https://github.com/LanternOps/breeze/pull/7950
- feat(web): show organization column on Custom Fields page (#7122) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8100
- fix(api): honour ?orgId on security recommendation complete/dismiss (#8086) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8094
- fix(ai): return discoveryQueued on gateway connection create (#7781) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8099
- fix(automations): fence ledger seeding against a racing run cancel (#8104) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8105
- feat(tickets): Pushover for ticket assignments to the assignee's own key by @bdunncompany in https://github.com/LanternOps/breeze/pull/8080
- feat(inbound-email): per-partner default assignee for new inbound tickets by @bdunncompany in https://github.com/LanternOps/breeze/pull/8106
- release: register v0.121.1-hotfix.1 candidate by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8109
- feat(mcp): partner service principal keys authenticate MCP at partner scope by @bdunncompany in https://github.com/LanternOps/breeze/pull/8090
- fix(agent/macos): download the update .pkg from the control plane that signed it by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8107
- fix(agent): file tools check the final path of the handle they use on Windows by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8108
- docs(api): partner tickets wave 2 review follow-ups by @lennonflima in https://github.com/LanternOps/breeze/pull/8111
- qa: v0.121.0 → main pre-release sweep — tracking doc + 9 small fixes by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8114
- fix(api): helper screenshots never orphan files; backup worker refuses another org's config by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8116
- fix(api): DNS policy writes refuse site-restricted callers by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8118
- fix(web): mint the partner ceiling step-up grant on enable and widen saves (#8112) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8115
- release: drop candidate registry rows whose tags no longer exist by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8122
- docs(qa): v0.121.0 sweep follow-up — PR #7235 review round by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8125
- perf(agents): heartbeat 9→3 transactions per beat, unifi-collectors poll 2→0 (#8053) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8128
- feat(release): server-only hotfix lane (ledger, base-executed guard, binaries carry-forward) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7235
- release: register v0.121.1-hotfix.2 candidate by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8131
- fix(web): Add Device install command uses the server's runtime URL (#8120) by @bdunncompany in https://github.com/LanternOps/breeze/pull/8124
- feat(portal): per-org hardware inventory (Wave 2, enableHardwareInventory flag) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8119
- feat(api): adopt ERROR_CODES for billing and invoices routes (E4b) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8123
- docs: define scoped contact responsibility model by @fabicarvano in https://github.com/LanternOps/breeze/pull/8087
- feat(web): delete time entries from the ticket rail and the timesheet (#8133) by @bdunncompany in https://github.com/LanternOps/breeze/pull/8135
- feat(agent): display branding for operator-facing strings (phase 1) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8061
- docs(spec): horizontal API scaling and agent capacity program by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8127
- fix(agent,api): report a failed AV/firewall collection as unknown, not off (#7965) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8043
- docs(spec): EDR provider framework + Sophos/Bitdefender/Emsisoft adapters (#3135) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7655
- docs(patching): ring-owned approval rules spec + plan (#1317) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8065
- feat(auth): /login/ sign-in page for hosted partners (#4017) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8070
- docs(billing): block hours — approved spec and W01–W04 implementation plans (#4547) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8071
- docs(devices): workload host inventory and container image currency spec + plans by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8077
- docs(plan): location-aware time suggestions W1–W2 plan by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8066
- docs(pam): ownership-epoch evidence continuity spec and plan (#4477) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8067
- docs(tickets): spec + plan for customer approval of over-budget and after-hours work by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8068
- fix(api): claim script suggestion before dispatch to stop concurrent /execute double-send (#7276) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8178
- fix(backup): device purge fences backup objects and honours policy legal holds (#7982) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8215
- fix(api): remove helper screenshot files when their rows are deleted (#8117) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8216
- perf(agents): heartbeat hierarchy pass-through — steady beat 69→26 statements (#8053) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8222
- fix(api): chat cooldown only on terminal provider failure (#7790) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8177
- fix(ai-agents): pair agent-run tool results with pre-call state by SDK tool_use id (#8163) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8214
- feat(edr): W01a — EDR provider framework tables + tenancy (#8165) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8220
- feat(billing): block hours W01 foundation — hour_block type, contract_hour_periods, time_entries.contract_line_id (#8180) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8217
- feat(ai): auto-execute read-only event_logs_query (System/Setup, no XPath) in chat (#7906) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7917
- feat(partner-api): live device-status feed behind opt-in device-status:read scope (#7577) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7586
- fix(agents): serve the watchdog from the control-plane origin and enroll before service install (#7576) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7585
- fix(agent): open Windows services query-only; access denied is not not_found (#7967) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8038
- feat(load-tests): realistic Go agent simulator (W0a) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8161
- docs(plan): scaling W04 pool admission gate + W08 API admission control by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8250
- docs(plan): scaling W03 batched policy read (heartbeat 26→14 statements, 2 tx) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8256
- fix(db): time the RLS prologue from pool acquisition; bound the pool wait separately (#8229) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8243
- fix(agent): anchor the service-name match so brands containing "service" map correctly by @fabicarvano in https://github.com/LanternOps/breeze/pull/8227
- chore(deps): Bump libc from 0.2.189 to 0.2.190 in /apps/helper/src-tauri by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8224
- test(agent): execute the MSI brand validation with pwsh and require exact match by @fabicarvano in https://github.com/LanternOps/breeze/pull/8228
- chore(deps): Bump the tauri group in /apps/viewer/src-tauri with 3 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/8225
- fix(viewer): release held input on focus loss, stop stale pastes, focus-gate clipboard (W1 #8236) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8244
- feat(api): partner API ticket writes — create/update/status/assign/comment (wave 3) by @lennonflima in https://github.com/LanternOps/breeze/pull/8235
- fix(patches): anchor Linux deferral on first-seen, show unknown release dates (#7800) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7930
- feat(api): device ownership epoch lineage foundation (#8203) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8219
- fix(reports): report_runs direct dual-axis tenancy (#4247) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8255
- fix(backup): enforce snapshot integrity on restores; confirm unattested restores with a step-up or typed confirmation by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8047
- fix(agent): match System Restore structs to the SDK layout and pin it (#4752) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8069
- docs(agents): cut CLAUDE.md from 51 KB to 11 KB; add Merge Danger to PR template by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8129
- test(api): per-route full-chain DB budget gate for every agentsim route (W0d) (#8151) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8274
- fix(portal): answer autopay-confirmation for a draft like a missing invoice (#8254) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8267
- fix(ai-agents): admit manual runs with no request transaction held (#7943) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8268
- fix(topology): org switch drops a site link instead of snapping back; no init grid layout (#8113) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8270
- fix(ai-models): show a refused Base URL on the field, not a toast (#7803) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8271
- fix(security): show an unknown AV/firewall state as Unknown, not Inactive (#8252) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8272
- fix(ai): chat shows the provider error when a turn fails before output (#7785) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8273
- feat(api): adopt ERROR_CODES for quotes routes (E4c) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8176
- docs(deploy): QBO_REDIRECT_URI example needs the /api/v1 prefix by @bdunncompany in https://github.com/LanternOps/breeze/pull/8295
- fix(api): bind manage_tags and C2C restore id lists as Postgres arrays by @bdunncompany in https://github.com/LanternOps/breeze/pull/8298
- fix(api): partner ticket writes — wave 3 review follow-ups (#8235) by @lennonflima in https://github.com/LanternOps/breeze/pull/8304
- fix(api): keep a Microsoft 365 ticket mailbox polling through transient Graph errors by @bdunncompany in https://github.com/LanternOps/breeze/pull/8300
- fix(web): offer "New destination" in the backup tab empty state (#8152) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8314
- fix(installer): bootstrap tokens default to a 7-day lifetime, capped at 30 days by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8280
- chore(agent): bump Go toolchain and x/net to clear GO-2026-6613 and GO-2026-6617 by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8305
- fix(web): download the patch compliance report with the session (#8306) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8315
- fix(patches): compliance report files expire after 30 days and are removed on org erasure by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8284
- fix(api): audit baseline approvals require MFA and refuse missing target devices by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8279
- fix(api): webhook reads require a dedicated webhooks:read permission by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8285
- fix(backup): confirming an unattested restore requires an enrolled second factor by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8302
- fix(agent): hash an empty peripheral group list as [] so ungrouped devices accept policy v2 (#8321) by @lennonflima in https://github.com/LanternOps/breeze/pull/8322
- docs(spec): physical placement and circuits V1 by @fabicarvano in https://github.com/LanternOps/breeze/pull/8162
- docs(spec): Agent localization and Helper runtime branding Phase 2 by @fabicarvano in https://github.com/LanternOps/breeze/pull/8277
- feat(api): publish ticket.updated/ticket.assigned and enrich ticket webhook payloads (wave 4) by @lennonflima in https://github.com/LanternOps/breeze/pull/8303
- fix(api): converting a quarantined Microsoft 365 email keeps its body and sender name by @bdunncompany in https://github.com/LanternOps/breeze/pull/8316
- docs(spec): mark the agent display branding spec as implemented by @fabicarvano in https://github.com/LanternOps/breeze/pull/8324
- feat(portal): add performance metrics visibility by @fabicarvano in https://github.com/LanternOps/breeze/pull/8175
- feat(api): implement scoped contact responsibilities by @fabicarvano in https://github.com/LanternOps/breeze/pull/8226
- fix(autopay): autopay runs only for active partners; resetting an invoice link also resets its autopay links by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8328
- fix(api): service principal keys are issued by their owner and end with the owner's sessions by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8332
- qa: 410aa55 → main sweep — tracking doc + 7 small fixes by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8336
- docs: Partner API ticket comments, scopes and feed checkpoints; backup bucket guidance by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8342
- fix(jobs): BullMQ custom job ids never contain ':' (DNS policy sync, sending-domain autosuspend, …) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8337
- fix(api): client AI templates get dedicated read/write permissions; writes require MFA by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8286
- ci(release): signing secrets come from the protected signing environments by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8343
- fix(diagnostics): credential stores are never grantable; self-approval needs a second factor by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8327
- fix(db): pool admission gate, lag-tolerant deadlines and deferred reclaim (W04) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8282
- fix(api): network proxy loads device CSS/JS when the sandbox drops the tunnel cookie by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8110
- fix(agent): keep macOS permission checks off ScreenCaptureKit and remember its verdict (#8058) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8154
- fix(ai): price an unbound BYOK refusal-fallback key at its own offering rate (#7773) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8212
- feat(api): ring app-rules column and dual-read evaluation (W01, #8185) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8218
- fix(api): customer email replies write a ticket.commented outbox row (#8326) by @lennonflima in https://github.com/LanternOps/breeze/pull/8344
- feat(quotes): require a part number for the parts order, and say so (#8232) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8248
- docs: network proxy dedicated tunnel origin — spec + wave plan (#8155) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8149
- docs: Community Ecosystem page with published listing criteria by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8172
- docs(specs): ticket migration windows and import mode (#8313, step 1) by @lennonflima in https://github.com/LanternOps/breeze/pull/8341
- docs(ticketing): specify on-demand service catalog (#8325) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8347
- qa: v0.122.0 delta pre-release sweep — tracking doc + 1 fix by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8253
- fix(agents): detach the edition-migration reinstall and canary it per org (#5016) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/7336
- feat(tickets): customer work approval W01 — schema, policy resolver, settings API, registrations (#8197) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8275
- docs(deploy): roll the worker container and drop a hotfix API pin in the deploy line by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8126
- feat(api): reliability baseline markers — reset after reimage, mark remediation (W01, #8311) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8319
- feat(billing): block hours drawdown engine — claim, period close, overage, close-out (#8181) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8276
- feat(quotes): public quote Sign & pay goes straight to Stripe checkout (#8231) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8249
- feat(edr): W01b — EDR provider framework + Bitdefender GravityZone read path (#8165) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8259
- fix(agent): release held keys and buttons when the viewer goes away; one input worker per session (W2a #8236) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8251
- fix(autopay): charge-now and payment-settings changes need a second-factor confirmation; cap checked before charging by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8358
- fix(dx): correct the documented dev setup and run govulncheck through the allowlist wrapper by @Bbomby in https://github.com/LanternOps/breeze/pull/8346
- test(api): give the no-colon job-id guard the repo-scan timeout budget by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8354
- fix(ci): full git ls-files listings get a 64 MiB maxBuffer (unblocks the merge queue) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8362
- feat(workloads): W01 API contract for workload host inventory (#8190) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8221
- fix(release): notarize-submit never dies of SIGPIPE on large notarytool output by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8355
- feat(agent): chunked clipboard transfers, policy status, no connect-time clipboard push (W4a #8236) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8262
- fix(agent): don't treat a failed Storage Spaces probe as pools present by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8150
- feat: one audit row per desktop session for clipboard activity (W4c #8236) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8263
- feat(viewer): clipboard v2 — chunked transfers, images, status chip, paste transactions (W4b #8236) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8266
- fix(helper): start Breeze Assist hidden in the tray; remove tray-icon setting (#8138) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8213
- fix(dns-security): use real Cloudflare Gateway APIs for event sync and list edits by @travroo321 in https://github.com/LanternOps/breeze/pull/7619
- feat(api): add physical placement for devices and discovered assets by @fabicarvano in https://github.com/LanternOps/breeze/pull/8348
- feat(web): reliability baseline markers UI — mark work done, provisional, before/after (W02, #8312) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8323
- feat(api,web): site location pins, location-sites read and partner toggle (#8210) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8223
- fix(billing): changing an organization's payment settings asks for a second-factor confirmation by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8363
- perf(agents): one RLS-guarded policy read per heartbeat — 26→14 statements, 2 tx (#8053) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8264
- qa: sweep B (release cut 2026-10-10 + whole-app crawl) — tracking doc + 10 fixes by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8374
- docs: remove stale db:push / db:generate references (refs #8345) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8376
- fix(api): backup prefix delete surfaces S3 per-key DeleteObjects errors (#8364) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8377
- fix(api): advertise MFA-gated config-policy actions as unavailable over MCP (#8340) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8378
- fix(agent): keep command results that fail to send during shutdown (#8296) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8379
- fix(email): send customer mail as the company name by @advenimus in https://github.com/LanternOps/breeze/pull/6574
- fix(agent,api): sync a moved device's org/site to the agent with a signed identity assertion (#8317) by @lennonflima in https://github.com/LanternOps/breeze/pull/8320
- fix(web): service principal edits keep the expiry in the browser's time zone and send only changed fields by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8383
- fix(web): time capture settings load the stored values, so Save no longer resets them by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8387
- docs(release): pre-cut notes for the next tag; signing-environment OIDC gotcha in /release by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8388
- feat(portal): add read-only software inventory visibility (#7734) by @fabicarvano in https://github.com/LanternOps/breeze/pull/8357
- docs: replace internal lab host names in testing and planning docs with generic placeholders by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8380
- release: What's New 0.122.0 + v0.122.0 pre-cut lab pass by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8392
- fix(installer): MSI build no longer fails on a runner with no WiX extensions yet by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8394
New Contributors
- @aayush-ashok made their first contribution in #7461
- @Bbomby made their first contribution in https://github.com/LanternOps/breeze/pull/8346
- @travroo321 made their first contribution in https://github.com/LanternOps/breeze/pull/7619
- fix(migrations): quarantine execution-authority migration no longer fails on DBs with security links by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/8396
Full Changelog: v0.121.0...v0.122.1