Understanding macOS Accessibility tree and how agent-native uses it
The macOS Accessibility (AX) tree is a hierarchical representation of every UI element in an application. It’s how agent-native “sees” and interacts with apps—similar to how a DOM represents a web page, the AX tree represents native macOS interfaces.
The Accessibility tree is provided by macOS through the Accessibility APIs (Carbon’s AXUIElement). Every running application exposes its UI hierarchy through this system, which was originally designed for assistive technologies like VoiceOver.Each node in the tree represents a UI element—buttons, text fields, windows, menus, etc. The tree structure mirrors the visual hierarchy: windows contain groups, groups contain buttons, and so on.
The Accessibility tree is built dynamically by querying macOS APIs. agent-native doesn’t modify the tree—it’s a read-only view of the application’s current UI state.
Beyond role, elements have attributes that provide additional information:
// From AXNode.swift:4-19struct AXNode { let role: String // AXButton, AXTextField, etc. let subrole: String? // More specific role variants let title: String? // AXTitle - button text, window title let value: String? // AXValue - text field contents, slider values let label: String? // AXDescription - accessibility label let identifier: String? // AXIdentifier - programmatic ID let enabled: Bool // AXEnabled - can the user interact? let focused: Bool // AXFocused - has keyboard focus? let x, y: Double? // AXPosition - screen coordinates let width, height: Double? // AXSize - element dimensions let actions: [String] // Available actions (AXPress, etc.)}
Not all attributes exist on every element. A button might have title but no value, while a text field has value but might not have title.
Accessing the Accessibility tree requires explicit user permission. agent-native checks and requests access:
// AXEngine.swift:379-386static func checkAccess() -> Bool { AXIsProcessTrusted()}static func requestAccess() { let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue(): true] as CFDictionary AXIsProcessTrustedWithOptions(options)}
You must grant Accessibility permissions in System Settings > Privacy & Security > Accessibility. Without this, all commands will fail with accessDenied.