@n1, @n2, @n3 to elements in the Accessibility tree. You then use these refs in subsequent commands to click, type, or inspect specific elements.
What are refs?
A ref (reference) is a short identifier like@n1, @n2, etc. that points to a specific UI element. Think of refs as temporary “handles” for elements discovered during a snapshot.
Refs are numbered sequentially starting from
n1 in each snapshot. The @ prefix distinguishes refs from app names.How snapshots work
Thesnapshot command walks the Accessibility tree and assigns refs to elements. From SnapshotCommand.swift:5-133:
1
Walk the tree
Traverse the app’s Accessibility tree to the specified depth:
2
Filter elements
Optionally filter to only interactive elements with
--interactive, or use --compact to skip empty structural nodes:3
Assign refs
Number each element sequentially:
4
Save to RefStore
Persist ref → element mappings to a temp JSON file:
The RefStore
Refs are persisted to disk at/tmp/agent-native-refs.json so they survive between CLI invocations. Each command runs as a separate process, so refs must be saved externally.
From RefStore.swift:4-35:
The RefStore contains only the metadata needed to re-find elements, not live
AXUIElement pointers (which can’t be serialized).Ref resolution
When you use a ref like@n5, agent-native must resolve it back to a live AXUIElement. This happens by re-searching the tree using the stored attributes.
From RefStore.swift:37-74:
1
Load ref metadata
Read the entry from
agent-native-refs.json.2
Search the live tree
Use
AXEngine.findElements() to search for elements matching the stored role, title, label, and identifier.3
Match exactly
Return the element that exactly matches all stored attributes.
4
Error if not found
If the element no longer exists or has changed, throw
elementNotFound.Ref lifecycle and invalidation
Refs become invalid when:- The UI changes - If a button is removed or its text changes, the ref can’t be resolved
- The app restarts - PIDs change, invalidating all refs for that app
- A new snapshot is taken - Each
snapshotcommand overwrites the entire RefStore
When refs fail
@n8 no longer exists or has different attributes. Solution: take a new snapshot.
Interactive vs full snapshots
You can control what gets refs:Interactive snapshots
Use--interactive to only assign refs to elements you can interact with:
interactiveRoles (buttons, text fields, checkboxes, links, etc.) and skips structural elements like groups and static text.
Compact snapshots
Use--compact to remove empty structural elements:
SnapshotCommand.swift:69-74, this skips elements with:
- No
title,label, orvalue - No
actions - Has children (i.e., is just a container)
Full snapshots
By default, every element gets a ref. This is useful for debugging or when you need to inspect structural elements:Example workflow
1
Take initial snapshot
2
Interact with refs
3
Re-snapshot after UI changes
After the page loads, the UI is different. Take a new snapshot:
See also
Accessibility tree
Understanding the tree that refs point into
Workflow
The snapshot → interact → re-snapshot pattern