open source · MIT · iOS + Android

Every agent gets its own simulator.

warden leases iOS simulators, Android emulators, ports and app builds across every worktree on your Mac, so parallel agents build, run and test your app without stepping on each other.

$ npm i -g @delacour/warden && warden install

Installs the CLI and the skill for every agent it finds.

warden batch salient-e2e37 Salient e2e specs · 5 iPhone 17 simulators · 3m25s (13m55s on one) · 37/37 passed · shown at 5× speed

Works with

  • Claude Code+hook
  • Codex+hook
  • Cursor
  • GitHub Copilot
  • Gemini CLI
  • OpenCode
  • Windsurf
  • Zed

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.

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 fingerprint, and never hands the same one to two owners.

  • Claude Code, leasedfeature/checkoutiPhone 17:80813f9a1c · cache
  • Codex, leasedfix/login-crashiPhone 17:80823f9a1c · cache
  • Cursor, leasedfeature/dark-modePixel 9 emulator:8083b72e04 · local
  • you, leasedmainiPhone 17 Pro:80843f9a1c · installed
  • Gemini CLI, queuedfeature/searchnext boot slot
Illustrative. Three worktrees share a native fingerprint, so one cached build serves all three; the fifth claim waits for a boot slot.

Parallel, never shared.

Every agent, worktree, CI job and shell on your Mac claims from one lease registry. Two agents asking at the same instant are served in turn, never both.

BEGIN IMMEDIATE

One registry

Leases live in one sqlite db at ~/.warden/warden.db. Every claim is a transaction, so there are no lockfiles to go stale.

--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.

SessionEnd

Cleans up after itself

When a session ends, the hook shuts down the simulators it booted and releases its leases.

warden golden

New simulators in seconds

Pool devices clone from a settled golden image: 3.7 s clone plus 11.9 s boot, instead of 146–239 s.

warden capacity

Boots wait their turn

Claims queue by host RAM, CPU and priority, so ten agents don't boot ten simulators at once.

warden app ensure

One build, every worktree

Builds are cached by native fingerprint and shared by every worktree of the repo. A native change builds once.

Everything it needs on that simulator.

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
Dev client per worktree →
terminal
# 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

Simulator control for agents

  • Reads the screen as @e refs: role, name, testID, state
  • Presses, fills, scrolls, waits and checks
  • Every call checks the lease and heartbeats it
  • Another agent's simulator is never a valid target
Drive a device →
terminal
# your agent, on its own simulator$ warden claim ios --json$ warden ui open com.example.app$ warden ui snapshot -i@e1 [textbox] "Add a todo" id=todo-input value="" enabled hittable@e2 [button] "Add" id=todo-add enabled hittable$ warden ui fill @e1 "Write e2e specs"$ warden ui press @e2 --settle$ warden ui wait text="Write e2e specs"

Debug it

Logs, network and profiles

  • Metro's bundle failures, with file, line and code frame
  • The app's console, exceptions and network, symbolicated
  • CPU, memory, frames, startup and React profiles with warden perf
  • The same functions as MCP tools with warden mcp
Debug the running app →
terminal
# 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

  • The testIDs warden ui found become the spec's locators
  • Specs are TypeScript on bun test with nine matchers
  • 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
Write your first test →
e2e/add-todo.e2e.ts
import { expect, test } from "@delacour/warden-e2e"; test("add a todo", async ({ screen }) => {  await screen.getByTestId("todo-input").fill("Write e2e specs");  await screen.getByTestId("todo-add").tap();  await expect(screen.getByText("Write e2e specs")).toBeVisible();  await expect(screen.getByTestId("remaining")).toHaveText("2 left");});

Run the suite

The suite on every simulator at once

  • warden e2e leases N simulators and installs the build
  • Starts Metro on its own port, one bun test per device
  • warden affected runs only the specs a diff reaches
  • Failures leave a screenshot, the screen tree and a trace
How e2e works →
1 simulator13m55s
5 simulators3m25s
Salient's 37 offline e2e specs on iPhone 17 simulators, job time after Metro is ready. Oct 2026.

Productive from the first prompt.

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.

What agents build with it.

The jobs agents get asked to do on a mobile app, and the warden command behind each.

warden dev

Parallel worktrees

Five agents, five worktrees, five simulators and five Metro ports, side by side on one Mac.

warden ui wait

Verify a UI change

The agent changes a screen, opens it on its own simulator and checks it before it says done.

warden ui snapshot

Reproduce a bug

Walk the steps from the issue on a clean device, then keep the repro as a failing spec.

warden affected

Gate every pull request

Only the specs a diff reaches run, in CI or a pre-push hook, across leased simulators.

Questions.

Short answers. The docs have the long ones.

What is warden?

An open-source CLI and e2e framework that gives every coding agent its own iOS simulator or Android emulator, Metro port and app build, so agents in parallel worktrees never collide. On that device the agent runs, drives and debugs the app, saves what it verified as a test, and runs suites in parallel.

How do I install it?

npm i -g @delacour/warden && warden install. The second command wires the skill and hooks for the agents it finds, showing a diff and asking first.

Can two agents end up on the same simulator?

No. Every claim is a transaction in one registry on the Mac, so a device or port has one owner at a time.warden ui checks the lease on every call.

Does it work on Android?

Yes. warden leases Android emulators (launched -read-only), and warden ui and specs drive them. 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. warden mcp serves a warden dev session's Metro output, console, exceptions, network, eval, logpoints and profiles over stdio. Devices, specs and suites stay on the CLI.

What does my app need?

Build, dev-client and Metro handling target Expo and React Native. warden ui and specs drive any installed app by bundle id; elements are found by testID, label, text or role.

Will it touch my own Simulator.app?

No. A booted device warden didn't create or lease is read-only. It is never handed to an agent unless you pass --adopt.

How much does it cost?

Nothing. warden is MIT-licensed and runs on your own Mac or CI runner. No account, no cloud.

Give every agent a simulator of its own.

$ npm i -g @delacour/warden && warden install