mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
1073 lines
365 KiB
HTML
1073 lines
365 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head><meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Commands - agent-device</title>
|
||
<script>{;const saved = localStorage.getItem('rspress-theme-appearance');const preferDark = window.matchMedia('(prefers-color-scheme: dark)').matches;const isDark = !saved || saved === 'auto' ? preferDark : saved === 'dark';document.documentElement.classList.toggle('dark', isDark);document.documentElement.classList.toggle('rp-dark', isDark);document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';}</script>
|
||
<link href="/agent-device/static/css/styles.cf5e9ab9a4.css" rel="stylesheet">
|
||
<script defer src="/agent-device/static/js/styles.308ea4bafe.js"></script>
|
||
<script defer src="/agent-device/static/js/lib-react.e84adf13b9.js"></script>
|
||
<script defer src="/agent-device/static/js/lib-router.270f17bfa6.js"></script>
|
||
<script defer src="/agent-device/static/js/476.52ed165336.js"></script>
|
||
<script defer src="/agent-device/static/js/index.8722046b0d.js"></script>
|
||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||
<meta name="generator" content="Rspress v2.0.12">
|
||
<meta property="og:url" content="https://oss.callstack.com/agent-device">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:title" content="Commands - agent-device">
|
||
<meta property="og:image" content="https://oss.callstack.com/agent-device/og-image.jpg">
|
||
<meta property="og:description" content="This page summarizes the primary command groups. For persistent defaults and project-scoped CLI settings, see Configuration. For agent workflow guidance that is matched to the installed CLI, run: Skills are recommended for auto-routing when your agent runtime supports them, but they are not required. The CLI help topics are the version-matched operating contract. For MCP-aware clients that support direct tools, run: The MCP server exposes direct structured tools for installed commands. Tools use structured input contracts through AgentDeviceClient; local-only workflows stay CLI-only rather than subprocess fallbacks. It does not expose generic shell execution over MCP. MCP tools can target platform: "web" after agent-device web setup, but setup and doctor stay CLI-only.">
|
||
<link rel="icon" href="/agent-device/logo.svg" type="image/svg+xml">
|
||
<meta name="description" content="This page summarizes the primary command groups. For persistent defaults and project-scoped CLI settings, see Configuration. For agent workflow guidance that is matched to the installed CLI, run: Skills are recommended for auto-routing when your agent runtime supports them, but they are not required. The CLI help topics are the version-matched operating contract. For MCP-aware clients that support direct tools, run: The MCP server exposes direct structured tools for installed commands. Tools use structured input contracts through AgentDeviceClient; local-only workflows stay CLI-only rather than subprocess fallbacks. It does not expose generic shell execution over MCP. MCP tools can target platform: "web" after agent-device web setup, but setup and doctor stay CLI-only."></head>
|
||
|
||
<body>
|
||
<div id="__rspress_root"><link rel="preload" as="image" href="/agent-device/logo-light.svg"/><link rel="preload" as="image" href="/agent-device/logo-dark.svg"/><link rel="preload" as="image" href="/agent-device/static/image/abstract-atom.4eca0300ff.avif"/><header class="rp-nav"><div class="rp-nav__left"><div class="rp-nav__title"><a href="/agent-device/" class="rp-nav__title__link rp-link"><div class="rp-nav__title__logo"><img src="/agent-device/logo-light.svg" alt="logo" id="logo" class="rspress-logo rp-nav__title__logo-image rp-nav__title__logo-image--light"/><img src="/agent-device/logo-dark.svg" alt="logo" id="logo" class="rspress-logo rp-nav__title__logo-image rp-nav__title__logo-image--dark"/></div></a></div></div><div class="rp-nav__right"><button class="rp-search-button"><div class="rp-search-button__content"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16" class="rp-search-button__icon"><path fill="#838289" d="M14.667 14.666h-1.333v-1.333h1.332zm-1.333-1.333H12V12h1.333zm-4-1.333H4v-1.334h5.334zM12 12h-1.335v-1.334h1.335zm-8-1.334H2.665V9.333H4zm6.665 0H9.334V9.333h1.332zm-8-1.333H1.335V4h1.333zm9.335 0h-1.335V4h1.335zM4 4H2.665V2.666H4zm6.665 0H9.334V2.666h1.332zM9.334 2.666H4V1.333h5.334z"></path></svg><span class="rp-search-button__word">Search</span></div><div class="rp-search-button__hotkey" style="opacity:0"><span></span><span>K</span></div></button><div class="rp-search-button--mobile"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16"><path fill="#838289" d="M14.667 14.666h-1.333v-1.333h1.332zm-1.333-1.333H12V12h1.333zm-4-1.333H4v-1.334h5.334zM12 12h-1.335v-1.334h1.335zm-8-1.334H2.665V9.333H4zm6.665 0H9.334V9.333h1.332zm-8-1.333H1.335V4h1.333zm9.335 0h-1.335V4h1.335zM4 4H2.665V2.666H4zm6.665 0H9.334V2.666h1.332zM9.334 2.666H4V1.333h5.334z"></path></svg></div><ul class="rp-nav-menu rp-nav-menu--right"><li class="rp-nav-menu__item"><a href="/agent-device/docs/introduction" class="rp-nav-menu__item__container rp-link">Docs</a></li></ul><div class="rp-nav__others"><div class="rp-nav-menu__divider"></div><div role="button" tabindex="0" class="rspress-nav-appearance"><div class="rp-p-1 rp-border rp-border-solid rp-border-gray-300 rp-text-gray-400 rp-cursor-pointer rp-rounded-md rp-transition-all rp-duration-300 rp-w-7 rp-h-7"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 24 24"><path fill="currentColor" d="M18 22H8v-2h10zM8 20H6v-2h2zm12 0h-2v-2h2zM6 18H4v-2h2zm16 0h-2v-4h-2v-2h2v-2h2zM4 16H2V6h2zm14 0h-6v-2h6zm-6-2h-2v-2h2zm-2-2H8V6h2zM6 6H4V4h2zm8-2h-2v2h-2V4H6V2h8z"></path></svg></div></div><div class="rp-social-links"><a href="https://github.com/callstack/agent-device" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></div></div></a><a href="https://discord.gg/eYapw6F3" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.37a19.8 19.8 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.3 18.3 0 0 0-5.487 0a13 13 0 0 0-.617-1.25a.08.08 0 0 0-.079-.037A19.7 19.7 0 0 0 3.677 4.37a.1.1 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.08.08 0 0 0 .084-.028a14 14 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13 13 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292a.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.08.08 0 0 0 .084.028a19.8 19.8 0 0 0 6.002-3.03a.08.08 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.06.06 0 0 0-.031-.03M8.02 15.33c-1.182 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418m7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418"/></svg></div></div></a><ul class="rp-hover-group rp-hover-group--hidden rp-hover-group--right"></ul></div></div><button aria-label="mobile hamburger" class="rp-nav-hamburger rp-nav-hamburger__sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#838289" fill-rule="evenodd" d="M1 9h6v6H1zm2 2v2h2v-2zm6-2h6v6H9zm2 2v2h2v-2zm6-2h6v6h-6zm2 2v2h2v-2z" clip-rule="evenodd"></path></svg></button><button aria-label="mobile hamburger" class="rp-nav-hamburger rp-nav-hamburger__md"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#838289" fill-rule="evenodd" d="M1 9h6v6H1zm2 2v2h2v-2zm6-2h6v6H9zm2 2v2h2v-2zm6-2h6v6h-6zm2 2v2h2v-2z" clip-rule="evenodd"></path></svg><ul class="rp-hover-group rp-hover-group--hidden rp-hover-group--right"><div class="rp-nav-menu__others-mobile__container"><div class="rp-nav-hamburger__md__hover-group"><div class="rp-nav-screen-appearance"><div class="rp-nav-screen-appearance__left">Theme</div><div class="rp-nav-screen-appearance__right"></div></div><div class="rp-nav-screen-divider"></div><div class="rp-social-links"><a href="https://github.com/callstack/agent-device" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></div></div></a><a href="https://discord.gg/eYapw6F3" target="_blank" rel="noopener noreferrer" class="rp-social-links__item"><div class="rp-social-links__icon"><div class="rp-social-links__icon"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.37a19.8 19.8 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.3 18.3 0 0 0-5.487 0a13 13 0 0 0-.617-1.25a.08.08 0 0 0-.079-.037A19.7 19.7 0 0 0 3.677 4.37a.1.1 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.08.08 0 0 0 .084-.028a14 14 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13 13 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292a.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.08.08 0 0 0 .084.028a19.8 19.8 0 0 0 6.002-3.03a.08.08 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.06.06 0 0 0-.031-.03M8.02 15.33c-1.182 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418m7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418"/></svg></div></div></a><ul class="rp-hover-group rp-hover-group--hidden rp-hover-group--right"></ul></div></div></div></ul></button></div></header><div class="rp-doc-layout__menu"><div class="rp-sidebar-menu"><button type="button" class="rp-sidebar-menu__left"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#838289" d="M20 18H4v-2h16zm0-5H4v-2h16zm0-5H4V6h16z"></path></svg><span>Menu</span></button><button type="button" class="rp-sidebar-menu__right"><span class="rp-sidebar-menu__right__text">Contents</span><svg width="14" height="14" class="rp-progress-circle"><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-divider-light)" stroke-width="2"></circle><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-brand)" stroke-width="2" stroke-dasharray="37.69911184307752" stroke-dashoffset="37.69911184307752" transform="rotate(-90 7 7)" style="transition:stroke-dashoffset 0.3s"></circle></svg><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" fill="none" viewBox="0 0 12 13" class="rp-sidebar-menu__right__icon" style="transform:rotate(0deg);transition:transform 0.2s ease-out"><path fill="#BCBBC2" d="M6.5 4.5h1v-1h-1v-1h-1v1h-1v1h1v6h1zm-2 0h-1v1h1zm4 0h-1v1h1zm-5 2v-1h-1v1zm6-1h-1v1h1z"></path></svg></button></div></div><div class="rp-doc-layout__container"><aside class="rp-doc-layout__sidebar rp-scrollbar"><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Getting Started</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/introduction" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Introduction</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/installation" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Installation</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/agent-setup" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">AI Agent Setup</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/quick-start" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Quick Start</span></div><div class="rp-sidebar-item__right"></div></a></div></div><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Using agent-device</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/commands" class="rp-sidebar-item rp-sidebar-item--active rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Commands</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/configuration" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Configuration</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/selectors" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Selectors</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/sessions" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Sessions</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/batching" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Batching</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/snapshots" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Snapshots</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/replay-e2e" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Replay & E2E testing</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/debugging-profiling" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Debugging & Profiling</span></div><div class="rp-sidebar-item__right"></div></a></div></div><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Integrations</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/client-api" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Node.js API</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/ai-sdk" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">AI SDK</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/eve" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Eve</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/remote-proxy" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Remote Proxy</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/device-clouds" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Device Clouds</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/browserstack" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">BrowserStack</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/aws-device-farm" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">AWS Device Farm</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/limrun" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Limrun</span></div><div class="rp-sidebar-item__right"></div></a></div></div><div class="rp-sidebar-item rp-sidebar-group" style="padding-left:12px" data-depth="0"><div class="rp-sidebar-item__left"><span class="rp-doc">Reference</span></div><div class="rp-sidebar-item__right"></div></div><div style="display:grid;grid-template-rows:1fr;transition:grid-template-rows 0.2s ease-out"><div style="overflow:hidden"><a href="/agent-device/docs/security-trust" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Security & Trust</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/known-limitations" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Known Limitations</span></div><div class="rp-sidebar-item__right"></div></a><a href="/agent-device/docs/migrating-gestures" class="rp-sidebar-item rp-sidebar-item--group-item rp-link" style="padding-left:calc(12px * 1 + 12px)" data-depth="1"><div class="rp-sidebar-item__left"><span class="rp-doc">Migrating Gestures</span></div><div class="rp-sidebar-item__right"></div></a></div></div></aside><div class="rp-doc-layout__doc"><main class="rp-doc-layout__doc-container"><div class="rp-doc rspress-doc"><!--$--><h1 class="rp-toc-include" id="commands"><a href="#commands" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Commands<!-- --> </h1><div class="rp-not-doc rp-llms-container"><button class="rp-not-doc rp-llms-button rp-llms-copy-button"><div class="rp-llms-copy-button__icon-wrapper"><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-llms-copy-button__icon-success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-llms-copy-button__icon-copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg></div><span>Copy Markdown</span></button><button class="rp-llms-button rp-llms-view-options__trigger "><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13" viewBox="0 0 12 13" class="rp-llms-view-options__arrow "><path fill="currentColor" d="M6.5 8.5h1v1h-1v1h-1v-1h-1v-1h1v-6h1zm-2 0h-1v-1h1zm4 0h-1v-1h1zm-5-2v1h-1v-1zm6 1h-1v-1h1z"></path></svg></button></div>
|
||
<p>This page summarizes the primary command groups.</p>
|
||
<p>For persistent defaults and project-scoped CLI settings, see <a href="/agent-device/docs/configuration" class="rp-link">Configuration</a>.</p>
|
||
<p>For agent workflow guidance that is matched to the installed CLI, run:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> workflow</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> debugging</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> react-native</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> react-devtools</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> remote</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> macos</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> dogfood</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> help</span><span style="color:var(--shiki-token-string)"> ios-system-ui</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p>Skills are recommended for auto-routing when your agent runtime supports them, but they are not required. The CLI help topics are the version-matched operating contract.</p>
|
||
<p>For MCP-aware clients that support direct tools, run:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> mcp</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p>The MCP server exposes direct structured tools for installed commands. Tools use structured input contracts through <code>AgentDeviceClient</code>; local-only workflows stay CLI-only rather than subprocess fallbacks. It does not expose generic shell execution over MCP. MCP tools can target <code>platform: "web"</code> after <code>agent-device web setup</code>, but setup and doctor stay CLI-only.</p>
|
||
<h2 class="rp-toc-include" id="navigation"><a href="#navigation" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Navigation</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> boot</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> boot</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> boot</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> boot</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --device</span><span style="color:var(--shiki-token-string)"> Pixel_9_Pro_XL</span><span style="color:var(--shiki-token-string)"> --headless</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> shutdown</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> shutdown</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --device</span><span style="color:var(--shiki-token-string)"> Pixel_9_Pro_XL</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-foreground)"> [app</span><span style="color:var(--shiki-token-keyword)">|</span><span style="color:var(--shiki-token-function)">url]</span><span style="color:var(--shiki-foreground)"> [url]</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> frontmost-app</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> desktop</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span><span style="color:var(--shiki-foreground)"> [app]</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> back</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> back</span><span style="color:var(--shiki-token-string)"> --in-app</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> back</span><span style="color:var(--shiki-token-string)"> --system</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> home</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> orientation</span><span style="color:var(--shiki-token-string)"> portrait</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> orientation</span><span style="color:var(--shiki-token-string)"> landscape-left</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> app-switcher</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>boot</code> ensures the selected target is ready without launching an app.</li>
|
||
<li><code>boot</code> requires either an active session or an explicit device selector.</li>
|
||
<li><code>shutdown</code> turns off the selected Apple simulator or Android emulator.</li>
|
||
<li><code>shutdown</code> must not target an active session device; use <code>close --shutdown</code> to end the session and turn it off.</li>
|
||
<li><code>daemon stop --state-dir <path></code> verifies the daemon PID/start-time identity, requests graceful shutdown, and reports whether provider-release state is known. Use <code>daemon stop --clean</code> to also remove retained Apple runner processes and leases owned by that daemon.</li>
|
||
<li><code>device status</code> reads host-local device claims without starting or contacting a daemon. Normal output shows live and attention-needed claims, then summarizes proven-stale records in one line; use <code>device status --stale</code> to inspect the hidden records. Scope either view with <code>--platform</code> plus <code>--udid</code> (Apple) or <code>--serial</code> (Android). A foreign live or uncertain claim blocks <code>open</code>, and a proven-dead owner is replaced only after its session's exact-owner durable resources reconcile successfully.</li>
|
||
<li><code>device release --stale</code> settles a provably dead owner's durable resources through the same exact-owner reconciliation <code>open</code> uses and clears its claim last, all without a daemon. Live, uncertain, PID-reused, and corrupt claims always fail closed and are reported with the reason; a live owner is released by closing its session from its own workspace or with <code>daemon stop --state-dir <owner state dir></code>. One claim condition is settled on the device instead: a device that rebooted after its claim was taken destroyed the app, runner, and accessibility session that claim described, so <code>open</code> reconciles that owner's resources, takes the claim, and reports the release in <code>warnings</code>. <code>device release --stale</code> never probes a device for its boot, so it keeps refusing such a claim.</li>
|
||
<li><code>--platform apple</code> is an alias for the Apple automation backend (<code>ios</code>, <code>tvOS</code>, <code>macOS</code> selection).</li>
|
||
<li>Use <code>--target mobile|tv|desktop</code> with <code>--platform</code> (required) to select phone/tablet vs TV-class vs desktop-class targets.</li>
|
||
<li><code>boot</code> is mainly needed when starting a new session and <code>open</code> fails because no booted simulator/emulator is available.</li>
|
||
<li>Android: <code>boot --platform android --device <avd-name></code> launches that emulator in GUI mode when needed.</li>
|
||
<li>Android: add <code>--headless</code> to launch without opening a GUI window.</li>
|
||
<li>Android: <code>shutdown --platform android --device <avd-name></code> stops a running emulator.</li>
|
||
<li><code>open [app|url] [url]</code> already boots/activates the selected target when needed.</li>
|
||
<li><code>open <app> --timeout <ms></code> is a startup budget for that boot. A never-booted iOS Simulator runs Apple's first-boot migration, which can take several minutes; without the flag the boot wait is capped at 120 seconds. When the budget runs out the command fails with <code>error.details.reason: boot_timeout</code> and the Simulator keeps booting, so a retry finds it further along.</li>
|
||
<li><code>open <url></code> deep links are supported on Android and iOS.</li>
|
||
<li><code>open <app> <url></code> opens a deep link on iOS.</li>
|
||
<li><code>open <app> --launch-console <path></code> captures launch-time stdout/stderr for direct iOS simulator app launches. It is not valid for URL opens or
|
||
non-simulator targets.</li>
|
||
<li><code>open --device-hub</code> uses Xcode Device Hub when surfacing Apple simulators.</li>
|
||
<li><code>open --platform macos --surface app|frontmost-app|desktop|menubar</code> selects the macOS session surface explicitly. <code>app</code> is the default when an app argument is provided.</li>
|
||
<li><code>back</code> now defaults to app-owned back navigation. On Apple targets that means visible in-app back UI only. On Android this currently maps to the same back keyevent because Android routes in-app back through that platform event.</li>
|
||
<li><code>back --in-app</code> is an explicit alias for the default app-owned behavior.</li>
|
||
<li><code>back --system</code> asks for system back input explicitly. On Android this is the normal back keyevent. On iOS and tvOS it uses the platform back gesture or Siri Remote menu action. On macOS, where there is no generic system back input, <code>back --system</code> reports unavailable instead of falling back to app-owned navigation.</li>
|
||
<li><code>orientation <orientation></code> forces a mobile device into <code>portrait</code>, <code>portrait-upside-down</code>, <code>landscape-left</code>, or <code>landscape-right</code>.</li>
|
||
<li><code>orientation</code> is supported on iOS and Android mobile targets. macOS and tvOS do not expose it.</li>
|
||
<li>On iOS devices, <code>http(s)://</code> URLs open in Safari when no app is active. Custom scheme URLs require an active app in the session.</li>
|
||
<li>Commands that need one concrete device refuse to guess: if no <code>--device</code>/<code>--udid</code>/<code>--serial</code> is given and several candidates are equally preferred (for example two booted emulators), the command fails with <code>AMBIGUOUS_MATCH</code> and lists them, rather than picking one and returning a successful answer about a device you did not select. Preferences still apply first — virtual over physical, booted over offline — so one booted emulator beside offline ones resolves normally, as does any command running inside an existing session. <code>devices</code> lists everything as before.</li>
|
||
<li>Commands that omit <code>--session</code> use an implicit <code>default</code> session scoped to the caller's current git worktree or working directory. This keeps independent local agents from accidentally attaching to each other's default session.</li>
|
||
<li><code>--session <name></code> or <code>AGENT_DEVICE_SESSION</code> opt into an explicitly named session when a script intentionally wants to share or reuse that session name.</li>
|
||
<li>A configured <code>AGENT_DEVICE_SESSION</code> implies bound-session lock mode by default. The CLI forwards that policy to the daemon, which enforces the same conflict handling for CLI, typed client, and direct RPC requests.</li>
|
||
<li><code>--session-lock reject|strip</code> and <code>AGENT_DEVICE_SESSION_LOCK=reject|strip</code> remain available for explicit named-session automation. <code>strip</code> resolves conflicts by dropping platform and scope selectors (<code>--platform</code>, <code>--target</code>, <code>--ios-simulator-device-set</code>, <code>--android-device-allowlist</code>) only. A selector that names a <em>different device</em> than the lock — <code>--udid</code>, <code>--serial</code>, <code>--device</code> — is never dropped: the request fails with <code>INVALID_ARGS</code> naming both the requested and the bound device, because continuing would run the command against a device the caller did not select. Recover by closing the bound session if the requested device is the one you want, or by removing the selector if the bound device is.</li>
|
||
<li>Direct RPC callers can pass <code>meta.lockPolicy</code> and optional <code>meta.lockPlatform</code> on <code>agent_device.command</code> requests for the same daemon-enforced behavior.</li>
|
||
<li>In <code>batch</code>, steps that omit <code>platform</code> still inherit the parent batch <code>--platform</code>; lock-mode defaults do not override that parent setting.</li>
|
||
<li>Tenant-scoped daemon runs can pass <code>--tenant</code>, <code>--session-isolation tenant</code>, <code>--run-id</code>, and <code>--lease-id</code> to enforce lease admission.</li>
|
||
<li>Remote daemon clients can pass <code>--daemon-base-url http(s)://host:port[/base-path]</code> to skip local daemon discovery/startup and call a remote HTTP daemon directly.</li>
|
||
<li>Use <code>--daemon-auth-token <token></code> (or <code>AGENT_DEVICE_DAEMON_AUTH_TOKEN</code>) for explicit service/API-token automation against non-loopback remote daemon URLs; the client sends it in both the JSON-RPC request token and HTTP auth headers.</li>
|
||
<li>Use <a href="/agent-device/docs/remote-proxy" class="rp-link">Remote Proxy</a> when you need to run <code>agent-device proxy</code> on a Mac with simulator/device access and drive it from another machine through cloudflared, ngrok, or another HTTP tunnel.</li>
|
||
<li>Use <a href="/agent-device/docs/browserstack" class="rp-link">BrowserStack</a> or <a href="/agent-device/docs/aws-device-farm" class="rp-link">AWS Device Farm</a> when a CI agent needs a hosted device session without interactive login.</li>
|
||
<li>For human cloud access, <code>connect</code> can discover a cloud connection profile, while <code>connect --remote-config ...</code> uses a local profile. Both refresh a stored CLI session into a short-lived <code>adc_agent_...</code> token when needed. If no CLI session exists, interactive shells start login automatically; CI and non-interactive shells fail with API-token setup instructions. Use <code>--no-login</code> to disable implicit login. <code>AGENT_DEVICE_CLOUD_BASE_URL</code> is the bridge/control-plane API origin; its <code>/api-keys</code> route may redirect to the dashboard for token creation.</li>
|
||
<li>For remote <code>connect</code> and <code>connect --remote-config</code> flows, see <a href="#remote-metro-workflow" class="rp-link">Remote Metro workflow</a>.</li>
|
||
<li>Android React Native relaunch flows require an installed package name for <code>open --relaunch</code>; install/reinstall the APK first, then relaunch by package. <code>open <apk|aab> --relaunch</code> is rejected because runtime hints are written through the installed app sandbox.</li>
|
||
<li>For Metro-backed React Native JS changes, use <code>metro reload</code> before <code>open <app> --relaunch</code>; it mirrors pressing <code>r</code> in the Metro terminal and keeps the native process alive.</li>
|
||
<li>Remote daemon screenshots and recordings are downloaded back to the caller path, so <code>screenshot page.png</code> and <code>record start session.mp4</code> remain usable when the daemon runs on another host.</li>
|
||
</ul>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string-expression)"> "https://example.com"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-comment)"> # open link in web browser</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> MyApp</span><span style="color:var(--shiki-token-string-expression)"> "myapp://screen/to"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-comment)"> # open deep link to MyApp</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> back</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-comment)"> # tap visible app back UI only</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> back</span><span style="color:var(--shiki-token-string)"> --system</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-comment)"> # use edge-swipe or remote back action</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> reinstall</span><span style="color:var(--shiki-token-string)"> MyApp</span><span style="color:var(--shiki-token-string)"> /path/to/app-debug.apk</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --serial</span><span style="color:var(--shiki-token-string)"> emulator-5554</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> com.example.myapp</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --serial</span><span style="color:var(--shiki-token-string)"> emulator-5554</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> my-session</span><span style="color:var(--shiki-token-string)"> --relaunch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> metro</span><span style="color:var(--shiki-token-string)"> reload</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<h2 class="rp-toc-include" id="human-takeover"><a href="#human-takeover" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Human Takeover</h2>
|
||
<p>Use <code>takeover</code> with an active remote connection when a person needs to interact with its leased
|
||
device without racing the agent:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> takeover</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> remote-session</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> takeover</span><span style="color:var(--shiki-token-string)"> status</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> remote-session</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> takeover</span><span style="color:var(--shiki-token-string)"> release</span><span style="color:var(--shiki-token-keyword)"> <</span><span style="color:var(--shiki-token-string)">hold-i</span><span style="color:var(--shiki-foreground)">d</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> remote-session</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p>The command uses the device from the admitted remote lease, installs a short-lived hold, keeps it
|
||
alive in the foreground, and releases it on Ctrl+C. Activation waits for admitted mutations to finish
|
||
before reporting active. While held, state-changing commands fail with
|
||
<code>DEVICE_IN_USE</code> and <code>details.reason: "human_control_active"</code>, explaining that agent interactions are
|
||
temporarily disabled. Snapshots, screenshots, selector reads, logs, and other read-only diagnostics
|
||
remain available. The hold also
|
||
protects an existing remote device lease from inactivity expiry so the human does not accidentally
|
||
hand the simulator to a different agent.</p>
|
||
<p>A foreground hold expires automatically if its process disappears. Releasing or expiring the final
|
||
hold refreshes the existing lease's inactivity window. Tenant commands can modify only holds owned
|
||
by their admitted lease, not provider-host administrative holds.</p>
|
||
<p>Holds do not survive daemon restart; reconnect and re-establish them before continuing human
|
||
interaction. Local takeover without a device-scoped remote lease is not supported in this version.
|
||
See <a href="/agent-device/docs/remote-proxy#human-takeover" class="rp-link">remote takeover and host administration</a> for the VM-side API.</p>
|
||
<h2 class="rp-toc-include" id="web-automation"><a href="#web-automation" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Web Automation</h2>
|
||
<p>Minimal <code>--platform web</code> support reuses <a href="https://github.com/vercel-labs/agent-browser" target="_blank" rel="noopener noreferrer" class="rp-link">agent-browser</a>. <code>agent-device</code> owns command/session/replay integration, refs/selectors, and artifact routing; <code>agent-browser</code> owns browser launch, page control, screenshots, and browser-specific mechanics.</p>
|
||
<p>Use <code>--platform web</code> when a browser step belongs inside an <code>agent-device</code> session, replay, batch, MCP, or typed-client flow. Use <code>agent-browser</code> directly for standalone web automation.</p>
|
||
<p>Set up and verify the managed web backend before relying on web sessions:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> web</span><span style="color:var(--shiki-token-string)"> setup</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> web</span><span style="color:var(--shiki-token-string)"> doctor</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string-expression)"> "https://example.com"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> get</span><span style="color:var(--shiki-token-string)"> text</span><span style="color:var(--shiki-token-string)"> @e2</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> visible</span><span style="color:var(--shiki-token-string-expression)"> 'label="Welcome"'</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> find</span><span style="color:var(--shiki-token-string)"> text</span><span style="color:var(--shiki-token-string-expression)"> "Welcome"</span><span style="color:var(--shiki-token-string)"> exists</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> click</span><span style="color:var(--shiki-token-string)"> @e12</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> hover</span><span style="color:var(--shiki-token-string)"> @e14</span><span style="color:var(--shiki-token-string)"> --settle</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> fill</span><span style="color:var(--shiki-token-string)"> @e13</span><span style="color:var(--shiki-token-string-expression)"> "test@example.com"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string)"> text</span><span style="color:var(--shiki-token-string-expression)"> "Welcome"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> network</span><span style="color:var(--shiki-token-string)"> dump</span><span style="color:var(--shiki-token-constant)"> 25</span><span style="color:var(--shiki-token-string)"> --include</span><span style="color:var(--shiki-token-string)"> headers</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> audio</span><span style="color:var(--shiki-token-string)"> probe</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-constant)"> 10</span><span style="color:var(--shiki-token-constant)"> 1000</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> audio</span><span style="color:var(--shiki-token-string)"> probe</span><span style="color:var(--shiki-token-string)"> status</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> audio</span><span style="color:var(--shiki-token-string)"> probe</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> ./artifacts/web-home.png</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> ./artifacts/web-full.png</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span><span style="color:var(--shiki-token-string)"> --fullscreen</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> viewport</span><span style="color:var(--shiki-token-constant)"> 1280</span><span style="color:var(--shiki-token-constant)"> 900</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>Web automation uses a managed, pinned <code>agent-browser</code> backend as an implementation detail.</li>
|
||
<li>Run <code>web setup</code> before first use and in CI bootstrap steps. Normal <code>--platform web</code> commands do not install the backend implicitly.</li>
|
||
<li>Runtime web commands resolve the backend only from the managed install in the effective agent-device state dir.</li>
|
||
<li><code>web setup</code> is idempotent and reuses the pinned backend when it is already installed.</li>
|
||
<li><code>web doctor</code> verifies the managed backend after setup.</li>
|
||
<li>The managed install respects <code>--state-dir</code> and <code>AGENT_DEVICE_STATE_DIR</code>.</li>
|
||
<li>Web automation requires Node 24+.</li>
|
||
<li>Supported through <code>agent-device</code>: URL open, snapshot refs, <code>get text/attrs</code>, <code>is visible/hidden/exists/absent/focused/text</code>, <code>find text/selector</code>, click/press, hover, fill/type, wait, <code>network dump</code>, <code>audio probe</code>, screenshot, close, and replay scripts composed from those commands.</li>
|
||
<li><code>hover <@ref|selector|x y></code> moves the pointer without pressing so hover-gated UI (row toolbars, menus) appears. Add <code>--settle</code> to read what it revealed instead of taking another snapshot. <code>hover @ref</code> hovers the browser's own element handle; like <code>click @ref --settle</code>, the <code>--settle</code> diff needs a selector or coordinate target on web because web refs carry no geometry.</li>
|
||
<li><code>audio probe start [durationSeconds] [bucketMs]</code> samples HTML media elements into compact RMS/peak dBFS buckets while the page keeps running. The first timing positional is seconds; the second is milliseconds.</li>
|
||
<li>URL-backed web media may be routed through the probe <code>AudioContext</code> while observed. Use <code>audio probe status</code> to poll partial buckets and <code>audio probe stop</code> to end the probe early.</li>
|
||
<li>Out of scope for <code>agent-device</code> web support: tab/window/devtools control, network routing/interception/HAR, cookies/storage, downloads/uploads, arbitrary page scripting, multi-page orchestration, and raw browser diagnostics. Use <code>agent-browser</code> directly for those browser-specific workflows.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="device-isolation-scopes"><a href="#device-isolation-scopes" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Device isolation scopes</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --ios-simulator-device-set</span><span style="color:var(--shiki-token-string)"> /tmp/tenant-a/simulators</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --android-device-allowlist</span><span style="color:var(--shiki-token-string)"> emulator-5554,device-1234</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>--ios-simulator-device-set <path></code> constrains simulator discovery and simulator command execution via <code>xcrun simctl --set <path> ...</code>.</li>
|
||
<li><code>--android-device-allowlist <serials></code> constrains Android discovery/selection to comma or space separated serials.</li>
|
||
<li>Scope is applied before selectors (<code>--device</code>, <code>--udid</code>, <code>--serial</code>), so out-of-scope selectors fail with <code>DEVICE_NOT_FOUND</code>.</li>
|
||
<li>With iOS simulator-set scope enabled, iOS physical devices are not enumerated.</li>
|
||
<li>Device scoping can also be configured with <code>iosSimulatorDeviceSet</code> and <code>androidDeviceAllowlist</code> config keys. Android allowlists can use <code>AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST</code>.</li>
|
||
<li>CLI scope flags override environment values unless bound-session lock mode is active with <code>strip</code>, in which case conflicting per-call selectors are ignored.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="device-discovery"><a href="#device-discovery" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Device discovery</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> harmonyos</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> vega</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --ios-simulator-device-set</span><span style="color:var(--shiki-token-string)"> /tmp/tenant-a/simulators</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --android-device-allowlist</span><span style="color:var(--shiki-token-string)"> emulator-5554,device-1234</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> capabilities</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> capabilities</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> checkout</span><span style="color:var(--shiki-token-string)"> --json</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>devices</code> lists available targets after applying any platform selector or isolation scope flags.</li>
|
||
<li>Use <code>--platform</code> to narrow discovery to Apple-family (<code>ios</code>, <code>tvOS</code>, <code>macOS</code>), Android, HarmonyOS, or Vega OS targets.</li>
|
||
<li>Use <code>--ios-simulator-device-set</code> and <code>--android-device-allowlist</code> when you need tenant- or lab-scoped discovery.</li>
|
||
<li><code>capabilities</code> reports the command names supported by the selected session device or an explicit <code>--platform</code>/<code>--device</code>/<code>--udid</code>/<code>--serial</code> target.</li>
|
||
<li>In JSON output, <code>capabilities</code> returns <code>{ device, availableCommands }</code>. Use <code>availableCommands</code> for dynamic integrations instead of maintaining a separate platform support table.</li>
|
||
</ul>
|
||
<h3 class="rp-toc-include" id="harmonyos-command-boundary"><a href="#harmonyos-command-boundary" class="rp-header-anchor rp-link" aria-hidden="true">#</a>HarmonyOS command boundary</h3>
|
||
<p>HarmonyOS support uses HDC and ArkUI <code>uitest</code>. On current API 24 devices it supports lifecycle and HAP deployment, ArkUI snapshot/screenshot and selector reads, one-pointer touch and text actions, keyboard <code>enter</code>/<code>dismiss</code>, app logs, foreground app state, process RSS samples, and <code>settings clear-app-state</code>. Run <code>agent-device capabilities --platform harmonyos</code> for the authoritative command list for a selected device.</p>
|
||
<ul>
|
||
<li><code>gesture pan|fling|swipe</code> and <code>swipe</code> use HDC's single-pointer input primitives. Multi-touch gestures and target-authored <code>gesture drag</code> return <code>UNSUPPORTED_OPERATION</code> rather than approximating the interaction.</li>
|
||
<li>Physical HarmonyOS devices support whole-screen recording through <code>record start <path> --scope device</code> or <code>--scope system</code>. This uses the device ScreenRecorder service, not HDC <code>screenrecord</code>; emulator recording is explicitly rejected. HarmonyOS recording does not support <code>--fps</code>, <code>--quality</code>, or <code>--hide-touches</code>.</li>
|
||
<li>Orientation control, clipboard, alert automation, network/audio capture, push and app-event delivery, React Native helpers, and trace capture are not advertised for HarmonyOS. The public API 24 HDC surface has no usable <code>pasteboard</code>, notification, or <code>aa send</code> command on the supported emulator and physical device.</li>
|
||
<li><code>settings</code> intentionally supports only <code>clear-app-state</code>; other system settings are not changed through undocumented parameter writes. <code>perf memory sample</code> provides process RSS; frame health and memory-snapshot artifacts remain unavailable.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="diagnostics"><a href="#diagnostics" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Diagnostics</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> doctor</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> doctor</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> doctor</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --app</span><span style="color:var(--shiki-token-string)"> com.example.myapp</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> doctor</span><span style="color:var(--shiki-token-string)"> --remote</span><span style="color:var(--shiki-token-string)"> --json</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>doctor</code> diagnoses device, app, Metro, and React Native setup/readiness issues for the selected target.</li>
|
||
<li>Use <code>--platform ios|android|vega|macos|linux|web|apple</code> to scope the checks to one backend; without it, <code>doctor</code> reports across the discoverable targets.</li>
|
||
<li><code>--app <id-or-name></code> focuses app-specific checks (install state, Metro/React Native wiring) on a single bundle id or app name.</li>
|
||
<li><code>--remote</code> runs the environment-only checks that do not require a booted device, which is what CI bootstrap and the packaged-CLI smoke use.</li>
|
||
<li><code>doctor</code> is read-only: it never boots, installs, or mutates the session device.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="prepare-apple-runner"><a href="#prepare-apple-runner" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Prepare Apple runner</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> prepare</span><span style="color:var(--shiki-token-string)"> ios-runner</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --timeout</span><span style="color:var(--shiki-token-constant)"> 240000</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>prepare ios-runner</code> is intended for Apple-platform CI setup before <code>snapshot</code>, <code>replay</code>, or <code>test</code>.</li>
|
||
<li>Run it after the simulator/device is booted and the app is installed, but before the first snapshot, replay, or test command.</li>
|
||
<li><code>--timeout <ms></code> is one budget shared by the Simulator boot (when the target is not booted yet) and the runner preparation; a never-booted Simulator's first-boot migration is bounded by it, not by the 120-second default boot wait.</li>
|
||
<li>It builds or reuses the local XCTest runner, starts a runner session, and verifies that the runner can answer a lightweight health command.</li>
|
||
<li>In JSON output, top-level <code>buildMs</code>, <code>connectMs</code>, and <code>healthCheckMs</code> are diagnostic fields and may overlap; use <code>timing.additiveParts</code> for additive wall-clock phase totals. <code>connectMs</code> contains <code>buildMs</code> when a runner artifact is built or rebuilt.</li>
|
||
<li>If health checking exposes a bad restored runner artifact, Agent Device marks that artifact bad and rebuilds once.</li>
|
||
<li>If a fresh runner launch gets stuck before accepting connections, Agent Device invalidates that runner session and launches it once more without forcing a rebuild.</li>
|
||
<li>CI may cache <code>~/.agent-device/apple-runner/derived</code> when the cache key includes the exact Agent Device package contents and selected Xcode version.</li>
|
||
<li>Avoid broad <code>restore-keys</code> fallbacks for runner caches. Reusing runner artifacts across Agent Device or Xcode versions can restore stale <code>.xctestrun</code> products; <code>prepare ios-runner</code> already handles bad exact-cache artifacts and one retryable non-connecting runner launch.</li>
|
||
<li>Runner build/start output is written to the session's <code>runner.log</code>. The top-level <code>daemon.log</code> is reserved for daemon lifecycle/startup issues.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="tv-targets"><a href="#tv-targets" class="rp-header-anchor rp-link" aria-hidden="true">#</a>TV targets</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> YouTube</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> apps</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> tv-remote</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-string)"> down</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> tv-remote</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-string)"> select</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> tv-remote</span><span style="color:var(--shiki-token-string)"> longpress</span><span style="color:var(--shiki-token-string)"> select</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> tv-remote</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-string)"> select</span><span style="color:var(--shiki-token-string)"> --duration-ms</span><span style="color:var(--shiki-token-constant)"> 900</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> tv-focus.png</span><span style="color:var(--shiki-token-string)"> --overlay-refs</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> Settings</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> apple-tv.png</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">vega</span><span style="color:var(--shiki-token-string)"> virtual-device</span><span style="color:var(--shiki-token-string)"> start</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> vega</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> com.example.app.main</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> vega</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> vega-tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> tv-remote</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-string)"> down</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> vega</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> vega-tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> tv-remote</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-string)"> select</span><span style="color:var(--shiki-token-string)"> --duration-ms</span><span style="color:var(--shiki-token-constant)"> 900</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> vega</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> tv</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> vega-tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span><span style="color:var(--shiki-token-string)"> com.example.app.main</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> vega-tv</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">vega</span><span style="color:var(--shiki-token-string)"> virtual-device</span><span style="color:var(--shiki-token-string)"> stop</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>AndroidTV app launch and app listing resolve TV launchable activities via <code>LEANBACK_LAUNCHER</code>.</li>
|
||
<li>TV target selection supports Apple TV and Android TV simulators/emulators and connected devices. Initial Vega OS support is limited to the Vega Virtual Device.</li>
|
||
<li>TV targets are focus-first. Use <code>tv-remote</code> to move D-pad/remote focus before selecting a control; avoid raw <code>adb shell input keyevent</code> in command plans.</li>
|
||
<li>On Android TV, <code>tv-remote</code> maps to ADB keyevents. <code>tv-remote longpress <button></code> is CLI sugar for a 500ms hold; <code>--duration-ms</code> overrides the preset and uses Android's longpress keyevent form for any positive duration because the platform command does not expose exact hold timing.</li>
|
||
<li>tvOS supports the same runner-driven interaction/snapshot flow as iOS (<code>snapshot</code>, <code>wait</code>, <code>press</code>, <code>fill</code>, <code>get</code>, <code>scroll</code>, <code>back</code>, <code>home</code>, <code>app-switcher</code>, <code>record</code>, and related selector flows).</li>
|
||
<li>On tvOS, <code>tv-remote</code>, runner <code>back</code>/<code>home</code>/<code>app-switcher</code> map to Siri Remote actions (<code>back</code> is Menu, <code>home</code> is Home, app switcher is double-home). <code>--duration-ms</code> is an exact remote-button hold duration.</li>
|
||
<li>Vega OS discovery and remote input use the SDK-matched Vega CLI and VDA. Initial support is VVD-only; use <code>--platform vega --target tv</code>, and use Vega component IDs such as <code>com.example.app.main</code>.</li>
|
||
<li>Use <code>--serial VirtualDevice</code> for explicit VVD selection.</li>
|
||
<li>The Vega VVD supports app open/close, <code>back</code>, <code>home</code>, and all shared <code>tv-remote</code> buttons. Exact holds are sent through <code>inputd-cli</code>.</li>
|
||
<li>Physical Fire TV, app inventory, snapshot, screenshot, selector, install, touch/text/gesture, logs, and performance backends are not part of the initial support and report unsupported.</li>
|
||
<li>On Android TV and tvOS, use <code>screenshot --overlay-refs</code> when visual focus evidence is useful or when focus metadata is unavailable/transient. On Vega OS, use the VVD display as visual truth.</li>
|
||
<li>tvOS follows iOS simulator-only command semantics for helpers like <code>gesture pinch</code>, <code>settings</code>, and <code>push</code>.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="desktop-targets"><a href="#desktop-targets" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Desktop targets</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> devices</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> TextEdit</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> desktop</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> apple</span><span style="color:var(--shiki-token-string)"> --target</span><span style="color:var(--shiki-token-string)"> desktop</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>--platform macos</code> selects the host Mac as a <code>desktop</code> target.</li>
|
||
<li><code>--platform apple --target desktop</code> selects the same macOS backend through the Apple-family alias.</li>
|
||
<li>Use <code>app</code> sessions for normal app control: <code>open</code>, <code>snapshot</code>, <code>click</code>, <code>fill</code>, <code>press</code>, <code>scroll</code>, <code>back</code>, <code>screenshot</code>, <code>record</code>.</li>
|
||
<li>Use <code>frontmost-app</code>, <code>desktop</code>, and <code>menubar</code> when you need to inspect desktop-global UI before choosing one app.</li>
|
||
<li><code>open --platform macos --surface frontmost-app</code> inspects the currently focused app without naming it first.</li>
|
||
<li><code>open --platform macos --surface desktop</code> inspects visible windows across the desktop.</li>
|
||
<li><code>open --platform macos --surface menubar</code> inspects the active app menu bar and system menu extras.</li>
|
||
<li><code>open <app> --platform macos --surface menubar</code> targets one menu bar app's extras bar, which is useful for status-item apps.</li>
|
||
<li>Status-item apps often expose little or no useful UI through the default macOS <code>app</code> surface. Prefer <code>--surface menubar</code> for discovery when the app lives in the top menu bar.</li>
|
||
<li>Use <code>frontmost-app</code>, <code>desktop</code>, and <code>menubar</code> mainly for <code>snapshot</code>, <code>get</code>, <code>is</code>, and <code>wait</code>.</li>
|
||
<li>If you inspect with <code>desktop</code> or <code>menubar</code> and then need to click or fill inside one app, open that app in a normal <code>app</code> session.</li>
|
||
<li>macOS also supports <code>clipboard read|write</code>, <code>trigger-app-event</code>, <code>logs</code>, <code>network dump</code>, <code>audio probe</code>, <code>alert</code>, <code>settings appearance</code>, and <code>settings permission <grant|reset> <accessibility|screen-recording|input-monitoring></code>.</li>
|
||
<li><code>audio probe start 10 1000 --platform macos</code> samples host system audio through ScreenCaptureKit. The same host-system audio backend is used for iOS simulators and Android emulators on macOS hosts; grant Screen Recording permission before relying on it in a run.</li>
|
||
<li>In macOS app sessions, <code>screenshot</code> captures the target app window bounds rather than the full desktop.</li>
|
||
<li>Prefer selector or <code>@ref</code>-driven interactions on macOS. Window position can shift between runs, so raw x/y point commands are less stable than snapshot-derived targets.</li>
|
||
<li>Use <code>click --button secondary</code> for context menus on macOS, then run <code>snapshot -i</code> again.</li>
|
||
<li>Mobile-only helpers remain unsupported on macOS: <code>boot</code>, <code>shutdown</code>, <code>home</code>, <code>orientation</code>, <code>app-switcher</code>, <code>install</code>, <code>reinstall</code>, <code>install-from-source</code>, and <code>push</code>.</li>
|
||
</ul>
|
||
<p>Recommended loops:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-comment)"># One app, full interaction</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> TextEdit</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> fill</span><span style="color:var(--shiki-token-string)"> @e3</span><span style="color:var(--shiki-token-string-expression)"> "hello"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> textedit.png</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-comment)"># Desktop-global inspection first</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> desktop</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> visible</span><span style="color:var(--shiki-token-string-expression)"> 'role="window" label="Notes"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> desktop.png</span><span style="color:var(--shiki-token-string)"> --fullscreen</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-comment)"># Menubar / menu-extra inspection</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> menubar</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string-expression)"> 'label~="Wi-Fi|Control Center|Battery"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-comment)"># Targeted menu bar app inspection</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> MenuBarApp</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> menubar</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<h2 class="rp-toc-include" id="snapshot-and-inspect"><a href="#snapshot-and-inspect" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Snapshot and inspect</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-foreground)"> [--diff] [-i] [--depth, </span><span style="color:var(--shiki-token-keyword)">-d</span><span style="color:var(--shiki-token-keyword)"> <</span><span style="color:var(--shiki-foreground)">depth</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-foreground)">] [--scope, </span><span style="color:var(--shiki-token-keyword)">-s</span><span style="color:var(--shiki-token-keyword)"> <</span><span style="color:var(--shiki-foreground)">scope</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-foreground)">] [--raw] [--actions] [--force-full] [--timeout </span><span style="color:var(--shiki-token-keyword)"><</span><span style="color:var(--shiki-foreground)">ms</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-foreground)">]</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> diff</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-foreground)"> [-i] [-d </span><span style="color:var(--shiki-token-keyword)"><</span><span style="color:var(--shiki-foreground)">depth</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-foreground)">] [-s </span><span style="color:var(--shiki-token-keyword)"><</span><span style="color:var(--shiki-foreground)">scope</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-foreground)">] [--raw]</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> get</span><span style="color:var(--shiki-token-string)"> text</span><span style="color:var(--shiki-token-string)"> @e1</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> get</span><span style="color:var(--shiki-token-string)"> attrs</span><span style="color:var(--shiki-token-string)"> @e1</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>iOS snapshots use XCTest on simulators and physical devices. iOS <code>--raw</code> is the acquired tree on
|
||
whichever backend serves the capture: it keeps offscreen nodes, decorations, and structural
|
||
wrappers the default and <code>-i</code> views fold away, so a recovered raw capture shows the same hierarchy
|
||
a healthy one does. <code>--depth</code> still applies to raw (it counts traversal depth there), while <code>-i</code>
|
||
narrows the default projection only — <code>--raw -i</code> returns the acquired tree.</li>
|
||
<li>Android snapshots require the bundled Android snapshot helper. The first snapshot verifies and
|
||
installs the helper APK if it is missing or outdated. Local ADB-backed sessions keep the helper
|
||
process warm over an <code>adb forward</code> socket and report <code>androidSnapshot.helperTransport</code> as
|
||
<code>persistent-session</code>; if that transport is unavailable, capture retries through one-shot
|
||
instrumentation in the same helper. Set <code>AGENT_DEVICE_ANDROID_SNAPSHOT_HELPER_SESSION=0</code> to
|
||
disable the persistent fast path. Missing or failed helper artifacts are reported directly; a
|
||
source checkout must run <code>pnpm build:android</code> before Android verification. The helper serializes
|
||
Android interactive window roots when available, so keyboard and system-overlay nodes can appear
|
||
alongside the app root; <code>androidSnapshot.captureMode</code> and <code>androidSnapshot.windowCount</code> describe
|
||
the capture. Default and <code>-i</code> snapshots keep same-window covered surfaces visible for diagnosis
|
||
and mark exactly ordered covered controls <code>interactionBlocked: "covered"</code>, so selectors cannot
|
||
act on stale React Native screens. API 23 cannot report sibling <code>drawing-order</code>, so this scan fails
|
||
conservative and <code>androidSnapshot.occlusionScanUnavailable: true</code> discloses the difference.
|
||
Android <code>--raw</code> is the acquired tree: it also keeps nodes Android marks invisible and stale
|
||
application windows. The helper does not report <code>checked</code>/<code>checkable</code> state, and it caps
|
||
captures at 5000 nodes before any <code>--scope</code> applies (<code>truncated: true</code>).</li>
|
||
<li><code>truncated: true</code> means the backend cut the capture at one of its limits — the Android helper
|
||
and the iOS Simulator AX bridge at 5000 nodes, the XCTest runner and the web provider at their
|
||
own bounds. Every backend walks the tree in document order, so what falls off is what comes
|
||
last: footers, tab bars, items after a long list, even when on screen. The snapshot carries a
|
||
warning that says so; navigate or scroll so fewer elements render and re-run, and use
|
||
<code>screenshot</code> as visual truth for the rest.</li>
|
||
<li><code>--scope <text|@ref></code> returns the subtree of the first node in document order whose label, value,
|
||
or identifier contains the scope text (case-insensitive) and whose subtree still has content in
|
||
the requested projection, re-rooted at depth 0; no match returns an empty snapshot rather than the
|
||
full tree. Under <code>-i</code> that means scoping to a layout container returns the actionable elements
|
||
inside it, even when the container itself is filtered out. <code>--depth</code> then counts from the scope
|
||
root. <code>@ref</code> scopes by that element's label from the last snapshot. Android resolves scope inside
|
||
its TypeScript presentation; iOS keeps acquisition broad and resolves scope once inside the
|
||
runner's Swift presentation. The daemon does not reapply scope after either platform returns.</li>
|
||
<li><code>--actions</code> names the custom accessibility affordances an element merged away (iOS
|
||
<code>UIAccessibilityCustomAction</code>, React Native <code>accessibilityActions</code>), so a card whose reply/options
|
||
controls are not separate elements still lists them. It is iOS-simulator-only and exists for
|
||
planning, not invocation: there is no API to trigger a named action, so reach the affordance
|
||
through the element's detail screen, the same control exposed as a labeled element elsewhere, or
|
||
coordinates from its rect. It is mutually exclusive with <code>--raw</code>, which takes a capture path that
|
||
cannot carry custom actions: the pair is rejected as <code>INVALID_ARGS</code> before any device work. See
|
||
<a href="/agent-device/docs/snapshots" class="rp-link">Snapshots</a> for the full constraints.</li>
|
||
<li><code>diff snapshot</code> compares the current snapshot with the previous session baseline and then updates baseline.</li>
|
||
<li><code>snapshot --diff</code> is an alias for <code>diff snapshot</code>.</li>
|
||
<li>Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions. It may collapse helper/accessibility noise; use <code>--raw</code> or <code>--json</code> when you need the full provider tree.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="wait-and-alerts"><a href="#wait-and-alerts" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Wait and alerts</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-constant)"> 1500</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string)"> text</span><span style="color:var(--shiki-token-string-expression)"> "Welcome back"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string)"> @e12</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string-expression)"> 'role="button" label="Continue"'</span><span style="color:var(--shiki-token-constant)"> 5000</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string)"> absent</span><span style="color:var(--shiki-token-string-expression)"> 'label="Loading..."'</span><span style="color:var(--shiki-token-constant)"> 5000</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> alert</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> alert</span><span style="color:var(--shiki-token-string)"> get</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> alert</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-constant)"> 3000</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> alert</span><span style="color:var(--shiki-token-string)"> accept</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> alert</span><span style="color:var(--shiki-token-string)"> dismiss</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>wait</code> accepts a millisecond duration, <code>text <value></code>, a snapshot ref (<code>@eN</code>), a selector, or strict <code>absent <selector></code>.</li>
|
||
<li><code>wait <selector> [timeoutMs]</code> polls until the selector resolves or the timeout expires. Selector waits use snapshot capture, including steps inside <code>replay</code>, so they share the capture backend and recovery used by <code>is</code>.</li>
|
||
<li><code>wait absent <selector> [timeoutMs]</code> polls until a complete, readable capture has zero matches. It is strict absence, not a visibility check: hidden or off-screen matches still keep the wait pending.</li>
|
||
<li>Strict absence rejects <code>--scope</code> and <code>--depth</code>. Sparse, truncated, incomplete, and Android unreadable-content captures do not count as readable captures and cannot satisfy the wait; they are ridden out until the deadline, and a run with no valid capture preserves its typed unreadable diagnostic.</li>
|
||
<li><code>wait @ref [timeoutMs]</code> requires an existing session snapshot from a prior <code>snapshot</code> command.</li>
|
||
<li><code>wait @ref</code> resolves the ref to its label/text from that stored snapshot, then polls for that text; it does not track the original node identity.</li>
|
||
<li>Because <code>wait @ref</code> is text-based after resolution, duplicate labels can match a different element than the original ref target.</li>
|
||
<li><code>wait</code> shares the selector/snapshot resolution flow used by <code>click</code>, <code>fill</code>, <code>get</code>, and <code>is</code>.</li>
|
||
<li>Wait failures carry a structured <code>error.details.reason</code> in <code>--json</code> output: <code>wait_target_absent</code> proves a positive wait never found a match; <code>wait_target_present</code> means strict <code>wait absent</code> reached its deadline with valid captures that still contained matches; <code>predicate_failed</code> means strict <code>wait absent</code> could not prove absence because no valid capture arrived, with the final observation/diagnostic preserved; <code>wait_capture_stalled</code> means no readable capture arrived and is retriable; <code>wait_deadline_exceeded</code> means a later capture consumed the remaining budget after an earlier readable capture; <code>wait_landmark_identity_mismatch</code> is a replay destination-guard refusal; and <code>wait_stable_timeout</code> means the UI did not settle. Use <code>readableCaptures</code>, <code>waitedMs</code>, <code>matches</code>, and <code>firstMatch</code> instead of parsing error text. <code>firstMatch</code> carries identity/text evidence only; absence failures do not claim visibility or rect evidence.</li>
|
||
<li>Polling wait timeouts (<code>wait <selector></code>, <code>wait text</code>, <code>wait @ref</code>, and <code>wait absent</code> once a readable capture has been seen) also carry <code>captures</code> (every poll attempted), <code>readableCaptures</code>, and <code>polls</code>, one entry per poll with <code>startedMs</code> on the wait's own clock, <code>durationMs</code>, and <code>outcome</code> (<code>readable</code>, <code>unreadable</code>, <code>retriable</code> for a poll the producer refused with a failure it marked retriable, <code>deadline</code>, or <code>runner-restart</code>), so a timeout says where its budget went; long waits keep the first five and last twenty-five polls. A replayed selector wait refused for a recorded landmark mismatch (<code>wait_landmark_identity_mismatch</code>) carries the same poll evidence next to its mismatch details. A wait that never saw a readable capture reports the cause its polls hit instead of a generic timeout: a content verdict is preserved as its producer wrote it, while a refusal the producer marked retriable keeps its code, message and retry details <strong>and</strong> carries the poll evidence above, so an exhausted budget stays distinguishable from a single immediate refusal. <code>wait --stable</code> timeouts and a never-readable strict absence keep their own diagnostics. <code>logPath</code> links the full request log.</li>
|
||
<li><code>alert</code> inspects or handles system alerts on iOS simulator, macOS desktop, and Android native/runtime permission dialogs.</li>
|
||
<li><code>alert</code> without an action is equivalent to <code>alert get</code>.</li>
|
||
<li><code>accept</code> and <code>dismiss</code> are sent once on every platform. A lost or unconfirmed response is reported as an error and never replayed; run <code>alert get</code> before acting again.</li>
|
||
<li>Use <code>alert get</code> for an immediate cheap check. Use <code>alert wait <short-ms></code> only when a prompt may appear after async work.</li>
|
||
<li>Within an iOS XCTest execution, <code>accept</code> and <code>dismiss</code> activate the selected button once, then only observe until the alert disappears, its presentation changes, or the deadline expires. A shared button label never triggers a second coordinate tap. A changed presentation can be an updated original alert or a replacement; it does not prove a permission was granted. Verify the application outcome separately.</li>
|
||
<li>An unreadable or ambiguous post-action capture fails with <code>error.details.runnerErrorCode: ALERT_CONFIRMATION_UNAVAILABLE</code>; an expired runner deadline uses <code>ALERT_DEADLINE_EXCEEDED</code> (the outer command watchdog can also report a timeout). Neither proves absence or that no action occurred. Identical-looking alerts remain unconfirmed. Inspect the current alert before deciding whether to act again.</li>
|
||
<li>Android support is snapshot-derived. If <code>alert</code> reports no alert but a sheet is visible, treat it as app-owned UI and use <code>snapshot -i</code> plus <code>press</code> by visible label/ref.</li>
|
||
<li>If an iOS permission sheet is visible in <code>snapshot</code> or <code>screenshot</code> but <code>alert accept</code> reports no alert, fall back to a scoped <code>snapshot -i -s "<visible label>"</code> plus <code>press @ref</code>; not every simulator permission surface is exposed as a native XCTest alert.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="interactions"><a href="#interactions" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Interactions</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> click</span><span style="color:var(--shiki-token-string)"> @e1</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> click</span><span style="color:var(--shiki-token-string)"> @e1</span><span style="color:var(--shiki-token-string)"> --button</span><span style="color:var(--shiki-token-string)"> secondary</span><span style="color:var(--shiki-token-comment)"> # macOS secondary click / context menu</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> focus</span><span style="color:var(--shiki-token-string)"> @e2</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> fill</span><span style="color:var(--shiki-token-string)"> @e2</span><span style="color:var(--shiki-token-string-expression)"> "text"</span><span style="color:var(--shiki-token-comment)"> # Clear then type</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> fill</span><span style="color:var(--shiki-token-string)"> @e2</span><span style="color:var(--shiki-token-string-expression)"> "search"</span><span style="color:var(--shiki-token-string)"> --delay-ms</span><span style="color:var(--shiki-token-constant)"> 80</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> type</span><span style="color:var(--shiki-token-string-expression)"> "text"</span><span style="color:var(--shiki-token-comment)"> # Type into focused field without clearing</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> type</span><span style="color:var(--shiki-token-string-expression)"> "query"</span><span style="color:var(--shiki-token-string)"> --delay-ms</span><span style="color:var(--shiki-token-constant)"> 80</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-constant)"> 300</span><span style="color:var(--shiki-token-constant)"> 500</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-constant)"> 300</span><span style="color:var(--shiki-token-constant)"> 500</span><span style="color:var(--shiki-token-string)"> --count</span><span style="color:var(--shiki-token-constant)"> 12</span><span style="color:var(--shiki-token-string)"> --interval-ms</span><span style="color:var(--shiki-token-constant)"> 45</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> press</span><span style="color:var(--shiki-token-constant)"> 300</span><span style="color:var(--shiki-token-constant)"> 500</span><span style="color:var(--shiki-token-string)"> --count</span><span style="color:var(--shiki-token-constant)"> 6</span><span style="color:var(--shiki-token-string)"> --hold-ms</span><span style="color:var(--shiki-token-constant)"> 120</span><span style="color:var(--shiki-token-string)"> --interval-ms</span><span style="color:var(--shiki-token-constant)"> 30</span><span style="color:var(--shiki-token-string)"> --jitter-px</span><span style="color:var(--shiki-token-constant)"> 2</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> swipe</span><span style="color:var(--shiki-token-constant)"> 540</span><span style="color:var(--shiki-token-constant)"> 1500</span><span style="color:var(--shiki-token-constant)"> 540</span><span style="color:var(--shiki-token-constant)"> 500</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> swipe</span><span style="color:var(--shiki-token-constant)"> 540</span><span style="color:var(--shiki-token-constant)"> 1500</span><span style="color:var(--shiki-token-constant)"> 540</span><span style="color:var(--shiki-token-constant)"> 500</span><span style="color:var(--shiki-token-string)"> --count</span><span style="color:var(--shiki-token-constant)"> 8</span><span style="color:var(--shiki-token-string)"> --pause-ms</span><span style="color:var(--shiki-token-constant)"> 30</span><span style="color:var(--shiki-token-string)"> --pattern</span><span style="color:var(--shiki-token-string)"> ping-pong</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> pan</span><span style="color:var(--shiki-token-constant)"> 200</span><span style="color:var(--shiki-token-constant)"> 420</span><span style="color:var(--shiki-token-constant)"> 0</span><span style="color:var(--shiki-token-string)"> -80</span><span style="color:var(--shiki-token-constant)"> 500</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> pan</span><span style="color:var(--shiki-token-constant)"> 200</span><span style="color:var(--shiki-token-constant)"> 420</span><span style="color:var(--shiki-token-constant)"> 80</span><span style="color:var(--shiki-token-string)"> -40</span><span style="color:var(--shiki-token-constant)"> 700</span><span style="color:var(--shiki-token-string)"> --pointer-count</span><span style="color:var(--shiki-token-constant)"> 2</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> fling</span><span style="color:var(--shiki-token-string)"> right</span><span style="color:var(--shiki-token-constant)"> 200</span><span style="color:var(--shiki-token-constant)"> 420</span><span style="color:var(--shiki-token-constant)"> 180</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> drag</span><span style="color:var(--shiki-token-string-expression)"> 'id="drag-source"'</span><span style="color:var(--shiki-token-string-expression)"> 'id="drop-target"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> drag</span><span style="color:var(--shiki-token-string)"> @e4~s12</span><span style="color:var(--shiki-token-string-expression)"> 'label="Archive"'</span><span style="color:var(--shiki-token-constant)"> 700</span><span style="color:var(--shiki-token-constant)"> 600</span><span style="color:var(--shiki-token-constant)"> 200</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> longpress</span><span style="color:var(--shiki-token-constant)"> 300</span><span style="color:var(--shiki-token-constant)"> 500</span><span style="color:var(--shiki-token-constant)"> 800</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> hover</span><span style="color:var(--shiki-token-string)"> @e12</span><span style="color:var(--shiki-token-string)"> --settle</span><span style="color:var(--shiki-token-comment)"> # Web only: move the pointer without pressing</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> scroll</span><span style="color:var(--shiki-token-string)"> down</span><span style="color:var(--shiki-token-constant)"> 0.5</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> scroll</span><span style="color:var(--shiki-token-string)"> down</span><span style="color:var(--shiki-token-string)"> --pixels</span><span style="color:var(--shiki-token-constant)"> 320</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> pinch</span><span style="color:var(--shiki-token-constant)"> 2.0</span><span style="color:var(--shiki-token-comment)"> # zoom in 2x</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> pinch</span><span style="color:var(--shiki-token-constant)"> 0.5</span><span style="color:var(--shiki-token-constant)"> 200</span><span style="color:var(--shiki-token-constant)"> 400</span><span style="color:var(--shiki-token-comment)"> # zoom out at coordinates</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> rotate</span><span style="color:var(--shiki-token-constant)"> 35</span><span style="color:var(--shiki-token-constant)"> 200</span><span style="color:var(--shiki-token-constant)"> 420</span><span style="color:var(--shiki-token-comment)"> # rotate app content</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> gesture</span><span style="color:var(--shiki-token-string)"> transform</span><span style="color:var(--shiki-token-constant)"> 200</span><span style="color:var(--shiki-token-constant)"> 420</span><span style="color:var(--shiki-token-constant)"> 80</span><span style="color:var(--shiki-token-string)"> -40</span><span style="color:var(--shiki-token-constant)"> 2</span><span style="color:var(--shiki-token-constant)"> 35</span><span style="color:var(--shiki-token-constant)"> 700</span><span style="color:var(--shiki-token-comment)"> # combined pan, zoom, and rotate</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p><code>fill</code> clears then types. <code>type</code> does not clear.
|
||
<code>type</code> accepts text only. Do not pass <code>@ref</code> to <code>type</code>; use <code>fill @ref "text"</code> to target a field directly, or <code>press @ref</code> then <code>type "text"</code> to append in the focused field.
|
||
If <code>type</code> reports <code>TEXT_INPUT_NOT_FOCUSED</code>, focus a visible text input and retry; when accessibility does not expose the input, use a coordinate focus command before typing.
|
||
On iOS, if <code>type</code> reports <code>TEXT_INPUT_SYNTHESIS_UNAVAILABLE</code> while the software keyboard is hidden, show the software keyboard, then retry <code>type</code> or <code>fill</code>. The runner reports this error instead of risking partial input through an unreliable text-entry path.
|
||
On iOS, if <code>type</code> or <code>fill</code> reports <code>TEXT_INPUT_COMMIT_NOT_OBSERVED</code>, the runner could not confirm the typed text reached the field — either it did not land before the runner's deadline, or the expected final text is identical to the field's placeholder. In the latter case, accessibility cannot distinguish committed text from an empty field rendering that placeholder, even if the field held content before dispatch. The field may hold none, part, or all of the text: run <code>snapshot -i</code> and inspect it. If it already matches, continue; otherwise retry with the full text quoted and <code>fill --delay-ms 80</code>, which replaces the whole value. Do not use <code>type</code>, which appends to whatever committed. This covers the bare-type route and the coordinate-driven <code>fill</code> route taken when the accessibility channel is under load, both of which observe the field after synthesizing; it is not a guarantee that every text-entry route verifies its result.
|
||
Use plain <code>fill</code> or <code>type</code> first for ordinary login and form fields. Use <code>--delay-ms</code> on <code>type</code> or <code>fill</code> only when a debounced search field or search-as-you-type input actually misses characters, or when the app must receive incremental updates.
|
||
Delayed typing intentionally prefers paced character entry over clipboard-style fallbacks so the target field receives each incremental update.
|
||
On Android, <code>fill</code> also verifies text and treats IME-owned capture as a terminal failure instead of retrying against the wrong field.
|
||
Android text entry is owned by <code>agent-device</code>: provider-native injection when available, then chunk-safe ASCII shell input. Do not switch to raw <code>adb</code>, clipboard, or paste as an agent fallback. If non-ASCII is unsupported in the current backend, report the tool/device gap.
|
||
<code>click --button secondary</code> is the desktop context-menu flow on macOS.
|
||
<code>click --button middle</code> is reserved for future runner support and currently returns an explicit unsupported-operation error on macOS.
|
||
<code>swipe</code> is a quick, fixed-duration directional throw. Use <code>gesture pan</code> for deliberate timed movement.
|
||
Neither <code>swipe</code> nor <code>gesture fling</code> takes a duration, and <code>gesture rotate</code> takes no velocity — see
|
||
<a href="/agent-device/docs/migrating-gestures" class="rp-link">Migrating Gestures</a> if you have scripts or recordings that still pass one.
|
||
Repeated coordinate swipes accept at most 200 repetitions and 10000ms pauses, and their combined
|
||
gesture/pause schedule must fit within 60000ms.
|
||
<code>gesture pan</code> accepts <code>x y dx dy [durationMs]</code> for deliberate drags. It uses one pointer by default. Add <code>--pointer-count 2</code> for a parallel two-finger pan with constant contact span and angle; this shares the bounded two-contact synthesizer used by transform while retaining pan intent. Android preserves the requested travel duration; iOS uses XCTest drag primitives for one-pointer pan and private XCTest synthesis for two-pointer pan.
|
||
<code>gesture drag</code> accepts <code>source destination [sourceHoldMs] [moveMs] [destinationHoldMs]</code>, where each endpoint is a selector or a snapshot ref. It resolves both endpoints before dispatch and keeps one pointer down continuously through activation, movement, and the optional destination hold. Defaults are 800ms, 500ms, and 0ms; the combined gesture is capped at 10000ms. Recordings convert refs to selector chains so saved <code>.ad</code> scripts remain portable.
|
||
Target-authored drag is supported on Android touch devices and iOS/iPadOS. Backends that cannot preserve all three authored phases reject it before injection.
|
||
<code>gesture fling</code> accepts <code>up|down|left|right x y [distance]</code> for fast directional throws.
|
||
<code>gesture rotate</code> accepts <code>degrees [x] [y]</code>; the degree sign controls direction. Pacing is derived from the requested rotation.
|
||
<code>gesture transform</code> accepts <code>x y dx dy scale degrees [durationMs]</code> for one combined two-finger pan/zoom/rotate gesture on Android and iOS simulators. Pinch, rotate, two-finger pan, and transform use the same viewport-aware pointer planning; impossible paths fail before injection instead of clamping or distorting the requested motion.
|
||
On iOS simulators it uses private XCTest synthesis for a continuous two-finger pan/scale/rotation path, so verify app-level metrics instead of assuming the requested values map exactly to recognizer output.
|
||
On Android, <code>gesture transform</code> injects a geometric two-finger path. App recognizers may report non-exact pan, scale, and rotation values, so verify qualitative state such as <code>pan changed yes</code>, <code>pinch changed yes</code>, and <code>rotate changed yes</code> unless the app explicitly promises exact centroid metrics. If exact app-state values matter, prefer isolated <code>gesture pan</code>, <code>gesture pinch</code>, or <code>gesture rotate</code> commands.
|
||
<code>scroll</code> accepts either a relative amount (<code>0.5</code> means a finger path spanning half of the viewport on that axis) or <code>--pixels <n></code> for a fixed-distance gesture. Directional scrolls decelerate through the drag on Android to reduce release momentum within the requested duration; <code>scroll top</code> and <code>scroll bottom</code> retain inertial release for edge traversal. Reduced momentum does not guarantee an exact content offset, especially for very short gestures: apps apply pan-recognition thresholds, collapsing headers, bounds, and their own scroll physics. Large distances are clamped to the usable drag band so the gesture stays reliable across Android, iOS, and macOS.
|
||
A directional scroll places its swipe across the middle of the viewport, so a focused field and its keyboard would put the swipe under the keys: the gesture would land on the keyboard, the surface would not move, and the scroll would read as stuck. On iOS and Android the scroll instead keeps the whole swipe in the band above the keyboard, reporting <code>keyboardAvoided</code> and <code>keyboardMinY</code> alongside a <code>referenceHeight</code> and <code>pixels</code> measured against that shorter band. It never dismisses the keyboard, because dismissing drops focus and breaks a <code>fill</code>/<code>scroll</code>/<code>fill</code> loop; run <code>keyboard dismiss</code> yourself when you want that. When the keyboard leaves too little room to swipe, the command refuses with the <code>scroll_keyboard_occludes_surface</code> reason rather than swiping into the keys, so a scroll that cannot work says so instead of appearing stuck.
|
||
Default snapshot text output is visible-first, so off-screen interactive content is summarized instead of shown as tappable refs.
|
||
When a target only appears in an off-screen summary, use <code>scroll <direction> --settle</code>: the response waits for the UI to go quiet and returns the diff against the tree you last observed, with fresh refs on the added lines, so no follow-up <code>snapshot -i</code> is needed. <code>back --settle</code> does the same for navigation. Both are best-effort and never fail the action. For repeated checks without settle, a small shell loop is enough:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-foreground)">previous</span><span style="color:var(--shiki-token-keyword)">=</span><span style="color:var(--shiki-token-string-expression)">''</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)">for</span><span style="color:var(--shiki-foreground)"> _ </span><span style="color:var(--shiki-token-keyword)">in</span><span style="color:var(--shiki-token-string)"> 1</span><span style="color:var(--shiki-token-string)"> 2</span><span style="color:var(--shiki-token-string)"> 3</span><span style="color:var(--shiki-token-string)"> 4</span><span style="color:var(--shiki-token-string)"> 5</span><span style="color:var(--shiki-token-string)"> 6</span><span style="color:var(--shiki-foreground)">; </span><span style="color:var(--shiki-token-keyword)">do</span></span>
|
||
<span class="line"><span style="color:var(--shiki-foreground)"> current</span><span style="color:var(--shiki-token-keyword)">=</span><span style="color:var(--shiki-token-string-expression)">"$(</span><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span><span style="color:var(--shiki-token-string-expression)">)"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)"> printf</span><span style="color:var(--shiki-token-string-expression)"> '%s\n'</span><span style="color:var(--shiki-token-string-expression)"> "$current"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)"> printf</span><span style="color:var(--shiki-token-string-expression)"> '%s\n'</span><span style="color:var(--shiki-token-string-expression)"> "$current"</span><span style="color:var(--shiki-token-keyword)"> |</span><span style="color:var(--shiki-token-function)"> grep</span><span style="color:var(--shiki-token-string)"> -q</span><span style="color:var(--shiki-token-string-expression)"> 'Sign in'</span><span style="color:var(--shiki-token-punctuation)"> &&</span><span style="color:var(--shiki-token-keyword)"> break</span></span>
|
||
<span class="line"><span style="color:var(--shiki-foreground)"> [ </span><span style="color:var(--shiki-token-string-expression)">"$current"</span><span style="color:var(--shiki-token-keyword)"> =</span><span style="color:var(--shiki-token-string-expression)"> "$previous"</span><span style="color:var(--shiki-foreground)"> ] </span><span style="color:var(--shiki-token-punctuation)">&&</span><span style="color:var(--shiki-token-keyword)"> break</span></span>
|
||
<span class="line"><span style="color:var(--shiki-foreground)"> previous</span><span style="color:var(--shiki-token-keyword)">=</span><span style="color:var(--shiki-token-string-expression)">"$current"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)"> agent-device</span><span style="color:var(--shiki-token-string)"> scroll</span><span style="color:var(--shiki-token-string)"> down</span><span style="color:var(--shiki-token-constant)"> 0.5</span><span style="color:var(--shiki-token-keyword)"> ></span><span style="color:var(--shiki-token-string)">/dev/null</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)">done</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p><code>longpress</code> is supported on iOS and Android.
|
||
<code>hover</code> is supported on web only. It moves the pointer over a target (<code>@ref</code>, selector, or coordinates) without pressing, so hover-gated UI such as row toolbars and menus appears; touch platforms have no hover state and reject it. Use <code>--settle</code> to get the diff of what the hover revealed and act on the fresh refs; use <code>longpress</code> for the mobile hold-gesture equivalent.
|
||
<code>gesture pinch</code> is supported on Android and iOS simulator app sessions.
|
||
<code>gesture rotate</code> is supported on Android and iOS simulator app sessions. Use <code>orientation</code> for device orientation.
|
||
Two-finger <code>gesture pan</code> and <code>gesture transform</code> are supported on Android and iOS simulator app sessions. One-finger <code>gesture pan</code> keeps the broader platform support of ordinary coordinate drags.</p>
|
||
<h2 class="rp-toc-include" id="find-semantic"><a href="#find-semantic" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Find (semantic)</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> find</span><span style="color:var(--shiki-token-string-expression)"> "Sign In"</span><span style="color:var(--shiki-token-string)"> click</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> find</span><span style="color:var(--shiki-token-string)"> label</span><span style="color:var(--shiki-token-string-expression)"> "Email"</span><span style="color:var(--shiki-token-string)"> fill</span><span style="color:var(--shiki-token-string-expression)"> "user@example.com"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> find</span><span style="color:var(--shiki-token-string)"> role</span><span style="color:var(--shiki-token-string)"> button</span><span style="color:var(--shiki-token-string)"> click</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> find</span><span style="color:var(--shiki-token-string-expression)"> "Follow"</span><span style="color:var(--shiki-token-string)"> list</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p>Actions: <code>click</code> (default; <code>press</code>/<code>tap</code> are aliases), <code>list</code>, <code>focus</code>, <code>fill</code>, <code>type</code>, <code>exists</code>, <code>wait</code>, <code>get text</code>, <code>get attrs</code>. <code>list</code> is read-only — it returns every match with its <code>@ref</code> and never taps, so use it to inspect before acting. Ambiguous matches are rejected with a candidates listing for text and selector queries alike; <code>--first</code>/<code>--last</code> opt into positional narrowing explicitly.</p>
|
||
<h2 class="rp-toc-include" id="assertions"><a href="#assertions" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Assertions</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> visible</span><span style="color:var(--shiki-token-string-expression)"> 'role="button" label="Continue"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> exists</span><span style="color:var(--shiki-token-string-expression)"> 'id="primary-cta"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> absent</span><span style="color:var(--shiki-token-string-expression)"> 'label="Loading..."'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> hidden</span><span style="color:var(--shiki-token-string-expression)"> 'text="Loading..."'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> editable</span><span style="color:var(--shiki-token-string-expression)"> 'id="email"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> selected</span><span style="color:var(--shiki-token-string-expression)"> 'label="Wi-Fi"'</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> is</span><span style="color:var(--shiki-token-string)"> text</span><span style="color:var(--shiki-token-string-expression)"> 'id="greeting"'</span><span style="color:var(--shiki-token-string-expression)"> "Welcome back"</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>is</code> evaluates UI predicates against a selector expression and exits non-zero on failure.</li>
|
||
<li>Supported predicates are <code>visible</code>, <code>hidden</code>, <code>exists</code>, <code>absent</code>, <code>editable</code>, <code>selected</code>, <code>focused</code>, and <code>text</code>.</li>
|
||
<li><code>is visible</code> checks whether the resolved element is present in the current visible snapshot viewport. A node without its own rect still passes when a visible ancestor within the viewport provides the on-screen geometry.</li>
|
||
<li><code>is exists</code> only checks whether the selector matches in the current snapshot.</li>
|
||
<li><code>is absent</code> passes only when the selector has zero matches in one readable, complete, unscoped, full-depth accessibility capture. It does not mean hidden; <code>--scope</code> and <code>--depth</code> are rejected, and sparse, unreadable, or truncated captures fail closed.</li>
|
||
<li><code>wait text</code> is a text-presence wait, not a hittability assertion.</li>
|
||
<li>Strict <code>wait absent</code> is not exported to Maestro's lenient <code>notVisible</code> condition; Maestro export reports it as unsupported unless an exact zero-candidate primitive becomes available.</li>
|
||
<li><code>is text <selector> <value></code> compares the resolved element text against the expected value.</li>
|
||
<li><code>is</code> does not accept snapshot refs like <code>@e3</code>; use a selector expression instead.</li>
|
||
<li><code>is</code> accepts the same selector-oriented snapshot flags as <code>click</code>, <code>fill</code>, <code>get</code>, and <code>wait</code>; <code>is absent</code> rejects <code>--scope</code> and <code>--depth</code> because its proof must cover the complete unscoped tree.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="replay"><a href="#replay" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Replay</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> Settings</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> e2e</span><span style="color:var(--shiki-token-string)"> --save-script</span><span style="color:var(--shiki-foreground)"> [path]</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> replay</span><span style="color:var(--shiki-token-string)"> ./session.ad</span><span style="color:var(--shiki-token-comment)"> # Run deterministic replay from .ad script</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> test</span><span style="color:var(--shiki-token-string)"> ./suite</span><span style="color:var(--shiki-token-comment)"> # Run every .ad file in a folder or glob serially</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> test</span><span style="color:var(--shiki-token-string)"> ./suite</span><span style="color:var(--shiki-token-string)"> --timeout</span><span style="color:var(--shiki-token-constant)"> 60000</span><span style="color:var(--shiki-token-string)"> --retries</span><span style="color:var(--shiki-token-constant)"> 1</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> replay</span><span style="color:var(--shiki-token-string)"> ./session.ad</span><span style="color:var(--shiki-token-string)"> --from</span><span style="color:var(--shiki-token-constant)"> 4</span><span style="color:var(--shiki-token-string)"> --plan-digest</span><span style="color:var(--shiki-token-keyword)"> <</span><span style="color:var(--shiki-token-string)">sha25</span><span style="color:var(--shiki-token-keyword)">6></span><span style="color:var(--shiki-token-comment)"> # Execute step 4; if already completed, use the next safe index with this digest</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> replay</span><span style="color:var(--shiki-token-string)"> ./session.ad</span><span style="color:var(--shiki-token-string)"> --keep-session</span><span style="color:var(--shiki-token-comment)"> # Suppress its terminal close and continue interactively</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>replay</code> runs deterministic <code>.ad</code> scripts.</li>
|
||
<li>Script paths belong to the caller: <code>replay <path></code> and <code>test <path-or-glob></code> are resolved and read by the client, which sends the script content (and any Maestro <code>runFlow</code> includes) with the request. The same command therefore works against a local daemon and against a remote one (<code>AGENT_DEVICE_DAEMON_BASE_URL</code>) with no copy step, and a script missing on the calling machine fails immediately, naming the path you typed.</li>
|
||
<li><code>replay --keep-session</code> suppresses exactly an authored terminal <code>close</code> in native <code>.ad</code>; interior closes still run, and a close-less script is unchanged. The option is rejected by <code>test</code> and Maestro YAML.</li>
|
||
<li><code>test</code> runs one or more <code>.ad</code> scripts as a serial suite from files, directories, or glob inputs.</li>
|
||
<li><code>test --platform <platform></code> filters suite files by <code>context platform=...</code> metadata instead of overriding the script target.</li>
|
||
<li><code>test --timeout <ms></code> and <code>test --retries <n></code> apply per script attempt; <code>context timeout=...</code> and <code>context retries=...</code> can be declared inside the <code>.ad</code> header. Retries are capped at <code>3</code>, duplicate metadata keys are rejected, and timeouts are cooperative.</li>
|
||
<li><code>test --artifacts-dir <path></code> overrides the default suite artifact root at <code>.agent-device/test-artifacts</code>.</li>
|
||
<li><code>test</code> prints a short <code>Running replay suite...</code> line before dispatch, then streams one-line <code>pass</code>, <code>fail</code>, or <code>skip</code> progress on stderr as each suite entry finishes or retries. Each line includes current/total suite position and elapsed seconds such as <code>pass 3/6 ... duration=12.34s</code>. The final summary still prints failures and flaky passed-on-retry tests by default; add <code>--verbose</code> to print every final result.</li>
|
||
<li>A failing step returns a <code>REPLAY_DIVERGENCE</code> report (screen digest, ranked selector suggestions, and a <code>resume</code> field); <code>replay --from <n> --plan-digest <sha256></code> resumes at and executes plan step <code>n</code> without re-running <code>1..n-1</code>. If the failed action was completed manually, resume from the next safe plan index using the matching digest. <code>replay</code>-only; <code>test</code> rejects <code>--from</code>.</li>
|
||
<li><code>replay -u</code>/<code>--update</code> no longer rewrites the script (retired — see <a href="/agent-device/docs/replay-e2e" class="rp-link">Replay & E2E</a>); it is a no-op kept for compatibility, since every divergence already carries the same ranked suggestions.</li>
|
||
<li><code>--save-script</code> records a replay script on <code>close</code>; optional path is a file path and parent directories are created. It writes on the daemon host, so it is rejected against a remote daemon.</li>
|
||
</ul>
|
||
<p>See <a href="/agent-device/docs/replay-e2e" class="rp-link">Replay & E2E</a> for recording, Maestro compatibility, and CI workflow details.</p>
|
||
<h2 class="rp-toc-include" id="batch"><a href="#batch" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Batch</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> batch</span><span style="color:var(--shiki-token-string)"> --steps-file</span><span style="color:var(--shiki-token-string)"> /tmp/batch-steps.json</span><span style="color:var(--shiki-token-string)"> --json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> batch</span><span style="color:var(--shiki-token-string)"> --steps</span><span style="color:var(--shiki-token-string-expression)"> '[{"command":"open","input":{"app":"settings"}}]'</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>batch</code> runs a JSON array of steps in a single daemon request.</li>
|
||
<li>Each step has <code>command</code>, <code>input</code>, and optional <code>runtime</code>.</li>
|
||
<li><code>input</code> uses the same fields as the matching MCP/Node command.</li>
|
||
<li>Legacy CLI step payloads with <code>positionals</code>/<code>flags</code> were removed in 0.21. Use structured input such as <code>{"command":"open","input":{"app":"settings","platform":"ios"}}</code>.</li>
|
||
<li>Unknown top-level step fields are rejected.</li>
|
||
<li>Stop-on-first-error is the supported behavior (<code>--on-error stop</code>).</li>
|
||
<li>Use <code>--max-steps <n></code> to tighten per-request safety limits.</li>
|
||
<li>Batch requests inherit the same daemon lock policy and session binding metadata as the parent command.</li>
|
||
<li>In non-JSON mode, successful batches print a short per-step summary.</li>
|
||
</ul>
|
||
<p>See <a href="/agent-device/docs/batching" class="rp-link">Batching</a> for payload format, response shape, and usage guidelines.</p>
|
||
<h2 class="rp-toc-include" id="app-install-in-place"><a href="#app-install-in-place" class="rp-header-anchor rp-link" aria-hidden="true">#</a>App install (in-place)</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> install</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string)"> ./build/app.apk</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> install</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string)"> ./build/MyApp.app</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>install <app> <path></code> installs from binary path without uninstalling first.</li>
|
||
<li>Supports Android devices/emulators, iOS simulators, and CoreDevice-backed iOS physical devices. On xctrace-only devices, install the app with Xcode before opening it by bundle ID.</li>
|
||
<li>Useful for upgrade flows where you want to keep existing app data when supported by the platform.</li>
|
||
<li>Remote daemons automatically upload local app artifacts for <code>install</code>; prefix the path with <code>remote:</code> to use a daemon-side path verbatim.</li>
|
||
<li>Supported binary formats: Android <code>.apk</code>/<code>.aab</code>, iOS <code>.app</code>/<code>.ipa</code>.</li>
|
||
<li><code>.aab</code> requires <code>bundletool</code> in <code>PATH</code>, or <code>AGENT_DEVICE_BUNDLETOOL_JAR=<absolute-path-to-bundletool-all.jar></code> with <code>java</code> in <code>PATH</code>.</li>
|
||
<li><code>.aab</code> installs use bundletool <code>build-apks --mode universal</code>.</li>
|
||
<li><code>.ipa</code> installs by extracting <code>Payload/*.app</code>; if multiple app bundles exist, <code><app></code> is used as a bundle id/name hint to select one.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="app-reinstall-fresh-state"><a href="#app-reinstall-fresh-state" class="rp-header-anchor rp-link" aria-hidden="true">#</a>App reinstall (fresh state)</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> reinstall</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string)"> ./build/app.apk</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> reinstall</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string)"> ./build/MyApp.app</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>reinstall <app> <path></code> uninstalls and installs in one command.</li>
|
||
<li>Supports Android devices/emulators, iOS simulators, and CoreDevice-backed iOS physical devices. XCTest-backed xctrace-only devices do not expose install or app inventory operations.</li>
|
||
<li>Useful for login/logout reset flows and deterministic test setup.</li>
|
||
<li>Remote daemons automatically upload local app artifacts for <code>reinstall</code>; prefix the path with <code>remote:</code> to use a daemon-side path verbatim.</li>
|
||
<li>Supported binary formats: Android <code>.apk</code>/<code>.aab</code>, iOS <code>.app</code>/<code>.ipa</code>.</li>
|
||
<li><code>.aab</code> accepts the same bundletool requirements as <code>install</code>.</li>
|
||
<li><code>.ipa</code> uses <code><app></code> as the selection hint when multiple <code>Payload/*.app</code> bundles are present.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="app-install-from-source-url"><a href="#app-install-from-source-url" class="rp-header-anchor rp-link" aria-hidden="true">#</a>App install from source URL</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> install-from-source</span><span style="color:var(--shiki-token-string)"> https://example.com/builds/app.apk</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> install-from-source</span><span style="color:var(--shiki-token-string)"> https://example.com/builds/app.aab</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> install-from-source</span><span style="color:var(--shiki-token-string)"> --github-actions-artifact</span><span style="color:var(--shiki-token-string)"> thymikee/RNCLI83:6635342232</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>install-from-source <url></code> installs from a URL source through the normal daemon artifact flow.</li>
|
||
<li><code>install-from-source --github-actions-artifact <owner/repo:artifact></code> passes a typed GitHub Actions artifact source through to a compatible remote daemon. Numeric artifacts are sent as <code>artifactId</code>; non-numeric artifacts are sent as <code>artifactName</code>.</li>
|
||
<li>Repeat <code>--header <name:value></code> for authenticated or signed artifact requests.</li>
|
||
<li>Supports the same device coverage as <code>install</code>: Android devices/emulators, iOS simulators, and CoreDevice-backed iOS physical devices.</li>
|
||
<li>Use <code>install</code> or <code>reinstall</code> for local <code>.apk</code>, <code>.aab</code>, <code>.app</code>, and <code>.ipa</code> paths; use <code>install-from-source</code> when the artifact already exists at a URL reachable by the daemon.</li>
|
||
<li>Direct Android URL sources may be <code>.apk</code> or <code>.aab</code>.</li>
|
||
<li>Trusted artifact service URLs may resolve to archives containing one installable <code>.apk</code>, <code>.aab</code>, <code>.ipa</code>, or iOS <code>.app</code> tar archive. Prefer <code>--github-actions-artifact</code> for GitHub Actions artifacts that a compatible remote daemon can resolve with its own credentials.</li>
|
||
<li>Downloads resolve and approve every redirect destination, pin each connection to the approved address, reject HTTPS downgrades, and follow at most five redirects. Sensitive caller headers are not forwarded across origins.</li>
|
||
<li>Downloaded artifacts are limited to 2 GiB compressed. Archive materialization is limited to 4 GiB expanded data, 100,000 entries, and three nested archive layers; links and special archive entries are rejected.</li>
|
||
<li>Standard <code>HTTP_PROXY</code>, <code>HTTPS_PROXY</code>, and <code>NO_PROXY</code> configuration is honored without delegating destination DNS resolution to the proxy.</li>
|
||
<li><code>--retain-paths</code> keeps retained materialized artifact paths after install, and <code>--retention-ms <ms></code> sets their TTL.</li>
|
||
<li>URL downloads follow the same <code>installFromSource()</code> safety checks and host restrictions as the JS client API.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="push-notification-simulation"><a href="#push-notification-simulation" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Push notification simulation</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> push</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string)"> ./payload.apns</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> push</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string-expression)"> '{"aps":{"alert":"Welcome","badge":1}}'</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> push</span><span style="color:var(--shiki-token-string)"> com.example.app</span><span style="color:var(--shiki-token-string-expression)"> '{"action":"com.example.app.PUSH","extras":{"title":"Welcome","unread":3,"promo":true}}'</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>push <bundle|package> <payload.json|inline-json></code> simulates push notification delivery.</li>
|
||
<li>iOS push simulation is simulator-only (<code>xcrun simctl push</code>) and requires an APNs-style JSON object payload.</li>
|
||
<li>Android uses <code>adb shell am broadcast</code> and accepts payload shape:
|
||
<code>{"action":"<intent-action>","receiver":"<optional component>","extras":{"key":"value","flag":true,"count":3}}</code>.</li>
|
||
<li>Android extras support <code>string</code>, <code>boolean</code>, and <code>number</code> values.</li>
|
||
<li><code>push</code> works with the active session device, or with explicit selectors (<code>--platform</code>, <code>--device</code>, <code>--udid</code>, <code>--serial</code>).</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="app-event-triggers-app-hook"><a href="#app-event-triggers-app-hook" class="rp-header-anchor rp-link" aria-hidden="true">#</a>App event triggers (app hook)</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> trigger-app-event</span><span style="color:var(--shiki-token-string)"> screenshot_taken</span><span style="color:var(--shiki-token-string-expression)"> '{"source":"qa"}'</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>trigger-app-event <event> [payloadJson]</code> dispatches app-defined events via deep link.</li>
|
||
<li><code>trigger-app-event</code> requires either an active session or explicit device selectors (<code>--platform</code>, <code>--device</code>, <code>--udid</code>, <code>--serial</code>).</li>
|
||
<li>On macOS, use <code>AGENT_DEVICE_MACOS_APP_EVENT_URL_TEMPLATE</code> to override the desktop deep-link template.</li>
|
||
<li>On iOS physical devices, custom-scheme deep links require active app context (open app first in the session).</li>
|
||
<li>Configure one of:
|
||
<ul>
|
||
<li><code>AGENT_DEVICE_APP_EVENT_URL_TEMPLATE</code></li>
|
||
<li><code>AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE</code></li>
|
||
<li><code>AGENT_DEVICE_MACOS_APP_EVENT_URL_TEMPLATE</code></li>
|
||
<li><code>AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE</code></li>
|
||
</ul>
|
||
</li>
|
||
<li>Template placeholders: <code>{event}</code>, <code>{payload}</code>, <code>{platform}</code>.</li>
|
||
<li>Example template: <code>myapp://agent-device/event?name={event}&payload={payload}</code>.</li>
|
||
<li><code>payloadJson</code> must be a JSON object.</li>
|
||
<li>This is app-hook-based simulation and does not inject OS-global notifications.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="settings-helpers"><a href="#settings-helpers" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Settings helpers</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> wifi</span><span style="color:var(--shiki-token-string)"> on</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> wifi</span><span style="color:var(--shiki-token-string)"> off</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> airplane</span><span style="color:var(--shiki-token-string)"> on</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> airplane</span><span style="color:var(--shiki-token-string)"> off</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> location</span><span style="color:var(--shiki-token-string)"> on</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> location</span><span style="color:var(--shiki-token-string)"> off</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> location</span><span style="color:var(--shiki-token-string)"> set</span><span style="color:var(--shiki-token-constant)"> 37.3349</span><span style="color:var(--shiki-token-string)"> -122.009</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> animations</span><span style="color:var(--shiki-token-string)"> off</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> animations</span><span style="color:var(--shiki-token-string)"> on</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> appearance</span><span style="color:var(--shiki-token-string)"> light</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> appearance</span><span style="color:var(--shiki-token-string)"> dark</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> appearance</span><span style="color:var(--shiki-token-string)"> toggle</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> faceid</span><span style="color:var(--shiki-token-string)"> match</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> faceid</span><span style="color:var(--shiki-token-string)"> nonmatch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> faceid</span><span style="color:var(--shiki-token-string)"> enroll</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> faceid</span><span style="color:var(--shiki-token-string)"> unenroll</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> touchid</span><span style="color:var(--shiki-token-string)"> match</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> touchid</span><span style="color:var(--shiki-token-string)"> nonmatch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> touchid</span><span style="color:var(--shiki-token-string)"> enroll</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> touchid</span><span style="color:var(--shiki-token-string)"> unenroll</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> fingerprint</span><span style="color:var(--shiki-token-string)"> match</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> fingerprint</span><span style="color:var(--shiki-token-string)"> nonmatch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> clear-app-state</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> clear-app-state</span><span style="color:var(--shiki-token-string)"> com.example.app</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> reset-keychain</span><span style="color:var(--shiki-token-string)"> clear</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> permission</span><span style="color:var(--shiki-token-string)"> grant</span><span style="color:var(--shiki-token-string)"> camera</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> permission</span><span style="color:var(--shiki-token-string)"> deny</span><span style="color:var(--shiki-token-string)"> microphone</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> permission</span><span style="color:var(--shiki-token-string)"> grant</span><span style="color:var(--shiki-token-string)"> photos</span><span style="color:var(--shiki-token-string)"> limited</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> permission</span><span style="color:var(--shiki-token-string)"> reset</span><span style="color:var(--shiki-token-string)"> notifications</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> permission</span><span style="color:var(--shiki-token-string)"> grant</span><span style="color:var(--shiki-token-string)"> accessibility</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> settings</span><span style="color:var(--shiki-token-string)"> permission</span><span style="color:var(--shiki-token-string)"> reset</span><span style="color:var(--shiki-token-string)"> screen-recording</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>iOS <code>settings</code> support is simulator-only except for <code>settings appearance</code> and the macOS permission subset on macOS.</li>
|
||
<li>macOS supports only <code>settings appearance <light|dark|toggle></code> and <code>settings permission <grant|reset> <accessibility|screen-recording|input-monitoring></code>.</li>
|
||
<li><code>settings wifi|airplane|location|animations</code> remain intentionally unsupported on macOS.</li>
|
||
<li>Android <code>settings animations off|on</code> toggles the global <code>window_animation_scale</code>, <code>transition_animation_scale</code>, and <code>animator_duration_scale</code> values. Use it as an opt-in stabilizer for automation runs with heavy system or app animations, then restore with <code>settings animations on</code> when needed.</li>
|
||
<li><code>settings appearance</code> maps to macOS appearance, iOS simulator appearance, and Android night mode.</li>
|
||
<li><code>settings location set <lat> <lon></code> sets precise coordinates on iOS simulators and Android emulators.</li>
|
||
<li><code>settings clear-app-state [app-id]</code> clears the active session app data, or the provided app id. Android uses <code>pm clear</code>, which removes SharedPreferences, databases, files, and cache. iOS simulator removes the app data container contents. iOS physical devices and macOS are unsupported. It does not touch the keychain, so keychain-backed credentials (e.g. Firebase auth) survive it.</li>
|
||
<li><code>settings reset-keychain clear</code> resets the iOS simulator's keychain (<code>xcrun simctl keychain <device> reset</code>), removing keychain-backed credentials such as Firebase auth tokens that <code>clear-app-state</code> leaves behind. simctl has no per-app keychain reset, so this clears the keychain for every app installed on that simulator, not only the app under test — treat it as a whole-simulator, opt-in operation and pair it with <code>clear-app-state</code> for a full fresh-install reset. iOS physical devices, Android, and macOS are unsupported.</li>
|
||
<li>Face ID and Touch ID controls are iOS simulator-only.</li>
|
||
<li>Android <code>settings airplane on|off</code> is applied by the connectivity service (<code>cmd connectivity airplane-mode</code>, Android 11+), which drives the radios rather than only writing the <code>airplane_mode_on</code> setting. The response reports the <code>airplaneMode</code> that service holds after the change, and Android builds without that command fail without changing device state. Connectivity takes a moment to settle after the switch, so poll the app under test rather than asserting offline behavior immediately.</li>
|
||
<li>Fingerprint simulation is supported on Android targets where <code>cmd fingerprint</code> or <code>adb emu finger</code> is available.
|
||
On physical Android devices, only <code>cmd fingerprint</code> is attempted.</li>
|
||
<li>Permission actions are scoped to the active session app.</li>
|
||
<li>iOS permission targets: <code>camera</code>, <code>microphone</code>, <code>photos</code> (<code>full</code> or <code>limited</code>), <code>contacts</code>, <code>notifications</code>.</li>
|
||
<li>Android permission targets: <code>camera</code>, <code>microphone</code>, <code>photos</code>, <code>contacts</code>, <code>notifications</code>.</li>
|
||
<li>macOS permission targets: <code>accessibility</code>, <code>screen-recording</code>, <code>input-monitoring</code>.</li>
|
||
<li>On macOS, <code>settings permission grant ...</code> checks/request access and opens System Settings guidance when needed; it does not silently grant TCC permissions.</li>
|
||
<li>On macOS, <code>settings permission deny ...</code> is intentionally unsupported.</li>
|
||
<li>Android uses <code>pm grant|revoke</code> for runtime permissions (<code>reset</code> maps to revoke) and <code>appops</code> for notifications. Every permission mutation names the foreground user explicitly (<code>--user <id></code>, resolved with <code>am get-current-user</code>): <code>pm</code> defaults these operations to user 0, so on a device whose foreground user is nonzero an unscoped revoke would edit user 0 and leave the running app's permission untouched. Resolving that user is a prerequisite — if <code>am get-current-user</code> does not answer, <code>settings permission</code> fails with <code>COMMAND_FAILED</code> and changes nothing rather than applying the mutation to user 0.</li>
|
||
<li>Android kills a running app whenever a runtime permission it currently holds is revoked, so <code>settings permission deny|reset</code> after a grant leaves the session app no longer running. The response reports the prior state of the revoked permission for the acting user as <code>priorGrantState: granted | not_granted | unknown</code>, and carries a warning naming <code>open <app> --relaunch</code> for both <code>granted</code> and <code>unknown</code> — <code>unknown</code> means the device did not report a readable state, not that the app was left alone. Revoking a permission the app does not hold (<code>not_granted</code>) is harmless and warns nothing.</li>
|
||
<li><code>full|limited</code> mode is supported only for iOS <code>photos</code>; other targets reject mode.</li>
|
||
<li>Use <code>match</code>/<code>nonmatch</code> to simulate valid/invalid Face ID, Touch ID, and Android fingerprint outcomes.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="app-state-and-app-lists"><a href="#app-state-and-app-lists" class="rp-header-anchor rp-link" aria-hidden="true">#</a>App state and app lists</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> appstate</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> apps</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> apps</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --all</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> apps</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> apps</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span><span style="color:var(--shiki-token-string)"> --all</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>Android <code>appstate</code> reports live foreground package/activity.</li>
|
||
<li>iOS <code>appstate</code> is session-scoped and reports the app tracked by the active session on the target device.</li>
|
||
<li><code>apps</code> shows user-installed apps by default. Use <code>--all</code> when you need the full inventory, including system/OEM apps.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="clipboard"><a href="#clipboard" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Clipboard</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> clipboard</span><span style="color:var(--shiki-token-string)"> read</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> clipboard</span><span style="color:var(--shiki-token-string)"> write</span><span style="color:var(--shiki-token-string-expression)"> "https://example.com"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> clipboard</span><span style="color:var(--shiki-token-string)"> write</span><span style="color:var(--shiki-token-string-expression)"> ""</span><span style="color:var(--shiki-token-comment)"> # clear clipboard</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>clipboard read</code> returns clipboard text for the selected target.</li>
|
||
<li>Treat <code>clipboard read</code> output as sensitive data; it can include secrets copied by the user or app.</li>
|
||
<li><code>clipboard write <text></code> updates clipboard text on the selected target.</li>
|
||
<li>Works with an active session device or explicit selectors (<code>--platform</code>, <code>--device</code>, <code>--udid</code>, <code>--serial</code>).</li>
|
||
<li>Supported on macOS, Android emulator/device, and iOS simulator.</li>
|
||
<li>iOS physical devices currently return <code>UNSUPPORTED_OPERATION</code> for clipboard commands.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="keyboard"><a href="#keyboard" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Keyboard</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> keyboard</span><span style="color:var(--shiki-token-string)"> status</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> keyboard</span><span style="color:var(--shiki-token-string)"> get</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> keyboard</span><span style="color:var(--shiki-token-string)"> dismiss</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>keyboard status</code> (or <code>keyboard get</code>) returns keyboard visibility and best-effort input type classification on Android.</li>
|
||
<li>To hide the keyboard, use <code>keyboard dismiss</code>. It taps safe controls like <code>Done</code> when available and verifies the keyboard closed.</li>
|
||
<li>If it reports <code>UNSUPPORTED_OPERATION</code>, press a visible app control such as <code>Done</code> only when that is the intended fallback.</li>
|
||
<li>Works with active sessions and explicit selectors (<code>--platform</code>, <code>--device</code>, <code>--udid</code>, <code>--serial</code>).</li>
|
||
<li><code>keyboard status|get</code> is supported on Android emulator/device.</li>
|
||
<li><code>keyboard dismiss</code> is supported on Android emulator/device and best-effort on iOS simulator/device.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="performance-diagnostics"><a href="#performance-diagnostics" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Performance diagnostics</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> frames</span><span style="color:var(--shiki-token-string)"> --json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> memory</span><span style="color:var(--shiki-token-string)"> sample</span><span style="color:var(--shiki-token-string)"> --json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> memory</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> android-hprof</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app.hprof</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> memory</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> memgraph</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app.memgraph</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> cdp</span><span style="color:var(--shiki-token-string)"> target</span><span style="color:var(--shiki-token-string)"> list</span><span style="color:var(--shiki-token-string)"> --url</span><span style="color:var(--shiki-token-string)"> http://127.0.0.1:8081</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> cdp</span><span style="color:var(--shiki-token-string)"> memory</span><span style="color:var(--shiki-token-string)"> usage</span><span style="color:var(--shiki-token-string)"> sample</span><span style="color:var(--shiki-token-string)"> --label</span><span style="color:var(--shiki-token-string)"> baseline</span><span style="color:var(--shiki-token-string)"> --gc</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> cdp</span><span style="color:var(--shiki-token-string)"> memory</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> capture</span><span style="color:var(--shiki-token-string)"> --name</span><span style="color:var(--shiki-token-string)"> baseline</span><span style="color:var(--shiki-token-string)"> --gc</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> cpu</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> xctrace</span><span style="color:var(--shiki-token-string)"> --template</span><span style="color:var(--shiki-token-string-expression)"> "Time Profiler"</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app.trace</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> cpu</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> xctrace</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app.trace</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> cpu</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> report</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> xctrace</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app-profile.json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> xctrace</span><span style="color:var(--shiki-token-string)"> --template</span><span style="color:var(--shiki-token-string-expression)"> "Animation Hitches"</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> hitches.trace</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> xctrace</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> hitches.trace</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> cpu</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> simpleperf</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> cpu.perf.data</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> cpu</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> simpleperf</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> cpu.perf.data</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> cpu</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> report</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> simpleperf</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> cpu-report.json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> perfetto</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app.perfetto-trace</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> perf</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-string)"> --kind</span><span style="color:var(--shiki-token-string)"> perfetto</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> app.perfetto-trace</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>Use an explicit <code>frames</code>, <code>memory</code>, <code>cpu</code>, or <code>trace</code> area so each request answers one profiling question. In 0.21, bare <code>perf</code>, <code>perf sample</code>, <code>perf metrics</code>, and the <code>metrics</code> alias fail with guidance to the focused replacements.</li>
|
||
<li><code>perf frames</code> returns a focused, bounded frame/jank-health JSON blob.</li>
|
||
<li><code>perf memory sample</code> returns a compact memory-only JSON blob for agents investigating growth/leaks without collecting a large artifact. It is better than raw memory command output for first-pass diagnosis because arrays and top offenders are bounded.</li>
|
||
<li>Example sample shape: <code>{"metrics":{"memory":{"available":true,"totalPssKb":562958,"totalRssKb":570304,"topConsumers":[{"name":"Dalvik Heap","pssKb":213456}]}}}</code>.</li>
|
||
<li><code>perf memory snapshot</code> writes a heap/memgraph artifact to disk and returns path, size, kind, method, and support metadata. Large artifacts are never dumped into CLI/MCP/default JSON output.</li>
|
||
<li>Example default snapshot output: <code>Memory artifact (android-hprof): /tmp/app.hprof (42MB)</code>.</li>
|
||
<li><code>cdp</code> targets React Native JavaScript heap evidence through Metro CDP. Use it for JS heap usage samples and heap snapshots; use <code>perf memory sample</code> and <code>perf memory snapshot</code> for native/process memory. See <a href="/agent-device/docs/debugging-profiling" class="rp-link">Debugging & Profiling</a> for the bounded leak workflow.</li>
|
||
<li><code>perf cpu profile ... --kind xctrace</code> records an Apple <code>.trace</code> with the requested xctrace template. <code>report</code> aggregates every run, writes compact JSON with at most ten weighted top self-time functions, and prints at most five while the raw trace stays on disk.</li>
|
||
<li><code>perf trace ... --kind xctrace</code> records an Apple <code>.trace</code> such as Animation Hitches for native diagnosis.</li>
|
||
<li>xctrace perf commands return artifact paths and compact metadata only; inspect <code>.trace</code> files in Instruments/Xcode instead of dumping trace contents into agent context.</li>
|
||
<li><code>perf cpu profile ... --kind simpleperf</code> starts/stops Android native CPU profiling for the active session package. Its report artifact keeps up to 50 parsed rows, while the response returns at most ten top functions and the CLI prints at most five.</li>
|
||
<li><code>perf trace ... --kind perfetto</code> starts/stops Android Perfetto trace capture for the active session package.</li>
|
||
<li>Native profile/trace outputs are compact agent evidence: state, artifact path, size, and method. Raw <code>.perf.data</code> and <code>.perfetto-trace</code> contents stay on disk.</li>
|
||
<li>Without <code>--json</code>, each explicit perf area prints a compact focused summary.</li>
|
||
<li>App startup duration is measured by <code>open</code> and returned in <code>open</code>'s <code>startup</code> result. Use that result directly instead of the removed aggregate perf form.</li>
|
||
<li>Use native perf stop/report results as compact agent evidence, not raw profiler output. A successful Perfetto stop can return <code>state: "stopped"</code>, <code>outPath: "/tmp/app.perfetto-trace"</code>, <code>sizeBytes: 5392410</code>, and <code>method: "adb-shell-perfetto"</code> while the 5.3 MB raw trace stays on disk as the artifact.</li>
|
||
<li>Android app sessions with an active package support:
|
||
<ul>
|
||
<li><code>fps</code> frame health from <code>adb shell dumpsys gfxinfo <package> framestats</code>, with <code>droppedFramePercent</code> as the primary value and <code>worstWindows</code> for dropped-frame clusters</li>
|
||
<li><code>memory</code> from <code>adb shell dumpsys meminfo <package></code> with values reported in kilobytes (<code>kB</code>)</li>
|
||
</ul>
|
||
</li>
|
||
<li>Apple app sessions with an active bundle ID support:
|
||
<ul>
|
||
<li><code>fps</code> frame health from <code>xcrun xctrace</code> Animation Hitches on connected iOS devices, with <code>droppedFramePercent</code> as the primary value and <code>worstWindows</code> for hitch clusters</li>
|
||
<li><code>memory</code> from process RSS snapshots reported in kilobytes (<code>kB</code>)</li>
|
||
</ul>
|
||
</li>
|
||
<li>Platform support:
|
||
<ul>
|
||
<li><code>memory</code>: Android emulator/device, HarmonyOS device, macOS app sessions, iOS simulators with an active app session (<code>open <app></code> first), and iOS physical devices with an active app session</li>
|
||
<li><code>fps</code>: Android emulator/device app sessions and connected iOS device app sessions. iOS simulator and macOS frame health is reported unavailable because Apple tooling does not expose trustworthy app hitch data there.</li>
|
||
<li><code>perf memory snapshot --kind android-hprof</code>: Android emulator/device app sessions with a running debuggable/profileable process and permitted heap dumping</li>
|
||
<li><code>perf memory snapshot --kind memgraph</code>: iOS simulator and macOS app sessions with a running app process. Physical iOS devices report memgraph unavailable with a recovery hint.</li>
|
||
<li><code>perf memory trace --kind heapprofd</code>: deferred until Android Perfetto/heapprofd plumbing is available.</li>
|
||
<li><code>perf cpu profile --kind xctrace</code>: iOS simulator app sessions, connected iOS device app sessions where xctrace can attach to the active process, and macOS app sessions when the app process can be resolved from the bundle ID.</li>
|
||
<li><code>perf trace --kind xctrace</code>: iOS simulator app sessions, connected iOS device app sessions where xctrace can attach to the active process, and macOS app sessions when the selected xctrace template supports the target.</li>
|
||
<li>Android native profiling is not implemented under Apple xctrace perf; Android profiling is tracked separately.</li>
|
||
</ul>
|
||
</li>
|
||
<li>HarmonyOS performance evidence is memory-only on the current public HDC surface: CPU profiling, frame sampling, and memory-snapshot artifacts are unavailable.</li>
|
||
<li>Android URL/deep-link opens infer the foreground package after launch when possible, including Expo Go/dev-client shells. If the session still has no app package/bundle ID, package-bound metrics remain unavailable until you <code>open <app></code>.</li>
|
||
<li>Android frame health is reset after each successful <code>perf frames</code> read and after <code>open <app></code>, so run <code>perf frames</code>, perform the interaction, then run <code>perf frames</code> again for a focused window.</li>
|
||
<li>Android Simpleperf and Perfetto collectors require an active Android app session with a running package process. They return artifact paths, sizes, and compact state summaries; they do not print profile or trace contents into the agent context. iOS native Simpleperf/Perfetto support is not provided by these commands.</li>
|
||
<li>On CoreDevice-backed physical iOS devices, <code>perf frames</code> records a short <code>xcrun xctrace</code> sample. Keep the device unlocked, connected, and the app active in the foreground while sampling.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="react-native-component-internals"><a href="#react-native-component-internals" class="rp-header-anchor rp-link" aria-hidden="true">#</a>React Native component internals</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> status</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> wait</span><span style="color:var(--shiki-token-string)"> --connected</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> get</span><span style="color:var(--shiki-token-string)"> tree</span><span style="color:var(--shiki-token-string)"> --depth</span><span style="color:var(--shiki-token-constant)"> 3</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> get</span><span style="color:var(--shiki-token-string)"> component</span><span style="color:var(--shiki-token-string)"> @c5</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> find</span><span style="color:var(--shiki-token-string)"> Button</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> start</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> stop</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> slow</span><span style="color:var(--shiki-token-string)"> --limit</span><span style="color:var(--shiki-token-constant)"> 5</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> rerenders</span><span style="color:var(--shiki-token-string)"> --limit</span><span style="color:var(--shiki-token-constant)"> 5</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> timeline</span><span style="color:var(--shiki-token-string)"> --limit</span><span style="color:var(--shiki-token-constant)"> 20</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-devtools</span><span style="color:var(--shiki-token-string)"> profile</span><span style="color:var(--shiki-token-string)"> report</span><span style="color:var(--shiki-token-string)"> @c5</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>react-devtools</code> dynamically runs pinned <code>agent-react-devtools@0.5.0</code> through npm and passes arguments through 1:1.</li>
|
||
<li>The first run may download the pinned package from npm; later runs can reuse the npm cache.</li>
|
||
<li><code>agent-device</code> global flags work before or after <code>react-devtools</code>. Use <code>--</code> before downstream flags only when they intentionally share an <code>agent-device</code> global flag name.</li>
|
||
<li>Use it when a React Native workflow needs component hierarchy, props, state, hooks, render causes, slow components, or re-render counts.</li>
|
||
<li>For profiling, keep the window narrow and make one bounded first-pass survey: use the <code>profile stop</code> summary, run <code>profile slow --limit 5</code> and <code>profile rerenders --limit 5</code> once, add <code>profile timeline --limit 20</code> only when commit timing matters, then drill into a specific <code>@c</code> ref with <code>profile report</code>.</li>
|
||
<li>Do not repeatedly raise broad <code>profile slow</code> limits such as <code>--limit 50</code>, <code>--limit 200</code>, or <code>--limit 500</code> unless you have a specific target that needs more rows.</li>
|
||
<li>Keep using <code>snapshot</code>, <code>press</code>, <code>fill</code>, <code>logs</code>, <code>network</code>, <code>audio probe</code>, <code>perf frames</code>, and <code>perf memory</code> for device/app runtime evidence. Use <code>react-devtools</code> for React internals.</li>
|
||
<li>For React Native apps, overlays, Metro/Fast Refresh blockers, and routing to React DevTools or debugging evidence, start with <code>agent-device help react-native</code>.</li>
|
||
<li>On Android, use <code>alert get</code>, <code>alert wait <short-ms></code>, <code>alert accept</code>, and <code>alert dismiss</code> for runtime permission prompts and native alerts. On iOS, use the same alert commands for XCTest alerts, app-owned modal popups with native blocking markers, and blocking system dialogs. Do not use <code>settings permission</code> to answer a dialog already on screen; reserve it for setup or resetting permission state before a flow.</li>
|
||
<li>React Native development builds can connect to the DevTools daemon on port 8097. For Android emulators or physical devices, run <code>adb reverse tcp:8097 tcp:8097</code> if the app cannot reach the host.</li>
|
||
<li>Direct Android <code>open</code> URL targets for local Metro hosts with a port auto-configure host reachability. For app/package launches or unsupported flows, run <code>adb reverse tcp:8081 tcp:8081</code> if the app cannot reach local Metro.</li>
|
||
<li>For Android and iOS sessions connected through a remote bridge profile, <code>react-devtools</code> registers a lease-scoped companion tunnel to the sandbox-local DevTools daemon at <code>127.0.0.1:8097</code>. Android bridge profiles use the bridge-owned remote <code>adb reverse</code> mapping; iOS bridge profiles use the bridge-owned wildcard Metro host tunnel. The CLI keeps the companion alive until <code>agent-device react-devtools stop</code> or <code>agent-device disconnect</code>.</li>
|
||
<li>For remote iOS bridge sessions, open the app once to create the bridge session, run <code>agent-device react-devtools start</code>, then relaunch the same bundle id with <code>agent-device open <bundle-id> --platform ios --relaunch</code> before <code>wait --connected</code>. React Native attempts the legacy DevTools websocket during JavaScript startup, so starting DevTools after the first launch can miss that connection attempt.</li>
|
||
<li>Remote bridge React DevTools assumes the React Native-bundled DevTools behavior in React Native 0.83+. Older browser/Chromium DevTools workflows are not assumed to exist inside remote sandboxes. Expo projects should be verified against the SDK's bundled React Native version before relying on this path; this release does not claim a separately verified Expo SDK version.</li>
|
||
<li>For cross-platform validation with explicit target selectors, use separate sessions/devices and restart <code>react-devtools</code> between iOS and Android runs.</li>
|
||
</ul>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-native</span><span style="color:var(--shiki-token-string)"> dismiss-overlay</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> react-native</span><span style="color:var(--shiki-token-string)"> dismiss-overlay</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> android</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>react-native dismiss-overlay</code> clears a React Native development overlay (a redbox/LogBox error or a collapsed warning banner) that is blocking interaction, then returns without changing app state otherwise.</li>
|
||
<li>Use it when a snapshot or interaction is blocked by a dev-only overlay; it is a no-op when no overlay is present.</li>
|
||
<li>It is supported on iOS simulators/devices and Android emulators/devices; <code>react-native</code> currently exposes only the <code>dismiss-overlay</code> helper.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="multiple-react-native-worktrees"><a href="#multiple-react-native-worktrees" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Multiple React Native worktrees</h2>
|
||
<p>You can reuse one installed iOS simulator debug build across multiple local worktrees when the native binary is compatible with both JavaScript trees. Run one Metro server per worktree on a unique port, then open the same app on different simulators with explicit Metro runtime hints:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-comment)"># Worktree A terminal</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">yarn</span><span style="color:var(--shiki-token-string)"> expo</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> --dev-client</span><span style="color:var(--shiki-token-string)"> --port</span><span style="color:var(--shiki-token-constant)"> 8081</span><span style="color:var(--shiki-token-string)"> --host</span><span style="color:var(--shiki-token-string)"> localhost</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-comment)"># Worktree B terminal</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">yarn</span><span style="color:var(--shiki-token-string)"> expo</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> --dev-client</span><span style="color:var(--shiki-token-string)"> --port</span><span style="color:var(--shiki-token-constant)"> 8082</span><span style="color:var(--shiki-token-string)"> --host</span><span style="color:var(--shiki-token-string)"> localhost</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string-expression)"> "React Navigation Example"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --device</span><span style="color:var(--shiki-token-string-expression)"> "iPhone 17"</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> rn-a</span><span style="color:var(--shiki-token-string)"> --metro-host</span><span style="color:var(--shiki-token-constant)"> 127.0.0.1</span><span style="color:var(--shiki-token-string)"> --metro-port</span><span style="color:var(--shiki-token-constant)"> 8081</span><span style="color:var(--shiki-token-string)"> --relaunch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string-expression)"> "React Navigation Example"</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --device</span><span style="color:var(--shiki-token-string-expression)"> "iPhone 17 Pro"</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> rn-b</span><span style="color:var(--shiki-token-string)"> --metro-host</span><span style="color:var(--shiki-token-constant)"> 127.0.0.1</span><span style="color:var(--shiki-token-string)"> --metro-port</span><span style="color:var(--shiki-token-constant)"> 8082</span><span style="color:var(--shiki-token-string)"> --relaunch</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>Use different simulators and sessions for each worktree. One simulator cannot run two copies of the same bundle id at the same time.</li>
|
||
<li>On iOS simulators, <code>open</code> writes React Native's per-simulator debug server settings before launching, so <code>rn-a</code> can use port <code>8081</code> while <code>rn-b</code> uses port <code>8082</code>. <code>open</code>'s <code>--metro-host</code>/<code>--metro-port</code> also bind each session's dev server, so a later flagless <code>metro reload --session rn-a</code> reloads the port <code>8081</code> server and <code>--session rn-b</code> reloads <code>8082</code> — no need to repeat the flags.</li>
|
||
<li>This covers JavaScript and Metro-resolved workspace changes. Rebuild/reinstall the app when native code, native dependencies, bundle identifiers, entitlements, or generated native project files change.</li>
|
||
<li>Close every manually opened session when done:</li>
|
||
</ul>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> rn-a</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> close</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span><span style="color:var(--shiki-token-string)"> --session</span><span style="color:var(--shiki-token-string)"> rn-b</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<h2 class="rp-toc-include" id="metro-reload"><a href="#metro-reload" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Metro reload</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> metro</span><span style="color:var(--shiki-token-string)"> reload</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> metro</span><span style="color:var(--shiki-token-string)"> reload</span><span style="color:var(--shiki-token-string)"> --metro-host</span><span style="color:var(--shiki-token-string)"> localhost</span><span style="color:var(--shiki-token-string)"> --metro-port</span><span style="color:var(--shiki-token-constant)"> 8081</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> metro</span><span style="color:var(--shiki-token-string)"> reload</span><span style="color:var(--shiki-token-string)"> --bundle-url</span><span style="color:var(--shiki-token-string-expression)"> "http://localhost:8081/index.bundle?platform=ios"</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>metro reload</code> triggers a dev-server reload, the same mechanism used by pressing <code>r</code> in the Metro terminal.</li>
|
||
<li>Use it for React Native dev builds that are already connected to Metro when JS changes should be loaded without restarting the native app process.</li>
|
||
<li>A flagless <code>metro reload --session <s></code> resolves against the dev server that session last bound — via <code>metro prepare</code> or <code>open</code>'s <code>--metro-host</code>/<code>--metro-port</code>/<code>--bundle-url</code> hint flags — so it never silently reloads a different project's server on the default port. Resolution priority is per-call flags, then that session's saved binding, then <code>http://localhost:8081/reload</code>; a host or port flag overrides only that field, while <code>--bundle-url</code> supplies the target bundle origin and route.</li>
|
||
<li>Session bindings are updated by each hinted <code>open</code> or <code>metro prepare</code>, cleared by <code>close</code>, and also cleared when a fresh same-name <code>open</code> has no Metro hint flags. This prevents a reused session name from reloading a previous project's dev server.</li>
|
||
<li>The reload URL keeps the bound bundle URL's mount prefix instead of collapsing to the host root. This applies to both <code>index.bundle</code> and Expo's virtual entry: <code>http://host/tenant-42/.expo/.virtual-metro-entry.bundle</code> maps to <code>http://host/tenant-42/reload</code>.</li>
|
||
<li>When the dev server has no HTTP <code>/reload</code> route and answers with the app page instead (Expo does this), <code>metro reload</code> broadcasts <code>{"version":2,"method":"reload"}</code> over the server's <code>/message</code> websocket — the channel the dev-server CLIs use for the <code>r</code> key — instead of reporting the app-page response as a successful reload. The result's <code>transport</code> field says which channel delivered the reload.</li>
|
||
<li>Pass <code>--metro-host</code>, <code>--metro-port</code>, or <code>--bundle-url</code> when you need to target a specific Metro instance for one call; explicit flags override the session binding.</li>
|
||
<li>Fall back to <code>open <app> --relaunch</code> when the app is not connected to Metro, reload fails, or the native process itself must restart.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="media-and-logs"><a href="#media-and-logs" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Media and logs</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-comment)"> # Auto filename</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> page.png</span><span style="color:var(--shiki-token-comment)"> # Explicit screenshot path</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> page.png</span><span style="color:var(--shiki-token-string)"> --scale</span><span style="color:var(--shiki-token-constant)"> 0.3</span><span style="color:var(--shiki-token-comment)"> # Resize both dimensions to 30% for agent context</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> page.png</span><span style="color:var(--shiki-token-string)"> --overlay-refs</span><span style="color:var(--shiki-token-comment)"> # Draw current @eN refs and target rectangles onto the PNG</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> page.png</span><span style="color:var(--shiki-token-string)"> --crop-on</span><span style="color:var(--shiki-token-string-expression)"> 'label="Save"'</span><span style="color:var(--shiki-token-comment)"> # Crop the capture to the frame the selector resolves on the same screen</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> baseline.png</span><span style="color:var(--shiki-token-string)"> --normalize-status-bar</span><span style="color:var(--shiki-token-comment)"> # Normalize iOS simulator chrome for reusable diff baselines</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> page.png</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span><span style="color:var(--shiki-token-string)"> --fullscreen</span><span style="color:var(--shiki-token-comment)"> # On web, --fullscreen/--full/-f captures the entire document</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> viewport</span><span style="color:var(--shiki-token-constant)"> 1280</span><span style="color:var(--shiki-token-constant)"> 900</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span><span style="color:var(--shiki-token-comment)"> # Resize the active web viewport for fixed-layout or 100vh apps</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> textedit.png</span><span style="color:var(--shiki-token-comment)"> # App-session window capture on macOS</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> --fullscreen</span><span style="color:var(--shiki-token-comment)"> # Force full-screen capture on macOS app sessions</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> macos</span><span style="color:var(--shiki-token-string)"> --surface</span><span style="color:var(--shiki-token-string)"> desktop</span><span style="color:var(--shiki-token-punctuation)"> &&</span><span style="color:var(--shiki-token-function)"> agent-device</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> desktop.png</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> diff</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> --baseline</span><span style="color:var(--shiki-token-string)"> baseline.png</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> diff.png</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> diff</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> --baseline</span><span style="color:var(--shiki-token-string)"> baseline.png</span><span style="color:var(--shiki-token-string)"> current.png</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> diff.png</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> diff</span><span style="color:var(--shiki-token-string)"> screenshot</span><span style="color:var(--shiki-token-string)"> --baseline</span><span style="color:var(--shiki-token-string)"> baseline.png</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> diff.png</span><span style="color:var(--shiki-token-string)"> --overlay-refs</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> record</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-comment)"> # Start app-scoped recording after open <app></span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> record</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> session.mp4</span><span style="color:var(--shiki-token-comment)"> # Start app-scoped recording to explicit path</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> record</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> session.mp4</span><span style="color:var(--shiki-token-string)"> --scope</span><span style="color:var(--shiki-token-string)"> device</span><span style="color:var(--shiki-token-comment)"> # Intentionally record the full simulator/device screen</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> record</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> session.mp4</span><span style="color:var(--shiki-token-string)"> --fps</span><span style="color:var(--shiki-token-constant)"> 30</span><span style="color:var(--shiki-token-comment)"> # Override iOS device runner FPS</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> record</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> session.mp4</span><span style="color:var(--shiki-token-string)"> --quality</span><span style="color:var(--shiki-token-string)"> high</span><span style="color:var(--shiki-token-comment)"> # Higher-quality export (slower)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> record</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-comment)"> # Stop active recording</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>Recordings always produce a video artifact. <code>record start</code> defaults to app scope and requires an active session from <code>open <app></code>; use <code>--scope device</code> or <code>--scope system</code> to explicitly request whole-screen capture where the selected backend supports it, such as recordings that intentionally span the full screen, multiple apps, settings, home screen, or app transitions. When touch visualization is enabled, recordings also produce a gesture telemetry sidecar that can be used for post-processing or inspection.</li>
|
||
<li><code>screenshot --scale <factor></code> proportionally resizes both dimensions. The accepted range is <code>0.01</code> through <code>1</code>; use <code>1</code> for full resolution. The former <code>--max-size <px></code> flag was removed and is refused with migration guidance wherever it appears (CLI, <code>.ad</code> scripts, Node options, config, and the retired <code>AGENT_DEVICE_SCREENSHOT_MAX_SIZE</code> env var).</li>
|
||
<li>Set <code>AGENT_DEVICE_SCREENSHOT_SCALE=0.3</code> (or <code>screenshotScale</code> in config) as a token-conscious screenshot default for agent workflows. An explicit <code>--scale</code> overrides it.</li>
|
||
<li>Keep the scale default unset, or use <code>--scale 1</code>, when full-resolution screenshots are required for reusable pixel-diff baselines.</li>
|
||
<li><code>screenshot --overlay-refs</code> captures a fresh full snapshot and burns visible <code>@eN</code> refs plus their target rectangles into the saved PNG.</li>
|
||
<li><code>screenshot --crop-on <selector></code> captures a fresh full snapshot of the same screen and crops the saved PNG to the frame the selector resolves to. The crop is re-encoded, so byte-comparing it against an older crop of the same frame is unreliable; a crop whose pixels are all opaque is written as truecolor RGB, while one containing transparency keeps RGBA. The selector must resolve to exactly one framed node; the result carries a <code>warnings</code> entry when the frame is clipped to the image. Currently accepted on iOS simulators and Android emulators — every other target is refused before any device work, and the flag cannot be combined with <code>--overlay-refs</code> or <code>--fullscreen</code> because both move the captured frame away from the snapshot viewport the crop is measured against.</li>
|
||
<li><code>screenshot --normalize-status-bar</code> temporarily normalizes iOS simulator status-bar chrome for deterministic screenshot baselines; ordinary screenshots leave the simulator's current chrome visible.</li>
|
||
<li><code>screenshot --scale <factor> --overlay-refs</code> writes a smaller image and draws refs for that final image size; avoid very small scales when text, icons, or labels need to remain readable.</li>
|
||
<li><code>diff screenshot</code> compares the current live screenshot to <code>--baseline</code>, or compares <code>--baseline</code> to an optional saved <code>current.png</code> path without requiring an active session. Its text output reports ranked changed regions with screen-space rectangles, changed-pixel counts, and each region's share of the diff; JSON also includes normalized rectangles. The earlier best-effort <code>ocr</code> and <code>nonTextDeltas</code> analyzers are retired; their optional result fields remain for source compatibility but are no longer emitted, so use the baseline/current images and diff artifact with vision for qualitative interpretation. It writes a diff PNG with a light grayscale current-screen context, red-tinted changed pixels, and outlined changed regions when <code>--out</code> is provided. Live iOS simulator diffs normalize status-bar chrome by default; use <code>screenshot --normalize-status-bar</code> when capturing reusable baselines.</li>
|
||
<li><code>diff screenshot --overlay-refs</code> additionally writes a separate current-screen overlay guide for live captures without using that annotated image for the pixel comparison. If current-screen refs intersect changed regions, the output lists the best ref matches under those regions. Saved-image comparisons do not have live accessibility refs, so <code>--overlay-refs</code> is unavailable when a <code>current.png</code> path is provided.</li>
|
||
<li><code>diff screenshot --threshold <0-1></code> sets the per-pixel RGB tolerance (default <code>0.1</code>): <code>0</code> requires exact colors and <code>1</code> ignores all color differences. Image dimensions must still match at every threshold.</li>
|
||
<li>In <code>--json</code> mode, each overlay ref also includes a screenshot-space <code>center</code> point for coordinate fallback like <code>press <x> <y></code>.</li>
|
||
<li>Burned-in touch overlays are exported only on macOS hosts, because the overlay pipeline depends on Swift + AVFoundation helpers.</li>
|
||
<li>On Linux or other non-macOS hosts, <code>record stop</code> still succeeds and returns the raw video plus telemetry sidecar, and includes <code>overlayWarning</code> when burn-in overlays were skipped.</li>
|
||
<li>On iOS simulators, a busy CoreSimulator host recording slot makes <code>record start</code> return non-retriable <code>DEVICE_IN_USE</code> with <code>details.reason: apple_simulator_recording_busy</code>. Use <code>record stop</code> in the session that owns the active recording. If a previous recorder died and no recording is active, ask the host operator to restart the CoreSimulator stream service before retrying.</li>
|
||
<li>Android uses <code>adb shell screenrecord</code>, which has a 180s platform limit. <code>record start</code> publishes a durable device manifest. Longer recordings are split into MP4 chunks while the daemon stays alive; after daemon restart, <code>record stop</code> recovers only manifest-owned chunks and warns when gesture overlay telemetry was lost.</li>
|
||
<li>Android <code>screenrecord</code> encodes a frame only when the screen changes, so a clip ends at the last frame the recorder encoded instead of at <code>record stop</code>: a window that ends on an unchanged screen yields a shorter video, while every on-screen change inside the window stays at its real offset in it. <code>record stop</code> reports <code>durationMs</code> as host wall clock from <code>record start</code> until the export finished, and when the video can be measured it also reports <code>capturedDurationMs</code> and warns with how much of the window that video covers.</li>
|
||
<li><code>record stop</code> is safe to repeat. When its request window ends while the daemon is still exporting — typical for a long touch-overlay burn-in on a remote daemon — the export keeps running there, and a second <code>record stop</code> in the same session returns that completed recording, including the caller-side output path, without starting another recording. A finished recording whose video file is already gone reports <code>no active recording</code>.</li>
|
||
</ul>
|
||
<p><strong>Session app logs (token-efficient debugging):</strong> Logging is off by default in normal flows. Enable it on demand for debugging. Logs are written to a file so agents can grep instead of loading full output into context.</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> path</span><span style="color:var(--shiki-token-comment)"> # Print session log file path (e.g. ~/.agent-device/sessions/default/app.log)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-comment)"> # Start streaming app stdout/stderr to that file (requires open first)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-comment)"> # Stop streaming</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> clear</span><span style="color:var(--shiki-token-comment)"> # Truncate app.log + remove rotated app.log.N files (requires stopped stream)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> clear</span><span style="color:var(--shiki-token-string)"> --restart</span><span style="color:var(--shiki-token-comment)"> # Stop stream, clear log files, and start streaming again</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> doctor</span><span style="color:var(--shiki-token-comment)"> # Show logs backend/tool checks and readiness hints</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> mark</span><span style="color:var(--shiki-token-string-expression)"> "before submit"</span><span style="color:var(--shiki-token-comment)"> # Insert timeline marker into app.log</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> events</span><span style="color:var(--shiki-token-comment)"> # Print recent session request/action events</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> events</span><span style="color:var(--shiki-token-constant)"> 50</span><span style="color:var(--shiki-token-constant)"> 100</span><span style="color:var(--shiki-token-comment)"> # Page 50 events starting at cursor 100</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> network</span><span style="color:var(--shiki-token-string)"> dump</span><span style="color:var(--shiki-token-constant)"> 25</span><span style="color:var(--shiki-token-comment)"> # Parse recent HTTP(s) requests (method/url/status)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> network</span><span style="color:var(--shiki-token-string)"> dump</span><span style="color:var(--shiki-token-constant)"> 25</span><span style="color:var(--shiki-token-string)"> --include</span><span style="color:var(--shiki-token-string)"> all</span><span style="color:var(--shiki-token-comment)"> # Include parsed headers/body when available (truncated)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> network</span><span style="color:var(--shiki-token-string)"> dump</span><span style="color:var(--shiki-token-constant)"> 25</span><span style="color:var(--shiki-token-string)"> --include</span><span style="color:var(--shiki-token-string)"> headers</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> web</span><span style="color:var(--shiki-token-comment)"> # Browser requests via managed agent-browser</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>Supported on iOS simulator, iOS physical device, and Android.</li>
|
||
<li>Preferred debug entrypoint: <code>logs clear --restart</code> for clean-window repro loops.</li>
|
||
<li><code>logs start</code> appends to <code>app.log</code> and rotates to <code>app.log.1</code> when the file exceeds 5 MB.</li>
|
||
<li><code>open</code> prints <code>Session state: <path></code> and JSON includes <code>sessionStateDir</code>, <code>runnerLogPath</code>, <code>requestLogPath</code>, and <code>eventLogPath</code>. Use the session directory to inspect concurrent runs without parsing global daemon logs.</li>
|
||
<li><code>events.ndjson</code> contains the session event timeline; <code>requests/<request-id>.ndjson</code> contains daemon request diagnostics; <code>runner.log</code> contains Apple runner and <code>xcodebuild</code> output.</li>
|
||
<li><code>events.ndjson</code> rotates to <code>events.ndjson.1</code> when it exceeds 5 MB (<code>AGENT_DEVICE_EVENT_LOG_MAX_BYTES</code> overrides, in whole bytes); one rotated generation is kept. <code>events</code> cursors stay absolute across rotation, so <code>nextCursor</code> still resumes; a cursor older than the retained window fails with <code>COMMAND_FAILED</code> and <code>details.reason: "EVENT_LOG_CURSOR_EXPIRED"</code>, with <code>details.earliestCursor</code> naming the oldest cursor that still resolves. If the retained files and their window record disagree — a hand-deleted generation, an edited file, a corrupt <code>events.ndjson.window.json</code> — <code>events</code> fails with <code>details.reason: "EVENT_LOG_WINDOW_UNVERIFIED"</code> rather than answering from a guessed offset; appends continue regardless.</li>
|
||
<li>Event timeline entries preserve command names, status, durations, bounded device/app inventory previews, lifecycle outcomes, artifact basenames, and structural action details such as scroll distance/direction, safe refs, and coordinates. User-entered text, clipboard contents, push/event payloads, selector values, free-form flags/messages/paths, and raw unknown command arguments are omitted or replaced with content-free placeholders. <code>--no-record</code> suppresses <code>action.recorded</code> entries, but request start/finish entries still record command/status/timing.</li>
|
||
<li><code>network dump [limit] [summary|headers|body|all]</code> parses recent HTTP(s) entries from <code>app.log</code> for app/device sessions and from managed <code>agent-browser</code> request history for web sessions; <code>network log ...</code> is an alias.</li>
|
||
<li>Prefer <code>--include headers|body|all</code> when you want explicit detail level without relying on positional ordering.</li>
|
||
<li>On macOS, <code>logs</code> and <code>network dump</code> are app-scoped and parse Unified Logging output associated with the active session app.</li>
|
||
<li>Network dump limits: scans up to 4000 recent log lines, returns up to 200 entries, and truncates payload/header fields at 2048 characters.</li>
|
||
<li>On web, <code>network dump</code> uses <code>agent-browser network requests</code>; request/response bodies are not exposed by that backend path, so use direct <code>agent-browser</code> HAR workflows for browser-specific body capture.</li>
|
||
<li>Android <code>network dump</code> also surfaces logcat timestamps and can backfill status and duration from adjacent GIBSDK packet lines when the URL is logged separately.</li>
|
||
<li>Android log streaming automatically rebinds to the app PID after process restarts.</li>
|
||
<li>iOS simulator log capture now streams from inside the simulator with <code>simctl spawn <udid> log ...</code>, and <code>network dump</code> can recover recent simulator log history with <code>simctl log show</code> when the live app-log window is sparse.</li>
|
||
<li>iOS log capture still relies on Unified Logging signals (for example <code>os_log</code>); plain stdout/stderr output may be limited depending on app/runtime.</li>
|
||
<li>On iOS, <code>network dump</code> can return zero HTTP entries for real app activity when the app does not emit request metadata into Unified Logging. The response notes now distinguish between an empty repro window and a non-network app log window.</li>
|
||
<li>On iOS, CFNetwork logs a request URL only on the line that opens a connection, so a request that reused a keep-alive connection has no URL anywhere in the log. Those requests are reported against the origin their connection was opened for, with <code>pathUnavailable: true</code>, their status, and their timing; ones whose connection was opened before the scanned window are counted in <code>unnamedRequests</code> instead, since they cannot be named at all. Treat a missing endpoint in an iOS dump as unproven rather than as evidence it was not called.</li>
|
||
<li>Retention knobs: set <code>AGENT_DEVICE_APP_LOG_MAX_BYTES</code> and <code>AGENT_DEVICE_APP_LOG_MAX_FILES</code> to override rotation limits.</li>
|
||
<li>Optional write-time redaction patterns: set <code>AGENT_DEVICE_APP_LOG_REDACT_PATTERNS</code> to a comma-separated regex list.</li>
|
||
</ul>
|
||
<p><strong>Crash symbols (bounded local symbolication):</strong> Use <code>debug symbols</code> when you already have an Apple crash artifact and local dSYMs and need the failing code path. The command matches crash Binary Images / IPS <code>usedImages</code> UUIDs to <code>dwarfdump --uuid</code> output, runs <code>atos</code>, writes a symbolicated artifact, and prints only the output path plus a compact crash report with app/thread, exception or termination, top symbolicated frames, and the first actionable frame finding. This is better than pasting raw crash logs because the agent sees the diagnosis and artifact path without ingesting the full crash body.</p>
|
||
<p>Crash routing: use <code>logs</code> for the lead-up timeline, <code>debug symbols</code> for a failing frame from <code>crash.ips</code>/<code>crash.log</code> plus matching dSYMs, and Xcode/LLDB for live state, breakpoints, variables, memory, or stepping.</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> debug</span><span style="color:var(--shiki-token-string)"> symbols</span><span style="color:var(--shiki-token-string)"> --artifact</span><span style="color:var(--shiki-token-string)"> crash.log</span><span style="color:var(--shiki-token-string)"> --dsym</span><span style="color:var(--shiki-token-string)"> MyApp.dSYM</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> crash-symbolicated.log</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> debug</span><span style="color:var(--shiki-token-string)"> symbols</span><span style="color:var(--shiki-token-string)"> --artifact</span><span style="color:var(--shiki-token-string)"> crash.ips</span><span style="color:var(--shiki-token-string)"> --search-path</span><span style="color:var(--shiki-token-string)"> ./build</span><span style="color:var(--shiki-token-string)"> --out</span><span style="color:var(--shiki-token-string)"> crash-symbolicated.ips</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>debug</code> is intentionally narrow: do not use it for app logs, network/audio evidence, performance samples, recordings, traces, or React Native internals.</li>
|
||
<li>Android Java/R8 <code>mapping.txt</code> and native <code>ndk-stack</code>/<code>addr2line</code> symbolication are deferred; capture Android crash evidence with <code>logs</code> and symbolicate externally for now.</li>
|
||
<li>The crash artifact body is written to <code>--out</code>; it is not dumped into agent context or default JSON.</li>
|
||
</ul>
|
||
<p><strong>Grepping app logs:</strong> Use <code>logs path</code> to get the file path, then run <code>grep</code> (or <code>grep -E</code>) on that path so only matching lines enter context—keeping token use low.</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-comment)"># Get path first (e.g. ~/.agent-device/sessions/default/app.log)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> logs</span><span style="color:var(--shiki-token-string)"> path</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-comment)"># Then grep the path; -n adds line numbers for reference</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">grep</span><span style="color:var(--shiki-token-string)"> -n</span><span style="color:var(--shiki-token-string-expression)"> "Error\|Exception\|Fatal"</span><span style="color:var(--shiki-token-string)"> ~/.agent-device/sessions/default/app.log</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">grep</span><span style="color:var(--shiki-token-string)"> -n</span><span style="color:var(--shiki-token-string)"> -E</span><span style="color:var(--shiki-token-string-expression)"> "Error|Exception|Fatal|crash"</span><span style="color:var(--shiki-token-string)"> ~/.agent-device/sessions/default/app.log</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">grep</span><span style="color:var(--shiki-token-string)"> -n</span><span style="color:var(--shiki-token-string)"> -E</span><span style="color:var(--shiki-token-string-expression)"> "agent-device.*mark|before submit"</span><span style="color:var(--shiki-token-string)"> ~/.agent-device/sessions/default/app.log</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:var(--shiki-token-comment)"># Last 50 lines only (bounded context)</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">tail</span><span style="color:var(--shiki-token-string)"> -50</span><span style="color:var(--shiki-token-string)"> ~/.agent-device/sessions/default/app.log</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li>
|
||
<p>Use <code>-n</code> to include line numbers. Use <code>-E</code> for extended regex and <code>|</code> without escaping in the pattern.</p>
|
||
</li>
|
||
<li>
|
||
<p>Prefer targeted patterns (e.g. <code>Error</code>, <code>Exception</code>, your log tags) over reading the whole file.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>logs mark "before submit"</code> lines are prefixed with <code>[agent-device][mark][...]</code>, so grep for <code>agent-device.*mark</code> when you need timing markers back quickly.</p>
|
||
</li>
|
||
<li>
|
||
<p>iOS <code>record</code> works on simulators and CoreDevice-backed physical devices.</p>
|
||
</li>
|
||
<li>
|
||
<p>iOS simulator recording uses native <code>simctl io ... recordVideo</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>Physical iOS device capture is runner-based and built from repeated <code>XCUIScreen.main.screenshot()</code> frames (no native video stream/audio capture).</p>
|
||
</li>
|
||
<li>
|
||
<p>App-scoped recording requires an active app session context (<code>open <app></code> first). Use <code>--scope device</code>/<code>--scope system</code> only when whole-screen capture is the intended artifact.</p>
|
||
</li>
|
||
<li>
|
||
<p>Physical iOS device capture is best-effort: dropped frames are expected and true 60 FPS is not guaranteed even with <code>--fps 60</code>.</p>
|
||
</li>
|
||
<li>
|
||
<p>Physical-device capture defaults to 15 FPS.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>--fps <n></code> (1-120) applies to physical iOS device recording as an explicit FPS cap.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>--quality <medium|high></code> controls recording output quality. Android maps it to <code>adb shell screenrecord --bit-rate</code>; Apple targets use it for export/encoding. <code>medium</code> is the default; pass <code>high</code> for evidence, release notes, or debugging visual artifacts. Legacy numeric values are still accepted for compatibility: <code>5</code>-<code>7</code> map to <code>medium</code>, and <code>8</code>-<code>10</code> map to <code>high</code>.</p>
|
||
</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="tracing"><a href="#tracing" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Tracing</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> start</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> start</span><span style="color:var(--shiki-token-string)"> session.trace</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> stop</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> trace</span><span style="color:var(--shiki-token-string)"> stop</span><span style="color:var(--shiki-token-string)"> session.trace</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>trace start [path]</code> begins trace-log capture for the active session.</li>
|
||
<li><code>trace stop [path]</code> stops capture and optionally writes or finalizes the trace artifact at the provided path.</li>
|
||
<li><code>trace</code> is intended for lower-level session diagnostics than <code>record</code> or <code>logs</code>.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="remote-metro-workflow"><a href="#remote-metro-workflow" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Remote Metro workflow</h2>
|
||
<p>When the cloud control plane owns the connection profile, connect can discover it directly:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> connect</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> com.example.myapp</span><span style="color:var(--shiki-token-string)"> --relaunch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> disconnect</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p>For local profile files, create an <code>agent-device.remote.json</code>:</p>
|
||
<div class="rp-codeblock language-json"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="json"><code><span class="line"><span style="color:var(--shiki-foreground)">{</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "daemonBaseUrl"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "https://bridge.example.com/agent-device"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "daemonTransport"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "http"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "tenant"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "acme"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "runId"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "run-123"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "session"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "adc-ios"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "sessionIsolation"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "tenant"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "platform"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "ios"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "leaseBackend"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "ios-instance"</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "metroProjectRoot"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "."</span><span style="color:var(--shiki-token-punctuation)">,</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-keyword)"> "metroProxyBaseUrl"</span><span style="color:var(--shiki-token-punctuation)">:</span><span style="color:var(--shiki-token-string-expression)"> "https://bridge.example.com"</span></span>
|
||
<span class="line"><span style="color:var(--shiki-foreground)">}</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> connect</span><span style="color:var(--shiki-token-string)"> --remote-config</span><span style="color:var(--shiki-token-string)"> ./agent-device.remote.json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> com.example.myapp</span><span style="color:var(--shiki-token-string)"> --relaunch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> disconnect</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<p>For self-contained scripts, pass the same profile to each step:</p>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> install-from-source</span><span style="color:var(--shiki-token-string)"> https://example.com/builds/Demo.app.zip</span><span style="color:var(--shiki-token-string)"> --remote-config</span><span style="color:var(--shiki-token-string)"> ./agent-device.remote.json</span><span style="color:var(--shiki-token-string)"> --platform</span><span style="color:var(--shiki-token-string)"> ios</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> open</span><span style="color:var(--shiki-token-string)"> com.example.myapp</span><span style="color:var(--shiki-token-string)"> --remote-config</span><span style="color:var(--shiki-token-string)"> ./agent-device.remote.json</span><span style="color:var(--shiki-token-string)"> --relaunch</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> snapshot</span><span style="color:var(--shiki-token-string)"> --remote-config</span><span style="color:var(--shiki-token-string)"> ./agent-device.remote.json</span><span style="color:var(--shiki-token-string)"> -i</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> disconnect</span><span style="color:var(--shiki-token-string)"> --remote-config</span><span style="color:var(--shiki-token-string)"> ./agent-device.remote.json</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>connect</code> without <code>--remote-config</code> authenticates to cloud when needed, fetches the connection profile, writes a generated local profile, stores the remote scope locally, and defers tenant lease allocation plus Metro preparation until a later command needs them.</li>
|
||
<li>Cloud connection profile responses must return a JSON object at <code>connection.remoteConfigProfile</code>. The older <code>connection.remoteConfig</code> JSON string shape is no longer accepted.</li>
|
||
<li><code>--remote-config <path></code> points to a local remote workflow profile that captures stable host, tenant/run, and any optional session, platform, lease backend, or Metro overrides for <code>connect</code>.</li>
|
||
<li><code>connect --remote-config ...</code> follows the same verification, state, and deferred-preparation flow using the local profile instead of cloud discovery. Direct-provider profiles therefore require their provider credentials when <code>connect</code> runs; no device lease is created until a later device command.</li>
|
||
<li>Auth management commands are available for inspection and recovery: <code>agent-device auth status</code>, <code>agent-device auth login</code>, and <code>agent-device auth logout</code>. Human login stores a revocable CLI session locally; it does not create or persist an <code>adc_live_...</code> service token.</li>
|
||
<li>Cloud auth uses three credential classes: <code>adc_agent_...</code> short-lived command tokens, revocable CLI session refresh credentials, and explicit <code>adc_live_...</code> service/API tokens for CI. The CLI implements credential selection, CI refusal, local storage permissions, logout, and output redaction; the cloud API must enforce token expiry, tenant/run scope, revocation, one-time device approval, polling rate limits, and dashboard/API separation.</li>
|
||
<li><code>AGENT_DEVICE_CLOUD_BASE_URL</code> should point at the bridge/control-plane API origin, not necessarily the dashboard origin. API-token setup links use <code>/api-keys</code> on that origin so the bridge can redirect users to the right dashboard page.</li>
|
||
<li>Deferred Metro preparation also applies to <code>batch</code> when any step opens an app and the batch does not provide its own per-step runtime.</li>
|
||
<li><code>connect</code> without <code>--session</code> always creates a fresh remote session. Its human and JSON next steps include the generated <code>--session</code>; concurrent processes must preserve that value on every command so they cannot adopt another process's ambient connection. The active connection fallback remains a convenience for one sequential workflow only. To replace a connection, pass its returned session explicitly with <code>--session <name> --force</code>; <code>--force</code> without a session creates another connection without overwriting or releasing the previous one.</li>
|
||
<li>After <code>connect</code>, <code>install-from-source</code>, <code>open</code>, <code>snapshot</code>, <code>devices</code>, <code>press</code>, <code>fill</code>, <code>screenshot</code>, and other normal commands can reuse active connection state in a single sequential workflow so agents do not repeat remote host/session/lease selectors inline. If <code>connection status</code> shows <code>leaseId=pending</code>, the first platform-bound command allocates or refreshes the lease. Passing the same <code>--remote-config</code> to a normal command is also supported for self-contained scripts; the CLI reuses matching saved state or creates it before dispatch.</li>
|
||
<li>Self-contained remote scripts should end with <code>disconnect --remote-config <path></code> or <code>disconnect</code> to release the lease and stop the owned Metro companion.</li>
|
||
<li>Explicit command-line flags override connected defaults. When <code>open</code> uses explicit remote daemon or tenant flags without saved runtime hints, the CLI warns because React Native apps may launch without Metro bundle/runtime hints.</li>
|
||
<li><code>metroProxyBaseUrl</code> is the bridge origin. Do not prebuild <code>/api/metro/...</code> paths in the client profile; the CLI calls the bridge endpoints itself.</li>
|
||
<li>For cloud stock React Native iOS, the bridge descriptor supplies direct wildcard HTTPS Metro hints such as <code><runtime>.metro.agent-device.dev:443</code>. The XCTest runner package is still used for runner-backed device commands, not for Metro reachability.</li>
|
||
<li>Android keeps using bridge-provided runtime routes such as <code>/api/metro/runtimes/<runtimeId>/...</code>.</li>
|
||
<li><code>metroPublicBaseUrl</code> is only needed for direct/non-bridge bundle hints. Bridged profiles can omit it and rely on <code>metroProxyBaseUrl</code>.</li>
|
||
<li><code>metro prepare --remote-config ...</code> remains an advanced inspection/debug path and can still write a <code>--runtime-file <path></code> artifact when needed.</li>
|
||
<li>The local Metro companion runs on the same machine as the React Native project and Metro. <code>disconnect</code> stops the companion owned by the connection, but it does not stop the user’s Metro server.</li>
|
||
</ul>
|
||
<h3 class="rp-toc-include" id="cloud-profile-response-migration"><a href="#cloud-profile-response-migration" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Cloud profile response migration</h3>
|
||
<p><code>/api/control-plane/connection-profile</code> must return an object at <code>connection.remoteConfigProfile</code>, for example <code>{"connection":{"remoteConfigProfile":{"daemonBaseUrl":"https://bridge.example.com/agent-device","daemonTransport":"http","tenant":"acme","runId":"run-123"}}}</code>. The old <code>connection.remoteConfig</code> JSON-string wrapper is rejected.</p>
|
||
<h2 class="rp-toc-include" id="session-inspection"><a href="#session-inspection" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Session inspection</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> session</span><span style="color:var(--shiki-token-string)"> list</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> session</span><span style="color:var(--shiki-token-string)"> list</span><span style="color:var(--shiki-token-string)"> --json</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>session list</code> shows active daemon sessions for the caller's implicit workspace scope, or the explicitly named session scope when <code>--session</code> / <code>AGENT_DEVICE_SESSION</code> is configured.</li>
|
||
<li>Use <code>--json</code> when you want to inspect or script against the raw session metadata.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="cloud-provider-artifacts"><a href="#cloud-provider-artifacts" class="rp-header-anchor rp-link" aria-hidden="true">#</a>Cloud provider artifacts</h2>
|
||
<div class="rp-codeblock language-bash"><div class="rp-codeblock__content"><div class="rp-codeblock__content__scroll-container rp-scrollbar rp-scrollbar--always"><pre class="shiki css-variables" style="background-color:var(--shiki-background);color:var(--shiki-foreground)" tabindex="0" data-lang="bash"><code><span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> artifacts</span><span style="color:var(--shiki-token-string)"> --provider</span><span style="color:var(--shiki-token-string)"> browserstack</span><span style="color:var(--shiki-token-string)"> --provider-session</span><span style="color:var(--shiki-token-keyword)"> <</span><span style="color:var(--shiki-token-string)">webdriver-session-i</span><span style="color:var(--shiki-foreground)">d</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-token-string)"> --json</span></span>
|
||
<span class="line"><span style="color:var(--shiki-token-function)">agent-device</span><span style="color:var(--shiki-token-string)"> artifacts</span><span style="color:var(--shiki-token-string)"> --provider</span><span style="color:var(--shiki-token-string)"> aws-device-farm</span><span style="color:var(--shiki-token-string)"> --provider-session</span><span style="color:var(--shiki-token-keyword)"> <</span><span style="color:var(--shiki-token-string)">remote-access-session-ar</span><span style="color:var(--shiki-foreground)">n</span><span style="color:var(--shiki-token-keyword)">></span><span style="color:var(--shiki-token-string)"> --json</span></span></code></pre></div><div class="rp-code-button-group"><button class="rp-code-button-group__button rp-code-wrap-button" title="Toggle code wrap"><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrapped"><path fill="currentColor" d="M21 5H3v2h18zM3 19h7v-2H3zm0-6h15c1 0 2 .43 2 2s-1 2-2 2h-2v-2l-4 3 4 3v-2h2c2.95 0 4-1.27 4-4 0-2.72-1-4-4-4H3z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" class="rp-code-button-group__icon rp-code-button-group__icon--wrap"><path fill="currentColor" d="M16 7H3V5h13zM3 19h13v-2H3zm19-7-4-3v2H3v2h15v2z"></path></svg></button><button class="rp-code-button-group__button rp-code-copy-button" title="Copy code"><svg xmlns="http://www.w3.org/2000/svg" width="272" height="272" viewBox="0 0 272 272" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--copy"><path fill="currentColor" fill-rule="evenodd" d="M45.883 23.368h123.823v22.514H68.396v146.336H45.883zm45.026 45.027H225.99v180.107H90.91zm22.514 22.513v135.08h90.053V90.908z" clip-rule="evenodd"></path></svg><svg xmlns="http://www.w3.org/2000/svg" width="271" height="271" viewBox="0 0 271 271" class="rp-code-button-group__icon rp-code-copy-button__icon rp-code-copy-button__icon--success"><path fill="currentColor" d="M112.687 203.223H90.174v-22.514h22.512v-22.514h22.512v22.514h-22.511zm-22.514-22.514H67.66v-22.514h22.513zm-22.514-22.514H45.146v-22.512H67.66zm90.054 0h-22.514v-22.512h22.514zm22.514-22.512h-22.514v-22.514h22.514zm22.513-22.514h-22.513V90.655h22.513zm22.514-22.514H202.74V68.143h22.514z"></path></svg></button></div></div></div>
|
||
<ul>
|
||
<li><code>artifacts</code> lists provider-hosted cloud artifacts such as videos, Appium logs, device logs, automation logs, and provider dashboard links.</li>
|
||
<li>The response uses <code>cloudArtifacts</code> so it stays separate from daemon-managed local <code>artifacts</code> returned by screenshot, recording, install, replay, and remote materialization flows.</li>
|
||
<li>Plain text output prints ready provider URLs. Use <code>--json</code> when scripts need the structured <code>cloudArtifacts</code> array.</li>
|
||
<li>Historical lookup requires <code>--provider-session <id></code> and <code>--provider <name></code>. BrowserStack uses <code>BROWSERSTACK_USERNAME</code> and <code>BROWSERSTACK_ACCESS_KEY</code>. AWS Device Farm uses the AWS CLI credential chain and infers the region from the session ARN when possible. See <a href="/agent-device/docs/browserstack" class="rp-link">BrowserStack</a> and <a href="/agent-device/docs/aws-device-farm" class="rp-link">AWS Device Farm</a> for CI credential setup.</li>
|
||
<li>When a cloud runtime is registered in-process by an embedding host, <code>artifacts</code> can infer the active provider session from the current lease before disconnect.</li>
|
||
<li><code>disconnect --json</code> and <code>close --json</code> include provider release data when the runtime returns final cloud artifacts after session teardown. Some providers only finalize video/log URLs after the remote session is stopped, so retry <code>agent-device artifacts <provider-session-id> --provider <name> --json</code> if the first response is <code>pending</code>.</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="ios-physical-device-prerequisites"><a href="#ios-physical-device-prerequisites" class="rp-header-anchor rp-link" aria-hidden="true">#</a>iOS physical-device prerequisites</h2>
|
||
<p>For CLI-discoverable setup guidance, run <code>agent-device help physical-device</code>.</p>
|
||
<ul>
|
||
<li>Xcode with <code>xcrun devicectl</code> and <code>xcrun xctrace</code> available.</li>
|
||
<li>Paired/trusted physical device, connected, unlocked when needed, with Developer Mode enabled.</li>
|
||
<li>Older devices discovered only through <code>xctrace</code> use the XCTest backend automatically; its runner commands travel through macOS <code>usbmuxd</code>, so keep the device connected by cable.</li>
|
||
<li>XCTest-backed devices support open/close, interactions, snapshots, and screenshots. App inventory, install/reinstall, logs, performance sampling, recording, deep links, and launch arguments require CoreDevice.</li>
|
||
<li>The <code>AgentDeviceRunner</code> XCTest host must be signed before commands can run on a physical device.</li>
|
||
<li>Start with Automatic Signing and only these env vars:
|
||
<ul>
|
||
<li><code>AGENT_DEVICE_IOS_TEAM_ID</code></li>
|
||
<li><code>AGENT_DEVICE_IOS_BUNDLE_ID</code> (runner bundle-id base; tests use <code><id>.uitests</code>)</li>
|
||
</ul>
|
||
</li>
|
||
<li>Find team ids and Apple Development signing certificates with <code>security find-identity -v -p codesigning</code>.</li>
|
||
<li>If Xcode cannot choose a profile, set <code>AGENT_DEVICE_IOS_PROVISIONING_PROFILE</code> to the profile name/specifier, not a file path.</li>
|
||
<li><code>AGENT_DEVICE_IOS_SIGNING_IDENTITY</code> is optional; omit it unless <code>xcodebuild</code> asks for a specific identity.</li>
|
||
<li>The profile/team must allow <code>AGENT_DEVICE_IOS_BUNDLE_ID</code> and <code><id>.uitests</code>.</li>
|
||
<li>First-run XCTest setup/build can take longer than normal commands; keep the device connected and use <code>--debug</code> to inspect signing/build diagnostics if setup times out.</li>
|
||
<li>If you override the iOS runner derived-data path and also force cleanup, keep <code>AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH</code> under the project <code>.tmp/</code> directory. Other cleanup override paths are rejected with a recovery hint.</li>
|
||
<li>For daemon startup troubleshooting:
|
||
<ul>
|
||
<li>follow stale metadata hints for <code><state-dir>/daemon.json</code> and <code><state-dir>/daemon.lock</code> (<code>state-dir</code> defaults to <code>~/.agent-device</code> for packaged installs, or a worktree-scoped dir under <code>~/.agent-device/dev/</code> from source)</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<h2 class="rp-toc-include" id="ios-springboard-widgets-and-system-ui-surfaces"><a href="#ios-springboard-widgets-and-system-ui-surfaces" class="rp-header-anchor rp-link" aria-hidden="true">#</a>iOS SpringBoard, widgets, and system-UI surfaces</h2>
|
||
<p>For CLI-discoverable workflow guidance, run <code>agent-device help ios-system-ui</code>.</p>
|
||
<ul>
|
||
<li><code>agent-device open com.apple.springboard --platform ios</code> binds the session to SpringBoard today; this is verified on iOS simulator only. Physical-iPhone SpringBoard support is not yet verified — see <a href="https://github.com/callstack/agent-device/issues/1296" target="_blank" rel="noopener noreferrer" class="rp-link">#1296</a>.</li>
|
||
<li>The full widget add/edit/remove flow is selector-driven from a fresh <code>snapshot -i</code>, except two coordinate-based steps: the empty-space long-press that enters edit mode, and (until fixed) the widget-gallery search-result rows, which currently return unlabeled accessibility nodes.</li>
|
||
<li>SpringBoard labels vary by iOS version and locale; discover them from the current snapshot rather than hard-coding strings like <code>Edit</code> or <code>Add Widget</code>.</li>
|
||
<li>Reopen the app bundle under test to return to normal app automation after a SpringBoard step.</li>
|
||
</ul><!--/$--></div><div class="container-uhcWmO"><img class="logo-IwzwG8" src="/agent-device/static/image/abstract-atom.4eca0300ff.avif" alt="Abstract Logo" aria-hidden="true"/><div class="content-uJxcIj"><div class="headlineContainer-NHNT4y"><h1 class="headline-iCUUUl">Need React or React Native
|
||
expertise you can count on?</h1></div><div class="buttonContainer-wOj8Y6"><div class="dark"><a href="https://www.callstack.com/contact?utm_campaign=open_source&utm_source=agent-device&utm_medium=referral&utm_content=FOOTER_CTA" class="button-DogSnd brand-rT2ahT ">Let's talk<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16" class="button-icon-Okk0hT" aria-hidden="true" focusable="false"><path fill="currentColor" d="M9.333 13.333h1.334V12H9.333zm-6.666-2.666h8V12H12v-1.333h1.333V9.333H12V8h-1.333v1.333H4V2.667H2.667zM9.333 8h1.334V6.667H9.333z"></path></svg></a></div></div></div></div><footer class="rp-doc-footer"><div class="rp-doc-footer__edit"><a href="https://github.com/callstack/agent-device/edit/main/website/docs/commands.md" target="_blank" rel="noopener noreferrer" class="rp-edit-link rp-link">Edit this page on GitHub</a></div><div class="rp-doc-footer__divider"></div><div class="container-aZLxg0"><a href="/agent-device/docs/quick-start" class="pagerLink-_WIlZJ rp-link"><span class="iconBox-AUO0Le"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24" class="icon-WRLCnG"><path d="M4 20h2V4H4zm8-5v2h2v-2zm-2-4H8v2h2v2h2v-2h8v-2h-8V9h-2zm2-2h2V7h-2z"></path></svg></span><span class="textWrap-lmdyLc"><span class="desc-sp3vRh">Previous page</span><span class="title-hrit_i">Quick Start</span></span></a><a href="/agent-device/docs/configuration" class="pagerLink-_WIlZJ next-axkYXz rp-link"><span class="textWrap-lmdyLc"><span class="desc-sp3vRh">Next page</span><span class="title-hrit_i">Configuration</span></span><span class="iconBox-AUO0Le"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24" class="icon-WRLCnG"><path d="M20 20h-2V4h2zm-8-5v2h-2v-2zm2-4h2v2h-2v2h-2v-2H4v-2h8V9h2zm-2-2h-2V7h2z"></path></svg></span></a></div></footer></main></div><aside class="rp-doc-layout__outline rp-scrollbar"><div class="rp-outline"><div class="rp-outline__title">Contents<svg width="14" height="14" class="rp-progress-circle"><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-divider-light)" stroke-width="2"></circle><circle cx="7" cy="7" r="6" stroke-linecap="round" fill="none" stroke="var(--rp-c-brand)" stroke-width="2" stroke-dasharray="37.69911184307752" stroke-dashoffset="37.69911184307752" transform="rotate(-90 7 7)" style="transition:stroke-dashoffset 0.3s"></circle></svg></div><nav class="rp-outline__toc rp-scrollbar"><a href="#navigation" class="rp-toc-item rp-link" title="Navigation" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Navigation</span></a><a href="#human-takeover" class="rp-toc-item rp-link" title="Human Takeover" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Human Takeover</span></a><a href="#web-automation" class="rp-toc-item rp-link" title="Web Automation" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Web Automation</span></a><a href="#device-isolation-scopes" class="rp-toc-item rp-link" title="Device isolation scopes" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Device isolation scopes</span></a><a href="#device-discovery" class="rp-toc-item rp-link" title="Device discovery" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Device discovery</span></a><a href="#harmonyos-command-boundary" class="rp-toc-item rp-link" title="HarmonyOS command boundary" style="padding-left:12px" data-depth="1"><span class="rp-toc-item__text rp-doc">HarmonyOS command boundary</span></a><a href="#diagnostics" class="rp-toc-item rp-link" title="Diagnostics" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Diagnostics</span></a><a href="#prepare-apple-runner" class="rp-toc-item rp-link" title="Prepare Apple runner" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Prepare Apple runner</span></a><a href="#tv-targets" class="rp-toc-item rp-link" title="TV targets" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">TV targets</span></a><a href="#desktop-targets" class="rp-toc-item rp-link" title="Desktop targets" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Desktop targets</span></a><a href="#snapshot-and-inspect" class="rp-toc-item rp-link" title="Snapshot and inspect" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Snapshot and inspect</span></a><a href="#wait-and-alerts" class="rp-toc-item rp-link" title="Wait and alerts" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Wait and alerts</span></a><a href="#interactions" class="rp-toc-item rp-link" title="Interactions" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Interactions</span></a><a href="#find-semantic" class="rp-toc-item rp-link" title="Find (semantic)" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Find (semantic)</span></a><a href="#assertions" class="rp-toc-item rp-link" title="Assertions" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Assertions</span></a><a href="#replay" class="rp-toc-item rp-link" title="Replay" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Replay</span></a><a href="#batch" class="rp-toc-item rp-link" title="Batch" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Batch</span></a><a href="#app-install-in-place" class="rp-toc-item rp-link" title="App install (in-place)" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">App install (in-place)</span></a><a href="#app-reinstall-fresh-state" class="rp-toc-item rp-link" title="App reinstall (fresh state)" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">App reinstall (fresh state)</span></a><a href="#app-install-from-source-url" class="rp-toc-item rp-link" title="App install from source URL" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">App install from source URL</span></a><a href="#push-notification-simulation" class="rp-toc-item rp-link" title="Push notification simulation" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Push notification simulation</span></a><a href="#app-event-triggers-app-hook" class="rp-toc-item rp-link" title="App event triggers (app hook)" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">App event triggers (app hook)</span></a><a href="#settings-helpers" class="rp-toc-item rp-link" title="Settings helpers" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Settings helpers</span></a><a href="#app-state-and-app-lists" class="rp-toc-item rp-link" title="App state and app lists" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">App state and app lists</span></a><a href="#clipboard" class="rp-toc-item rp-link" title="Clipboard" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Clipboard</span></a><a href="#keyboard" class="rp-toc-item rp-link" title="Keyboard" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Keyboard</span></a><a href="#performance-diagnostics" class="rp-toc-item rp-link" title="Performance diagnostics" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Performance diagnostics</span></a><a href="#react-native-component-internals" class="rp-toc-item rp-link" title="React Native component internals" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">React Native component internals</span></a><a href="#multiple-react-native-worktrees" class="rp-toc-item rp-link" title="Multiple React Native worktrees" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Multiple React Native worktrees</span></a><a href="#metro-reload" class="rp-toc-item rp-link" title="Metro reload" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Metro reload</span></a><a href="#media-and-logs" class="rp-toc-item rp-link" title="Media and logs" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Media and logs</span></a><a href="#tracing" class="rp-toc-item rp-link" title="Tracing" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Tracing</span></a><a href="#remote-metro-workflow" class="rp-toc-item rp-link" title="Remote Metro workflow" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Remote Metro workflow</span></a><a href="#cloud-profile-response-migration" class="rp-toc-item rp-link" title="Cloud profile response migration" style="padding-left:12px" data-depth="1"><span class="rp-toc-item__text rp-doc">Cloud profile response migration</span></a><a href="#session-inspection" class="rp-toc-item rp-link" title="Session inspection" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Session inspection</span></a><a href="#cloud-provider-artifacts" class="rp-toc-item rp-link" title="Cloud provider artifacts" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">Cloud provider artifacts</span></a><a href="#ios-physical-device-prerequisites" class="rp-toc-item rp-link" title="iOS physical-device prerequisites" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">iOS physical-device prerequisites</span></a><a href="#ios-springboard-widgets-and-system-ui-surfaces" class="rp-toc-item rp-link" title="iOS SpringBoard, widgets, and system-UI surfaces" style="padding-left:0" data-depth="0"><span class="rp-toc-item__text rp-doc">iOS SpringBoard, widgets, and system-UI surfaces</span></a></nav><div class="rp-outline__divider"></div><div class="rp-outline__bottom"><a href="https://github.com/callstack/agent-device/edit/main/website/docs/commands.md" target="_blank" rel="noopener noreferrer" class="rp-outline__action-row rp-edit-link rp-link"><svg width="16" height="16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5z"></path></svg><span>Edit this page on GitHub</span></a></div></div><div class="container-LzbylO"><div><div class="headline-y75_LS">Curious about developing mobile apps with AI agents?</div><div class="description-muYVs3">We can help you take your agentic workflows to the next level and ship faster.</div></div><a href="https://www.callstack.com/contact?utm_campaign=open_source&utm_source=agent-device&utm_medium=referral&utm_content=OUTLINE_CTA" class="button-DogSnd brand-rT2ahT ">Book a call<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none" viewBox="0 0 16 16" class="button-icon-Okk0hT" aria-hidden="true" focusable="false"><path fill="currentColor" d="M9.333 13.333h1.334V12H9.333zm-6.666-2.666h8V12H12v-1.333h1.333V9.333H12V8h-1.333v1.333H4V2.667H2.667zM9.333 8h1.334V6.667H9.333z"></path></svg></a></div></aside></div></div>
|
||
<div id="__rspress_modal_container"></div>
|
||
</body>
|
||
</html>
|