We build CobraHQ for the web, Android and iOS. To coordinate that shared mobile development environment, we extracted our device ownership tooling into Agent Mobile Device Lease: a local, MIT-licensed CLI that assigns a device to an agent's worktree and keeps commands pointed at it.
A mobile development session stretches beyond installation. There are UI checks, screenshots and often a person testing the app while the agent waits for feedback. We needed device ownership to cover that whole session.
Separate code, shared devices
Consider two agents working on different fixes. Each has its own branch and build output. Both can still see the same emulator through adb. If their launchers pick the first available device, neither source tree tells them that the other agent is already using it.
Passing a device ID solves selection for one command. A development session needs more context: who owns that device, how long the claim lasts, and when another task may use it.
One shared registry · separate device leases
Worktree A
feature/session-plan
Android emulator A
Leased to worktree A
Worktree B
fix/attendance
Android emulator B
Leased to worktree B
The same device stays selected through commands, captures and manual testing, while the lease remains valid.
A lease follows the session
The tool records a device lease for the calling worktree. Acquisition returns the owner, device ID and a token. Subsequent commands use that captured token to prove they still hold the lease.
Wrapped Android commands receive ANDROID_SERIAL. For iOS commands, the wrapper replaces the MOBILE_DEVICE argument with the leased simulator's UDID. A shared registry lets participating worktrees coordinate ownership, and occupied capacity is something to wait for.
During a wrapped command, exec renews the lease and checks ownership. If the lease expires or ownership is lost, the wrapper stops its supervised command processes and reports failure.
Try it in an Android worktree
This example uses the personal installation: Node 22 or later on macOS, Android SDK tools on your path, and an available Android emulator. Start an emulator with Android Studio first. For parallel sessions, provide more than one emulator; the device-pool guide covers provisioning.
npm install --global github:nick-cobra/agent-mobile-device-lease#v0.1.5
device-lease doctor --platform androidThe read-only doctor reports prerequisites and capacity. Before asking agents to use the tool, merge the project's personal standing rule into your agent client's instructions. Installation alone does not make an agent participate.
From your application's Git worktree, acquire a device:
device-lease acquire --platform android --jsonCapture the returned owner, deviceId and token once. Replace <captured-token> in each command below with that acquisition's token. Query the selected emulator, then capture its screen:
device-lease exec --platform android --token '<captured-token>' -- adb shell getprop ro.product.model
device-lease exec --platform android --token '<captured-token>' -- adb exec-out screencap -p > device.pngBoth commands target the leased emulator through ANDROID_SERIAL. The screenshot is saved as device.png in the current directory. Use the same captured lease for your build, installation and UI checks. An existing launcher must honour the device pin internally; see the integration guide before wrapping a launcher that selects its own device.
Keep it while a person tests
A returning installer or completed screenshot does not finish a manual session. Keep the lease while the developer uses the app and while the agent waits for feedback.
Leases still expire. Acquisition starts no background renewer, and the exec heartbeat ends with its child command. Inspect the actual expiry and renew before it, including during idle periods:
device-lease list --platform android --json
device-lease renew --platform android --token '<captured-token>'When the developer has finished testing, requested release or switched devices, wait for device commands to finish and release that same token:
device-lease release --platform android --token '<captured-token>'The same ownership model on iOS
With Xcode and an installed simulator runtime, acquire using --platform ios. Explicit simulator commands use the leased UDID through MOBILE_DEVICE:
device-lease acquire --platform ios --json
# Replace this placeholder with the token returned above.
device-lease exec --platform ios --token '<captured-ios-token>' -- xcrun simctl io MOBILE_DEVICE screenshot ios.pngAcquisition selects a simulator; it does not boot it. Boot the selected simulator if needed before capturing. The complete iOS example includes boot, installation, renewal and release. Avoid a literal booted target when several simulators can be running.
A shorter path for unattended work
When the entire device session fits inside one command and no person will continue testing afterwards, device-session handles acquisition, renewal and cleanup:
device-session --platform android -- adb shell getprop sys.boot_completedIt releases its captured lease when the child exits, including on failure. Run it from a worktree without an existing manual lease. Keep persistent acquire and exec for sessions that continue across agent replies or human feedback.
What the tool can protect
Device leasing is a cooperative protocol. An unwrapped SDK command can still interact with a device. A wrapper cannot inspect device selection hidden inside an arbitrary script. All participating projects sharing devices must use the same registry and compatible protocol.
The v0.1.5 release targets macOS and uses Node built-ins with no runtime package dependencies. It does not require an account or hosted service. Windows and remote-device coordination are outside that release's supported scope.
Open source at CobraHQ
Give every session a device.
If you run mobile development agents in parallel, try it in your own worktrees. The repository includes the CLI, integration examples and tests that use fake devices and temporary registries, so contributors can run them without booting an emulator.
View Agent Mobile Device Lease on GitHub