Skip to main content

Core principles

When building AI agents that use agent-native, follow these principles:
  1. Always re-snapshot after UI changes
  2. Use interactive mode by default (-i flag)
  3. Handle errors gracefully and retry with context
  4. Fall back to keyboard when AX tree is sparse
  5. Verify state after critical operations
The most common mistake is forgetting to re-snapshot after clicking, navigating, or changing state. Old refs may not resolve after UI structure changes.

Always re-snapshot after UI changes

Why re-snapshotting matters

Refs from snapshot 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)
Old refs may:
  • 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
The -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
For production agent workflows, always use -i.

Combine with -c for even cleaner output

The -c (compact) flag removes empty structural elements that have no content or actions.

Handle errors gracefully

Common error scenarios

Cause: UI structure changed, element removed, or never snapshotted.Solution: Re-snapshot and find element by attributes.
Cause: Element is disabled (grayed out) or not yet ready.Solution: Wait or check prerequisites.
Cause: App not running, wrong name, or not launched yet.Solution: Open the app first, retry with fuzzy matching.
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. When snapshot -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:
Screenshots are especially useful for Electron apps, custom controls, and visual confirmation of state.

Next steps

JSON output reference

Complete reference for all JSON output formats

OpenCode skill

Install the pre-built skill for instant integration