Core principles
When building AI agents that use agent-native, follow these principles:- Always re-snapshot after UI changes
- Use interactive mode by default (
-iflag) - Handle errors gracefully and retry with context
- Fall back to keyboard when AX tree is sparse
- Verify state after critical operations
Always re-snapshot after UI changes
Why re-snapshotting matters
Refs fromsnapshot are stable identifiers tied to the current UI structure. When the UI changes:
- New elements appear (modals, sheets, panels)
- Elements are removed (closed dialogs, hidden sections)
- Element hierarchy changes (expanded trees, navigated views)
- Point to elements that no longer exist
- Point to elements with different attributes
- Fail to resolve entirely
When to re-snapshot
Re-snapshot after any action that changes the UI:1
After navigation
2
After opening dialogs/sheets
3
After state changes
4
After form submission
When NOT to re-snapshot
You can skip re-snapshotting for:- Reading state without changing it (
get text,is enabled) - Multiple interactions on the same view without navigation
- Typing text in a single field
- Taking screenshots
Use interactive mode by default
Why -i matters
The full AX tree contains hundreds of structural elements (groups, static text, images) that aren’t interactive. For AI agents:
- Too much noise makes LLMs less effective at finding targets
- Longer context consumes more tokens
- Slower processing from parsing large trees
-i flag filters to only interactive elements:
- Buttons, text fields, checkboxes, links, sliders, etc.
- Elements that have actions like
AXPress,AXConfirm
Always use -i unless…
Only omit -i when:
- Debugging why an element isn’t appearing
- Reading static content like labels or error messages
- Exploring an unfamiliar app’s structure
-i.
Combine with -c for even cleaner output
-c (compact) flag removes empty structural elements that have no content or actions.
Handle errors gracefully
Common error scenarios
Ref not found
Ref not found
Cause: UI structure changed, element removed, or never snapshotted.Solution: Re-snapshot and find element by attributes.
Element not enabled
Element not enabled
Cause: Element is disabled (grayed out) or not yet ready.Solution: Wait or check prerequisites.
App not found
App not found
Cause: App not running, wrong name, or not launched yet.Solution: Open the app first, retry with fuzzy matching.
Timeout waiting for element
Timeout waiting for element
Cause: Element took longer to appear than expected.Solution: Increase timeout, check if navigation succeeded.
Retry with exponential backoff
For transient failures (network, slow UI), retry with increasing delays:When to use keyboard vs AX tree
Prefer AX tree when possible
The AX tree is more reliable and semantic:- Semantic understanding: Know what element you’re interacting with
- State validation: Check if element is enabled, focused, etc.
- Precise targeting: No guessing about key sequences
- Cross-version compatibility: Less brittle than keyboard shortcuts
Use keyboard for Electron apps
Electron apps (Slack, Discord, VS Code, etc.) expose minimal AX trees. Whensnapshot -i returns very few elements:
Common keyboard patterns
Slack
VS Code
Discord
Safari
Combine both approaches
Performance tips
Limit snapshot depth
Deeper trees take longer to walk and parse:Use wait instead of sleep
Cache snapshots when possible
If making multiple queries on the same view:Batch independent operations
Verify state after critical operations
For important operations, verify success:Use screenshots for visual context
When the AX tree doesn’t provide enough information:Next steps
JSON output reference
Complete reference for all JSON output formats
OpenCode skill
Install the pre-built skill for instant integration