{
  "schemaVersion": "1.0",
  "item": {
    "slug": "atl-mobile",
    "name": "Agent Touch Layer",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/JordanCoin/atl-mobile",
    "canonicalUrl": "https://clawhub.ai/JordanCoin/atl-mobile",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/atl-mobile",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=atl-mobile",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md",
      "scripts/setup.sh"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/atl-mobile"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/atl-mobile",
    "agentPageUrl": "https://openagent3.xyz/skills/atl-mobile/agent",
    "manifestUrl": "https://openagent3.xyz/skills/atl-mobile/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/atl-mobile/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "ATL — Agent Touch Layer",
        "body": "The automation layer between AI agents and iOS\n\nATL provides HTTP-based automation for iOS Simulator — both browser (mobile Safari) and native apps. Think Playwright, but for mobile."
      },
      {
        "title": "🔀 Two Servers: Browser & Native",
        "body": "ATL uses two separate servers for browser and native app automation:\n\nServerPortUse CaseKey CommandsBrowser9222Web automation in mobile Safarigoto, markElements, clickMark, evaluateNative9223iOS app automation (Settings, Contacts, any app)openApp, snapshot, tapRef, find\n\n┌─────────────────────────────────────────────────────────────┐\n│  BROWSER SERVER (9222)     │     NATIVE SERVER (9223)      │\n│  (mobile Safari/WebView)   │     (iOS apps via XCTest)     │\n│                            │                                │\n│  markElements + clickMark  │     snapshot + tapRef         │\n│  CSS selectors             │     accessibility tree        │\n│  DOM evaluation            │     element references        │\n│  tap, swipe, screenshot    │     tap, swipe, screenshot    │\n└─────────────────────────────────────────────────────────────┘\n\nWhy two ports? Native app automation requires XCTest APIs (XCUIApplication, XCUIElement) which are only available in UI Test bundles. The native server runs as a UI Test that exposes an HTTP API."
      },
      {
        "title": "Starting the Servers",
        "body": "# Browser server (starts automatically with AtlBrowser app)\nxcrun simctl launch booted com.atl.browser\ncurl http://localhost:9222/ping  # → {\"status\":\"ok\"}\n\n# Native server (run as UI Test)\ncd ~/Atl/core/AtlBrowser\nxcodebuild test -workspace AtlBrowser.xcworkspace \\\n  -scheme AtlBrowser \\\n  -destination 'id=<SIMULATOR_UDID>' \\\n  -only-testing:AtlBrowserUITests/NativeServer/testNativeServer &\n  \n# Wait for it to start, then:\ncurl http://localhost:9223/ping  # → {\"status\":\"ok\",\"mode\":\"native\"}"
      },
      {
        "title": "Quick Port Reference",
        "body": "TaskPortExampleBrowse websites9222curl localhost:9222/command -d '{\"method\":\"goto\",...}'Open native app9223curl localhost:9223/command -d '{\"method\":\"openApp\",...}'Screenshot (browser)9222curl localhost:9222/command -d '{\"method\":\"screenshot\"}'Screenshot (native)9223curl localhost:9223/command -d '{\"method\":\"screenshot\"}'"
      },
      {
        "title": "📱 Native App Automation (Port 9223)",
        "body": "Native automation uses port 9223 and automates any iOS app using the accessibility tree — no DOM, no JavaScript, just direct element interaction."
      },
      {
        "title": "Opening & Closing Apps",
        "body": "# Open an app by bundle ID\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"openApp\",\"params\":{\"bundleId\":\"com.apple.Preferences\"}}'\n# → {\"success\":true,\"result\":{\"bundleId\":\"com.apple.Preferences\",\"mode\":\"native\",\"state\":\"running\"}}\n\n# Check current app state\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"appState\"}'\n# → {\"success\":true,\"result\":{\"mode\":\"native\",\"bundleId\":\"com.apple.Preferences\",\"state\":\"running\"}}\n\n# Close current app\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"closeApp\"}'\n# → {\"success\":true,\"result\":{\"closed\":true}}"
      },
      {
        "title": "Common Bundle IDs",
        "body": "AppBundle IDSettingscom.apple.PreferencesContactscom.apple.MobileAddressBookCalculatorcom.apple.calculatorCalendarcom.apple.mobilecalPhotoscom.apple.mobileslideshowNotescom.apple.mobilenotesReminderscom.apple.remindersClockcom.apple.mobiletimerMapscom.apple.MapsSafaricom.apple.mobilesafari"
      },
      {
        "title": "The snapshot Command",
        "body": "snapshot returns the accessibility tree — all visible elements with their properties and tap-able references.\n\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"snapshot\",\"params\":{\"interactiveOnly\":true}}' | jq '.result'\n\nExample output:\n\n{\n  \"count\": 12,\n  \"elements\": [\n    {\n      \"ref\": \"e0\",\n      \"type\": \"cell\",\n      \"label\": \"Wi-Fi\",\n      \"value\": \"MyNetwork\",\n      \"identifier\": \"\",\n      \"x\": 0,\n      \"y\": 142,\n      \"width\": 393,\n      \"height\": 44,\n      \"isHittable\": true,\n      \"isEnabled\": true\n    },\n    {\n      \"ref\": \"e1\",\n      \"type\": \"cell\",\n      \"label\": \"Bluetooth\",\n      \"value\": \"On\",\n      \"identifier\": \"\",\n      \"x\": 0,\n      \"y\": 186,\n      \"width\": 393,\n      \"height\": 44,\n      \"isHittable\": true,\n      \"isEnabled\": true\n    },\n    {\n      \"ref\": \"e2\",\n      \"type\": \"button\",\n      \"label\": \"Back\",\n      \"value\": null,\n      \"identifier\": \"Back\",\n      \"x\": 0,\n      \"y\": 44,\n      \"width\": 80,\n      \"height\": 44,\n      \"isHittable\": true,\n      \"isEnabled\": true\n    }\n  ]\n}\n\nParameters:\n\ninteractiveOnly (bool, default: false) — Only return hittable elements\nmaxDepth (int, optional) — Limit tree traversal depth"
      },
      {
        "title": "The tapRef Command",
        "body": "Tap an element by its reference from the last snapshot:\n\n# Take snapshot first\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"snapshot\",\"params\":{\"interactiveOnly\":true}}'\n\n# Tap element e0 (Wi-Fi cell from example above)\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"tapRef\",\"params\":{\"ref\":\"e0\"}}'\n# → {\"success\":true}"
      },
      {
        "title": "The find Command",
        "body": "Find and interact with elements by text — no need to parse snapshot manually:\n\n# Find and tap \"Wi-Fi\"\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Wi-Fi\",\"action\":\"tap\"}}'\n# → {\"success\":true,\"result\":{\"found\":true,\"ref\":\"e0\"}}\n\n# Check if an element exists\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Bluetooth\",\"action\":\"exists\"}}'\n# → {\"success\":true,\"result\":{\"found\":true,\"ref\":\"e1\"}}\n\n# Find and fill a text field\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"First name\",\"action\":\"fill\",\"value\":\"John\"}}'\n\n# Get element info without interacting\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Cancel\",\"action\":\"get\"}}'\n# → {\"success\":true,\"result\":{\"found\":true,\"ref\":\"e5\",\"element\":{...}}}\n\nParameters:\n\ntext (string) — Text to search for (matches label, value, or identifier)\naction (string) — One of: tap, fill, exists, get\nvalue (string, optional) — Text to fill (required for action:\"fill\")\nby (string, optional) — Narrow search: label, value, identifier, type, or any (default)"
      },
      {
        "title": "🔄 Native App Workflow Example",
        "body": "Here's a complete flow: open Settings, navigate to Wi-Fi, take a screenshot:\n\n# 1. Open Settings app\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"openApp\",\"params\":{\"bundleId\":\"com.apple.Preferences\"}}'\n\n# 2. Wait for app to launch\nsleep 1\n\n# 3. Take snapshot to see available elements\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"snapshot\",\"params\":{\"interactiveOnly\":true}}' | jq '.result.elements[:5]'\n\n# 4. Find and tap Wi-Fi\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Wi-Fi\",\"action\":\"tap\"}}'\n\n# 5. Wait for navigation\nsleep 0.5\n\n# 6. Take screenshot of Wi-Fi settings\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"screenshot\"}' | jq -r '.result.data' | base64 -d > /tmp/wifi-settings.png\n\n# 7. Navigate back (swipe right from left edge)\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"swipe\",\"params\":{\"direction\":\"right\"}}'\n\n# 8. Close the app\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"closeApp\"}'"
      },
      {
        "title": "Helper Script Version",
        "body": "source ~/.openclaw/skills/atl-browser/scripts/atl-helper.sh\n\natl_openapp \"com.apple.Preferences\"\nsleep 1\natl_find \"Wi-Fi\" tap\nsleep 0.5\natl_screenshot /tmp/wifi-settings.png\natl_swipe right\natl_closeapp"
      },
      {
        "title": "💡 Core Insight: Vision-Free Automation",
        "body": "ATL's killer feature is spatial understanding without vision models:\n\n┌─────────────────────────────────────────────────────────────┐\n│  markElements + captureForVision = COMPLETE PAGE KNOWLEDGE  │\n└─────────────────────────────────────────────────────────────┘\n\n1. markElements  → Numbers every interactive element [1] [2] [3]\n2. captureForVision → PDF with text layer + element coordinates\n3. tap x=234 y=567 → Pixel-perfect touch at exact position\n\nWhy this matters:\n\nNo vision API calls — zero token cost for \"seeing\" the page\nFaster — no round-trip to GPT-4V/Claude Vision\nDeterministic — same page = same coordinates, every time\nReliable — pixel-perfect coordinates vs. vision interpretation"
      },
      {
        "title": "The Vision-Free Workflow",
        "body": "# 1. Mark elements (adds numbered labels + stores coordinates)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"1\",\"method\":\"markElements\",\"params\":{}}'\n\n# 2. Capture PDF with text layer (machine-readable, has coordinates)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"2\",\"method\":\"captureForVision\",\"params\":{\"savePath\":\"/tmp\",\"name\":\"page\"}}' \\\n  | jq -r '.result.path'\n# → /tmp/page.pdf (text-selectable, contains element positions)\n\n# 3. Get specific element's position by mark label\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"3\",\"method\":\"getMarkInfo\",\"params\":{\"label\":5}}' | jq '.result'\n# → {\"label\":5, \"tag\":\"button\", \"text\":\"Add to Cart\", \"x\":187, \"y\":432, \"width\":120, \"height\":44}\n\n# 4. Tap at exact coordinates\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"4\",\"method\":\"tap\",\"params\":{\"x\":187,\"y\":432}}'\n\nThe marks tell you WHERE everything is. The PDF tells you WHAT everything says. Together = full page understanding."
      },
      {
        "title": "🎯 The Escalation Ladder",
        "body": "When automation gets stuck, escalate through these levels:\n\n┌─────────────────────────────────────────────────────────────┐\n│  Level 1: COORDINATES (fast, cheap, no API calls)          │\n│  markElements → getMarkInfo → tap x,y                      │\n│                                                             │\n│  ↓ If stuck after 2-3 tries...                             │\n│                                                             │\n│  Level 2: VISION FALLBACK (screenshot to understand state) │\n│  screenshot → analyze UI → identify blockers (modals, etc) │\n│                                                             │\n│  ↓ If still stuck...                                       │\n│                                                             │\n│  Level 3: JS INJECTION (direct DOM manipulation)           │\n│  evaluate → dispatchEvent → force interactions             │\n└─────────────────────────────────────────────────────────────┘"
      },
      {
        "title": "When to Escalate",
        "body": "SymptomLikely CauseActionTap succeeds but nothing changesModal/overlay openedScreenshot → find new buttonCart count doesn't updateSite needs login or has bot detectionTry JS click with eventsElement not found after scrollMarks are page-relative, not viewportUse getBoundingClientRect via evaluateSame error 3+ timesUI state changed unexpectedlyScreenshot to see actual state"
      },
      {
        "title": "Real-World Pattern: E-commerce Checkout",
        "body": "# 1. Search and find product\natl_goto \"https://store.com/search?q=headphones\"\natl_mark\n\n# 2. First, dismiss any modals/banners (ALWAYS DO THIS)\n# Look for: close, dismiss, continue, accept, no thanks, got it\nCLOSE=$(atl_find \"close\")\n[ -n \"$CLOSE\" ] && atl_click $CLOSE\n\n# 3. Find and click Add to Cart\nATC=$(atl_find \"Add to cart\")\natl_click $ATC\n\n# 4. Wait, then CHECK if it worked\nsleep 2\natl_screenshot /tmp/after-click.png\n\n# 5. If cart didn't update, LOOK at the screenshot\n# Maybe a \"Choose options\" modal opened - find the NEW Add to Cart button\n# This is the vision fallback - you need to SEE what happened"
      },
      {
        "title": "Key Insight: Modals Change Everything",
        "body": "When you click \"Add to cart\" on sites like Target, Amazon, etc., they often:\n\nOpen a \"Choose options\" modal (size, color, quantity)\nShow an upsell (protection plans, accessories)\nDisplay a confirmation with \"View cart\" or \"Continue shopping\"\n\nYour original tap WORKED — you just can't see the result without a screenshot."
      },
      {
        "title": "🚀 Quick Start (30 seconds)",
        "body": "# 1. Setup (boots sim, installs ATL)\n~/.openclaw/skills/atl-browser/scripts/setup.sh\n\n# 2. Navigate somewhere\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"1\",\"method\":\"goto\",\"params\":{\"url\":\"https://example.com\"}}'\n\n# 3. Mark elements (shows [1], [2], [3] labels)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"2\",\"method\":\"markElements\",\"params\":{}}'\n\n# 4. Take screenshot\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"3\",\"method\":\"screenshot\",\"params\":{}}' | jq -r '.result.data' | base64 -d > /tmp/page.png\n\n# 5. Click element [1]\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"4\",\"method\":\"clickMark\",\"params\":{\"label\":1}}'\n\nOr use the helper functions:\n\nsource ~/.openclaw/skills/atl-browser/scripts/atl-helper.sh\natl_goto \"https://example.com\"\natl_mark\natl_screenshot /tmp/page.png\natl_click 1"
      },
      {
        "title": "Quick Reference",
        "body": "Base URL: http://localhost:9222"
      },
      {
        "title": "Common Commands",
        "body": "# Check if ATL is running\ncurl -s http://localhost:9222/ping\n\n# Navigate to URL\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"goto\",\"params\":{\"url\":\"https://example.com\"}}'\n\n# Wait for page ready\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"waitForReady\",\"params\":{\"timeout\":10}}'\n\n# Take screenshot (returns base64 PNG)\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"3\",\"method\":\"screenshot\",\"params\":{}}' | jq -r '.result.data' | base64 -d > screenshot.png\n\n# Mark interactive elements (shows numbered labels)\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"4\",\"method\":\"markElements\",\"params\":{}}'\n\n# Click by mark label\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"5\",\"method\":\"clickMark\",\"params\":{\"label\":3}}'\n\n# Scroll page\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"6\",\"method\":\"evaluate\",\"params\":{\"script\":\"window.scrollBy(0, 500)\"}}'\n\n# Type text\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"7\",\"method\":\"type\",\"params\":{\"text\":\"Hello world\"}}'\n\n# Click by CSS selector\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"8\",\"method\":\"click\",\"params\":{\"selector\":\"button.submit\"}}'"
      },
      {
        "title": "1. Start Simulator",
        "body": "# Boot iPhone 17 simulator (or another device)\nxcrun simctl boot \"iPhone 17\"\n\n# Open Simulator app\nopen -a Simulator"
      },
      {
        "title": "2. Build & Install AtlBrowser",
        "body": "cd ~/Atl/core/AtlBrowser\n\n# Build for simulator (RECOMMENDED: target by UDID)\n# Why: name-based destinations can cause Xcode to pick an older iOS runtime (15/16)\n# and fail if AtlBrowser has an iOS 17+ deployment target.\n#\n# 1) Find a suitable simulator UDID (iOS 17+):\n#   xcrun simctl list devices available\n#\n# 2) Build targeting that UDID:\nxcodebuild -workspace AtlBrowser.xcworkspace \\\n  -scheme AtlBrowser \\\n  -destination 'id=<SIM_UDID>' \\\n  -derivedDataPath /tmp/atl-dd \\\n  build\n\n# Install to a specific simulator (preferred)\nxcrun simctl install <SIM_UDID> \\\n  /tmp/atl-dd/Build/Products/Debug-iphonesimulator/AtlBrowser.app\n\n# Launch the app\nxcrun simctl launch <SIM_UDID> com.atl.browser"
      },
      {
        "title": "3. Verify Server",
        "body": "curl -s http://localhost:9222/ping\n# Should return: {\"status\":\"ok\"}"
      },
      {
        "title": "App Control (Native Mode)",
        "body": "MethodParamsModeDescriptionopenApp{bundleId}Any→NativeOpen app, switch to native modecloseApp-NativeClose current app, return to browser modeappState-AnyGet current mode and bundleIdopenBrowser-Native→BrowserSwitch back to browser mode"
      },
      {
        "title": "Native Accessibility",
        "body": "MethodParamsModeDescriptionsnapshot{interactiveOnly?, maxDepth?}NativeGet accessibility treetapRef{ref}NativeTap element by ref (e.g., \"e0\")find{text, action, value?, by?}NativeFind element and interactfillRef{ref, text}NativeTap element and type textfocusRef{ref}NativeFocus element without typing"
      },
      {
        "title": "Navigation (Browser)",
        "body": "MethodParamsModeDescriptiongoto{url}BrowserNavigate to URLreload-BrowserReload pagegoBack-BrowserGo backgoForward-BrowserGo forwardgetURL-BrowserGet current URLgetTitle-BrowserGet page title"
      },
      {
        "title": "Interactions (Browser)",
        "body": "MethodParamsModeDescriptionclick{selector}BrowserClick elementdoubleClick{selector}BrowserDouble-clicktype{text}BothType textfill{selector, value}BrowserFill input fieldpress{key}BothPress keyhover{selector}BrowserHover over elementscrollIntoView{selector}BrowserScroll to element"
      },
      {
        "title": "Mark System (Browser)",
        "body": "MethodParamsModeDescriptionmarkElements-BrowserMark visible interactive elementsmarkAll-BrowserMark ALL interactive elementsunmarkElements-BrowserRemove marksclickMark{label}BrowserClick by label numbergetMarkInfo{label}BrowserGet element info by label"
      },
      {
        "title": "Screenshots & Capture",
        "body": "MethodParamsModeDescriptionscreenshot{fullPage?, selector?}BothTake screenshotcaptureForVision{savePath?, name?}BrowserFull page PDFcaptureJPEG{quality?, fullPage?}BothJPEG capturecaptureLight-BrowserText + interactives only"
      },
      {
        "title": "Waiting (Browser)",
        "body": "MethodParamsModeDescriptionwaitForSelector{selector, timeout?}BrowserWait for elementwaitForNavigation-BrowserWait for navigationwaitForReady{timeout?, stabilityMs?}BrowserWait for page readywaitForAny{selectors, timeout?}BrowserWait for any selector"
      },
      {
        "title": "JavaScript (Browser)",
        "body": "MethodParamsModeDescriptionevaluate{script}BrowserRun JavaScriptquerySelector{selector}BrowserFind elementquerySelectorAll{selector}BrowserFind all elementsgetDOMSnapshot-BrowserGet page HTML"
      },
      {
        "title": "Cookies (Browser)",
        "body": "MethodParamsModeDescriptiongetCookies-BrowserGet all cookiessetCookies{cookies}BrowserSet cookiesdeleteCookies-BrowserDelete all cookies"
      },
      {
        "title": "Touch Gestures (Both Modes)",
        "body": "MethodParamsModeDescriptiontap{x, y}BothTap at coordinateslongPress{x, y, duration?}BothLong press (default 0.5s)swipe{direction}BothSwipe up/down/left/rightswipe{fromX, fromY, toX, toY}BothSwipe between pointspinch{scale, duration?}BothPinch zoom (scale > 1 = zoom in)\n\nSwipe Examples\n\n# Swipe up (scroll down)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"1\",\"method\":\"swipe\",\"params\":{\"direction\":\"up\"}}'\n\n# Swipe left (next page in carousel)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"2\",\"method\":\"swipe\",\"params\":{\"direction\":\"left\",\"distance\":400}}'\n\n# Custom swipe path\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"3\",\"method\":\"swipe\",\"params\":{\"fromX\":200,\"fromY\":600,\"toX\":200,\"toY\":200}}'\n\n# Long press for context menu\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"4\",\"method\":\"longPress\",\"params\":{\"x\":150,\"y\":300,\"duration\":1.0}}'\n\n# Pinch to zoom in\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"5\",\"method\":\"pinch\",\"params\":{\"scale\":2.0}}'"
      },
      {
        "title": "Typical Workflow",
        "body": "# 1. Navigate to site\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"goto\",\"params\":{\"url\":\"https://www.apple.com/shop\"}}'\n\n# 2. Wait for page to load\nsleep 2\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"waitForReady\",\"params\":{\"timeout\":10}}'\n\n# 3. Mark elements to see what's clickable\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"3\",\"method\":\"markElements\",\"params\":{}}'\n\n# 4. Take screenshot to see the marks\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"4\",\"method\":\"screenshot\",\"params\":{}}' | jq -r '.result.data' | base64 -d > /tmp/page.png\n\n# 5. Click a marked element (e.g., label 14)\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"5\",\"method\":\"clickMark\",\"params\":{\"label\":14}}'\n\n# 6. Repeat as needed"
      },
      {
        "title": "Navigation not working (goto returns success but page doesn't change)",
        "body": "Known issue: goto command may return success without navigating. Use JS workaround:\n\n# Instead of goto, use evaluate to navigate\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"evaluate\",\"params\":{\"script\":\"location.href = \\\"https://example.com\\\"; true\"}}'\n\n# Wait for page load\nsleep 3\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"waitForReady\",\"params\":{\"timeout\":10}}'"
      },
      {
        "title": "Server not responding",
        "body": "# Check if app is running\nxcrun simctl listapps booted | grep atl\n\n# Restart the app\nxcrun simctl terminate booted com.atl.browser\nxcrun simctl launch booted com.atl.browser\n\n# Check logs\nxcrun simctl spawn booted log show --predicate 'process == \"AtlBrowser\"' --last 1m"
      },
      {
        "title": "Need to rebuild (iOS version changes)",
        "body": "cd ~/Atl/core/AtlBrowser\nxcodebuild -workspace AtlBrowser.xcworkspace -scheme AtlBrowser -sdk iphonesimulator build\nxcrun simctl install booted ~/Library/Developer/Xcode/DerivedData/AtlBrowser-*/Build/Products/Debug-iphonesimulator/AtlBrowser.app\nxcrun simctl launch booted com.atl.browser"
      },
      {
        "title": "Port 9222 in use",
        "body": "The ATL server runs inside the simulator app. If port 9222 is blocked, check for other processes:\n\nlsof -i :9222"
      },
      {
        "title": "1. Clean UI Before Acting",
        "body": "Real users dismiss popups. You should too.\n\n# Before any workflow, check for and dismiss:\n# - Cookie consent banners\n# - Newsletter popups  \n# - Health/privacy consent modals\n# - \"Download our app\" prompts\natl_mark\nfor KEYWORD in \"close\" \"dismiss\" \"no thanks\" \"accept\" \"got it\" \"continue\"; do\n  LABEL=$(atl_find \"$KEYWORD\")\n  [ -n \"$LABEL\" ] && atl_click $LABEL && sleep 1\ndone"
      },
      {
        "title": "2. Verify State After Actions",
        "body": "Don't assume — confirm.\n\natl_click $ADD_TO_CART\nsleep 2\n# Check if cart updated\nCART=$(atl_find \"cart [1-9]\")\nif [ -z \"$CART\" ]; then\n  # Didn't work - take screenshot to see why\n  atl_screenshot /tmp/debug.png\n  echo \"Action may have opened a modal - check screenshot\"\nfi"
      },
      {
        "title": "3. Use Viewport Coordinates for Taps",
        "body": "Marks give page-relative coordinates. For tap to work, the element must be visible.\n\n# Option A: Scroll element into view first\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"evaluate\",\"params\":{\"script\":\"document.querySelector(\\\"#my-button\\\").scrollIntoView()\"}}'\n\n# Option B: Get viewport-relative coords via JS\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"evaluate\",\"params\":{\"script\":\"var r = document.querySelector(\\\"#my-button\\\").getBoundingClientRect(); JSON.stringify({x: r.x + r.width/2, y: r.y + r.height/2})\"}}'"
      },
      {
        "title": "4. Screenshot is Your Debugging Superpower",
        "body": "When in doubt, look.\n\natl_screenshot /tmp/current-state.png\n# Then analyze with vision or just open the file"
      },
      {
        "title": "Notes",
        "body": "ATL runs inside the iOS Simulator, sharing the host's network\nPort 9222 is the default (matches Chrome DevTools Protocol convention)\nThe mark system shows red numbered labels on interactive elements\nScreenshots are PNG base64-encoded; use base64 -d to decode\niOS 26+ compatible (fixed NWListener binding issue)"
      },
      {
        "title": "Requirements",
        "body": "macOS with Xcode installed\niOS Simulator (comes with Xcode)\nThat's it!"
      },
      {
        "title": "Examples",
        "body": "See examples/ folder:\n\ntest-browse.sh - Quick bash test workflow"
      },
      {
        "title": "API Reference",
        "body": "For machine-readable API spec, see openapi.yaml — includes all commands, parameters, and response schemas."
      },
      {
        "title": "Source",
        "body": "GitHub: https://github.com/JordanCoin/Atl\nAuthor: @JordanCoin"
      }
    ],
    "body": "ATL — Agent Touch Layer\n\nThe automation layer between AI agents and iOS\n\nATL provides HTTP-based automation for iOS Simulator — both browser (mobile Safari) and native apps. Think Playwright, but for mobile.\n\n🔀 Two Servers: Browser & Native\n\nATL uses two separate servers for browser and native app automation:\n\nServer\tPort\tUse Case\tKey Commands\nBrowser\t9222\tWeb automation in mobile Safari\tgoto, markElements, clickMark, evaluate\nNative\t9223\tiOS app automation (Settings, Contacts, any app)\topenApp, snapshot, tapRef, find\n┌─────────────────────────────────────────────────────────────┐\n│  BROWSER SERVER (9222)     │     NATIVE SERVER (9223)      │\n│  (mobile Safari/WebView)   │     (iOS apps via XCTest)     │\n│                            │                                │\n│  markElements + clickMark  │     snapshot + tapRef         │\n│  CSS selectors             │     accessibility tree        │\n│  DOM evaluation            │     element references        │\n│  tap, swipe, screenshot    │     tap, swipe, screenshot    │\n└─────────────────────────────────────────────────────────────┘\n\n\nWhy two ports? Native app automation requires XCTest APIs (XCUIApplication, XCUIElement) which are only available in UI Test bundles. The native server runs as a UI Test that exposes an HTTP API.\n\nStarting the Servers\n# Browser server (starts automatically with AtlBrowser app)\nxcrun simctl launch booted com.atl.browser\ncurl http://localhost:9222/ping  # → {\"status\":\"ok\"}\n\n# Native server (run as UI Test)\ncd ~/Atl/core/AtlBrowser\nxcodebuild test -workspace AtlBrowser.xcworkspace \\\n  -scheme AtlBrowser \\\n  -destination 'id=<SIMULATOR_UDID>' \\\n  -only-testing:AtlBrowserUITests/NativeServer/testNativeServer &\n  \n# Wait for it to start, then:\ncurl http://localhost:9223/ping  # → {\"status\":\"ok\",\"mode\":\"native\"}\n\nQuick Port Reference\nTask\tPort\tExample\nBrowse websites\t9222\tcurl localhost:9222/command -d '{\"method\":\"goto\",...}'\nOpen native app\t9223\tcurl localhost:9223/command -d '{\"method\":\"openApp\",...}'\nScreenshot (browser)\t9222\tcurl localhost:9222/command -d '{\"method\":\"screenshot\"}'\nScreenshot (native)\t9223\tcurl localhost:9223/command -d '{\"method\":\"screenshot\"}'\n📱 Native App Automation (Port 9223)\n\nNative automation uses port 9223 and automates any iOS app using the accessibility tree — no DOM, no JavaScript, just direct element interaction.\n\nOpening & Closing Apps\n# Open an app by bundle ID\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"openApp\",\"params\":{\"bundleId\":\"com.apple.Preferences\"}}'\n# → {\"success\":true,\"result\":{\"bundleId\":\"com.apple.Preferences\",\"mode\":\"native\",\"state\":\"running\"}}\n\n# Check current app state\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"appState\"}'\n# → {\"success\":true,\"result\":{\"mode\":\"native\",\"bundleId\":\"com.apple.Preferences\",\"state\":\"running\"}}\n\n# Close current app\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"closeApp\"}'\n# → {\"success\":true,\"result\":{\"closed\":true}}\n\nCommon Bundle IDs\nApp\tBundle ID\nSettings\tcom.apple.Preferences\nContacts\tcom.apple.MobileAddressBook\nCalculator\tcom.apple.calculator\nCalendar\tcom.apple.mobilecal\nPhotos\tcom.apple.mobileslideshow\nNotes\tcom.apple.mobilenotes\nReminders\tcom.apple.reminders\nClock\tcom.apple.mobiletimer\nMaps\tcom.apple.Maps\nSafari\tcom.apple.mobilesafari\nThe snapshot Command\n\nsnapshot returns the accessibility tree — all visible elements with their properties and tap-able references.\n\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"snapshot\",\"params\":{\"interactiveOnly\":true}}' | jq '.result'\n\n\nExample output:\n\n{\n  \"count\": 12,\n  \"elements\": [\n    {\n      \"ref\": \"e0\",\n      \"type\": \"cell\",\n      \"label\": \"Wi-Fi\",\n      \"value\": \"MyNetwork\",\n      \"identifier\": \"\",\n      \"x\": 0,\n      \"y\": 142,\n      \"width\": 393,\n      \"height\": 44,\n      \"isHittable\": true,\n      \"isEnabled\": true\n    },\n    {\n      \"ref\": \"e1\",\n      \"type\": \"cell\",\n      \"label\": \"Bluetooth\",\n      \"value\": \"On\",\n      \"identifier\": \"\",\n      \"x\": 0,\n      \"y\": 186,\n      \"width\": 393,\n      \"height\": 44,\n      \"isHittable\": true,\n      \"isEnabled\": true\n    },\n    {\n      \"ref\": \"e2\",\n      \"type\": \"button\",\n      \"label\": \"Back\",\n      \"value\": null,\n      \"identifier\": \"Back\",\n      \"x\": 0,\n      \"y\": 44,\n      \"width\": 80,\n      \"height\": 44,\n      \"isHittable\": true,\n      \"isEnabled\": true\n    }\n  ]\n}\n\n\nParameters:\n\ninteractiveOnly (bool, default: false) — Only return hittable elements\nmaxDepth (int, optional) — Limit tree traversal depth\nThe tapRef Command\n\nTap an element by its reference from the last snapshot:\n\n# Take snapshot first\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"snapshot\",\"params\":{\"interactiveOnly\":true}}'\n\n# Tap element e0 (Wi-Fi cell from example above)\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"tapRef\",\"params\":{\"ref\":\"e0\"}}'\n# → {\"success\":true}\n\nThe find Command\n\nFind and interact with elements by text — no need to parse snapshot manually:\n\n# Find and tap \"Wi-Fi\"\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Wi-Fi\",\"action\":\"tap\"}}'\n# → {\"success\":true,\"result\":{\"found\":true,\"ref\":\"e0\"}}\n\n# Check if an element exists\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Bluetooth\",\"action\":\"exists\"}}'\n# → {\"success\":true,\"result\":{\"found\":true,\"ref\":\"e1\"}}\n\n# Find and fill a text field\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"First name\",\"action\":\"fill\",\"value\":\"John\"}}'\n\n# Get element info without interacting\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Cancel\",\"action\":\"get\"}}'\n# → {\"success\":true,\"result\":{\"found\":true,\"ref\":\"e5\",\"element\":{...}}}\n\n\nParameters:\n\ntext (string) — Text to search for (matches label, value, or identifier)\naction (string) — One of: tap, fill, exists, get\nvalue (string, optional) — Text to fill (required for action:\"fill\")\nby (string, optional) — Narrow search: label, value, identifier, type, or any (default)\n🔄 Native App Workflow Example\n\nHere's a complete flow: open Settings, navigate to Wi-Fi, take a screenshot:\n\n# 1. Open Settings app\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"openApp\",\"params\":{\"bundleId\":\"com.apple.Preferences\"}}'\n\n# 2. Wait for app to launch\nsleep 1\n\n# 3. Take snapshot to see available elements\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"snapshot\",\"params\":{\"interactiveOnly\":true}}' | jq '.result.elements[:5]'\n\n# 4. Find and tap Wi-Fi\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"find\",\"params\":{\"text\":\"Wi-Fi\",\"action\":\"tap\"}}'\n\n# 5. Wait for navigation\nsleep 0.5\n\n# 6. Take screenshot of Wi-Fi settings\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"screenshot\"}' | jq -r '.result.data' | base64 -d > /tmp/wifi-settings.png\n\n# 7. Navigate back (swipe right from left edge)\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"swipe\",\"params\":{\"direction\":\"right\"}}'\n\n# 8. Close the app\ncurl -s -X POST http://localhost:9223/command \\\n  -d '{\"method\":\"closeApp\"}'\n\nHelper Script Version\nsource ~/.openclaw/skills/atl-browser/scripts/atl-helper.sh\n\natl_openapp \"com.apple.Preferences\"\nsleep 1\natl_find \"Wi-Fi\" tap\nsleep 0.5\natl_screenshot /tmp/wifi-settings.png\natl_swipe right\natl_closeapp\n\n💡 Core Insight: Vision-Free Automation\n\nATL's killer feature is spatial understanding without vision models:\n\n┌─────────────────────────────────────────────────────────────┐\n│  markElements + captureForVision = COMPLETE PAGE KNOWLEDGE  │\n└─────────────────────────────────────────────────────────────┘\n\n1. markElements  → Numbers every interactive element [1] [2] [3]\n2. captureForVision → PDF with text layer + element coordinates\n3. tap x=234 y=567 → Pixel-perfect touch at exact position\n\n\nWhy this matters:\n\nNo vision API calls — zero token cost for \"seeing\" the page\nFaster — no round-trip to GPT-4V/Claude Vision\nDeterministic — same page = same coordinates, every time\nReliable — pixel-perfect coordinates vs. vision interpretation\nThe Vision-Free Workflow\n# 1. Mark elements (adds numbered labels + stores coordinates)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"1\",\"method\":\"markElements\",\"params\":{}}'\n\n# 2. Capture PDF with text layer (machine-readable, has coordinates)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"2\",\"method\":\"captureForVision\",\"params\":{\"savePath\":\"/tmp\",\"name\":\"page\"}}' \\\n  | jq -r '.result.path'\n# → /tmp/page.pdf (text-selectable, contains element positions)\n\n# 3. Get specific element's position by mark label\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"3\",\"method\":\"getMarkInfo\",\"params\":{\"label\":5}}' | jq '.result'\n# → {\"label\":5, \"tag\":\"button\", \"text\":\"Add to Cart\", \"x\":187, \"y\":432, \"width\":120, \"height\":44}\n\n# 4. Tap at exact coordinates\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"4\",\"method\":\"tap\",\"params\":{\"x\":187,\"y\":432}}'\n\n\nThe marks tell you WHERE everything is. The PDF tells you WHAT everything says. Together = full page understanding.\n\n🎯 The Escalation Ladder\n\nWhen automation gets stuck, escalate through these levels:\n\n┌─────────────────────────────────────────────────────────────┐\n│  Level 1: COORDINATES (fast, cheap, no API calls)          │\n│  markElements → getMarkInfo → tap x,y                      │\n│                                                             │\n│  ↓ If stuck after 2-3 tries...                             │\n│                                                             │\n│  Level 2: VISION FALLBACK (screenshot to understand state) │\n│  screenshot → analyze UI → identify blockers (modals, etc) │\n│                                                             │\n│  ↓ If still stuck...                                       │\n│                                                             │\n│  Level 3: JS INJECTION (direct DOM manipulation)           │\n│  evaluate → dispatchEvent → force interactions             │\n└─────────────────────────────────────────────────────────────┘\n\nWhen to Escalate\nSymptom\tLikely Cause\tAction\nTap succeeds but nothing changes\tModal/overlay opened\tScreenshot → find new button\nCart count doesn't update\tSite needs login or has bot detection\tTry JS click with events\nElement not found after scroll\tMarks are page-relative, not viewport\tUse getBoundingClientRect via evaluate\nSame error 3+ times\tUI state changed unexpectedly\tScreenshot to see actual state\nReal-World Pattern: E-commerce Checkout\n# 1. Search and find product\natl_goto \"https://store.com/search?q=headphones\"\natl_mark\n\n# 2. First, dismiss any modals/banners (ALWAYS DO THIS)\n# Look for: close, dismiss, continue, accept, no thanks, got it\nCLOSE=$(atl_find \"close\")\n[ -n \"$CLOSE\" ] && atl_click $CLOSE\n\n# 3. Find and click Add to Cart\nATC=$(atl_find \"Add to cart\")\natl_click $ATC\n\n# 4. Wait, then CHECK if it worked\nsleep 2\natl_screenshot /tmp/after-click.png\n\n# 5. If cart didn't update, LOOK at the screenshot\n# Maybe a \"Choose options\" modal opened - find the NEW Add to Cart button\n# This is the vision fallback - you need to SEE what happened\n\nKey Insight: Modals Change Everything\n\nWhen you click \"Add to cart\" on sites like Target, Amazon, etc., they often:\n\nOpen a \"Choose options\" modal (size, color, quantity)\nShow an upsell (protection plans, accessories)\nDisplay a confirmation with \"View cart\" or \"Continue shopping\"\n\nYour original tap WORKED — you just can't see the result without a screenshot.\n\n🚀 Quick Start (30 seconds)\n# 1. Setup (boots sim, installs ATL)\n~/.openclaw/skills/atl-browser/scripts/setup.sh\n\n# 2. Navigate somewhere\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"1\",\"method\":\"goto\",\"params\":{\"url\":\"https://example.com\"}}'\n\n# 3. Mark elements (shows [1], [2], [3] labels)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"2\",\"method\":\"markElements\",\"params\":{}}'\n\n# 4. Take screenshot\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"3\",\"method\":\"screenshot\",\"params\":{}}' | jq -r '.result.data' | base64 -d > /tmp/page.png\n\n# 5. Click element [1]\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"4\",\"method\":\"clickMark\",\"params\":{\"label\":1}}'\n\n\nOr use the helper functions:\n\nsource ~/.openclaw/skills/atl-browser/scripts/atl-helper.sh\natl_goto \"https://example.com\"\natl_mark\natl_screenshot /tmp/page.png\natl_click 1\n\nQuick Reference\n\nBase URL: http://localhost:9222\n\nCommon Commands\n# Check if ATL is running\ncurl -s http://localhost:9222/ping\n\n# Navigate to URL\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"goto\",\"params\":{\"url\":\"https://example.com\"}}'\n\n# Wait for page ready\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"waitForReady\",\"params\":{\"timeout\":10}}'\n\n# Take screenshot (returns base64 PNG)\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"3\",\"method\":\"screenshot\",\"params\":{}}' | jq -r '.result.data' | base64 -d > screenshot.png\n\n# Mark interactive elements (shows numbered labels)\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"4\",\"method\":\"markElements\",\"params\":{}}'\n\n# Click by mark label\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"5\",\"method\":\"clickMark\",\"params\":{\"label\":3}}'\n\n# Scroll page\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"6\",\"method\":\"evaluate\",\"params\":{\"script\":\"window.scrollBy(0, 500)\"}}'\n\n# Type text\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"7\",\"method\":\"type\",\"params\":{\"text\":\"Hello world\"}}'\n\n# Click by CSS selector\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"8\",\"method\":\"click\",\"params\":{\"selector\":\"button.submit\"}}'\n\nSetup (First Time)\n1. Start Simulator\n# Boot iPhone 17 simulator (or another device)\nxcrun simctl boot \"iPhone 17\"\n\n# Open Simulator app\nopen -a Simulator\n\n2. Build & Install AtlBrowser\ncd ~/Atl/core/AtlBrowser\n\n# Build for simulator (RECOMMENDED: target by UDID)\n# Why: name-based destinations can cause Xcode to pick an older iOS runtime (15/16)\n# and fail if AtlBrowser has an iOS 17+ deployment target.\n#\n# 1) Find a suitable simulator UDID (iOS 17+):\n#   xcrun simctl list devices available\n#\n# 2) Build targeting that UDID:\nxcodebuild -workspace AtlBrowser.xcworkspace \\\n  -scheme AtlBrowser \\\n  -destination 'id=<SIM_UDID>' \\\n  -derivedDataPath /tmp/atl-dd \\\n  build\n\n# Install to a specific simulator (preferred)\nxcrun simctl install <SIM_UDID> \\\n  /tmp/atl-dd/Build/Products/Debug-iphonesimulator/AtlBrowser.app\n\n# Launch the app\nxcrun simctl launch <SIM_UDID> com.atl.browser\n\n3. Verify Server\ncurl -s http://localhost:9222/ping\n# Should return: {\"status\":\"ok\"}\n\nAll Available Methods\nApp Control (Native Mode)\nMethod\tParams\tMode\tDescription\nopenApp\t{bundleId}\tAny→Native\tOpen app, switch to native mode\ncloseApp\t-\tNative\tClose current app, return to browser mode\nappState\t-\tAny\tGet current mode and bundleId\nopenBrowser\t-\tNative→Browser\tSwitch back to browser mode\nNative Accessibility\nMethod\tParams\tMode\tDescription\nsnapshot\t{interactiveOnly?, maxDepth?}\tNative\tGet accessibility tree\ntapRef\t{ref}\tNative\tTap element by ref (e.g., \"e0\")\nfind\t{text, action, value?, by?}\tNative\tFind element and interact\nfillRef\t{ref, text}\tNative\tTap element and type text\nfocusRef\t{ref}\tNative\tFocus element without typing\nNavigation (Browser)\nMethod\tParams\tMode\tDescription\ngoto\t{url}\tBrowser\tNavigate to URL\nreload\t-\tBrowser\tReload page\ngoBack\t-\tBrowser\tGo back\ngoForward\t-\tBrowser\tGo forward\ngetURL\t-\tBrowser\tGet current URL\ngetTitle\t-\tBrowser\tGet page title\nInteractions (Browser)\nMethod\tParams\tMode\tDescription\nclick\t{selector}\tBrowser\tClick element\ndoubleClick\t{selector}\tBrowser\tDouble-click\ntype\t{text}\tBoth\tType text\nfill\t{selector, value}\tBrowser\tFill input field\npress\t{key}\tBoth\tPress key\nhover\t{selector}\tBrowser\tHover over element\nscrollIntoView\t{selector}\tBrowser\tScroll to element\nMark System (Browser)\nMethod\tParams\tMode\tDescription\nmarkElements\t-\tBrowser\tMark visible interactive elements\nmarkAll\t-\tBrowser\tMark ALL interactive elements\nunmarkElements\t-\tBrowser\tRemove marks\nclickMark\t{label}\tBrowser\tClick by label number\ngetMarkInfo\t{label}\tBrowser\tGet element info by label\nScreenshots & Capture\nMethod\tParams\tMode\tDescription\nscreenshot\t{fullPage?, selector?}\tBoth\tTake screenshot\ncaptureForVision\t{savePath?, name?}\tBrowser\tFull page PDF\ncaptureJPEG\t{quality?, fullPage?}\tBoth\tJPEG capture\ncaptureLight\t-\tBrowser\tText + interactives only\nWaiting (Browser)\nMethod\tParams\tMode\tDescription\nwaitForSelector\t{selector, timeout?}\tBrowser\tWait for element\nwaitForNavigation\t-\tBrowser\tWait for navigation\nwaitForReady\t{timeout?, stabilityMs?}\tBrowser\tWait for page ready\nwaitForAny\t{selectors, timeout?}\tBrowser\tWait for any selector\nJavaScript (Browser)\nMethod\tParams\tMode\tDescription\nevaluate\t{script}\tBrowser\tRun JavaScript\nquerySelector\t{selector}\tBrowser\tFind element\nquerySelectorAll\t{selector}\tBrowser\tFind all elements\ngetDOMSnapshot\t-\tBrowser\tGet page HTML\nCookies (Browser)\nMethod\tParams\tMode\tDescription\ngetCookies\t-\tBrowser\tGet all cookies\nsetCookies\t{cookies}\tBrowser\tSet cookies\ndeleteCookies\t-\tBrowser\tDelete all cookies\nTouch Gestures (Both Modes)\nMethod\tParams\tMode\tDescription\ntap\t{x, y}\tBoth\tTap at coordinates\nlongPress\t{x, y, duration?}\tBoth\tLong press (default 0.5s)\nswipe\t{direction}\tBoth\tSwipe up/down/left/right\nswipe\t{fromX, fromY, toX, toY}\tBoth\tSwipe between points\npinch\t{scale, duration?}\tBoth\tPinch zoom (scale > 1 = zoom in)\nSwipe Examples\n# Swipe up (scroll down)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"1\",\"method\":\"swipe\",\"params\":{\"direction\":\"up\"}}'\n\n# Swipe left (next page in carousel)\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"2\",\"method\":\"swipe\",\"params\":{\"direction\":\"left\",\"distance\":400}}'\n\n# Custom swipe path\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"3\",\"method\":\"swipe\",\"params\":{\"fromX\":200,\"fromY\":600,\"toX\":200,\"toY\":200}}'\n\n# Long press for context menu\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"4\",\"method\":\"longPress\",\"params\":{\"x\":150,\"y\":300,\"duration\":1.0}}'\n\n# Pinch to zoom in\ncurl -s -X POST http://localhost:9222/command \\\n  -d '{\"id\":\"5\",\"method\":\"pinch\",\"params\":{\"scale\":2.0}}'\n\nTypical Workflow\n# 1. Navigate to site\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"goto\",\"params\":{\"url\":\"https://www.apple.com/shop\"}}'\n\n# 2. Wait for page to load\nsleep 2\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"waitForReady\",\"params\":{\"timeout\":10}}'\n\n# 3. Mark elements to see what's clickable\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"3\",\"method\":\"markElements\",\"params\":{}}'\n\n# 4. Take screenshot to see the marks\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"4\",\"method\":\"screenshot\",\"params\":{}}' | jq -r '.result.data' | base64 -d > /tmp/page.png\n\n# 5. Click a marked element (e.g., label 14)\ncurl -s -X POST http://localhost:9222/command \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"5\",\"method\":\"clickMark\",\"params\":{\"label\":14}}'\n\n# 6. Repeat as needed\n\nTroubleshooting\nNavigation not working (goto returns success but page doesn't change)\n\nKnown issue: goto command may return success without navigating. Use JS workaround:\n\n# Instead of goto, use evaluate to navigate\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"evaluate\",\"params\":{\"script\":\"location.href = \\\"https://example.com\\\"; true\"}}'\n\n# Wait for page load\nsleep 3\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"waitForReady\",\"params\":{\"timeout\":10}}'\n\nServer not responding\n# Check if app is running\nxcrun simctl listapps booted | grep atl\n\n# Restart the app\nxcrun simctl terminate booted com.atl.browser\nxcrun simctl launch booted com.atl.browser\n\n# Check logs\nxcrun simctl spawn booted log show --predicate 'process == \"AtlBrowser\"' --last 1m\n\nNeed to rebuild (iOS version changes)\ncd ~/Atl/core/AtlBrowser\nxcodebuild -workspace AtlBrowser.xcworkspace -scheme AtlBrowser -sdk iphonesimulator build\nxcrun simctl install booted ~/Library/Developer/Xcode/DerivedData/AtlBrowser-*/Build/Products/Debug-iphonesimulator/AtlBrowser.app\nxcrun simctl launch booted com.atl.browser\n\nPort 9222 in use\n\nThe ATL server runs inside the simulator app. If port 9222 is blocked, check for other processes:\n\nlsof -i :9222\n\nBest Practices\n1. Clean UI Before Acting\n\nReal users dismiss popups. You should too.\n\n# Before any workflow, check for and dismiss:\n# - Cookie consent banners\n# - Newsletter popups  \n# - Health/privacy consent modals\n# - \"Download our app\" prompts\natl_mark\nfor KEYWORD in \"close\" \"dismiss\" \"no thanks\" \"accept\" \"got it\" \"continue\"; do\n  LABEL=$(atl_find \"$KEYWORD\")\n  [ -n \"$LABEL\" ] && atl_click $LABEL && sleep 1\ndone\n\n2. Verify State After Actions\n\nDon't assume — confirm.\n\natl_click $ADD_TO_CART\nsleep 2\n# Check if cart updated\nCART=$(atl_find \"cart [1-9]\")\nif [ -z \"$CART\" ]; then\n  # Didn't work - take screenshot to see why\n  atl_screenshot /tmp/debug.png\n  echo \"Action may have opened a modal - check screenshot\"\nfi\n\n3. Use Viewport Coordinates for Taps\n\nMarks give page-relative coordinates. For tap to work, the element must be visible.\n\n# Option A: Scroll element into view first\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"1\",\"method\":\"evaluate\",\"params\":{\"script\":\"document.querySelector(\\\"#my-button\\\").scrollIntoView()\"}}'\n\n# Option B: Get viewport-relative coords via JS\ncurl -s -X POST http://localhost:9222/command -H \"Content-Type: application/json\" \\\n  -d '{\"id\":\"2\",\"method\":\"evaluate\",\"params\":{\"script\":\"var r = document.querySelector(\\\"#my-button\\\").getBoundingClientRect(); JSON.stringify({x: r.x + r.width/2, y: r.y + r.height/2})\"}}'\n\n4. Screenshot is Your Debugging Superpower\n\nWhen in doubt, look.\n\natl_screenshot /tmp/current-state.png\n# Then analyze with vision or just open the file\n\nNotes\nATL runs inside the iOS Simulator, sharing the host's network\nPort 9222 is the default (matches Chrome DevTools Protocol convention)\nThe mark system shows red numbered labels on interactive elements\nScreenshots are PNG base64-encoded; use base64 -d to decode\niOS 26+ compatible (fixed NWListener binding issue)\nRequirements\nmacOS with Xcode installed\niOS Simulator (comes with Xcode)\nThat's it!\nExamples\n\nSee examples/ folder:\n\ntest-browse.sh - Quick bash test workflow\nAPI Reference\n\nFor machine-readable API spec, see openapi.yaml — includes all commands, parameters, and response schemas.\n\nSource\nGitHub: https://github.com/JordanCoin/Atl\nAuthor: @JordanCoin"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/JordanCoin/atl-mobile",
    "publisherUrl": "https://clawhub.ai/JordanCoin/atl-mobile",
    "owner": "JordanCoin",
    "version": "0.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/atl-mobile",
    "downloadUrl": "https://openagent3.xyz/downloads/atl-mobile",
    "agentUrl": "https://openagent3.xyz/skills/atl-mobile/agent",
    "manifestUrl": "https://openagent3.xyz/skills/atl-mobile/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/atl-mobile/agent.md"
  }
}