open source · MIT · iOS + Android

Mobile testing for coding agents.

warden gives your agent its own iOS simulator or Android emulator. It drives your app, keeps what it verified as an e2e test, and runs the whole suite across every simulator on your Mac.

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

Let your agent take it from here.

Your agent runs your iOS or Android app, sees what happened, and keeps going in the same session. Then it keeps what it checked, and the suite runs everywhere at once.

Drive it

Simulator control for agents

  • Claims a simulator or emulator no one else holds
  • Reads the screen as @e refs: role, name, testID, state
  • Presses, fills, scrolls, waits and checks
  • Every call checks the lease and heartbeats it
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"

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 it

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.

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 dev

A Metro port per worktree

Each worktree gets its own simulator and Metro port, and never attaches to another checkout's Metro.

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. Claim an iOS simulator, open the app 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 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.

warden dev

Parallel worktrees

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

Questions.

Short answers. The docs have the long ones.

What is warden?

An open-source CLI and e2e framework. It lets coding agents drive iOS simulators and Android emulators, save what they verify as tests, and run suites in parallel, with every device leased to one owner at a time.

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.

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.

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 your agent a simulator of its own.

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