Skip to main content

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.

Command output formats

apps

List running GUI applications.
agent-native apps --json
Output
[
  {
    "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
Output
[
  {
    "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
Output
{
  "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
Output
{
  "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
Output
{
  "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
Output
{
  "text": "Wi-Fi",
  "element": {
    "role": "AXButton",
    "title": "Wi-Fi",
    "path": "/AXWindow/AXButton[@title='Wi-Fi']"
  }
}
agent-native get value @n2 --json
Output
{
  "value": "search query",
  "element": {
    "role": "AXTextField",
    "label": "Search",
    "path": "/AXWindow/AXSearchField"
  }
}
agent-native get attr @n1 AXEnabled --json
Output
{
  "attribute": "AXEnabled",
  "value": "true",
  "element": {
    "role": "AXButton",
    "path": "/AXWindow/AXButton"
  }
}

get title

Get frontmost window title.
agent-native get title Safari --json
Output
{
  "title": "GitHub - ericclemmons/agent-native"
}

is enabled / focused

Check element state.
agent-native is enabled @n1 --json
Output
{
  "enabled": true
}
agent-native is focused @n2 --json
Output
{
  "focused": false
}

inspect

Get all attributes and actions.
agent-native inspect @n1 --json
Output
{
  "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
Output
[
  {
    "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
Output
{
  "path": "/tmp/agent-native-screenshot.png",
  "width": 1920,
  "height": 1080
}
agent-native screenshot Slack /tmp/custom.png --json
Output
{
  "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
Output
{
  "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:
  1. Prints JSON error to stderr (if --json was used)
  2. Exits with non-zero code
Example error:
agent-native click @n999 --json
stderr
{
  "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

Build docs developers (and LLMs) love