Breeze RMM v0.111.0 — work that waits for offline devices, a real customer record page, and a Stop button for running scripts.
Another large one: 201 commits, ~1,750 files and 35 migrations since v0.110.0. Seven multi-wave programs land together (offline work queue, script/automation cancellation, the organization record page + Service Management mode, configuration-policy inheritance, manual assets, manual network assets, the AI agent builder), plus the first thin slice of an opt-in AI Operator, the custom-field importer for migrations off another RMM, and a 62-row pre-release browser sweep that found and fixed five functional defects and four High paper cuts before the tag — with service install verified on real Windows and Linux hosts.
⚠️ No breaking API changes, but five defaults change on upgrade. Read them before you pull: work aimed at an offline device now queues instead of failing (#5243); "Remove device" now uninstalls the agent by default (#5034); network-monitor alerts now send notifications and fire automations (#5309); QuickBooks connections start pushing payments into QuickBooks at deploy (#4624); and on Linux/macOS breeze-agent service stop is now temporary while the watchdog is installed (#5296). Two migrations deliberately abort the deploy if they find pre-existing bad data — preflight SQL is shipped for both (#4991, #5028).
Summary
- Offline work queue — patch jobs, automation
run_script/execute_commandactions and scan/rollback commands aimed at an offline device are persisted with a delivery deadline and claimed on the agent's next heartbeat instead of failing withdevice_offline. Queued work is visible and cancellable on the device page, and expires undelivered after its TTL. On by default (#5145, #5164, #5174, #5243, #5248). - Stop a running script or automation — per-row Stop and Force stop on execution history and execution detail, Cancel run on automation runs, honest status when a stop lands too late, and a real process-tree kill on the agent (#4967, #4971, #4990, #5030, #5033).
- Organization record page + Service Management mode — one page per customer with Overview, Contacts, Sites, Devices, Tickets, Contracts & Billing and Activity tabs, cross-linked from tickets, invoices and quotes; plus a partner-level Service Management mode (
native/external/off, Settings → Partner → Company) that gates the new Service Desk sidebar section and Billing (#5086, #5109, #5110, #5108). - Configuration-policy inheritance — a policy can inherit from a partner-wide baseline, with Override/Revert per feature tab, and every reader (agent delivery, automations, patch scheduling, event log, monitoring) now resolves the inherited settings instead of silently delivering nothing (#5099, #5122, #5125).
- Devices without an agent — hand-entered manual assets as a third device class with warranty lookup and inventory reporting (#5242, #5255, #5253, #5261); manually added network assets including website/URL targets with an inline hand-off to an HTTP monitor (#5239, #5258, #5260); and the network device page with the unified device list now on by default (#5090).
- AI agent builder — a four-step guided create flow with a server-evaluated review card, a 15-capability picker replacing the tool-allowlist textarea, a partner ceiling projection, and a per-agent list of scripts allowed to run unattended (#5054, #5057, #5062, #5064, #5065, #5067, #5089).
- AI Operator (opt-in, off by default) — delegate a service-recovery incident from a device or alert to an operator task that keeps working after you close the browser, with a task detail page, a device feed tab and approval through the existing inbox (#5214, #5244, #5245, #5254, #5259, #5262, #5263, #5272).
- Custom-field import from another RMM — a wizard for Datto, NinjaOne, ConnectWise Automate, N-central and CSV that imports both field definitions and device values, including the warranty target (#4991, #5028, #5043, #5044, #5055, #5060, #5061).
- Device removal, finished — bulk restore, async bulk permanent delete with progress, an agent-uninstall state badge on removed devices, and an optional retention policy that purges removed devices after N days (#5034, #5035, #5042, #5047, #5053).
- QuickBooks payment push — payments recorded in Breeze against an invoice already in QuickBooks are created there automatically, and removed when the Breeze payment is voided or fully refunded (#4624).
Added
- Offline work queue —
device_commands.deliver_byplus a two-clock reaper and claim eligibility (#5145); a "Queued actions" section with cancel on the device page and uniform "Queued — device offline" copy (#5164); patch-policyoffline_behavior(queue/skip, defaultqueue) and a newqueuedpatch result (#5174); a per-action "If the device is offline" Queue/Skip control on automationrun_script/execute_command(#5243); an AI-tool live-connection hint and a docs sweep to the queued-on-reconnect promise (#5248). - Cancellation — the five closers that finalize a cancelling execution (#4967); a blocking, process-tree agent kill with honest reporting (#4971); the request side with
graceSecondsand acancel_script_executionAI tool at tier 3 (#4990);POST /automations/runs/:runId/cancelwithdevices_cancelled(#5030); the Stop / Force stop / Cancel run UI in all eight locales (#5033). - Organization record page — org-pinned shell and Overview (#5086); Contacts, Sites, Devices and Activity tabs (#5109); Tickets and Contracts & Billing tabs plus
lockedOrgIdcross-links (#5110); partner Service Management mode and the Service Desk sidebar section (#5108). - Config-policy inheritance —
parent_policy_id, constraint triggers and an effective-links view (#5099); the create/detail/list UI, "Inheriting from" / "Inherited by N policies" banners and the tab payload matrix (#5122); the resolver sweep that makes every reader honour the parent, plus automation execution identity and the patch loader (#5125). - Manual assets — the
manual_assetstable with RLS and cascade registration (#5242); CRUD plus link/unlink routes (#5255); warranty subject XOR and inclusion in the inventory report (#5253); the third device class, add/edit modal and Manual segment in the device list (#5261). - Manual network assets — nullable
discovered_assets.ip_addresswith asourceprovenance column and writer guards (#5239); the create route, form and entry points (#5258); website/URL targets, partner inventory export and docs (#5260). - AI agent builder — tool catalog, ceiling projection, wildcard policy merge and grant-only supervised keys (#5054); the capability picker (#5057); the four-step guided create flow with
POST /ai/agents/preview(#5062); the edit drawer rendering the create flow's step components (#5067); scripts allowed to run unattended (#5065, #5089); truthfulrun_scriptoutcomes and reachable stepper (#5064); the first Playwright spec for the flow (#5074). - AI Operator — baseline contracts, recipe cards and writer inventory (#5214); the thin-slice schema for tasks, operations and the task outbox (#5244); the EXPLAIN-as-
breeze_appharness and lineage fixtures (#5245); task-scoped intent identity and dispatch claim on the release CAS (#5259); terminal outbox events and the outbox publisher (#5262); the task coordinator, continuation-run admission,submit_task_stepand service-recovery verification (#5263); the read routes, task detail page and device feed (#5254); the task admission route and the Delegate to Operator action (#5272). - Custom fields — definition uniqueness, org-XOR-partner ownership and org-merge reconcile (#4991); one effective key namespace per device with no cross-axis shadowing (#5028);
device_custom_field_valuesas a real table with projection and backfill (#5044); the definitions importer preview/commit (#5043); the device-value importer including the warranty target (#5055); the "Import from another RMM" wizard (#5060) and its migration guides (#5061). - Devices — bulk restore and async bulk permanent delete with a purge-run progress route (#5042); "Remove" asks about the agent and uninstalls by default (#5034); an agent-uninstall state badge on removed devices (#5035); a
device_lifecycleconfig-policy feature and daily job that purges removed devices after N days, off by default (#5053); the Agent Version column coloured by its relation to the effective pin, withGET /agent-versions/effective(#5298). - Scripts — per-script acknowledgement of Strict security patterns, so a routine config script is no longer hard-blocked while Basic-level dangerous patterns stay unconditional (#5167).
- Auth — Android Key Attestation and Play Integrity verifiers for L4 approver devices (#4969, #5165); the iOS Secure Enclave P-256 + App Attest client (#5163); an MFA policy change that would lock out already-enrolled users is refused with
409 mfa_policy_would_lock_out_usersand an affected-user count (#5120). - Mobile — device detail now carries IP, logged-in user, OS version and open alert/ticket counts (#5144); the Systems tab issue count includes open fleet findings via
GET /fleet/findings/counts(#5143); a fleet status strip on the Home empty state (#5142); new-ticket org selector and assignee picker (#5189). - i18n — a server-side i18n runtime with recipient-locale resolution for email and PDF (#3918) and a locale cookie with
Astro.locals.localeand a correct<html lang>on first load (#5041). - PAM — Windows Event Log entries (IDs 1004–1008) plus
audit.jsonlfor the whole elevation lifecycle, carrying requester and approver identity (#5019). - Ops —
/readyand/health/readyas a real aggregate readiness contract, with API admission gated on the consumers the process role requires (#4007).
Improved
- Performance — an
(org_id, timestamp)index ondevice_process_samplesfor the per-org rollup (#5009), a partialaudit_logsindex for the abuse-signals sweep (#5018) and indexes for four recurring-job predicates that had no covering index (#5021), all builtCONCURRENTLY; metric-anomaly runs no longer pile up onmetric_rollups(#5297); collector command capture is bounded, shipped log batches are cleared and PIDs are counted cheaply (#5045). - Devices — dynamic device groups are re-evaluated off the request path on device change (#4630, #5015, #5039); manual maintenance actuation is gated and the lease persisted (#4921); maintenance mode is reachable per device and its toasts are pluralised (#5007); "show removed" adds rows and Compare stays visible past four selected (#5066); the network-asset modal stays mounted across the post-create refresh (#5271).
- Remote access — Remote Tools and Overview pick up
desktopAccesschanges live (#5294); the viewer's watchdog-fallback WebRTC frame counter no longer sticks FPS at 0 (#5293); session teardown carries a reason so mid-session capture failures surface (#5303, #4929). - Agent packaging —
service installon Linux and macOS now restarts the service on an enrolled host instead of leaving it stopped, and the watchdog recovers a stranded agent (#5296); the same class of fix for the Windows service install, which previously reported "running" when it was not and failed over an existing install (#5302); macOS package artifacts are cleaned up on uninstall (#5185); the desktop-helper launchd plist has one source (#5003). - Alerts — correlation-member moves are gated on the group with a group-first lock order (#5036); alert-axis
org_idchildren are rewritten on a device org-move (#5005). - QuickBooks — mappings auto-sync after a decision and the sync states are named (#5094); a live sync state shows on the invoice card after Issue (#5093); Integrations stays on Accounting for nested QuickBooks tab hashes (#5092); the
quick_supportorg is hidden from the mapping workbench (#5072). - CI / operability — expected DB guard trips now report as warnings with event codes rather than 500s: the software-inventory lock answers 503 and auto-retries, and a filter-preview timeout answers 422 (#5186).
Fixed
- Maintenance windows — a device inside a window with Suppress scripts is now skipped by every script path (AI assistant
run_script, automationrun_script/execute_command, fleet-fix remediation, edition auto-migration), not just manual runs. The check is fail-closed and each path records a skip, not a failure; a window that cannot be evaluated still fails loudly (#4919, #5202). - Auth sessions — disabling your own MFA, registering or deleting a passkey, and confirming a phone number that replaces an active SMS factor all still revoke every other session but now replace the calling session in the same response instead of bouncing you to
/login?reason=session-expiredby your own action (#4934, #5008, #5038, #5194, #5198, #5203). An admin MFA reset now removes all factors including passkeys, transactionally, across all four reset paths (#4920, RMM-QA-166); recovery-code rotation can no longer save an empty set (#5037); unsafe MFA policy activation is refused (#4060, #5120); unresolved advanced-filter action scopes are closed and alert bulk actions use the full matched set rather than the capped 100-row preview (#5118). - Network-monitor alerts — ICMP/TCP/HTTP/DNS monitor alerts were written straight into
alertswithout publishingalert.triggered, so they only ever appeared in the inbox. They now go through the shared create+publish path (#5241, #5309). See the upgrade notes — this changes notification volume. - Tenancy / GDPR —
script_categories.parent_idis erasure-safe and ownership-guarded (#4873, #5200); the intent org is preserved on ticket deletion (#4872, #4903); agent attribution survives a ticket org move (#4830, #4902);config_policyparent_policy_idis pinned in the erasure ledger and owner-move races are scoped to system (#5123, #5127); a single permanent delete cascades in a system context like bulk purge (#5047); the extensions boot tenancy sweep is restored (#4283, #4927); workspace SQLSTATE errors are unwrapped and direct comparisons guarded (#4245, #4928);precheckCommandExecutionis gated on the deciding org (#5264, #5311). - Integrations — UniFi device/client list pagination is followed by offset (#5101, #5191), MAC comparisons are canonicalised in the cloud sync (#5102, #5195) and camelCase Integration API fields decode in deep telemetry (#5087, #5096); the Umbrella sync moved to the next-gen
/reports/v2/activityendpoint (#4597, #5097); Windows service names with interior spaces are accepted and failed service commands surface (#5088, #5095). - QuickBooks — voiding a paid invoice no longer fails against QuickBooks (stale revision token, re-read and retried once) and voiding a QuickBooks-synced invoice with applied payments now fails fast with
409 INVOICE_HAS_PAYMENTSrather than desyncing (#5180, #5187); re-pushing an invoice after payment activity no longer fails with a staleSyncToken; a reauth outage no longer retires pending payment pushes; org erasure and org merge no longer discard a payment deletion Breeze still owes;invoices.paid_atis cleared whenever an invoice falls out ofpaid(#4542) — all in #4624, and the first two also fix v0.110.0. - Agent / remote desktop — the Winlogon GDI capture path honours the
GetDIBitsselection contract, fixing blank logon/UAC/secure-desktop capture (#5284, #5295); one reboot-deferral dialog per Windows session (#4940, #4993) and a re-prompt with a postponementWARN(#4941, #4997). - Self-hosting — with
BINARY_SOURCE=githubandAGENT_AUTO_PROMOTE=false, the download route now serves the pinned version, so pinned devices no longer sit in "Updating" forever on a checksum mismatch (#5159, #5196). - AI — a lost
transitionIntentCAS is handled at everyaiAgentSdkcall site (#5232, #5310); an org-only agent with no partner baseline is warned about (#4170, #5014); theexecute_commandapproval headline and impact are command-type aware (#5173, #5178); an approved-by-worker result is no longer rendered as a FAILED tool result (#5107, #5121); the AI kill-switch actor resolves to a name (#4931, #4994). - Web — the Processes tab no longer reads a 503 as "0 processes / No Data" (#4935, #4996);
ScriptExecutionModal's auto-close timer is cancelled on unmount (#5270, #5308); device-removal browser-walk defects — uninstall badge never rendered, stale filter after restore, purge confirm parity (#5023, #5058); collapsed-sidebar rail icons are centred (#5068); quote-editor paper cuts and multi-run cell alignment with theme fonts (#4438, #4937, #5006, #5013). - Portal — disabled visibility pages redirect instead of erroring (#4932, #4995) and ticket-page gate 403s route through the shared home redirect (#5029).
- Mobile — chat render paper cuts (streaming markdown, expandable errors, honest tool labels) (#5170, #5176); findings 404s degrade silently and the approval empty state stops flashing (#5172, #5177); ticket keyboard dismiss, toast clearance and US spelling (#5171, #5175); runaway timer warning, MFA auto-submit, approval header and org offline count (#5115, #5138); metrics key mismatch, keyboard persistence, missing org on device rows and 0m timesheets (#5104, #5113); ticket photo upload FormData part and the library permission prompt (#5103, #5112); toast/composer overlap and Systems org-filter hero (#5105, #5114).
- API — device diagnose no longer 500s on bigint metric columns (#4974, #4992);
:idis validated as a UUID on fleet findings routes (#5179, #5184); a patch job result summary accepts a nullablepatch_id; Sentry tags inaccountingConnectionService/quickbooksProvider/accountingPaymentPulluse allowlisted snake_case keys (#5126, #5192, #5193, #5201). - Plus ~35 further fixes across CI, tests, i18n copy and internal tooling.
Security
Self-hosters are encouraged to upgrade. No advisories are pending for this range (draft-advisory pre-flight run and clean).
Security — hardening
- Delegated API keys with site restrictions could bypass them on custom-field writes and dev-push binary distribution. Both are now denied (#5182, RMM-QA-162).
- Alert summaries ignored read permission and site scope — a custom role without
alerts:readcould read alert summaries, and a site-restricted user saw organization-wide alert counts. Both closed; some users will correctly see less data than before (#5070). - Software and SentinelOne summaries were org-wide for site-restricted users, and organization status / integration metadata leaked across the RLS boundary. SentinelOne status now requires
devices:read(#5071, RMM-QA-221). - Partner-wide config rows were reachable from the wrong axis, and unreachable from the right one. The missing
FOR SELECT-only partner-wide branch was added to the identity-contracts, notification, software-security, automation/alert-rule, AI and custom-field-definition tables — five migrations plus their RLS-coverage registrations (#4942–#4963, #4970, #4944, #4949–#4958, #4998, #4999, #5000, #5010, #5012, #5197). custom_field_definitionscould shadow across the org/partner axis, letting one axis silently override the other's value for the same device key; a trigger now refuses it (#5028) and definition uniqueness plus org-XOR-partner ownership is enforced at the schema level (#4991).script_categories.parent_idblocked erasure and was not ownership-guarded (#4873, #5200);getConnectionByIdis anchored on the caller's access axis (#4959, #5011).- AI agents — an organization-owned agent can no longer grant itself a
supervisedActionKeysentry it does not already hold (422 supervised_keys_grant_only); keys reach org rows only through the four-eyes graduation grant.actAssets.scriptIdsis validated on every write (#5054, #5089). - PAM elevation is now auditable off-box on Windows — Event Log IDs 1004–1008 plus
audit.jsonl, with requester and approver identity (#4913, #5019).
Self-Hosting / Upgrade Notes
No breaking API changes. No new required environment variables. Five defaults change on upgrade — read "Behaviour changes" below before you pull.
Upgrade command — bump BREEZE_VERSION in /opt/breeze/.env, then:
docker compose pull api web portal && docker compose up -d binaries-init api web portal(portal is a separate container — include it. If you have opted into the worker split, add worker. Building from source: pnpm install first.)
⚠️ Known upgrade blocker in 0.111.0 (found during the hosted rollout): 2026-10-14-100100-discovered-assets-manual-source.sql crash-loops the API on any database whose discovered_assets rows span more than one organization or partner. Its set-based backfill fires the partner-export consistency triggers row by row, which trips the lock-hierarchy guards (partner export lock hierarchy violation / organization locks must be acquired in ascending UUID order); the file rolls back and boot fails until it succeeds. Hosted US hit this for ~20 minutes; EU and single-tenant installs are unaffected. Before you pull 0.111.0, run this once against your database (it is idempotent and safe on 0.110.0; the migration's own backfill then matches zero rows), or, better, install v0.111.1 instead, which ships this as a migration that sorts ahead of the failing one:
BEGIN;
SELECT set_config('breeze.scope', 'system', true);
DO $$ BEGIN CREATE TYPE public.discovered_asset_source AS ENUM ('scan','unifi','manual'); EXCEPTION WHEN duplicate_object THEN NULL; END $$;
ALTER TABLE public.discovered_assets ADD COLUMN IF NOT EXISTS source public.discovered_asset_source;
ALTER TABLE public.discovered_assets ADD COLUMN IF NOT EXISTS url text;
SELECT public.breeze_partner_export_lock_partners_shared(ARRAY(
SELECT DISTINCT o.partner_id FROM public.discovered_assets d JOIN public.organizations o ON o.id = d.org_id
WHERE d.source IS NULL AND o.partner_id IS NOT NULL ORDER BY 1));
SELECT public.breeze_partner_export_lock_orgs_exclusive(ARRAY(
SELECT DISTINCT d.org_id FROM public.discovered_assets d WHERE d.source IS NULL AND d.org_id IS NOT NULL ORDER BY 1));
UPDATE public.discovered_assets a SET source = 'unifi'
WHERE a.source IS NULL AND (a.detected_type_source = 'unifi_controller'
OR EXISTS (SELECT 1 FROM public.unifi_devices u WHERE u.discovered_asset_id = a.id));
UPDATE public.discovered_assets SET source = 'scan' WHERE source IS NULL;
COMMIT;If you already pulled and the API is looping on that file: run the block above, then restart the API; the remaining migrations complete. After the API is healthy, run docker compose up -d web portal — compose leaves them in Created while the API is unhealthy and does not start them on its own.
Database — 35 idempotent migrations (plus 2 preflight files). Take a snapshot first. All auto-apply on API boot via autoMigrate (unless AUTO_MIGRATE=false).
Two of them will deliberately abort your deploy if they find pre-existing bad data. This is intentional — the alternative is silently picking a winner among rows that must be unique:
2026-10-10-100300-custom-field-definition-integrity.sql(#4991) aborts on duplicate or ownerlesscustom_field_definitionsrows. Preflight:apps/api/migrations/preflight/2026-10-10-100300-custom-field-definition-integrity-preflight.sql.2026-10-11-141000-custom-field-no-cross-axis-shadowing.sql(#5028) aborts on an existing org/partner cross-axis key collision. Preflight:apps/api/migrations/preflight/2026-10-11-141000-custom-field-shadowing-preflight.sql.
Run both preflights against your DB before you pull, and reconcile anything they report. Hosted EU/US are clean.
Backfills that touch existing rows run under breeze.scope=system and log their row counts as Postgres WARNINGs. Three to read after the first boot:
device_custom_field_values backfill: copied N value(s) out of devices.custom_fields,minted N definition(s) for previously undefined keysandN stored key(s) do not match the enforced key pattern and stay in the jsonb projection only(2026-10-11-160000-device-custom-field-values.sql, #5044) — proportional to devices × custom-field keys. Camel-case keys written before the pattern was enforced are deliberately preserved in the jsonb only.backfilled N discovered_assets rows to source=unifi/source=scan(2026-10-14-100100-discovered-assets-manual-source.sql, #5239) — an unboundedUPDATEover everydiscovered_assetsrow with a nullsource. Sized by your discovery inventory, not your device count; on a large scanned estate this is the longest statement in the set.2026-10-11-170000-partner-admin-force-mfa-reconcile.sql(#4491) stampsforce_mfa = trueon every existing system Partner Admin role. Enforcement is off this release — see behaviour changes.
The three perf(db) index migrations (device_process_samples (org_id, timestamp), the abuse-sweep partial audit_logs index, four recurring-job indexes — #5009, #5018, #5021) build CONCURRENTLY through the no-transaction lane, so writes are not blocked; an interrupted build leaves an INVALID index the migration reports loudly on the next boot (recovery: DROP INDEX CONCURRENTLY <name> and restart). 2026-10-14-100000-manual-assets.sql takes a brief SHARE lock on discovered_assets while it creates the new table's FKs.
Migration audit (35 files, reviewed statement-by-statement before the tag). No CREATE ROLE, ALTER … OWNER TO, CREATE EXTENSION or schema-level GRANT/REVOKE; every GRANT is table-, sequence-, view- or function-level and issued by the object's own owner, so a non-superuser migrating role (DigitalOcean doadmin, RDS master) is sufficient. All twelve files that write rows elect breeze.scope = system before their first statement, and two also abort if that elevation did not take. Every CREATE OR REPLACE FUNCTION in the set was diffed against its predecessor: byte-identical plus the intended change. Expected boot cost is dominated by index builds and one hot-table constraint:
2026-10-13-100000-device-commands-deliver-by.sqladds a foreign key and a partial index ondevice_commandswithoutNOT VALID/CONCURRENTLY, so it holds an exclusive lock on the agent command path for the duration of one sequential scan. At hosted sizes (tens of thousands of rows) that is seconds; on an estate with millions of retained commands, pre-build them by hand before pulling (ADD CONSTRAINT device_commands_submitted_org_id_fkey … NOT VALIDthenVALIDATE CONSTRAINT, andCREATE INDEX CONCURRENTLY idx_device_commands_deliver_by …with that exact name) so the migration's guards no-op at boot.- The six
CONCURRENTLYindexes are the long pole on a largeaudit_logs/device_process_samples: minutes on a small managed instance, zero if they already exist by name (the API does not serve until they finish). 2026-10-11-160000-device-lifecycle-feature-and-decommissioned-at.sqlbuilds one non-concurrent partial index ondevicesand2026-10-14-100000-manual-assets.sqlone ondiscovered_assets; both briefly block writes to those tables.2026-10-14-100100-discovered-assets-manual-source.sqlalso takesSET NOT NULLplus twoCHECKvalidations under an exclusive lock ondiscovered_assets.2026-10-14-100200-device-warranty-manual-asset-subject.sqlreplaces threeSECURITY DEFINERexport trigger functions; after boot confirmSELECT proname, proacl FROM pg_proc WHERE proname LIKE 'breeze_partner_export_device_child_%'still shows no=X/grant to PUBLIC (hosted baseline before the deploy: owner-only).
New optional environment variables (missing = the documented default; none of these fail boot; map any you set in the api service's environment: block of your compose, not just .env):
DEVICE_COMMAND_OFFLINE_QUEUE_ENABLED— defaults to ON (#5243). Setfalseto restore the pre-#5128 harddevice_offlinerejection for patch jobs, automationrun_script/execute_commandand scan/rollback commands. This escape hatch is removed in a later release (#5249). Companion TTL knobs, all documented in.env.example:DEVICE_COMMAND_QUEUE_TTL_HOURS(168),DEVICE_COMMAND_QUEUE_SHORT_TTL_HOURS(24),DEVICE_COMMAND_QUEUE_POWER_STATE_TTL_HOURS(24).MFA_FORCE_FOR_PARTNER_ADMIN— now defaults tofalse(#5307). Settrueto enforce forced MFA for Partner Admins now; otherwise the reconcile migration'sforce_mfa = trueis recorded but not acted on. Enforcement returns to default-on once the notification-period rollout ships (#5306).AI_OPERATOR_TASKS_ENABLED— defaultfalse. Gates AI Operator task admission and continuation-run admission (#5263, #5272).AI_OPERATOR_RECIPE_SERVICE_RECOVERY_ENABLED— defaultfalse. Gates the one shipped recipe (service recovery). Both flags off means the whole AI Operator subsystem is inert, including its two background workers.PLAY_INTEGRITY_SERVICE_ACCOUNT— Google service-account JSON (raw or base64) for decoding Play Integrity verdicts on Android approver-device registration (#4969). Absent = Key-Attestation-only. Format is validated, so a mangled paste stops the boot rather than silently reporting "not configured" forever.READINESS_CACHE_TTL_MS(5000),READINESS_PROBE_TIMEOUT_MS(3000) — tuning for the new readiness contract (#4007).OFFLINE_DETECTOR_WORKER_CONCURRENCY(5) — offline-sweep worker concurrency (#4007).
Readiness vs liveness (#4007). /health remains liveness and is unchanged. /ready and /health/ready now serve a real aggregate readiness contract, and API admission is gated on the live consumers the process role requires. If your load balancer or compose healthcheck should hold traffic until Redis and Postgres consumers are actually up, point it at /ready; /health will answer 200 before that.
New workers and routes. Two new background workers ship with AI Operator — aiOperatorTaskWorker (task coordinator, 15 s tick) and aiOperatorTaskOutboxPublisher (5 s tick) — both inert while the two AI Operator flags are off. No other new BullMQ queue. New routes: POST|GET /api/v1/ai/operator/tasks and /:id; GET /ai/agents/tool-catalog, GET /ai/agents/ceiling, POST /ai/agents/preview; POST /automations/runs/:runId/cancel; POST /custom-fields/import/preview, POST /custom-fields/import, POST /devices/custom-fields/import/preview, POST /devices/custom-fields/import (MFA + devices:write; API keys rejected; capped at 1,000 rows / 5,000 values per batch); GET|POST|PATCH|DELETE /devices/manual plus link/unlink; POST /devices/network; GET /devices/removal-config; POST /devices/bulk/permanent-delete (202 + jobId), GET /devices/bulk/purge-runs/:jobId, POST /devices/bulk/restore; GET /configuration-policies/eligible-parents; GET /agent-versions/effective; GET /fleet/findings/counts; GET /discovery/assets/:id gains siteName and suggestedBridgeDeviceId; GET /roles gains activeUserCount. Agent download routes accept an optional ?version=.
Behaviour changes
- ⚠️ QuickBooks starts pushing payments into every connected realm at deploy (#4624). The new
accounting_connections.push_paymentscolumn defaults totrue, so a realm that is connected and inpush_mode = autobegins creating QuickBooks Payments as soon as the API restarts — no operator action, no per-realm opt-in. If you are not ready for Breeze to write into a realm's books, set it tofalsefirst (Integrations → QuickBooks → "Push payments to QuickBooks"). Only payments recorded after the switch became active are pushed: the migration stamps every existing connection'spush_payments_sincewith the deploy time, and toggling the switch off and on re-stamps it, so a pause never later flushes a backlog. There is no supported way to push a payment recorded before that horizon. A payment deletion propagates regardless of bothpush_modeandpush_payments— once Breeze created a Payment in QuickBooks it owns the removal, so switching the feature off cannot strand money in the books. A failing push gives up after 100 attempts (~5 hours in practice) with a message naming the reason; "Push to QuickBooks" clears the counter. The reconcile gate widened frompull_paymentstopull_payments OR push_payments, so a pull-off/push-on realm now runs the CDC pass over Breeze's own payments only, counting every QuickBooks-origin line asskipped_pull_disabledand holding the CDC cursor so nothing is permanently skipped when pull is turned back on. - Work aimed at an offline device queues instead of failing (#5243). Patch jobs, automation
run_script/execute_commandactions and scan/rollback commands are persisted with a delivery deadline (7 days standard; 24 hours for inventory and power-state work) and claimed on the agent's next successful heartbeat. A waiting step reads "Queued — device offline" instead of Failed, so a nightly automation over sleeping laptops no longer shows a wall of red — and correspondingly, work you previously saw fail fast now sits pending for up to a week. Queued rows are visible and cancellable on the device page. Existing automations have no storedwhenOfflinevalue and therefore queue; set the new per-action control to Skip for a step that is only meaningful against a live device. Manual Run Script and software installs already queued and are unaffected. - "Remove device" now uninstalls the agent by default (#5034). The web flow asks about the agent and defaults to uninstalling it; previously a wiring bug meant the uninstall was effectively never sent and agents were left running on removed devices. A permanent delete now refuses with
409 UNINSTALL_PENDINGuntil the uninstall has been collected (#5042), and the single permanent-delete response no longer carriesagentUninstallSent/warning. - ⚠️ Network-monitor alerts now notify, escalate and automate (#5241, #5309). ICMP/TCP/HTTP/DNS monitor alerts previously landed in the Alerts inbox only. They now publish
alert.triggered, so they send email/Teams/Slack/webhook/PagerDuty/SMS/Pushover notifications, start escalation policies, firealert.triggeredautomations and receive AI verdicts. Expect a step change in notification and automation volume on upgrade if you have network monitors with alert rules — review those rules, channels and escalation policies before deploying. The 5-minute per-rule cooldown and thesource = network_monitordedupe still apply, and recovery still auto-resolves. The event carriessource: 'network_monitor',monitorId,alertRuleId,monitorTypeandtarget, so an automation filter can be narrowed;ruleIdisnullfor these alerts. - ⚠️ On Linux and macOS,
breeze-agent service stopis now temporary while the watchdog is installed (#5296). The watchdog restarts the agent afterwatchdog.standby_grace(default ~2 minutes). For a durable stop, stop or uninstall the watchdog too. Related:service installnow restarts the service on an already-enrolled host rather than leaving it stopped — the old behaviour stranded a host Offline until someone ransystemctl startby hand. The Windows equivalent is fixed in #5302, which also fixes an install over an existing service (it previously failed withAccess is deniedand reported "running" when it was not). Both paths were verified on real hosts (Server 2022 and Ubuntu 22.04) before the tag. Known Linux-only wrinkle:systemctl stop breeze-agentruns the fullTimeoutStopSec=30sand ends in9/KILL, so each install takes ~32 s and the unit is brieflyfailed— pre-existing, tracked as #5334. - Forced MFA for Partner Admins is reconciled but NOT enforced (#4491, #5307).
2026-10-11-170000-partner-admin-force-mfa-reconcile.sqlmarks every existing system Partner Admin roleforce_mfa = trueon every install, reconciling installs that predate RMM-QA-164 — butMFA_FORCE_FOR_PARTNER_ADMINnow defaults tofalse, because the migration alone would otherwise lock existing Partner Admins into enrolment at upgrade time with no warning. Set it totrueto enforce now. A notification-period rollout (grace window, banner, deadline) ships next release as #5306, at which point enforcement returns to default-on. Neither hosted region pins the variable. - Maintenance windows suppress every script path (#4919, #5202). A device inside a window with Suppress scripts is now skipped by the AI assistant's
run_script, automationrun_script/execute_command, fleet-fix remediation and edition auto-migration — not just manual Run Script. Scripts that used to run during a window will now be skipped (recorded as a skip, not a failure: the automation run stays green and trailing actions still run; fleet-fix targets get amaintenance_windowskip reason). A window that cannot be evaluated is deliberately the opposite and keeps the ordinary failure treatment, so an outage of the maintenance config can never render as a fleet of green runs. - Script cancellation kills the whole process tree (#4971). Cancel and timeout now terminate descendants on Windows and Unix. A script that intentionally detaches a child process will now have that child killed too — worth a canary ring if you rely on that pattern.
- Metric-anomaly detection: lookback shortened 30 → 15 minutes with a 90 s statement timeout (#5283, #5297). This stops overlapping runs piling up lock waits on
metric_rollups(a real incident). The trade-off: a skipped tick no longer self-heals — a gap needs a manual backfill. - Unified device list is on by default (#5090).
PUBLIC_ENABLE_NETWORK_DEVICES_IN_LISTnow defaults totrue. It is a build-timePUBLIC_variable baked into the web image, so the published GHCRwebimage ships with the unified list (All / Agent / Network / Manual segments) on. Nothing to change in.envor compose. Self-hosters who build the web image themselves can passfalseto keep the agent-only list. - Service Management mode is a PARTNER setting, not per-organization — Settings → Partner → Company (Modules card), via
PATCH /partners/me(#5108).nativeis the default and existing partners are unchanged.offhides the Service Desk and Billing surfaces (including the org record's Tickets and Contracts & Billing tabs) and refuses ticket creation everywhere with a 409 (UI, portal, email-to-ticket, AI tool).externalhas no UI yet — it requires a bound partner-widepsa_connectionsrow and is reachable only via the API in this release. - Config-policy inheritance changes what a "linked" policy delivers (#5099, #5125). Previously a policy marked as inheriting could silently deliver nothing to its devices; every reader now resolves the real inherited settings. If you had such a policy, devices under it will start receiving configuration they were not receiving before.
- Cross-org device moves may now drop custom-field values not visible in the target org (#5044) — previously kept silently, now dropped and logged.
- API contract tightening — a fully cancelled automation run reports
cancelled, notfailed(#5030);POST /scripts/executions/:id/cancelgainsgraceSeconds/cancellingand answers 409 on a terminal state (#4990); a colliding custom-field create answers 409 instead of 500 (#5028); voiding a QuickBooks-synced invoice with applied payments answers409 INVOICE_HAS_PAYMENTS(#5187); passkey register/delete and phone confirm can now answer 409 (concurrent auth issuance / factor set changed — nothing written) and 428 (client auth binding must rotate first) (#5038, #5198); an MFA policy change that would lock out enrolled users answers409 mfa_policy_would_lock_out_users(#5120); an org-owned AI agent adding an unheldsupervisedActionKeysentry answers422 supervised_keys_grant_only, and badactAssets.scriptIdsanswer422 invalid_script_ids(#5054, #5089); the software-inventory lock answers 503 (auto-retried) and a filter-preview timeout answers 422, both previously 500 (#5186). - Still off by default:
BREEZE_AI_AGENTS_ENABLEDgates the whole AI-agent subsystem including the new builder;AI_OPERATOR_TASKS_ENABLEDandAI_OPERATOR_RECIPE_SERVICE_RECOVERY_ENABLEDgate AI Operator; reboot deferral is still per-policy opt-in; the removed-device purge retention policy (#5053) ships off, bounded to 1–3,650 days when you enable it.
Not verified on real hardware before the tag (each needs an environment we do not have in the lab, and each is flagged in the pre-release sweep): the iOS Secure Enclave / App Attest client (#5163, TestFlight round), Winlogon logged-out console capture (#5295), UniFi dedupe (#5195, #5096), Umbrella v2 (#5097), and the QuickBooks payment-push rows that need a live sandbox connection — though the QuickBooks sandbox walkthrough itself was run on 2026-09-06 and found and fixed four defects on the branch.
Privileged statements were audited against a non-superuser role: the range creates SECURITY DEFINER trigger functions owned by the migrating role and nothing else privileged — no CREATE ROLE, ALTER … OWNER TO, CREATE EXTENSION or schema GRANTs.
Full Changelog: v0.110.0...v0.111.0
What's Changed
- feat(api): close every cancelling execution — the five closers (#3525 W03) by @ToddHebebrand in #4967
- feat(auth): Android Key Attestation + Play Integrity verifiers (#1374 W04) by @ToddHebebrand in #4969
- fix(agent): honest, blocking, process-tree script cancellation (#3525 W04) by @ToddHebebrand in #4971
- fix(api): device diagnose 500s on bigint metric columns (#4974) by @ToddHebebrand in #4992
- fix(agent): one reboot-deferral dialog per Windows session (#4940) by @ToddHebebrand in #4993
- fix(admin): resolve AI kill-switch actor to a name (#4931) by @ToddHebebrand in #4994
- fix(portal): redirect disabled visibility pages instead of erroring (#4932) by @ToddHebebrand in #4995
- fix(web): Processes tab must not read a 503 as "0 processes / No Data" (#4935) by @ToddHebebrand in #4996
- fix(rls): partner-wide SELECT branch for identity-contracts tables (#4959, #4960, #4961, #4962, #4963, #4970) by @ToddHebebrand in #4998
- fix(agent): reboot deferral re-prompt and postponement WARN (#4941) by @ToddHebebrand in #4997
- feat(api): the request side of script cancellation (#4761 W07, plan W02b) by @ToddHebebrand in #4990
- feat(api): custom_field_definitions uniqueness + org-XOR-partner + org-merge reconcile (#3257 W02) by @ToddHebebrand in #4991
- fix(i18n): review machine-translated alert-verdict badge copy (#4449) by @ToddHebebrand in #5001
- chore(agent): consolidate desktop-helper launchd plist to one source (#4379) by @ToddHebebrand in #5003
- fix(ai-agents): memoise cronDue formatter, fix ephemeral orgId, add org-token RLS case (#4450 #4448 #4455) by @ToddHebebrand in #5004
- fix(web): quote editor paper cuts — title collapse, illegal reprice offer, triple label (#4937) by @ToddHebebrand in #5006
- fix(web): reach maintenance mode per-device, pluralise its toasts (#4936) by @ToddHebebrand in #5007
- fix(auth): keep the caller's session when MFA is disabled (#4934) by @ToddHebebrand in #5008
- perf(db): (org_id, timestamp) index on device_process_samples for the per-org rollup by @ToddHebebrand in #5009
- fix(alerts): rewrite alert-axis org_id children on device org-move (#4867) by @ToddHebebrand in #5005
- fix(quotes): thread theme fonts through line table/summary + fix multi-run cell alignment (#4438) by @ToddHebebrand in #5013
- fix(rls): partner-wide SELECT branch for notification tables (#4956, #4957, #4958, #4955) by @ToddHebebrand in #4999
- fix(psa): anchor getConnectionById on the caller's access axis (#4959 follow-up) by @ToddHebebrand in #5011
- fix(ai-agents): warn when an org-only agent has no partner baseline (#4170) by @ToddHebebrand in #5014
- perf(db): partial audit_logs index for the abuse-signals sweep by @ToddHebebrand in #5018
- docs: device removal completion — design + 3 wave plans (#5023) by @ToddHebebrand in #5027
- perf(db): indexes for four recurring-job predicates with no covering index by @ToddHebebrand in #5021
- fix(groups): wire dynamic device group re-evaluation to device change (#4630) by @ToddHebebrand in #5015
- fix(rls): partner-wide SELECT branch for software-security tables (#4946, #4947, #4948, #4953, #4954) by @ToddHebebrand in #5000
- fix(portal): route ticket-page gate 403s through the shared home redirect (#4932 follow-up) by @ToddHebebrand in #5029
- fix(agent): PAM: Windows Event Log for elevation lifecycle with requester/approver identity (#4913) by @ToddHebebrand in #5019
- feat: surface agent-uninstall state on removed devices (#3987) by @ToddHebebrand in #5035
- feat(api): cancel a running automation run (#4761 W05, plan W05) by @ToddHebebrand in #5030
- fix(web): give the AI-agent inert badge its own accessible label prefix (#4170 follow-up) by @ToddHebebrand in #5031
- fix(alerts): gate correlation-member move on the group, group-first lock order (#4867) by @ToddHebebrand in #5036
- fix(auth): make MFA factor removal an explicit call, require codes on rotation (#4934 follow-up) by @ToddHebebrand in #5037
- test(quotes): pin single-run center/right cell placement on the aligned path (#4438 follow-up) by @ToddHebebrand in #5032
- fix(rls): partner-wide SELECT branch for automation tables (#4952, #4950, #4951, #4949) by @ToddHebebrand in #5010
- feat(web): Remove asks about the agent — uninstall by default (#3987 items 2, 6) by @ToddHebebrand in #5034
- feat(web): stop a running script or automation from the UI (#4761 W06) by @ToddHebebrand in #5033
- fix(rls): partner-wide SELECT branch for ai tables (#4942, #4943, #4945) by @ToddHebebrand in #5012
- feat(api): one effective custom-field key namespace per device (#3257 W03) by @ToddHebebrand in #5028
- feat: bulk restore + async bulk permanent delete for removed devices; harden single lifecycle routes (#2787) by @ToddHebebrand in #5042
- feat(api): custom-field definitions importer — preview + commit (#3257 W07) by @ToddHebebrand in #5043
- docs: device removal follow-up plans 04 + 05 (#5023) by @ToddHebebrand in #5046
- fix(devices): re-evaluate dynamic groups off the request path (#4630 review follow-up) by @ToddHebebrand in #5039
- feat(api): device_custom_field_values — normalize, project, backfill, register (#3257 W05) by @ToddHebebrand in #5044
- fix(api): single permanent delete cascades in a system context like bulk purge by @ToddHebebrand in #5047
- docs(ai-agents): agent builder spec + plan (#5048) by @ToddHebebrand in #5052
- feat: purge removed devices after N days — device_lifecycle config-policy feature + daily job (#2787 item 4) by @ToddHebebrand in #5053
- feat(api): device custom-field VALUE importer incl. the warranty target (#3257 W08) (#4776) by @ToddHebebrand in #5055
- feat(ai-agents): agent tool catalog, ceiling projection, wildcard policy merge, grant-only supervised keys (W01 #5048) by @ToddHebebrand in #5054
- fix(web): device removal browser-walk defects — uninstall badge never rendered, stale filter after restore, purge confirm parity (#5023) by @ToddHebebrand in #5058
- feat(web): capability picker replaces the AI agent tool allowlist textarea (W02 #5048) by @ToddHebebrand in #5057
- feat(web): Import from another RMM wizard for custom fields (#3257 W09) by @ToddHebebrand in #5060
- docs(migration): custom-field import guides for the RMM importer (#3257 W10) by @ToddHebebrand in #5061
- feat(web): four-step guided create flow with server-evaluated review (W03 #5048) by @ToddHebebrand in #5062
- fix(ai-agents): truthful run_script outcome, reachable stepper, op-level search, recipient copy, plurals (#5048 QA) by @ToddHebebrand in #5064
- fix(auth): system Partner Admin roles store force_mfa=true on every creation path (RMM-QA-164) by @ToddHebebrand in #4491
- feat(api): server-side i18n runtime + recipient locale resolution (Phase 4, Tasks 1–2) by @ToddHebebrand with @Copilot in #3918
- fix(auth): MFA reset revokes passkeys — one transactional factor reset across all four paths (RMM-QA-166) by @ToddHebebrand in #4920
- fix: gate admission on readiness and drain offline sweeps by @ToddHebebrand in #4007
- fix(devices): gate manual maintenance actuation and persist the lease (RMM-QA-176) by @ToddHebebrand in #4921
- fix(web): devices list — 'show removed' adds rows; Compare stays visible past 4 selected (#5023 paper cuts) by @ToddHebebrand in #5066
- fix(web): center icons in the collapsed sidebar rail by @ToddHebebrand in #5068
- test(ai-agents): pin the web tool-category ↔ API capability contract (#5056) by @ToddHebebrand in #5069
- fix(accounting): hide the quick_support org from the QuickBooks mapping workbench by @ToddHebebrand in #5072
- refactor(web): AI agent edit drawer renders the create flow's step components (#5063) by @ToddHebebrand in #5067
- docs: organization record page + Service Management mode spec and plan (#5075) by @ToddHebebrand in #5085
- feat(web,api): organization record page shell + org-pinned fetching (W01 of #5075) by @ToddHebebrand in #5086
- feat(web): network device detail page + unified device list on by default by @ToddHebebrand in #5090
- feat(web): locale cookie + Astro.locals.locale + html lang attribute by @fabicarvano in #5041
- docs(config-policy): inheritance design spec + W01–W03 implementation plans (#5080) by @ToddHebebrand in #5084
- feat(config-policy): W01 API foundation — parent_policy_id, constraint triggers, effective-links view (#5080) by @ToddHebebrand in #5099
- docs(config-policy): plan 01 SQL matches shipped two-valued guard; W01 outcome in review log (#5080) by @ToddHebebrand in #5111
- test(web): org record page tab assertions query role=tab after OverflowTabs became a tablist by @ToddHebebrand in #5100
- fix(billing): show a live QuickBooks sync state on the invoice card after Issue by @ToddHebebrand in #5093
- fix(web): auto-sync QuickBooks mappings after a decision and name the sync states by @ToddHebebrand in #5094
- fix(web): keep Integrations on Accounting for nested QuickBooks tab hashes by @ToddHebebrand in #5092
- fix(config-policy): pin parent_policy_id in the erasure ledger; scope owner-move races to system (#5123) by @ToddHebebrand in #5127
- feat(web): W03 config-policy inheritance — create/detail/list from API, tab payload matrix, inheritance display, docs (#5080) by @ToddHebebrand in #5122
- fix(mobile): ticket photo upload FormData part + library permission prompt (#5103) by @ToddHebebrand in #5112
- fix(agent,web): accept interior spaces in Windows service names; surface failed service commands (#5088) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5095
- fix(mobile): metrics key mismatch, keyboard persists, no org on device rows, timesheet 0m (#5104) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5113
- fix(agent): decode UniFi Integration API camelCase fields in deep telemetry (#5087) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5096
- fix(dns-security): move Umbrella sync to the next-gen /reports/v2/activity endpoint (#4597) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5097
- fix(api): mobile summary decommissioned count, approval label hostname, impact text, text-block separator (#5106) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5119
- fix(ai,mobile,web): approved-by-worker is not a FAILED tool result (#5107) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5121
- feat(web): organization record — tickets and contracts & billing tabs, lockedOrgId, cross-links (W03 of #5075) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5110
- fix(mobile): toast/composer overlap, Systems org-filter hero, timer papercuts (#5105) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5114
- feat(config-policy): W02 resolver sweep — effective links everywhere, automation execution identity, patch loader (#5080) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5125
- fix(mobile): runaway timer warning, MFA auto-submit, approval header, org offline count (#5115) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5138
- feat(mobile): Home empty state fleet strip (#5117 decision 3) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5142
- feat(api,mobile): Systems tab issue count includes open fleet findings (#5139) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5143
- feat(mobile,api): Device Details v1 fields — IP, logged-in user, OS version, open alerts/tickets (#5140) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5144
- feat(accounting): QuickBooks Phase D2 — payment push (Breeze → QuickBooks) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4624
- feat(commands): offline work queue W01 — deliver_by, policy seam, two-clock reaper, claim eligibility, cancel (#5131) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5145
- chore(deps): bump @tauri-apps/plugin-deep-link from 2.4.9 to 2.4.10 by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5158
- chore(deps): bump @testing-library/user-event from 14.6.6 to 14.6.7 in the testing group by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5157
- chore(deps): bump @hono/zod-validator from 0.9.0 to 0.9.1 in the hono group by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5156
- chore(deps): bump postcss from 8.5.26 to 8.5.28 in the tailwind group by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5155
- chore(deps): bump the react-native-animation group with 2 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5150
- chore(deps): bump tsx from 4.23.12 to 4.23.13 in /e2e-tests by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5148
- chore(deps): bump @types/node from 26.4.0 to 26.4.1 in /e2e-tests by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5147
- chore(deps): bump vitest from 4.1.11 to 5.0.0 in /e2e-tests by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5146
- docs(release): next-release notes for #5090 (network devices in the device list) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5091
- docs(deploy): reconcile compose files during upgrades (#4922) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4924
- feat(ai-agents): scripts allowed to run unattended — picker, ceiling-aware validation, live outcome (#5065) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5089
- test(e2e): first Playwright spec for the AI agent guided create flow (#5048) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5074
- ci: enable merge-queue support (merge_group trigger, docs-only CI Success fallback, merge guidance) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5169
- fix(mobile): ticket keyboard dismiss, toast clearance, US spelling (#5171) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5175
- fix(mobile): chat render papercuts — streaming markdown, expandable errors, honest tool labels (#5170) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5176
- fix(mobile): degrade findings 404 silently, stop approval empty-state flash (#5172) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5177
- fix(ai): command-type-aware execute_command approval headline + impact (#5173) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5178
- fix(viewer): surface capture failure diagnostics (#4162) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4929
- fix(ai): preserve agent attribution for ticket org moves (#4830) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4902
- fix(extensions): restore boot tenancy sweep (#4283) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4927
- fix(workspace): unwrap SQLSTATE errors and guard direct comparisons (#4245) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4928
- fix(tenancy): preserve intent org on ticket deletion (#4872) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4903
- fix(agent): bound collector command capture, clear shipped log batches, count PIDs cheaply by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5045
- fix(ci): compile iOS simulator for mobile changes (#4489) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/4939
- chore(deps): bump the react group across 1 directory with 2 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5154
- fix(api): Android KeyStore attestation challenge cannot embed the SPKI — add pre-key keygen digest (#4707) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5165
- feat(scripts,agent): acknowledge Strict security patterns per script (#5129) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5167
- feat(web,api): service management mode + service desk sidebar section (W04 of #5075) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5108
- docs: merge-queue command is a bare gh pr merge by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5183
- feat(web,api): offline work queue W02 — admission delivery, device-page queued actions, uniform queued-offline copy (#5131) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5164
- fix(api): validate :id as a UUID on fleet findings routes (#5179) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5184
- fix(billing,accounting): refuse to void an invoice with applied payments (#5180) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5187
- fix(api): report expected DB guard trips as warnings with event codes (#5181) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5186
- ci: merge-queue janitor cancels superseded merge_group runs by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5190
- fix(mobile): new-ticket org selector row + assignee picker (#5188) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5189
- feat(patches): offline work queue W03 — queued results, non-terminal jobs, finalizer, offline_behavior, supersession (#5131) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5174
- fix(api): serve the pinned agent version from the github-mode download route (#5159) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5196
- fix(api): passkey register/delete must keep the caller's session (#5038) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5194
- chore(deps): bump the astro group across 1 directory with 4 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5153
- fix(api): accountingPaymentPull Sentry tags use allowlisted snake_case keys (#5126) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5192
- fix(api): canonicalise MAC comparisons in UniFi cloud sync (#5102) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5195
- fix(agent): follow offset pagination on UniFi device/client list endpoints (#5101) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5191
- fix(api): make script_categories.parent_id erasure-safe and ownership-guarded (#4873) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5200
- docs(ai-operator): completion spec + delivery plan, reviewed (Fable + Codex xhigh quorum) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5204
- feat(web): organization record — contacts, sites, devices, activity tabs (W02 of #5075) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5109
- docs(ai-operator): P3-0a baseline contracts, recipe cards, writer inventory, sunset list (W01 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5214
- docs: tool catalog (BYO MCP/OpenAPI) + AI-authored flows design, roadmap, W1 plan (#5215) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5223
- chore(deps): bump the typescript-tooling group across 1 directory with 2 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5152
- feat(automations,commands): offline work queue W04 — whenOffline action option, queued step state, requireOnline removed, flag default ON (#5131) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5243
- test(ai-operator): EXPLAIN-as-breeze_app harness, lineage fixtures, anomaly-trigger and late-result coverage (W02 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5245
- docs(ai-operator): fold W01 baseline contradictions C1–C20 into the completion spec and plan by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5247
- feat(discovery): manual network assets W01 — source column, nullable IP, writer guards (#5213) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5239
- feat(ai-operator): thin-slice schema — tasks, operations, task outbox, intent/run task columns, RLS, indexes, registrations (W03 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5244
- feat(devices): manual assets W01 — table, migration, RLS, registration (#4622) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5242
- docs,feat(ai): offline work queue W05 — AI-tool live-connection hint, docs sweep to the queued-on-reconnect promise (#5131) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5248
- chore(deps): bump the expo-sdk group across 1 directory with 6 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5149
- feat(devices): manual assets W02 — CRUD, link and unlink routes (#4622) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5255
- ci: stop rerunning the full suite on pushes to main (queue already evaluated it) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5257
- feat(devices): manual assets W03 — warranty subject XOR and inventory report (#4622) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5253
- feat(ai-operator): task-scoped intent identity, dispatch claim on the release CAS, cancel/kill-switch extension, operation result persistence (W04 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5259
- feat(discovery): manual network assets W02 — create route, form, entry points (#5213) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5258
- feat(ai-operator): task DTO, read routes, task detail page, device feed (W07 of #5205, read side) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5254
- feat(ai-operator): intent terminal outbox events, task outbox writes on every writer, outbox publisher (W05 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5262
- feat(discovery): manual network assets W03 — website/URL targets, partner inventory, docs, e2e (#5213) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5260
- feat(web): manual assets W04 — third device class, add/edit modal, e2e, docs (#4622) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5261
- feat(ai-operator): task coordinator, continuation run admission, submit_task_step, service-recovery verification, recovery scans (W06 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5263
- fix(web): keep the network-asset modal mounted across the post-create refresh (#5265) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5271
- feat(ai-operator): task admission route, Delegate to Operator action, Playwright approve-after-browser-close (W08 of #5205) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5272
- chore(deps): bump the aws-sdk group in /agent with 5 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5275
- chore(deps): bump golang.org/x/sys from 0.47.0 to 0.48.0 in /agent by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5276
- chore(deps): bump google.golang.org/api from 0.295.0 to 0.297.0 in /agent by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5279
- chore(deps): bump cloud.google.com/go/storage from 1.66.0 to 1.67.0 in /agent by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5277
- test(web): deflake the NetworkDeviceDetailPage identical-live-region test by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5280
- ci: fold docs-only detection into ci.yml so one workflow reports CI Success by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5281
- chore(deps): bump golang.org/x/time from 0.15.0 to 0.16.0 in /agent by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5278
- chore(deps): bump the mobile group across 1 directory with 4 updates by @dependabot[bot] in https://github.com/LanternOps/breeze/pull/5282
- docs(monitoring): Monitoring & Automation unification design spec (#4984) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5286
- fix(agent): clean up macOS package artifacts on uninstall (#4060) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5185
- fix(api): honor delegated key device site restrictions (RMM-QA-162) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5182
- fix(security): site-scoped software and SentinelOne summaries (RMM-QA-221) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5071
- fix(alerts): enforce read permission and site-scoped summaries by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5070
- fix(viewer): watchdog-fallback WebRTC frame counter so FPS never sticks at 0 (#5292) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5293
- fix(remote-access): Remote Tools + Overview pick up desktopAccess changes live (#5250) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5294
- fix(agent): honor the GetDIBits selection contract on the Winlogon GDI capture path (#5284) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5295
- fix(agent): start the service
service installstopped, and let the watchdog recover a stranded agent (#5252) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5296 - fix(api): stop metric-anomaly runs piling up on metric_rollups (#5283) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5297
- fix(rls): partner-wide SELECT branch for custom_field_definitions (#4944) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5197
- test(api): guard WiX installer sources against "--" in XML comments (WIX0104) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5301
- fix(api): accountingConnectionService/quickbooksProvider Sentry tags use allowlisted snake_case keys (#5193) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5201
- fix(api): phone replacement must keep the caller's session (#5198) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5203
- fix(agent): give session teardown a reason so mid-session capture failures surface (#5300) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5303
- fix(api): honour device maintenance windows on every script dispatch path (#4919) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5202
- fix(agent): start the Windows service
service installleaves stopped (#5299) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5302 - fix(auth): prevent unsafe MFA policy activation (#4060) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5120
- fix(web): close unresolved advanced filter action scopes (#4060) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5118
- test(api): de-flake SR2-22 forgot-password duration ratio (warm-up + interleave) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5305
- feat(mobile): iOS Secure Enclave P-256 + App Attest client (#4707 W05) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5163
- fix(auth): default MFA_FORCE_FOR_PARTNER_ADMIN to off for this release by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5307
- fix(web): cancel ScriptExecutionModal's auto-close timer on unmount (#5270) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5308
- fix(api): publish alert.triggered for network-monitor alerts (#5241) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5309
- fix(ai): handle the lost transitionIntent CAS at every aiAgentSdk call site (#5232) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5310
- fix(api): gate precheckCommandExecution on the deciding org (#5264) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5311
- fix(e2e): pin the forced-MFA relief valve off for wt-stack and diagnose login failures (#5266) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5312
- feat(devices): colour the Agent Version column by relation to the effective pin (#5285) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5298
- fix(web): script editor custom-field help shows the stdout marker, not PATCH-via-API-key (#5233) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5324
- qa: pre-release sweep v0.110.0 → main — 9 fixes + tracking doc (2026-09-08) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5323
- fix(web): show a manual TOTP setup key with copy beside the QR (#5319) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5335
- fix(web): human status labels and a Stop action on the device Scripts tab (#5318) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5339
- fix(api): count pre-execution action-intent CAS losses as cas_lost (#5326) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5338
- fix(api): exclude removed devices from organization device counts (#5315) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5337
- feat(web): device-group name picker in the filter chip bar + View devices link from Groups page by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5342
- docs(m365): tenant sync foundation spec + 6 wave plans (feature #5327) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5344
- fix(api): roll back the alert row when alert.triggered fails to publish (#5325) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5341
- fix(tickets): give the Log time quick-add an hourly rate (#5321) by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5340
- release: v0.111.0 What's New entry + clear next-release draft by @ToddHebebrand in https://github.com/LanternOps/breeze/pull/5345
New Contributors
- @ToddHebebrand with @Copilot made their first contribution in #3918
- @fabicarvano made their first contribution in #5041
Full Changelog: v0.110.0...v0.111.0