Figment.so
Mac hostingWebsite hostingGuidesHow to usePricing

Set Permissions for Desktop Agents on a Mac

Desktop automation agents — tools that drive the UI through Accessibility APIs, capture the screen, or synthesise keyboard and mouse input — hit macOS's TCC framework the moment they start. TCC (Transparency, Consent, and Control) gates Accessibility, Screen Recording, Full Disk Access, microphone, camera, and input monitoring. Without the right grants, the agent hangs, returns empty frames, or fails silently.

This guide maps which services each capability needs, how to grant and verify them on a hosted Mac, and how to handle updates that invalidate the grants.

Choose a Mac plan and define the job

Start by confirming the architecture of your agent binary:

file /path/to/your-agent-binary
# Universal:            Mach-O universal binary with 2 architectures: [x86_64 arm64]
# Intel only:           Mach-O 64-bit executable x86_64
# Apple silicon only:   Mach-O 64-bit executable arm64
  • x86_64 or universal runs on the Figment $29/month virtual Intel macOS environment (2 vCPU, 8 GiB RAM, 80 GiB disk, Intel on Linux/KVM, no GPU acceleration, no audio). TCC configuration works the same way as on a physical Mac for the capabilities below.
  • arm64-only needs a physical M-series Mac, which starts at $95/month. Confirm the exact chip, RAM and disk in your quote; physical plans collect requests until supply is confirmed.

If the agent depends on Xcode 27, visionOS, or any tool that explicitly requires Apple silicon, choose a physical M-series plan. Agents that are arm64-agnostic — Electron apps, Python/Node scripts, Intel-compiled utilities — fit the $29 virtual Intel macOS.

Setting TCC up correctly for a brand-new agent type is the kind of work covered by the Managed Build Mac ($249/month): one M-series Mac, CI setup, backups, monitoring, and 30 minutes of monthly support.

How TCC decides for a running agent

macOS checks Accessibility trust and Screen Recording access when a process first requests the service. Granting permission after the process is already running does not promote the running process; you must restart it after flipping the toggle.

tccutil, built into macOS, is the supported command for resetting TCC entries. After a reset, macOS prompts again the next time the app asks for the service:

# Reset Accessibility for one app (by bundle ID):
tccutil reset Accessibility com.example.myagent

# Reset Screen Recording for all apps (service name is ScreenCapture):
tccutil reset ScreenCapture

If your agent is a bare binary with no bundle, macOS uses the binary path as its TCC identifier. Change the path and the agent is, for TCC's purposes, a new application. To see denials in real time:

log show --last 5m \
  --predicate 'subsystem == "com.apple.TCC" AND eventMessage CONTAINS "denied"' \
  --info

A denial in this log confirms the symptom is a missing permission, not a bug in the agent.

Least-permission setup matrix

Grant only the services your agent actually uses. Extra permissions are a security liability and add tccutil reset calls to every deploy.

Agent capabilityRequired TCC serviceSystem Settings path
Synthetic keyboard or mouse eventsAccessibilityPrivacy & Security › Accessibility
AXUIElement queries (read UI text, state, hierarchy)AccessibilityPrivacy & Security › Accessibility
Screenshots, pixel reads, screen captureScreen RecordingPrivacy & Security › Screen & System Audio Recording
Reading other apps' window titlesScreen RecordingPrivacy & Security › Screen & System Audio Recording
Reading files outside the app's sandboxFull Disk AccessPrivacy & Security › Full Disk Access
Microphone inputMicrophonePrivacy & Security › Microphone
Camera inputCameraPrivacy & Security › Camera
Global keyboard hooksInput MonitoringPrivacy & Security › Input Monitoring

Start with Accessibility and Screen Recording only. Add the rest after you see a specific denial in the TCC log.

Implement the workflow

1. Identify the TCC identifier

# App bundle:
defaults read /Applications/MyAgent.app/Contents/Info CFBundleIdentifier
# Output example: com.example.myagent

# Bare binary: no bundle ID — TCC keys on the full executable path.

For a shell script that execs a Python or Node interpreter, the TCC identifier is the interpreter (/usr/bin/python3, /usr/local/bin/node), not the script. Prefer bundling the agent as a signed .app so the identifier stays stable across releases.

2. Grant Accessibility

  1. Open System Settings › Privacy & Security › Accessibility.
  2. Click +, pick the agent binary or .app, and add it.
  3. Flip the toggle on.
  4. Quit and relaunch the agent.

For launchd agents that start at login, run launchctl bootout (or launchctl unload on older systems), grant the permission, then launchctl bootstrap/load to pick up the new trust state.

3. Grant Screen Recording (only if needed)

Same path: System Settings › Privacy & Security › Screen & System Audio Recording. Screen Recording cannot be pre-granted by a script on a single machine — it requires an interactive toggle. In an MDM-managed fleet, a PPPC configuration profile can pre-approve specific bundle IDs.

4. Verify both permissions

Run these after granting and before you put the agent on a schedule:

# Screen Recording check: a real capture produces a non-trivial PNG.
screencapture -x /tmp/tcc_check.png
python3 - <<'PY'
import os
sz = os.path.getsize('/tmp/tcc_check.png')
print('Screen Recording OK' if sz > 5000 else f'DENIED or empty ({sz} bytes)')
PY
rm -f /tmp/tcc_check.png

# Accessibility check: list foreground apps via System Events.
osascript -e \
  'tell application "System Events" to return name of every process whose background only is false'
# Returns a list if Accessibility is granted; errors with
# "osascript is not allowed assistive access" if denied.

A black or near-empty PNG means Screen Recording is denied. An "assistive access" error on the osascript call means Accessibility is denied — most often because the agent binary path on disk does not match the entry in System Settings.

5. Handle resets after agent updates

When you ship a new agent build, macOS can invalidate TCC grants if the code signature or path changes. Build the reset into the deploy script so the next launch asks fresh:

#!/usr/bin/env bash
# deploy.sh — run after staging the new agent build at /tmp/MyAgent-new.app
set -euo pipefail

AGENT_ID="com.example.myagent"
AGENT_APP="/Applications/MyAgent.app"
PLIST="$HOME/Library/LaunchAgents/com.example.myagent.plist"

echo "Stopping agent..."
launchctl bootout "gui/$(id -u)/${AGENT_ID}" 2>/dev/null || true

echo "Resetting TCC entries..."
tccutil reset Accessibility "$AGENT_ID"
tccutil reset ScreenCapture "$AGENT_ID"

echo "Installing new build..."
rm -rf "$AGENT_APP"
cp -R /tmp/MyAgent-new.app "$AGENT_APP"

echo "Launching for first-run prompts..."
open "$AGENT_APP"
# Grant Accessibility and Screen Recording when prompted, then:
#   launchctl bootstrap gui/$(id -u) "$PLIST"

Failure and recovery checks

SymptomLikely causeFix
Agent stalls at startup with no visible UITCC prompt rendered in a session you cannot seeGrant the permissions once interactively via the browser console desktop, then start headlessly
Accessibility works, screen capture returns black framesScreen Recording missingToggle Screen & System Audio Recording for the agent
Permissions disappear after a releaseCode signature or binary path changedInclude tccutil reset in the deploy script and re-grant
Child process denied although parent is allowedDifferent signing identityGrant TCC to the child binary directly
osascript returns "not allowed assistive access"Accessibility denied for the invoking shellGrant Accessibility to Terminal (or your automation host)

For more than a handful of Macs, PPPC profiles delivered by MDM can pre-approve Accessibility for specific bundle IDs and stop per-machine clicking. Mention fleet size when requesting an enterprise quote.

Cost and operating limits for the task

TCC setup is one-time work per agent build. It adds no ongoing runtime cost.

PlanFit for desktop agents
$29/month virtual Intel macOSx86_64 or universal agents; grant Accessibility and Screen Recording via the browser console desktop session
Physical M-series from $95/monthRequired for arm64-only binaries and tooling that needs Apple silicon; exact chip/RAM/disk is confirmed in the quote
Managed Build Mac $249/monthOne M-series Mac, CI setup, backups, monitoring, 30 minutes of monthly support — useful for the first TCC bring-up
Managed Mac Team $999/monthTwo M-series Macs, two CI runners, team setup, backups, monitoring, one hour of monthly support

Input Monitoring (global keyboard hooks) is treated more strictly than Accessibility. Confirm the requirement before locking in a plan.

The virtual Intel macOS is reached through the browser console desktop; inbound public SSH to that VM is not currently offered, so TCC prompts are handled in that session. Outbound connections from the VM to your CI service run normally.

Start or migrate the workload

  1. Pick a plan at /mac-hosting: the $29 virtual Intel macOS for x86_64 or universal agents, or a physical M-series from $95 for arm64-only binaries. Confirm the exact spec in the quote.
  2. Run file against the agent to confirm architecture.
  3. Launch the agent interactively once (via the browser console desktop) so TCC prompts appear.
  4. Grant Accessibility and Screen Recording in System Settings.
  5. Run the screencapture and osascript checks above.
  6. Add tccutil reset Accessibility and tccutil reset ScreenCapture steps to the deploy script.
  7. Load the launchd plist for persistent scheduling.

Configure your plan and start →

Related guides: Idempotent jobs for Mac agents · Retry budget for Mac agents · Self-hosted GitHub Actions runner on Mac


Subscribe for Figma design and website publishing guides.


Figment.so

Contact

Twitter

Website pricing

Compute index

About

Privacy

Terms