Skip to content

macos-workflow

Use when building multi-step macOS automation workflows — composing Peekaboo GUI commands with AppleScript execution in see-act-verify loops. Also use when generating .peekaboo.json scripts for repeatable automation.

ModelSource
sonnetpack: macos-automation
Full Reference

Pipeline skill for composing multi-step macOS automation from three tool layers: Peekaboo (GUI), macos-automator (scripts), and applescript-mcp (raw bridge). Core pattern: See→Act→Verify with automatic retry.

Mandatory Announcement — FIRST OUTPUT before anything else:

┏━ ⚡ macos-workflow ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ [one-line description of workflow being built] ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

No exceptions. Box frame first, then work.

Every workflow step follows this cycle:

Terminal window
peekaboo see --app "TargetApp" --json-output

Captures: snapshot_id, ui_elements[] with roles, labels, element IDs (elem_123, B1), bounding boxes.

Analyze the snapshot output:

  • Identify target elements by role + label
  • Choose tool layer (see Tool Selection Matrix)
  • Determine success criteria for verification

Execute the action using the chosen tool:

Terminal window
# GUI layer (Peekaboo)
peekaboo click --on elem_123
peekaboo type "text content" --on elem_456
# Script layer (macos-automator)
# Use execute_script MCP tool with kb_script_id or inline script
# Raw bridge (applescript-mcp)
# Use applescript_execute MCP tool with code_snippet
Terminal window
peekaboo see --app "TargetApp" --json-output

Compare against expected state:

  • Element appeared/disappeared?
  • Text content changed?
  • Window title updated?
  • New dialog/alert present?
  • If verification passes → next step
  • If verification fails → retry (max 3 attempts per step)
  • If 3 retries exhausted → report failure with last snapshot
Task TypeBest ToolWhy
Click a button/linkPeekaboo (click)Direct element targeting via AX tree
Type text into a fieldPeekaboo (type)Element focus + controlled input
Read screen contentPeekaboo (see)Structured AX metadata
Get app data (tabs, emails, events)AppleScript via macos-automatorApp dictionaries are faster + more reliable
Send keystrokes/hotkeysPeekaboo (hotkey, press)Reliable modifier key handling
File dialogs (open/save)Peekaboo (dialog file)Handles native file picker
Menu bar interactionPeekaboo (menu click)Hierarchical path navigation
Manage windows/spacesPeekaboo (window, space)AX-level window control
System settings/preferencesMixedPeekaboo for UI + script for plist
Data extraction + processingJXA via applescript-mcpJSON handling + ObjC bridge
Batch file operationsAppleScript via macos-automatorFinder dictionary

Decision rule: If the app has an AppleScript dictionary for the operation → use script. If you need to interact with UI visually → use Peekaboo. If both → script for data, Peekaboo for UI interaction.

Example: “Rename all files on the desktop matching a pattern”

1. OBSERVE: peekaboo see --app Finder
2. ACT: AppleScript via macos-automator (Finder dictionary — faster than GUI)
3. VERIFY: peekaboo see --app Finder (confirm names changed)

Example: “Get all Safari tab URLs, paste into a new Numbers spreadsheet”

1. ACT: AppleScript — get URL of every tab of front window of Safari
2. ACT: AppleScript — create new Numbers document
3. LOOP for each URL:
a. OBSERVE: peekaboo see --app Numbers
b. ACT: peekaboo click on next empty cell
c. ACT: peekaboo type URL
4. VERIFY: peekaboo see --app Numbers (confirm all rows populated)

Example: “Set up focus mode — dark mode on, notifications off, arrange windows”

1. ACT: AppleScript — set dark mode (System Events > appearance preferences)
2. ACT: AppleScript — enable Do Not Disturb
3. LOOP for each app in layout:
a. ACT: peekaboo app launch "AppName"
b. ACT: peekaboo window set-bounds --app "AppName" --x N --y N --width W --height H
4. VERIFY: peekaboo image --mode multi (screenshot all screens)

For repeatable workflows, export as Peekaboo scripts:

{
"name": "workflow-name",
"description": "What this workflow does",
"steps": [
{
"command": "see",
"args": ["--app", "Safari", "--json-output"],
"description": "Capture Safari state"
},
{
"command": "click",
"args": ["--on", "elem_123"],
"description": "Click the target element"
},
{
"command": "type",
"args": ["Hello world", "--on", "elem_456"],
"description": "Type into the field"
}
]
}

Run with: peekaboo run workflow.peekaboo.json

Options:

  • --no-fail-fast — continue on step failure (default: stop on first failure)
  • Non-zero exit code on any failure (CI-friendly)

GOTCHA [silent-bug]: Element IDs (elem_123) are ephemeral — they change between see snapshots. Never hardcode element IDs in .peekaboo.json scripts. Use fuzzy text matching or re-capture before each interaction.

ErrorRecovery
Element not foundRe-capture with broader scope (--app instead of --window-title), or try fuzzy text match
Permission deniedCheck peekaboo list permissions, guide user to grant in System Settings
App not respondingpeekaboo app relaunch "AppName", wait, retry
Unexpected dialogpeekaboo dialog dismiss, then retry the blocked step
Wrong window focusedpeekaboo window focus --app "TargetApp", then retry
Script timeoutIncrease timeout_seconds in macos-automator, or break into smaller steps
Coordinates shiftedNever use raw coordinates — always re-capture and use element IDs
  1. Always start with peekaboo see — never assume UI state
  2. Verify after every mutation — don’t chain actions without checking results
  3. Prefer script layer for data — AppleScript dictionaries are faster + more reliable than GUI interaction for data extraction
  4. Use GUI for interaction — clicking, typing, navigating menus
  5. Handle the unexpected — dialogs, alerts, permission prompts can appear at any time
  6. Max 3 retries per step — fail loudly after that, don’t loop forever
  7. Log each step — for debugging, include step number + action + result in output
NeedSkill
Peekaboo CLI referencepeekaboo (capture.md, interaction.md, system.md)
Script executionmacos-automator (tools.md)
App-specific patternsapplescript-reference (app-dictionaries.md)
Generate a script for a stepapplescript-forge
AI agent for unknown UImacos-agent-builder