{"id":51340401,"url":"https://github.com/andriyo/shadowdroid","last_synced_at":"2026-07-02T07:01:27.061Z","repository":{"id":361282990,"uuid":"1247345551","full_name":"andriyo/ShadowDroid","owner":"andriyo","description":"ShadowDroid — fast, agent-friendly Android UI automation CLI. Lets AI coding agents drive, inspect, and debug real Android apps and emulators via JSON. An Appium/Maestro alternative built for live agent loops.","archived":false,"fork":false,"pushed_at":"2026-06-26T06:35:26.000Z","size":767,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T08:15:19.805Z","etag":null,"topics":["adb","agentic","ai-agents","android","android-automation","android-studio","android-studio-plugin","appium-alternative","cli","debugger","jetpack-compose","llm","mitm-proxy","mobile-testing","proxy","rust","ui-automation","uiautomator"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andriyo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-23T07:29:02.000Z","updated_at":"2026-06-26T06:35:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/andriyo/ShadowDroid","commit_stats":null,"previous_names":["andriyo/shadowdroid"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/andriyo/ShadowDroid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andriyo%2FShadowDroid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andriyo%2FShadowDroid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andriyo%2FShadowDroid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andriyo%2FShadowDroid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andriyo","download_url":"https://codeload.github.com/andriyo/ShadowDroid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andriyo%2FShadowDroid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35036553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adb","agentic","ai-agents","android","android-automation","android-studio","android-studio-plugin","appium-alternative","cli","debugger","jetpack-compose","llm","mitm-proxy","mobile-testing","proxy","rust","ui-automation","uiautomator"],"created_at":"2026-07-02T07:01:26.431Z","updated_at":"2026-07-02T07:01:27.039Z","avatar_url":"https://github.com/andriyo.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ShadowDroid\n\n**An agent-first Android control plane** for UI automation, app/device control,\nlayout inspection, debugger access, diagnostics, and HTTP(S) interception.\n\n[![Latest release](https://img.shields.io/github/v/release/andriyo/ShadowDroid?sort=semver\u0026display_name=tag\u0026label=release\u0026color=blue)](https://github.com/andriyo/ShadowDroid/releases/latest)\n[![License: Apache-2.0](https://img.shields.io/github/license/andriyo/ShadowDroid?color=blue)](LICENSE)\n[![Platform: Android](https://img.shields.io/badge/platform-Android-3DDC84?logo=android\u0026logoColor=white)](#install)\n[![Built with Rust](https://img.shields.io/badge/built%20with-Rust-CE422B?logo=rust\u0026logoColor=white)](#how-it-works)\n\nShadowDroid is an open-source **Android automation and debugging CLI for AI\nagents**. It lets coding agents such as Claude Code, Cursor, Codex, Gemini, and\nAntigravity drive, inspect, and debug real Android apps and emulators through a\nfast, JSON-first command line — no test DSL, no client library, no Appium server.\n\nShadowDroid turns a real Android device or emulator into a structured surface an\nAI agent can read and act on. It pairs a Rust binary on your laptop with a tiny\nKotlin instrumentation service on the device, then exposes UI state, app\nlifecycle, device controls, permissions, files, display profile, toasts,\ncrashes, HTTP(S) traffic, Android Studio debugger state, Layout Inspector data,\nand an optional in-app debug AAR through one CLI.\n\nIn the tight loop, the agent reads the screen as a flat list of elements, taps /\ntypes / swipes / scrolls **by selector**, waits for state to settle, streams\nscreen changes, crashes, toasts, and network events, and drops into\nAndroid Studio-backed debugging or Compose layout inspection when it needs to\nunderstand why the app behaved that way. Core UI reads are roughly **25 ms per\ndump**, fast enough that the agent loop does not stall.\n\nThere's no test DSL and no extra runtime to babysit — just the CLI and `adb`.\nAutomation commands are structured and JSON-first: `shadowdroid ui …` for live\nUI automation, `shadowdroid app …` for app lifecycle, `shadowdroid net …` for\nHTTP(S) traffic, `shadowdroid debug …` for runtime causality, `shadowdroid\nlayout …` for hierarchy/source/recomposition data, and `shadowdroid aar …` for\nabove-TLS in-app capture. The machine-readable source of truth is\n`shadowdroid commands --json`.\n\n```jsonc\n$ shadowdroid ui dump\n{\"screen_hash\":\"a1b2…\",\"viewport\":{\"w\":1080,\"h\":2424},\"current_app\":{…},\"element_count\":42,\n \"elements\":[{\"id\":7,\"rid\":\"main_tab_profile\",\"tap\":[980,2256],\"clickable\":true}, …]}\n\n$ shadowdroid ui tap --rid main_tab_profile\n{\"type\":\"action\",\"cmd\":\"tap\",\"via\":\"selector\",\"x\":980,\"y\":2256,\"matched\":true}\n\n$ shadowdroid ui wait --text \"Welcome back\" --timeout-ms 5000\n{\"type\":\"action\",\"cmd\":\"wait\",\"matched\":true,\"gone\":false,\"screen_hash\":\"c3d4…\"}\n```\n\n\u003e Android-only by design, and not a test framework — ShadowDroid is the fast,\n\u003e observable layer an agent drives directly against a running app.\n\n## Key benefits\n\n- **The agent loop never stalls** — a persistent on-device service answers core\n  UI reads in ~25 ms, versus ~500 ms to 1 s for `adb shell uiautomator dump`.\n- **No test DSL, no SDK, no Appium server** — if your agent can run a shell\n  command and parse JSON, it can drive Android.\n- **Robust, selector-based actions** — tap / type / swipe / scroll by `--rid`,\n  `--text`, `--desc`, or `--xpath`, so flows survive layout changes instead of\n  breaking on hard-coded coordinates.\n- **Full Android operator surface** — app install/start/stop/clear/info, runtime\n  permissions, app-ops, device power/orientation/clipboard/notifications,\n  display profiles, and on-device file push/pull live in the same CLI.\n- **First-class Jetpack Compose support** — a semantics-aware element tree\n  (AndroidX UI Automator 2.3.0+), enriched with Compose source locations and\n  recomposition counts when Android Studio's Layout Inspector is live.\n- **Sees _why_, not just _what_** — a read-only Android Studio debugger exposed as\n  JSON: breakpoints, call stack, threads, variables, watches, bounded expression\n  eval, native/tombstone readiness, and conservative coroutine insight.\n- **One live event stream** — `watch` emits screen diffs, crashes, toasts,\n  popup-watcher actions, and decrypted HTTP(S) on a single timeline.\n- **Built-in HTTP(S) interception** — a host-side MITM proxy built into the\n  binary; an optional debug-only in-app AAR reaches pinned / Cronet / QUIC\n  traffic above TLS with no CA.\n- **Self-describing and agent-ready** — `shadowdroid commands --json` emits the\n  whole catalog with agent decision hints, and one command installs skills for\n  Claude Code, Cursor, Codex, Gemini, and Antigravity.\n- **Trivial to install, safe to run** — a single native binary plus a tiny,\n  SHA-256-verified APK; macOS / Linux / Windows hosts; real devices, emulators, and\n  Android TV / leanback.\n\n## Contents\n\n- [Why it exists](#why-it-exists)\n- [How it works](#how-it-works)\n- [Install](#install)\n- [Connect](#connect)\n- [How agents should use ShadowDroid](#how-agents-should-use-shadowdroid)\n- [What you can drive](#what-you-can-drive)\n- [Agent debugging](#agent-debugging)\n- [Agent integration](#agent-integration)\n- [FAQ](#faq)\n- [License](#license)\n\n## Why it exists\n\nTo drive a *running* app in a tight agent loop, the tools you'd otherwise reach\nfor each fall short:\n\n| Tool                              | Gap for a live agent loop                                                          |\n| --------------------------------- | --------------------------------------------------------------------------------- |\n| `adb shell uiautomator dump`      | ~500ms–1s per dump — the loop stalls between every step.                           |\n| `adb shell input tap`             | Stateless: no idea what's on screen, fragile to any layout change.                 |\n| `android` CLI (`layout`/`screen`) | Built for project create / build / run / SDK — and great at it. But for live UI, each `layout` call runs a fresh `ui-dump` (the slow path): no persistent service, no streaming loop, no interaction-by-selector, no crash/popup events, no agent debugger. |\n\nShadowDroid is the **complement, not a replacement**. Keep using the `android`\nCLI to scaffold, build, deploy, and manage the SDK — then hand the *running* app\nto ShadowDroid. A persistent on-device service keeps dumps at ~25ms, a streaming\nJSON event model lets the agent follow the app live, and it ships with\n**first-class Jetpack Compose support** (AndroidX UI Automator 2.3.0+),\n**built-in crash detection**, **declarative popup watchers**, and — uniquely — an\n**agent-facing Android Studio debugger** (see [Agent debugging](#agent-debugging)).\nIt even follows the `android` CLI's own conventions (`init`, `skill`, `layout`,\n`studio`), so it slots in right beside it.\n\n## How it works\n\n```\n        Laptop                         adb forward                Android device\n  ┌───────────────────────┐         tcp:7912 ⇆ 7912         ┌───────────────────────────┐\n  │  shadowdroid (Rust)   │  ── HTTP + JSON (loopback) ──▶  │  instrumentation APK      │\n  │  • clap CLI           │                                 │  • Ktor 3 / CIO server    │\n  │  • XML → element JSON │ ◀────────  adb logcat  ──────── │  • UiDevice (AndroidX     │\n  │  • watch/crash/watcher│                                 │    UI Automator 2.3.0+)   │\n  └───────────────────────┘                                 └───────────────────────────┘\n```\n\nThe on-device APK is a **stateless RPC over UI Automator** — it just exposes\n`UiDevice.click / swipe / dump` and a toast monitor over HTTP. All *policy* lives\non the laptop: the dump-then-diff watch loop, crash parsing from logcat, the\nwatcher rule engine, and the XML→JSON transform. That keeps the APK tiny and lets\nit rev independently of the CLI.\n\nOptional integrations extend the same command surface:\n\n- The Android Studio plugin exposes debugger state and Layout Inspector models to\n  `shadowdroid debug ...` and `shadowdroid layout ...`.\n- The built-in host-side MITM proxy wires through `adb reverse` and device proxy\n  settings so `shadowdroid net ...` can inspect, intercept, mutate, and replay\n  HTTP(S) traffic.\n- The debug-only in-app AAR auto-installs through a merged `ContentProvider` in\n  apps you can build, giving `shadowdroid aar ...` above-TLS capture and\n  interception for pinned, Cronet, and QUIC traffic.\n\nOn the first `connect`, the CLI auto-installs a **version-matched APK pair**\n(downloaded from the matching GitHub Release, SHA-256 verified, cached under\n`~/.shadowdroid/`), runs `adb forward`, and starts the instrumentation. Later\ncalls just probe `GET /v1/state` and reuse the live server, so steady-state\nlatency stays low.\n\nAt the wire level the server is a loopback HTTP/JSON API, but the supported\npublic interface for agents is the CLI surface and `shadowdroid commands --json`.\n\n## Install\n\nHomebrew:\n\n```bash\nbrew install andriyo/tap/shadowdroid\n```\n\nmacOS / Linux:\n\n```bash\ncurl --proto '=https' --tlsv1.2 -LsSf https://github.com/andriyo/ShadowDroid/releases/latest/download/shadowdroid-installer.sh | sh\n```\n\nScoop:\n\n```powershell\nscoop bucket add andriyo https://github.com/andriyo/scoop-bucket\nscoop install shadowdroid\n```\n\nWindows PowerShell:\n\n```powershell\npowershell -ExecutionPolicy Bypass -c \"irm https://github.com/andriyo/ShadowDroid/releases/latest/download/shadowdroid-installer.ps1 | iex\"\n```\n\nShadowDroid also requires Android Platform Tools (`adb`) on PATH — the\ninstallers print a hint if it's missing. On macOS:\n`brew install --cask android-platform-tools`; on Windows: `scoop install adb`.\nThe direct shell/PowerShell installers also seed global agent skills; for\npackage-manager installs, run `shadowdroid init` once.\n\nFor manual installs, use the assets attached to the latest GitHub Release.\n\n## Connect\n\nStart an emulator or plug in a device with USB debugging, then:\n\n```bash\nshadowdroid devices        # list attached devices / emulators\nshadowdroid connect        # install the on-device server, forward, and verify\n```\n\nOn first `connect`, the CLI downloads the matching instrumentation APKs from the\nGitHub Release, verifies them with SHA-256, caches them under\n`~/.shadowdroid/apks/\u003cversion\u003e/`, and installs them on the device. When working\ninside this repo it auto-discovers local Gradle build outputs before falling\nback to cached or release APKs.\n\nKeep the CLI current and diagnose a flaky pipe:\n\n```bash\nshadowdroid update --check  # compare against the latest GitHub Release\nshadowdroid doctor          # diagnose device state, APK version, forward, server\nshadowdroid doctor --fix    # attempt repairs (reinstall, re-forward, restart)\nshadowdroid collect         # bundle a self-contained diagnostic snapshot\n```\n\n\u003e **Running instrumentation tests?** While connected, ShadowDroid holds the\n\u003e device's single `UiAutomation` slot, so Espresso / UI Automator tests\n\u003e (`AndroidJUnitRunner`) fail with `UiAutomationService ... already registered!`.\n\u003e Run `shadowdroid disconnect` before the test run, then `shadowdroid connect`\n\u003e again. `connect` reports this in its `ui_automation` field and `doctor` shows\n\u003e the current slot owner.\n\nInitialize host integrations (Android Studio plugin for debugger + layout,\nplus agent skills):\n\n```bash\nshadowdroid init                    # install/update Studio plugin + agent skills\nshadowdroid init --no-studio-plugin # only inspect Studio and install skills\n```\n\nPut repeated values in config instead of spending prompt/context on every\ncommand. ShadowDroid loads `~/.shadowdroid/config.json` first, then\n`.shadowdroid.json` files from the current directory's ancestors, with the\nnearest project file winning:\n\n```bash\nshadowdroid config schema --json\nshadowdroid config init --project --app Livd --package com.livd --project-path /Users/you/Work/Livd\nshadowdroid config validate --json\n```\n\n```json\n{\n  \"device\": \"emulator-5554\",\n  \"app\": \"Livd\",\n  \"project\": \"/Users/you/Work/Livd\",\n  \"apps\": {\n    \"Livd\": {\n      \"package\": \"com.livd\",\n      \"run_configuration\": \"app\",\n      \"debugger\": \"Android Debugger\"\n    }\n  }\n}\n```\n\n## How agents should use ShadowDroid\n\nThis section is intentionally explicit for LLMs and coding agents. Treat it as\nthe canonical operating contract:\n\n1. Discover the live command surface with `shadowdroid commands --json`. Do not\n   invent command names from memory or scrape prose when the catalog is available.\n2. Put repeated app context in config with `shadowdroid config init ...`, then\n   verify with `shadowdroid config validate --json`. Use app aliases instead of\n   spending tokens on package/project/debugger flags every time.\n3. Establish the device pipe with `shadowdroid connect`; if it fails, run\n   `shadowdroid doctor --json`, then `shadowdroid doctor --fix` only when repair\n   side effects are acceptable.\n4. Use `shadowdroid ui dump` for the current actionable tree. Prefer `--rid`,\n   `--desc`, and exact text selectors over coordinates. Use coordinate taps only\n   as a last resort.\n5. Use `shadowdroid watch` when the task depends on time: screen changes,\n   crashes, ANRs, toasts, popup watcher actions, and network events in one JSONL\n   stream.\n6. Use `shadowdroid layout snapshot --compose --semantics --source-map` and\n   `shadowdroid layout recompositions` when Android Studio Layout Inspector is\n   active and the task needs Compose source, semantics, or recomposition data.\n7. Use `shadowdroid debug auto`, `debug snapshot`, and targeted `debug break` /\n   `debug stack` / `debug variables` / `debug eval` when the agent needs runtime\n   causality instead of more UI polling.\n8. Use `shadowdroid net ...` for proxy-aware HTTP(S) capture, mutation, rules,\n   HAR/curl export, fixtures, and replay. Use `shadowdroid aar ...` for apps you\n   can build when pinned TLS, Cronet, QUIC, or above-TLS interception matters.\n9. Use `shadowdroid test -- \u003cyour instrumentation command\u003e` or\n   `shadowdroid disconnect` before running Espresso / UI Automator tests, because\n   Android only allows one `UiAutomation` owner at a time.\n10. When handing off a failure, run `shadowdroid collect` to produce a bundle\n    with doctor output, device info, logcat/crash context, screenshot, screen\n    dump, and app state when available.\n\nOutput rules for agents:\n\n- Command results go to **stdout**. ShadowDroid operational logs go to\n  **stderr**. Add `--quiet` or `SHADOWDROID_QUIET=1` for the cleanest JSON.\n- Many automation commands emit a single JSON object/event. Setup and diagnostic\n  commands that default to human output usually provide `--json`; prefer that\n  flag in autonomous flows.\n- Selector actions are strict. If a selector matches several nodes and none is\n  an exact match, ShadowDroid returns a structured `ambiguous_match` error rather\n  than guessing.\n\n## What you can drive\n\nAutomation commands are JSON-first, and selectors are consistent across commands:\n`--text`, `--rid` (resource id), `--desc` (content description), and `--xpath`.\nA typical agent reads `ui dump` once, acts by `--rid`/`--text`, and re-reads only\nwhen `screen_hash` changes.\n\nText/desc selectors match as a **normalized, case-insensitive substring** by\ndefault: before comparing, surrounding whitespace is collapsed, curly\nquotes/apostrophes/ellipsis are folded to ASCII, and zero-width characters are\nstripped — so `--text \"sign in\"` matches a `SIGN IN` button and `--text \"Don't\nallow\"` matches text rendered with a typographic apostrophe. Add `--exact` (on\n`ui find`/`tap`/`text`/`wait`/`focus`) to require a full match (so `--text Allow`\nwon't hit a label reading \"Allow Disney+…\"), and `--clickable` to skip\nnon-clickable labels. `--rid` is the most reliable target when a stable resource\nid exists. Matching is **literal** — `*`, `.`, `?` and other symbols match\nthemselves, with no wildcards or regex (a value starting with `-` needs the\n`--text=-50%` equals form so it isn't read as a flag).\n\nSelector **actions** are **strict**: if `ui tap`/`text`/`focus` matches several\nelements and none is an exact match, they fail with a structured\n`ambiguous_match` error listing the candidates rather than guessing — narrow with\n`--exact`, `--rid`, or `--clickable`. On a hit, `ui tap`/`wait`/`focus` echo back\nthe matched element so you can confirm the right node was targeted.\n\n`ui wait` also syncs on the foreground app, not just elements: `--pkg \u003cpackage\u003e`\nblocks until that app reaches the foreground (e.g. a Custom Tab or share sheet\nopened), and `--pkg-not \u003cpackage\u003e` blocks until the screen leaves it.\n\nResults go to **stdout**; ShadowDroid's own logs go to **stderr**, so `… | jq`\nalready sees clean JSON. Add `--quiet`/`-q` (or `SHADOWDROID_QUIET=1`) to silence\nthose logs entirely — handy when you pipe with `2\u003e\u00261`.\n\n**Android TV / leanback** is focus + D-pad driven, not touch driven: `/v1/state`\nreports `is_television: true`, each element carries a `focused` flag, and\n`ui focus --text/--rid/--desc [--center]` walks the D-pad to a selector (then\noptionally activates it) — the TV analog of `ui tap` / `ui scroll-to`. Prefer it\n(and `ui key dpad_*`) over coordinate taps there.\n\n| Group | Commands |\n| --- | --- |\n| **Discovery/setup** | `commands`, `config paths` / `schema` / `explain` / `init` / `validate`, `skill`, `studio status` / `install`, `init`, `update` |\n| **Session/diagnostics** | `devices`, `connect`, `disconnect`, `test`, `doctor`, `collect` |\n| **UI automation** | `ui dump`, `ui audit`, `ui gen`, `ui screenshot`, `ui find`, `ui tap`, `ui double-tap`, `ui long-tap`, `ui swipe`, `ui drag`, `ui swipe-ext`, `ui pinch`, `ui scroll-to`, `ui focus`, `ui text`, `ui key`, `ui hide-keyboard`, `ui back`, `ui home`, `ui wait`, `ui toast` |\n| **Live timeline** | `watch` (screen changes, crashes, ANRs, toasts, watcher actions, and HTTP events when network capture is active) |\n| **Layout / Compose** | `layout snapshot`, `layout diff`, `layout source`, `layout recompositions` |\n| **Debugger** | `debug auto`, `snapshot`, `record`, `replay`, `status`, `sessions`, `clients`, `attach`, `break`, `breakpoints`, `pause`, `resume`, `step-in`, `step-over`, `step-out`, `stop`, `stack`, `threads`, `variables`, `eval`, `inspect`, `coroutines`, `continue-until`, `watch`, `step-until-screen-change`, `step-until-log`, `run-until-crash`, `native`, `tombstones` |\n| **App lifecycle** | `app start`, `stop`, `install`, `reinstall`, `clear`, `info`, `wait`, `current` |\n| **Permissions/app-ops** | `perm grant`, `revoke`, `list`, `reset`; `appops get`, `set` |\n| **Device/system** | `device info`, `shell`, `wake`, `sleep`, `unlock`, `orientation`, `clipboard`, `notifications`, `quick-settings`, `open-url` |\n| **Display profile** | `profile snapshot`, `apply`, `reset` (animations, font, density, size, rotation) |\n| **Files** | `files ls`, `push`, `pull` |\n| **Network MITM** | `net check`, `trust`, `start`, `stop`, `status`, `log`, `show`, `export`, `intercept`, `resume`, `drop`, `respond`, `rule`, `rules`, `replay` |\n| **In-app AAR agent** | `aar install`, `status`, `remove`, `capture`, `intercept`, `resume`, `drop`, `agent` |\n| **Authoring/testing helpers** | `ui audit` (selector gaps), `ui gen` (Screen Object scaffold), `net export fixtures` (replayable response set + `manifest.json`, GraphQL keyed by operationName), `test` (instrumentation command with the slot freed), `debug replay --repeat --diff` (flake hunting) |\n\n`watch` is the streaming workhorse — it emits debounced, hash-diffed `screen`\nevents plus `crash`, `toast`, `watcher_fired`, and `http` events when a `net`\nproxy is running. If network capture is not available, `watch` emits a structured\n`warning` event with the suggested recovery command, so an agent can decide\nwhether to run `net start` or continue UI/crash-only (`watch --no-net`).\n\n`net` is a host-side MITM proxy built into the single binary — no Python, no\nexternal mitmproxy. `net start` spawns the proxy, wires the device through\n`adb reverse` and proxy settings, and decrypted HTTP(S) transactions then stream\nas `http` events on the same timeline as `screen` when `watch` is running.\nBeyond observing, the agent can **intercept** a flow — `net intercept` pauses\nmatching requests/responses and emits them as `http_intercept` events on `watch`;\nthe agent inspects with `net show`, then releases with\n`net resume --set-status/--body/…`, `net drop`, or `net respond` (a canned\nreply). Repeated edits can be promoted to declarative `net rule`s (map-local /\nmap-remote / set-status / set-header / replace / block / delay) or served offline\nfrom a saved session with `net replay`. `net check \u003capp\u003e` reports whether a build\nis interceptable; `net export har|curl|fixtures` hands flows to other tools.\n\nRun `shadowdroid commands` for the full command tree, or `shadowdroid --help` on\nany subcommand for its flags.\n\n## Agent debugging\n\n**This is the part nothing else gives an agent.** Driving a UI tells an agent\n*what* happened on screen; debugging tells it *why*. ShadowDroid hands a coding\nagent a live Android Studio debugger as plain JSON — so when a tap doesn't do\nwhat the agent expected, it can set a breakpoint and read the actual program\nstate instead of guessing from screenshots. It's a bounded, read-only surface\ndesigned for autonomous use, not a remote shell.\n\nBacked by an optional Android Studio plugin:\n\n- **`debug auto [app]`** — low-effort path: resolve an app alias/name/package,\n  launch it, attach the Studio debugger when available, then return a full\n  snapshot with setup guidance if the bridge is missing.\n- **`debug`** — attach to the running app; set breakpoints (line, exception,\n  method, field watchpoint; conditional, temporary, logpoints); read the call\n  stack, local variables, and watches; evaluate/inspect read-only expressions\n  (`this`, locals, fields, array indexes) and follow object handles while the\n  session remains suspended. Requests are bounded — they return a structured\n  `ok:false` instead of blocking when no suspended frame is available.\n- **`debug snapshot`** — one shot: device + build, foreground app, screen tree,\n  screenshot, recent logcat, and the live debugger stack / variables / breakpoints\n  in a single JSON object.\n- **`debug record` / `debug replay`** — JSONL timelines of screen changes,\n  lifecycle, logcat, and replayable actions (taps, text, keys, swipes, drags).\n- **`debug run-until-crash` / `step-until-screen-change` / `step-until-log`** —\n  let the app run until something interesting happens, then return a full snapshot;\n  crash waits emit parsed Java/native/ANR events and can write local bundles.\n- **`debug native` / `debug tombstones` / `debug coroutines`** — native/mixed\n  readiness, tombstone artifacts, and conservative suspended-state coroutine\n  insight without arbitrary code execution.\n- **`layout`** — UI-tree snapshots and diffs, enriched (when Studio's Layout\n  Inspector is live) with Compose source locations, semantics, and recomposition\n  counters.\n\nMultiple devices debugged in one Studio are addressable: `debug sessions` reports\neach session's device, and the global `-d \u003cserial\u003e` selects that device's session\nfor the session-bound commands (an explicit `--session \u003cindex\u003e` still wins).\n\nEverything degrades gracefully: with no Studio plugin running, the device and UI\ncommands still work and the debugger section just reports `available:false`.\nRun `shadowdroid debug --help` and `shadowdroid layout --help` for the live\ncommand surface.\n\n## Agent integration\n\nShadowDroid is self-describing. `shadowdroid commands --json` emits the full\ncommand catalog (names, nesting, args, help, and agent-facing decision hints)\nstraight from the CLI definition — the machine-readable counterpart to `--help`\nthat an agent reads once to discover the whole tool.\n\n`shadowdroid init` installs/updates global agent skills automatically.\nProject-scoped Codex `AGENTS.md` remains explicit so installers do not write\ninto an arbitrary current directory. `shadowdroid skill \u003cagent\u003e` is still\navailable when you want a specific integration file, project-scoped output, or\na dry run. Supported agents: `claude-code`, `cursor`, `codex`, `gemini`,\n`antigravity`.\n\n```bash\nshadowdroid skill claude-code --install   # → ~/.claude/skills/shadowdroid/SKILL.md\nshadowdroid skill cursor      --install   # → ~/.cursor/skills/shadowdroid/SKILL.md\nshadowdroid skill gemini      --install   # → ~/.gemini/skills/shadowdroid/SKILL.md\nshadowdroid skill antigravity --install   # → ~/.gemini/antigravity*/skills/shadowdroid/SKILL.md\nshadowdroid skill codex                   # → prints an AGENTS.md section to stdout\n```\n\nCursor `--install` creates a personal skill available across projects; pass\n`--out /path/to/project/.cursor/rules/shadowdroid.mdc` to write a project-scoped\nCursor rule instead.\n\nInstalled skills are version-stamped. After upgrading the CLI, refresh them in\none shot — unmodified skills are rewritten in place, hand-edited ones are left\nalone (pass `--force` to overwrite those too):\n\n```bash\nshadowdroid skill --sync   # refresh every installed skill to this version\n```\n\n`connect` runs this refresh automatically (pristine skills only), so an upgraded\nCLI keeps its installed skills current with no extra step.\n\n\n## FAQ\n\n**What is ShadowDroid?**\nAn open-source command-line tool that turns a real Android device or emulator\ninto a structured surface an AI agent can read, drive, debug, configure, and\ninstrument. It covers UI automation, app/device control, permissions, files,\ndisplay profile, crashes/toasts, network interception, Android Studio debugger\nstate, Layout Inspector data, Compose recompositions, and an optional in-app AAR\nfor above-TLS capture.\n\n**Who is it for?**\nAnyone pointing an AI or coding agent at a *running* Android app: building agentic\nQA, reproducing bugs, automating end-to-end flows, or letting an agent self-verify a\nUI change. It's equally handy by hand for quick scripted automation.\n\n**Is ShadowDroid a test framework?**\nNo. There's no assertion DSL or test runner to babysit — it's a fast, observable\ncontrol surface an agent drives live. It *can* launch your existing instrumentation\ntests (`shadowdroid test`, which frees the `UiAutomation` slot first), but it isn't a\nreplacement for Espresso or JUnit.\n\n**How is it different from Appium, Maestro, or Espresso?**\nThose are built for authored test suites — WebDriver scripts, YAML flows, compiled\nJUnit — running in CI. ShadowDroid is built for a *live agent loop*: a persistent\non-device service answers core UI reads in ~25 ms, automation commands emit\nstructured JSON, and the agent can stream crash / toast / HTTP events or attach\nan Android Studio debugger. Use those frameworks for regression suites; use\nShadowDroid when an agent needs to drive and reason about a running app right now.\n\n**How is it different from `adb` and the `android` CLI?**\nIt complements them. Keep `adb` and the `android` CLI for scaffold, build, deploy,\nand SDK management, then hand the *running* app to ShadowDroid. Raw\n`adb shell uiautomator dump` is ~500 ms–1 s and stateless; ShadowDroid keeps a warm\nservice at ~25 ms, acts by selector, and streams events. See\n[Why it exists](#why-it-exists).\n\n**Does it support Jetpack Compose?**\nYes — first-class, via AndroidX UI Automator 2.3.0+. Compose nodes appear in the\nsame element tree. When Android Studio's Layout Inspector is running,\n`layout snapshot --compose --semantics --source-map` adds Compose semantics and\nsource locations, and `layout recompositions` reports recomposition counters.\n\n**When should I use `net` versus `aar`?**\nUse `net` first for proxy-aware HTTP(S): it is built into the host CLI, requires\nno app code changes, and supports capture, intercept, mutation, rules, fixtures,\nHAR/curl export, and replay. Use `aar` for apps you can build when you need the\ndebug-only in-app agent: above-TLS capture/interception for pinned TLS, Cronet,\nQUIC, or traffic that will not honor the device proxy/CA.\n\n**Do I need Android Studio?**\nNot for the core. The CLI plus `adb` cover UI automation, app lifecycle, network\ncapture, and event streaming. Android Studio (via the optional plugin) only adds the\nlive debugger and Layout Inspector enrichment; without it those sections report\n`available:false` and everything else keeps working.\n\n**Which devices work? Emulators? Android TV?**\nReal devices and emulators with USB debugging, plus Android TV / leanback, which is\nfocus + D-pad driven via `ui focus` and `ui key dpad_*`.\n\n**Which agents can use it?**\nAny agent that can run a shell command and read JSON. One-command skill install ships\nfor Claude Code, Cursor, Codex, Gemini, and Antigravity, and\n`shadowdroid commands --json` emits the whole catalog for anything else.\n\n**What host platforms are supported?**\nmacOS, Linux, and Windows hosts (Homebrew, Scoop, or a one-line installer). The\ntarget is always Android.\n\n**Is it open source?**\nYes — licensed under Apache-2.0.\n\n\n## License\n\nApache-2.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandriyo%2Fshadowdroid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandriyo%2Fshadowdroid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandriyo%2Fshadowdroid/lists"}