Every agentagentagent gets its own simulator.simulator.simulator.
warden leases iOS simulators, Android emulators and real phones to your coding agents, drives the app on them and keeps what they checked as tests. Devices, ports and builds, leased across every worktree on your Mac. One CLI, free and open source.
$ npm i -g @delacour/warden && warden install
Installs the CLI and the skill for every agent it finds.
Every agent the skills CLI supports gets the warden skill. Claude Code and Codex also get a SessionEnd hook that releases what the session leased.
Claim a device. Drive it. Keep the proof.
Leasing, device control and e2e tests in one tool, on one driver, so what an agent checked by hand passes the same way as a spec.
01
Install
One global CLI, then warden install adds the skill to every agent it finds. There is no daemon to start.
$ npm i -g @delacour/warden
02
Claim
Ask for a platform. You get a booted simulator no other agent, worktree or shell on the Mac will be handed.
$ warden claim ios --json
03
Drive and keep
Read the screen, tap and type with warden ui, then keep the same checks as a spec that warden e2e runs on many devices.
$ warden ui snapshot -i
One Mac. Every branch at once.
Each agent works in its own worktree. warden hands each one a simulator, a Metro port and the build for its native fingerprint, and never hands the same one to two owners.
agentworktreedevicemetrobuild
Claude Code, leasedfeature/checkoutiPhone 17:80813f9a1c · cache
Illustrative. Three worktrees share a native fingerprint, so one cached build serves all three; the fifth claim waits for a boot slot.
Devices that look after themselves, for agents that don't wait.
Every agent, worktree, CI job and shell on the Mac claims from one sqlite registry. Each claim is a transaction, so two agents asking at the same instant are served in turn, never both.
--ttl 30m
One lease, one device
A leased device belongs to one holder until it releases it or the TTL runs out. Wrapper commands heartbeat every 30 s and release when they exit.
A device that fails its health check at claim time is quarantined, and the claim tries another. Release one as bad yourself and it is set aside for 24 h.
Claim a plugged-in Android phone or iPhone and drive it with warden ui or a spec. warden never boots or shuts one down, and only uninstalls what it installed.
Once it holds a simulator, your agent runs the app, drives it, reads what went wrong and keeps what it checked as a test. Every step stays on its own device.
Run it
warden dev in every worktree
Claims a device and leases a Metro port per worktree
Installs the cached build: installed, cache, EAS, then local
Never attaches to another checkout's Metro
Expo or bare React Native, with or without a config
# worktree 1: feature/checkout$ warden dev ios --json# worktree 2: fix/login-crash, at the same time$ warden dev ios --json# each gets its own simulator and Metro port,# and the cached build for its native fingerprint
Drive it
Device control for agents
Reads the screen as @e refs: role, name, testID, state
# what broke, from the running app$ warden dev logs --kind bundle_failed,error$ warden ui exceptions$ warden ui network --status 4xx# why it is slow$ warden perf record --all --duration 15s --udid $UDID# or all of it over MCP$ claude mcp add warden -- warden mcp
Keep it
What it verified becomes a test
warden ui record writes the session as a spec and runs it once
The testIDs warden ui found become the spec's locators
warden ui and specs share one driver, so a check that passed by hand passes in the spec
The warden skill tells the agent when a check belongs in a spec
Salient's 37 offline e2e specs on iPhone 17 simulators, job time after Metro is ready. Oct 2026.
Change the world around the app.
Take it offline, break one host, move the GPS, jump the clock or fail Face ID, from a spec or a terminal, on a leased simulator. The app runs unmodified, and warden undoes every condition when the lease ends.
warden ui biometrics fail and match answer the real system prompt. Face ID and Touch ID on simulators, fingerprint on emulators, enrolled with warden claim --biometrics.Read more →
It only touches what it leased.
warden is advisory, not a sandbox. What it enforces is its own reach.
--adopt
Your simulator stays yours
A device warden didn't create or lease is read-only: never handed to an agent, shut down, erased or installed on unless you pass --adopt.
No server to run and no open port: leases are rows in one sqlite file, and warden's helpers talk over unix sockets. The network proxy binds loopback, only while it shapes traffic.
Wrappers release when they exit. The Claude Code and Codex hook releases what a session leased and shuts down what it booted; device conditions are undone on release.
Paste this into Claude Code, Codex, Cursor or any agent in your app's directory. The warden skill tells it the rest.
prompt
Install warden (npm i -g @delacour/warden && warden install) and set this Expo app up with warden init.
Run the app from this worktree with warden dev, then drive it with warden ui and check the home screen renders.
Save what you checked as an e2e spec under e2e/, run it with warden e2e, and release the simulator when you're done.
One open-source CLI that leases iOS simulators, Android emulators and phones to coding agents, drives the app on them, and runs e2e specs across many of them at once. Devices, Metro ports and app builds are leased per worktree, so agents in parallel never collide.
Does warden sandbox my agents?
No. It is advisory: the skill tells agents to use only devices a lease hands them, and raw simctl or adb are not intercepted. What it enforces is its own reach: warden ui refuses a device leased to someone else, and warden only shuts down, erases or deletes devices it created.
What happens when an agent dies holding a device?
Every lease has a TTL (30 min, 5 min for a bare agent warden claim) and lives only while it is renewed. warden run, dev, batch and e2e heartbeat every 30 s and release when they exit, so a killed wrapper frees its device within about 90 s; one that vanishes costs the device until the TTL runs out.
What if every device is busy?
warden boots or creates another, up to a capacity it derives from the Mac's RAM and CPU. After that the claim waits in a queue ordered by priority and age, up to --wait (30 min by default); --no-wait fails at once.
Does it work on Android and real phones?
Yes. Android emulators are leased like simulators, and warden ui and specs drive them. Plugged-in Android phones and iPhones are opt-in with --physical; device conditions and biometrics are simulator and emulator only. iOS needs macOS with Xcode.
Which agents does it support?
Any agent the skills CLI installs into gets the warden skill: Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Windsurf, Zed and more. Claude Code and Codex also get the SessionEnd cleanup hook.
Is there an MCP server?
Yes, for debugging. warden mcp serves a warden dev session's Metro output, console, exceptions, network, eval, logpoints and profiles over stdio. Claiming devices and running specs stay on the CLI.
What does my app need?
Builds, the dev client and Metro target Expo and React Native. warden ui and specs drive any installed app by bundle id, finding elements by testID, label, text or role.
How much does it cost?
Nothing. warden is MIT-licensed and runs on your own Mac or CI runner. No account, no cloud.