AI for macOS, Below the Chat Window: the Permission Layer No Other Guide Covers
Every listicle about AI for macOS ranks the same chat apps. None of them talk about what actually separates a macOS-native AI from a web app in a window: the TCC permission layer. This guide walks through the four-stage accessibility detector Fazm ships (file path, line numbers, and why the macOS 26 Tahoe TCC cache makes a two-line check insufficient), because that is the part you cannot copy from a roundup.
Why "Best AI for macOS" Roundups Miss the Actual Problem
Search for "ai for macos" and you get a predictable stack: Timing, ClickUp, Setapp, MacObserver, Recoverit, Dottie. They rank ChatGPT, Claude, Grammarly, Elephas, Cursor, and Superwhisper. Each of those is useful. None of them describe what happens when a macOS-native AI tries to do something that a chat window cannot do on its own: read the window in front of you, click a button in another app, organize a folder you have open.
That is the moment the operating system gets involved. macOS gates that capability behind the Accessibility TCC entitlement. If you have ever turned on VoiceOver, you have seen the same permission screen. Every serious "AI for macOS" that controls other apps passes through it. The chat-app listicles do not.
This guide is the other half of the conversation. It covers the part every Mac-native AI engineer has to solve, and it does it with a real, verifiable example: the four-stage accessibility permission detector Fazm ships, with file paths and line numbers you can open in a browser tab.
Works With Any App on Your Mac
Accessibility APIs speak the same protocol VoiceOver uses, so Fazm sees structured UI across the whole system, not just the browser.
“A macOS-native AI lives or dies on its accessibility permission detector. Screenshot agents do not have this problem, because they never ask. They also never see anything the model cannot read in pixels.”
AppState.swift:310-504
What a macOS-Native AI Is Actually Doing
When you ask an AI for macOS to move some files around, it is reading window state, building a prompt with structured UI, calling a model, and then posting accessibility actions or synthetic keystrokes back to the OS. Every arrow in this diagram is gated by a macOS permission.
Any macOS AI that actually controls apps
The Anchor Fact: Why a Two-Line Permission Check Is Not Enough on macOS 26
If you read one Apple tutorial on accessibility permission, it will tell you to call AXIsProcessTrusted() and call it a day. That works on older macOS. It does not work on macOS 26 Tahoe, because Apple changed the behavior of the per-process TCC cache. After the app is re-signed, updated, or you toggle the Accessibility switch in System Settings, the TCC database is updated but the in-process cache is not. The app reports no permission even though it has it.
There is a second failure mode from the other direction. Some apps (Qt-based, OpenGL-based, PyMOL, certain games) do not implement the AX protocol at all. When you call AXUIElementCopyAttributeValue against them you get AXError.cannotComplete, which is exactly the same error code you would get from a truly broken permission. A naive detector would tell the user their permission is broken every time they alt-tab to Blender.
Fazm's detector handles both failure modes. Here is the core dispatch, verbatim from the file. The two failure modes land in the two branches at the top level.
The full file is 1,049 lines long, and the permission dispatch alone occupies lines 310 through 504. You can open it at github.com/mediar-ai/fazm.
The Four Stages, in Order
Each stage exists to disambiguate a specific failure mode the previous stage cannot see. None of them is optional if you want the detector to stay accurate across every macOS version Fazm supports.
checkAccessibilityPermission() dispatch
AXIsProcessTrusted()
TCC self-report. Fast, cached, lies on macOS 26 after re-signs.
Functional AX probe
AXUIElementCopyAttributeValue(kAXFocusedWindowAttribute). Proves AX calls really work against the frontmost app.
Finder disambiguation
If the functional probe returned cannotComplete, re-run against Finder. Finder is always AX-compliant, so a Finder failure proves the permission is broken, not app-specific.
CGEvent tap probe
CGEvent.tapCreate bypasses the per-process TCC cache and reads the live database. This is what catches the macOS 26 Tahoe stale-cache case.
Stage 3: Why Finder Gets the Tiebreaker Vote
AXError.cannotComplete is ambiguous. It can mean our process lost permission, or it can mean the frontmost app does not speak the AX protocol properly. Fazm settles it by calling AX against Finder, which is known to be AX-compliant. If Finder fails too, the permission is truly broken. If Finder succeeds, the original failure was app-specific.
Notice the comment in the source: "Qt, OpenGL, Python-based apps like PyMOL." These are real apps Fazm users have in the foreground. Without this disambiguation step, every Blender user would see a permission-broken banner every time they came back to the app. Most detectors skip this step.
Stage 4: The CGEvent Tap That Sees Past the Cache
This stage is the macOS 26 Tahoe workaround. It creates a listen-only mouse-movement event tap and immediately invalidates it. Tap creation is special: it goes through a different TCC path than AXIsProcessTrusted, so it reads the live TCC database instead of the stale per-process cache. If tap creation succeeds, we really do have permission, regardless of what AXIsProcessTrusted() returned.
Important guardrail in the source: Fazm only runs this probe if the user previously had permission. Running it on a fresh install would trigger the "prevented from modifying apps" Privacy & Security notification every polling cycle. The comment at line 337-341 calls this out explicitly.
The Detector in Numbers
The retry loop (AppState.swift:375-395) fires every 5 seconds, re-running the full four-stage detector. After 3 failures, Fazm surfaces a "Quit & Reopen" modal. That is how it recovers from the macOS 26 stale cache without the user ever reading a release note.
Verify It Yourself
Three commands. The first clones the source, the second shows you the exact detector, the third shows the retry loop that catches the macOS 26 Tahoe stale-cache case.
What Happens the Moment You Click "Grant Accessibility"
The detector is the quiet half. The other half is the path from the onboarding button to a working permission grant. Here is what Fazm does, step by step.
triggerAccessibilityPermission() fires
AppState.swift:512-534. Fazm calls AXIsProcessTrustedWithOptions with kAXTrustedCheckOptionPrompt=true. On macOS Sequoia and later this does NOT show a dialog anymore, so Fazm also opens the System Settings Accessibility pane directly via x-apple.systempreferences://.
User flips the toggle in System Settings
macOS writes the TCC record. On macOS 26 Tahoe, the per-process cache is NOT updated, which is the entire bug this detector exists to work around.
Polling loop catches the change
Fazm polls checkAccessibilityPermission() and exercises all four stages. Stage 4 (the CGEvent tap probe) succeeds even though AXIsProcessTrusted() still returns false.
hasAccessibilityPermission = true
Fazm flips the state, stops the retry timer, and unblocks the Ask-AI input. The user never sees the cache bug.
If all four stages fail for 15 seconds
showAccessibilityRestartAlert() (AppState.swift:404-418) runs. A Quit & Reopen modal appears. Relaunch resets the per-process state and the permission takes effect on the next start.
Two AIs, Same macOS, Very Different Experience
The difference between a macOS AI that reads the accessibility tree and one that takes screenshots is not aesthetic. It is latency, token cost, reliability across apps, and how well it survives OS updates.
Screenshot-based AI vs accessibility-based AI on macOS
Takes a full-screen capture on every turn. Sends the PNG to a vision model. Asks the model to decide where to click. Posts the click via CGEvent. Repeats.
- 1,700 to 3,000 image tokens per turn
- Vision-model OCR on every click target
- Pixel hallucinations cause retries
- Does not see occluded or off-screen state
Fazm vs the Chat Apps Everyone Else Ranks
| Feature | ChatGPT / Claude desktop | Fazm |
|---|---|---|
| Can click buttons in other apps | No (chat only) | Yes (AXPress, AXSetValue) |
| Reads the current window | Pasted text only | Yes (accessibility tree) |
| Needs Accessibility permission | No | Yes (documented, open source detector) |
| Works without a screenshot | N/A (does not touch other apps) | Yes (structured AX data) |
| macOS 26 Tahoe TCC stale-cache handled | N/A | Yes (four-stage detector, event-tap probe) |
| Open source | No | Yes (github.com/mediar-ai/fazm) |
| Runs on-device-only model option | Cloud only | Configurable (Ollama/LM Studio endpoint) |
Frequently asked questions
What is the best AI for macOS in 2026?
It depends on what you want the AI to do. For chat, Claude.ai and ChatGPT are the default picks. For writing assistance, Elephas and Grammarly. For coding, Cursor. For actually automating your Mac (clicking buttons, reading windows, organizing files across real apps), you need an AI that talks to macOS's accessibility APIs directly. Fazm is a consumer-friendly option in that category because it uses real AXUIElement calls plus the Claude models, is open source, and works across any app, not just the browser.
Why do most macOS AI apps need accessibility permission?
Any AI that reads or controls another app on your Mac needs the Accessibility TCC entitlement. This is how the OS exposes the text of menu items, button roles, window titles, focused field contents, and so on. Without it, the AI can only see what you paste into it. Screen-recording permission covers pixel capture, but pixels alone require vision models to read back the UI, which is slower and costs more tokens than reading the accessibility tree directly.
What is the macOS 26 Tahoe TCC stale-cache bug?
On macOS 26 (Tahoe), AXIsProcessTrusted() can return stale data after the app is re-signed, updated, or the user toggles the Accessibility switch in System Settings. The TCC database is updated, but the per-process cache is not, so the app incorrectly reports that it has no permission even though it does. You can verify this in Fazm's source at Desktop/Sources/AppState.swift lines 336 through 359, where the code deliberately probes with a CGEvent.tapCreate call because tap creation reads the live TCC database and bypasses the stale cache.
How does Fazm handle the macOS 26 TCC cache issue?
Four stages. First: AXIsProcessTrusted(). If that returns true, verify with a live AXUIElementCopyAttributeValue call against the frontmost app's focused window. If that call returns .cannotComplete (ambiguous), disambiguate against Finder, because Finder is always AX-compliant. If Finder is not running, fall back to a CGEvent.tapCreate(.cgSessionEventTap, listenOnly) probe, which bypasses the stale per-process cache. The full chain lives in AppState.swift:310-504 and the 5-second retry loop tops out at 3 attempts before prompting you to quit and reopen the app.
Which macOS AI apps use accessibility APIs instead of screenshots?
A short list: Fazm (consumer app, open source at github.com/mediar-ai/fazm), Terminator (MIT-licensed Rust library at github.com/mediar-ai/terminator, Fazm uses it on Windows), and Dottie (proprietary). Most venture-backed 'AI desktop agent' apps use screenshots and vision models. Anthropic Computer Use and OpenAI Operator are both screenshot-first. Accessibility APIs are faster and cheaper, but harder to implement reliably across every app on the system, which is probably why most teams skip them.
Can I run an AI for macOS that stays fully on-device?
You can run the model fully on-device with apps like Locally AI, Ollama, or LM Studio, but anything that interacts with other apps (not just chats) still needs accessibility permission. On-device inference plus accessibility-API-based automation is a reasonable privacy posture. Fazm ships cloud models by default for quality, but can be configured to route to a local model endpoint if you have one running.
How do I reset a broken accessibility permission on macOS?
Fazm ships a one-click reset that calls `/usr/bin/tccutil reset Accessibility <bundle id>` and restarts the app. Source: Desktop/Sources/AppState.swift:544-590. You can run the same command manually: `tccutil reset Accessibility com.fazm.app`. This clears the TCC record entirely, and the next launch re-prompts for permission, which usually clears a stale-cache state in one cycle.
Why would I pick an accessibility-API AI over Apple Intelligence or Siri?
Apple Intelligence can only call a fixed set of App Intents that developers opted into. Siri's scripting scope is similarly constrained. An accessibility-API AI can click any button or read any window in any app on your system, because it talks to the same OS layer VoiceOver uses. That is a much larger addressable surface, at the cost of needing an explicit permission grant. If the app you want to automate did not ship an App Intent, Apple Intelligence cannot help you. An accessibility AI can.
Try an AI for macOS that actually reads the OS
Fazm uses real accessibility APIs instead of screenshots. Works with any app. Open source. Free to start.
Download Fazm →The permission layer is the product.
A macOS AI that cannot survive the OS's own permission quirks is a chat window in a different font. Fazm's four-stage detector is the boring, uncopyable part that makes everything else work.
Try Fazm free
Comments
Public and anonymous. No signup.
Loading…