macOS Permissions
macOS gates access to the screen, input events, and protected files behind per-app privacy permissions (TCC). The Breeze agent and its desktop helper need three of these permissions for full functionality. Apple does not allow applications to grant these permissions to themselves – the supported paths are an MDM-delivered PPPC (Privacy Preferences Policy Control) configuration profile for zero-touch deployment, or a manual grant in System Settings.
Permissions Overview
Section titled “Permissions Overview”| Permission | Binary | Used For | How to Grant |
|---|---|---|---|
| Full Disk Access | /usr/local/bin/breeze-agent or /Library/Breeze/bin/breeze-agent (see agent path), /usr/local/bin/breeze-desktop-helper |
System data collection, backup features | MDM PPPC profile (zero-touch) or manual System Settings grant |
| Accessibility | /usr/local/bin/breeze-agent or /Library/Breeze/bin/breeze-agent (see agent path), /usr/local/bin/breeze-desktop-helper |
Remote input (mouse and keyboard) during remote desktop sessions | MDM PPPC profile (zero-touch) or manual System Settings grant |
| Screen Recording | /usr/local/bin/breeze-desktop-helper |
Remote desktop screen capture | User approval only. MDM cannot pre-grant it – a PPPC profile can only allow standard (non-admin) users to approve it themselves, via the ScreenCapture service’s AllowStandardUserToSetSystemService authorization (macOS 11+) |
Agent Path: /usr/local/bin or /Library/Breeze/bin
Section titled “Agent Path: /usr/local/bin or /Library/Breeze/bin”macOS ties Full Disk Access for a bare (non-bundle) binary to its file path, not just its code-signing identity, so which path the agent runs from decides where you grant FDA.
From agent 0.118.3:
- The agent and watchdog stay in
/usr/local/binwhen/usr/local/binand every directory above it are owned by root and not writable by group or other – the stock macOS state. Nothing moves, and existing Full Disk Access and other privacy grants keep working. - The agent moves to
/Library/Breeze/binonly when/usr/local/binis unsafe for a root daemon: the binary or a directory above it is not owned by root, or is group- or world-writable. The known case is Homebrew on Intel Macs, which hands/usr/local/binto an admin user. Only in this case do you need to re-grant Full Disk Access, for/Library/Breeze/bin/breeze-agent. The agent logs a warning when it moves. - Agents 0.118.0 through 0.118.2 moved every install, safe or not, which is why fleets on those versions saw Full Disk Access break widely. 0.118.3 does not move an install back to
/usr/local/binonce it has moved – a re-grant you already made for/Library/Breeze/binkeeps holding. Move any Mac still on 0.118.0-0.118.2 to 0.118.3 or later; do not promote those versions to Macs you cannot touch. - The
.pkginstaller (used for installs and for macOS agent updates) always installs to wherever the existing install lives, so it never moves an install back and forth on its own.breeze-agent service install(manual CLI install) and the dev install script install to/Library/Breeze/bindirectly. - The desktop helper is never moved – it always stays at
/usr/local/bin/breeze-desktop-helper.
For an MDM-managed fleet, the simplest zero-touch approach is a PPPC profile that lists both paths (see below) so it covers a Mac regardless of which one it runs from.
See After an agent relocation for what changes on a Mac that does move, and how to confirm the grant landed.
Zero-Touch Grants with a PPPC Profile
Section titled “Zero-Touch Grants with a PPPC Profile”If the Mac is enrolled in an MDM (Jamf, Mosyle, Kandji, Intune, etc.), deploy a PPPC configuration profile that grants Full Disk Access and Accessibility to both Breeze binaries. This is the recommended path for fleet deployments – no on-device interaction is required for those two permissions.
The profile identifies each binary by its installed path plus a code-signing requirement, so the grant only applies to a genuine, Developer ID-signed Breeze binary at that path.
The following profile is ready to import into your MDM (most consoles accept a raw .mobileconfig upload):
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>PayloadContent</key> <array> <dict> <key>PayloadType</key> <string>com.apple.TCC.configuration-profile-policy</string> <key>PayloadIdentifier</key> <string>com.breezermm.pppc.privacy</string> <key>PayloadUUID</key> <string>7D3F2A91-5B4C-4E8D-9A16-C2E7F0B83D54</string> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadDisplayName</key> <string>Breeze Agent Privacy Preferences</string> <key>Services</key> <dict> <key>SystemPolicyAllFiles</key> <array> <dict> <key>Identifier</key> <string>/usr/local/bin/breeze-agent</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-agent-darwin-arm64" or identifier "breeze-agent-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Allowed</key> <true/> </dict> <dict> <key>Identifier</key> <string>/Library/Breeze/bin/breeze-agent</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-agent-darwin-arm64" or identifier "breeze-agent-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Allowed</key> <true/> </dict> <dict> <key>Identifier</key> <string>/usr/local/bin/breeze-desktop-helper</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-desktop-helper-darwin-arm64" or identifier "breeze-desktop-helper-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Allowed</key> <true/> </dict> </array> <key>Accessibility</key> <array> <dict> <key>Identifier</key> <string>/usr/local/bin/breeze-agent</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-agent-darwin-arm64" or identifier "breeze-agent-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Allowed</key> <true/> </dict> <dict> <key>Identifier</key> <string>/Library/Breeze/bin/breeze-agent</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-agent-darwin-arm64" or identifier "breeze-agent-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Allowed</key> <true/> </dict> <dict> <key>Identifier</key> <string>/usr/local/bin/breeze-desktop-helper</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-desktop-helper-darwin-arm64" or identifier "breeze-desktop-helper-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Allowed</key> <true/> </dict> </array> <key>ScreenCapture</key> <array> <dict> <key>Identifier</key> <string>/usr/local/bin/breeze-desktop-helper</string> <key>IdentifierType</key> <string>path</string> <key>CodeRequirement</key> <string>(identifier "breeze-desktop-helper-darwin-arm64" or identifier "breeze-desktop-helper-darwin-amd64") and anchor apple generic and certificate leaf[subject.OU] = D8W6N2JYMA</string> <key>Authorization</key> <string>AllowStandardUserToSetSystemService</string> </dict> </array> </dict> </dict> </array> <key>PayloadDescription</key> <string>Grants Full Disk Access and Accessibility to the Breeze agent and desktop helper, and allows standard users to approve Screen Recording.</string> <key>PayloadDisplayName</key> <string>Breeze RMM - macOS Privacy Permissions</string> <key>PayloadIdentifier</key> <string>com.breezermm.pppc</string> <key>PayloadScope</key> <string>System</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>E19C6B0F-8A72-4D35-B6E4-1F5A9D27C803</string> <key>PayloadVersion</key> <integer>1</integer></dict></plist>The code requirements match both the Apple Silicon (-darwin-arm64) and Intel (-darwin-amd64) builds, so a single profile covers a mixed fleet. The agent entry is listed twice, once per path, so the same profile grants the permission whether a given Mac’s agent runs from /usr/local/bin or /Library/Breeze/bin (see Agent Path). You can verify the signing identity of an installed binary at any time, using whichever path the agent currently runs from:
codesign -dvvv /usr/local/bin/breeze-agent 2>&1 | grep -E '^Identifier|TeamIdentifier'# or, on a Mac where the agent moved:codesign -dvvv /Library/Breeze/bin/breeze-agent 2>&1 | grep -E '^Identifier|TeamIdentifier'# Identifier=breeze-agent-darwin-arm64# TeamIdentifier=D8W6N2JYMAManual Grants in System Settings
Section titled “Manual Grants in System Settings”Without an MDM, grant the permissions on the device under System Settings > Privacy & Security:
-
Full Disk Access – open Privacy & Security > Full Disk Access, click +, press Cmd+Shift+G in the file picker, and add
/usr/local/bin/breeze-desktop-helperplus the agent binary at whichever path it runs from –/usr/local/bin/breeze-agenton most Macs, or/Library/Breeze/bin/breeze-agentif it has moved (see Agent Path). Runls /Library/Breeze/bin/breeze-agentfirst if you are not sure which one applies. -
Accessibility – open Privacy & Security > Accessibility and add the same two binaries.
-
Screen Recording – open Privacy & Security > Screen & System Audio Recording (labeled Screen Recording on macOS 12-14) and enable
breeze-desktop-helper. If the helper has already attempted a capture, it appears in the list automatically; otherwise the first remote desktop connection triggers the standard macOS approval prompt.
Changes to Full Disk Access take effect after the agent service restarts:
sudo launchctl kickstart -k system/com.breeze.agentAfter an agent relocation
Section titled “After an agent relocation”This applies only to a Mac where /usr/local/bin was unsafe for a root daemon and the agent moved to /Library/Breeze/bin (see Agent Path). Most Macs never hit this.
- Grant Full Disk Access at the new path. Add
/Library/Breeze/bin/breeze-agentin System Settings > Privacy & Security > Full Disk Access, or push the PPPC update, if you have not already covered both paths as shown above. - How to tell a Mac needs this. Until the grant lands, the device’s Full Disk Access status still shows as missing, and the agent’s self-health reports a
macos_fda_relocationwarning naming the old and new path (fromGET /devices/{id}/health). The warning clears on its own once Full Disk Access is granted for the new path – there is no separate UI panel for it. - Leftover binaries are cleaned up automatically. After moving, the agent removes the old
breeze-agent,breeze-watchdogandbreeze-backupcopies left behind in/usr/local/binon its next start. - A PPPC profile covering both paths needs zero further action. If your profile already lists both
/usr/local/bin/breeze-agentand/Library/Breeze/bin/breeze-agentwith the same code requirement (as in the sample profile above), the grant applies automatically regardless of which path the agent ends up on.
Troubleshooting
Section titled “Troubleshooting”A permission “disappears” after an agent update. For a bare (non-bundle) binary like the agent, macOS keys a TCC grant to the binary’s file path, not just its code-signing identity, so a grant made for one path does not carry over if the binary starts running from a different one – see After an agent relocation if that is what happened. Within a stable path, official Breeze binaries are Developer ID signed with a stable identity, so grants survive ordinary updates. If a grant stops applying after an update at the same path, check that the binary is still properly signed:
codesign -dvvv /usr/local/bin/breeze-agent# or /Library/Breeze/bin/breeze-agent, whichever path the agent runs fromExpect Authority=Developer ID Application: LanternOps LLC (D8W6N2JYMA) and TeamIdentifier=D8W6N2JYMA. An ad-hoc or unsigned binary – typical of a manual or development build – gets a new identity on every build, so macOS treats each update as a brand-new app and drops the grant. Reinstall an official signed release, or re-grant after each build for development installs.
The PPPC profile is installed but permissions are not granted.
Confirm the profile arrived through MDM (profiles list should show it under a device channel). PPPC payloads are ignored when the profile is installed manually. Also verify the code requirement matches the installed binary, at whichever path it runs from: codesign -d -r- /usr/local/bin/breeze-agent (or the /Library/Breeze/bin path) prints the designated requirement to compare against.
Remote desktop connects but shows a black screen.
Screen Recording has not been approved for breeze-desktop-helper. This permission always requires a one-time user approval – see the table above.
Remote desktop is unavailable even though the device shows Online. The desktop helper runs alongside the agent and can briefly lose its connection to it — after an agent update, or when the Mac sleeps and wakes. The helper now reconnects on its own when that happens, so this should clear within moments. Earlier agent versions left the helper stopped until it was relaunched or the user logged out and back in; if you are seeing that, update the agent.