Overview
Every agent-native command supports the --json flag for structured output. This makes agent-native ideal for AI agents and programmatic use.
JSON output uses pretty-printed, sorted keys for readability and consistency.
Why JSON output?
For AI agents and programmatic use:
- Structured data that’s easy to parse and query
- Consistent format across all commands
- Rich metadata including element attributes, actions, and state
- No text parsing required — direct access to all fields
- Type safety when used with typed languages
Global pattern
Add --json to any command:
agent-native <command> [args] --json
The output is always valid JSON printed to stdout, with errors printed to stderr.
apps
List running GUI applications.
[
{
"bundleId": "com.apple.systempreferences",
"isActive": true,
"isHidden": false,
"name": "System Settings",
"pid": 1234
},
{
"bundleId": "com.tinyspeck.slackmacgap",
"isActive": false,
"isHidden": false,
"name": "Slack",
"pid": 5678
}
]
Fields:
name (string): Application name
pid (number): Process ID
bundleId (string | null): Bundle identifier
isActive (boolean): Whether app is frontmost
isHidden (boolean): Whether app is hidden
snapshot
Capture AX tree with refs.
agent-native snapshot "System Settings" -i --json
[
{
"ref": "n1",
"role": "AXButton",
"title": "Wi-Fi",
"label": null,
"value": null,
"enabled": true,
"actions": ["AXPress"],
"depth": 0
},
{
"ref": "n2",
"role": "AXSearchField",
"title": null,
"label": "Search",
"value": "",
"enabled": true,
"actions": ["AXConfirm", "AXPress"],
"depth": 0
},
{
"ref": "n3",
"role": "AXCheckBox",
"title": "Wi-Fi",
"label": null,
"value": "1",
"enabled": true,
"actions": ["AXPress"],
"depth": 1
}
]
Fields:
ref (string): The ref identifier (e.g. “n1”, “n2”)
role (string): AX role (e.g. “AXButton”, “AXTextField”)
title (string | null): Element title
label (string | null): Accessibility label
value (string | null): Current value (for inputs, checkboxes, etc.)
enabled (boolean): Whether element is enabled
actions (string[]): Available AX actions
depth (number): Depth in the tree (0 = root)
Use the ref field to interact with elements in subsequent commands.
click
Click an element.
agent-native click @n1 --json
{
"action": "AXPress",
"success": true,
"element": {
"role": "AXButton",
"subrole": null,
"title": "Wi-Fi",
"value": null,
"label": null,
"identifier": null,
"enabled": true,
"focused": false,
"x": 120.0,
"y": 200.0,
"width": 80.0,
"height": 32.0,
"path": "/AXWindow/AXButton[@title='Wi-Fi']",
"actions": ["AXPress"],
"childCount": 0
}
}
Fields:
action (string): The action performed
success (boolean): Whether action succeeded
element (object): Full element metadata
fill / type
Fill or type into a field.
agent-native fill @n2 "search query" --json
{
"action": "fill",
"success": true,
"text": "search query",
"element": {
"role": "AXTextField",
"title": null,
"label": "Search",
"value": "search query",
"enabled": true,
"focused": true,
"path": "/AXWindow/AXSearchField[@label='Search']",
"actions": ["AXConfirm"],
"childCount": 0
}
}
Fields:
action (string): “fill” or “type”
success (boolean): Whether operation succeeded
text (string): The text that was entered
element (object): Full element metadata
check / uncheck
Toggle checkbox state.
agent-native check @n3 --json
{
"action": "check",
"success": true,
"element": {
"role": "AXCheckBox",
"title": "Wi-Fi",
"value": "1",
"enabled": true,
"path": "/AXWindow/AXCheckBox[@title='Wi-Fi']",
"actions": ["AXPress"],
"childCount": 0
}
}
Fields:
action (string): “check” or “uncheck”
success (boolean): Whether operation succeeded
element (object): Full element metadata with updated value
The check and uncheck commands are idempotent — they check current state first and only toggle if needed.
get text / value / attr
Read element data.
agent-native get text @n1 --json
{
"text": "Wi-Fi",
"element": {
"role": "AXButton",
"title": "Wi-Fi",
"path": "/AXWindow/AXButton[@title='Wi-Fi']"
}
}
agent-native get value @n2 --json
{
"value": "search query",
"element": {
"role": "AXTextField",
"label": "Search",
"path": "/AXWindow/AXSearchField"
}
}
agent-native get attr @n1 AXEnabled --json
{
"attribute": "AXEnabled",
"value": "true",
"element": {
"role": "AXButton",
"path": "/AXWindow/AXButton"
}
}
get title
Get frontmost window title.
agent-native get title Safari --json
{
"title": "GitHub - ericclemmons/agent-native"
}
is enabled / focused
Check element state.
agent-native is enabled @n1 --json
agent-native is focused @n2 --json
inspect
Get all attributes and actions.
agent-native inspect @n1 --json
{
"element": {
"role": "AXButton",
"title": "Wi-Fi",
"enabled": true,
"path": "/AXWindow/AXButton[@title='Wi-Fi']",
"actions": ["AXPress"],
"childCount": 0
},
"attributes": {
"AXDescription": "Wi-Fi settings",
"AXEnabled": "true",
"AXFocused": "false",
"AXFrame": "{{120, 200}, {80, 32}}",
"AXParent": "[AXObject]",
"AXPosition": "{120, 200}",
"AXRole": "AXButton",
"AXSize": "{80, 32}",
"AXTitle": "Wi-Fi"
},
"actions": [
"AXPress"
]
}
Fields:
element (object): Basic element info
attributes (object): All AX attributes as key-value pairs
actions (string[]): Available actions
find
Find elements by filters.
agent-native find "System Settings" --role AXButton --json
[
{
"role": "AXButton",
"subrole": null,
"title": "Wi-Fi",
"value": null,
"label": null,
"identifier": null,
"enabled": true,
"focused": false,
"x": 120.0,
"y": 200.0,
"width": 80.0,
"height": 32.0,
"path": "/AXWindow/AXButton[@title='Wi-Fi']",
"actions": ["AXPress"],
"childCount": 0
}
]
Returns an array of full AXNode objects matching the filters.
screenshot
Capture app window.
agent-native screenshot Slack --json
{
"path": "/tmp/agent-native-screenshot.png",
"width": 1920,
"height": 1080
}
agent-native screenshot Slack /tmp/custom.png --json
{
"path": "/tmp/custom.png",
"width": 1920,
"height": 1080
}
Fields:
path (string): Path to saved screenshot
width (number): Image width in pixels
height (number): Image height in pixels
action
Perform arbitrary AX action.
agent-native action @n5 AXIncrement --json
{
"action": "AXIncrement",
"success": true,
"element": {
"role": "AXStepper",
"value": "5",
"actions": ["AXIncrement", "AXDecrement"]
}
}
Parsing strategies
Python
import subprocess
import json
def run_agent_native(args: list[str]) -> dict | list:
"""Run agent-native command and parse JSON output."""
cmd = ["agent-native"] + args + ["--json"]
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
return json.loads(result.stdout)
# Example: Find a button by title
snapshot = run_agent_native(["snapshot", "System Settings", "-i"])
wifi_button = next(
el for el in snapshot
if el["role"] == "AXButton" and el["title"] == "Wi-Fi"
)
print(f"Found Wi-Fi button: {wifi_button['ref']}")
# Click it
result = run_agent_native(["click", wifi_button["ref"]])
print(f"Click success: {result['success']}")
JavaScript / TypeScript
import { execSync } from 'child_process';
function runAgentNative(args: string[]): any {
const cmd = ['agent-native', ...args, '--json'].join(' ');
const output = execSync(cmd, { encoding: 'utf-8' });
return JSON.parse(output);
}
// Example: Check if Wi-Fi is enabled
const snapshot = runAgentNative(['snapshot', 'System Settings', '-i']);
const wifiToggle = snapshot.find(
(el: any) => el.role === 'AXCheckBox' && el.title === 'Wi-Fi'
);
if (wifiToggle.value === '1') {
console.log('Wi-Fi is enabled');
} else {
console.log('Wi-Fi is disabled');
}
Bash (with jq)
#!/bin/bash
# Get snapshot
snapshot=$(agent-native snapshot "System Settings" -i --json)
# Find Wi-Fi button ref
wifi_ref=$(echo "$snapshot" | jq -r '.[] | select(.role=="AXButton" and .title=="Wi-Fi") | .ref')
echo "Wi-Fi button ref: $wifi_ref"
# Click it
click_result=$(agent-native click "@$wifi_ref" --json)
success=$(echo "$click_result" | jq -r '.success')
if [ "$success" = "true" ]; then
echo "Successfully clicked Wi-Fi button"
else
echo "Failed to click"
exit 1
fi
Error handling
When a command fails, agent-native:
- Prints JSON error to stderr (if
--json was used)
- Exits with non-zero code
Example error:
agent-native click @n999 --json
{
"error": "Ref not found",
"ref": "n999",
"message": "No ref 'n999' in store. Run snapshot first."
}
try:
result = subprocess.run(
["agent-native", "click", "@n999", "--json"],
capture_output=True,
text=True,
check=True
)
except subprocess.CalledProcessError as e:
error = json.loads(e.stderr)
print(f"Error: {error['message']}")
# Handle error: re-snapshot, retry, etc.
Always check command exit codes or use check=True in subprocess to catch errors.
Type definitions
For TypeScript projects, you can define types for agent-native output:
interface RefNode {
ref: string;
role: string;
title: string | null;
label: string | null;
value: string | null;
enabled: boolean;
actions: string[];
depth: number;
}
interface AXNode {
role: string;
subrole: string | null;
title: string | null;
value: string | null;
label: string | null;
identifier: string | null;
enabled: boolean;
focused: boolean;
x: number | null;
y: number | null;
width: number | null;
height: number | null;
path: string;
actions: string[];
childCount: number;
}
interface ActionResult {
action: string;
success: boolean;
element: AXNode;
}
interface AppInfo {
name: string;
pid: number;
bundleId: string | null;
isActive: boolean;
isHidden: boolean;
}
Next steps
Best practices
Learn patterns for reliable AI automation
AI integration
See example workflows and integration patterns