The Problem
AI agents need to interact with mobile devices, but existing tools don't give them a clean, scriptable interface. agent-device solves this by exposing device control as a CLI with a stable snapshot/ref model, so an agent can inspect a screen, target an element, and act on it without fragile coordinate math.
What This Does
agent-device is a TypeScript CLI that controls iOS and Android devices via adb, simctl, and devicectl. It runs on Node 22+ with no build step. Core commands (open, press, type, scroll, screenshot) live in src/cli.ts and dispatch to platform implementations in src/platforms/.
The key abstraction is the accessibility snapshot. snapshot returns a tree of UI nodes with stable refs (@e7), and interactions accept those refs instead of raw coordinates. iOS supports three backends — ax, xctest, and a hybrid that fills AX gaps with scoped XCTest snapshots — selected via --backend.
How It Is Wired
Execution starts in runCli (src/cli.ts), which sends commands to a daemon process via sendToDaemon (src/daemon-client.ts). The daemon's handleRequest (src/daemon.ts:111) is the hub: it reaches 111 functions and is called from one place. It routes to dispatchCommand (src/core/dispatch.ts), which resolves the target device and calls platform code.
The most-connected modules are src/utils/errors.ts (16 dependents, 0 imports — a zero-instability hub) and src/utils/exec.ts (11 dependents). runCmd in exec.ts is called from 34 places, so any signature change ripples widely. The daemon (src/daemon.ts, 1644 lines) owns session state, tracing, and filesystem effects; the Android platform (src/platforms/android/index.ts) is the largest platform module with 39 functions.
Filesystem effects are two hops from entry: runCli -> sendToDaemon -> ensureDaemon -> readDaemonInfo reads fs.readFileSync; shutdown -> writeSessionLog writes session logs. No database or network I/O beyond local device tooling.
How To Use It
git clone https://github.com/moses-y/agent-device
cd agent-device
pnpm install
# Run directly
npx agent-device open SampleApp
npx agent-device snapshot
npx agent-device click @e7
Configuration is flag-based (--platform, --udid, --serial, --session). No env vars or config files are required. The skills/agent-device/SKILL.md file documents agent-facing usage patterns.
Real-World Use
A test agent verifying a login flow:
agent-device open MyApp --platform ios
agent-device snapshot
agent-device fill @e3 "user@example.com"
agent-device fill @e4 "password123"
agent-device click @e5
agent-device wait text "Welcome"
agent-device screenshot --out ./login.png
agent-device close
Code Health & Issues
Static analysis found 14 issues: 3 high, 11 medium. The high-severity findings are:
- High - Deep nesting in
src/utils/args.tsandios-runner/AXSnapshot/Sources/AXSnapshot/main.swift(max indentation depth 11). Fix with early returns and guard clauses. - High - Duplicated code blocks — 37 repeated 6-line blocks across 8 files including
src/core/dispatch.ts,src/utils/args.ts,src/daemon.ts. Extract shared helpers. - High - Oversized files —
src/daemon.tsat 1644 lines andios-runner/.../RunnerTests.swiftare hard to reason about. Split by responsibility.
Medium findings include high branching density in src/utils/device.ts, src/core/dispatch.ts, and src/cli.ts, plus the errors.ts hub module.
SDLC observations: tests exist (5 files) but there is no CI pipeline — nothing builds or tests on push. No Dependabot/Renovate for the single manifest. Missing .editorconfig and formatter config.
The Bottom Line
A functional, well-scoped CLI for agent-driven mobile automation with a sensible ref-based interaction model. The daemon is overloaded and the duplicated logic needs consolidation, but the core design is sound. Suitable for teams building AI agents that need iOS/Android control today; wait for CI before treating it as production infrastructure.