warden

Framework comparison

The same 8-test suite on one build and one device in warden, Argent, agent-device and tester.army. Suite time, per-test medians, cold start, resources and footprint.

Every framework runs the same 8 parity tests against the same .app, with no LLM involved. Every run happens on EAS Workflows, one macos-large worker and one fresh simulator per framework (see iOS run 2026-10-25 on EAS for how, and for every artifact). See Benchmark e2e frameworks to run it yourself.

iOS run of 2026-10-25 · full report

Fastest, all tests passing

91.77 s

agent-device, warm suite median

Ratio spread

1× to 1.44×

agent-device to tester.army

Passed every test

4 of 4

every framework that ran passed every test

Suite

8 tests

5 runs each, run 1 cold

  • warden
  • Argent
  • agent-device
  • tester.army

Suite time

Warm suite wall time, measured by the harness around the whole suite process. Warm numbers leave out the first, cold run.

Warm suite wall time per frameworkWarm suite median: warden 97.04 s; Argent 131.81 s; agent-device 91.77 s; tester.army 132.34 s050 s100 s150 s200 swardenwarden: 97.04 s · 1.06× (p95 98.63 s, cold rep 1 98.33 s)97.04 s · 1.06×Argentargent: 131.81 s · 1.44× (p95 132.14 s, cold rep 1 132.43 s)131.81 s · 1.44×agent-deviceagent-device: 91.77 s · 1.00× (p95 91.93 s, cold rep 1 92.86 s)91.77 s · 1.00×tester.armytester-army: 132.34 s · 1.44× (p95 133.43 s, cold rep 1 151.03 s)132.34 s · 1.44×
Bar: warm median. Whisker: p95. Dot: cold first run. The ratio is the median over the fastest framework that passed every test. A ✗ marks a framework with failing tests, whose time is not comparable.

Per test

Warm median per canonical test. Compare these before the step numbers.

Warm median per test and framework
TestwardenArgentagent-devicetester.army
onboarding steps through to sign-in3.14 s1.00×8.22 s2.62×3.87 s1.23×6.03 s1.92×
invalid email and short password show field errors17.99 s1.09×17.96 s1.09×16.55 s1.00×20.87 s1.26×
a locked account shows the form alert11.05 s1.14×14.04 s1.45×9.67 s1.00×12.80 s1.32×
valid credentials land on todos10.94 s1.12×14.98 s1.53×9.77 s1.00×14.89 s1.52×
add, complete and filter todos17.00 s1.10×20.87 s1.35×15.50 s1.00×21.20 s1.37×
open a todo, mark it done, then delete it12.02 s1.00×18.88 s1.57×12.49 s1.04×18.17 s1.51×
deep link opens a todo by id11.79 s1.13×17.37 s1.67×10.42 s1.00×18.06 s1.73×
settings shows the account, toggles switches and signs out13.02 s1.00×19.12 s1.47×13.23 s1.02×18.07 s1.39×

Bold: fastest in the row. ✗: the test failed in at least one run, so the time is not comparable.

Step latency

Per-step latency per frameworkMedian step latency: warden 170 ms; Argent 318 ms; agent-device 479 ms; tester.army 494 ms02 s4 s6 sStep latencywarden: warden · median 170 ms (p95 3.93 s, max 5.00 s, 504 steps)warden · median 170 msargent: Argent · median 318 ms (p95 1.82 s, max 2.82 s, 1192 steps)Argent · median 318 msagent-device: agent-device · median 479 ms (p95 1.62 s, max 1.90 s, 632 steps)agent-device · median 479 mstester-army: tester.army · median 494 ms (p95 3.18 s, max 3.98 s, 592 steps)tester.army · median 494 ms
Whisker: min to max. Box: min to p95. Tick: median. Step timings are not defined the same way in every tool, so compare per-test totals first.

Cold start, prepare, teardown

Cold-start cost is the first run minus the warm median, plus the time spent in prepare: what installing a runner app or starting a daemon costs, not steady-state speed. Overhead is suite wall time minus the sum of test durations.

A negative cold-start cost is not a duration. It means the cold first run finished faster than the warm median (run-to-run noise on a framework with little startup cost), so the table shows "none (rep 1 not slower, ...)" and leaves it out of the fastest-cell highlight.

Suite time, cold start, prepare, teardown and reliability
MetricwardenArgentagent-devicetester.army
Warm suite median97.04 s131.81 s91.77 s132.34 s
Warm suite p9598.63 s132.14 s91.93 s133.43 s
Cold first run98.33 s132.43 s92.86 s151.03 s
Cold-start cost1.94 s2.35 s18.41 s18.69 s
Prepare652 ms1.73 s17.32 s0 ms
Teardown85 ms511 ms322 ms523 ms
Overhead outside tests80 ms168 ms223 ms2.21 s
Run-to-run spread (cv)1.3%0.3%0.2%0.5%
Pass rate100%100%100%100%
Flake rate0%0%0%0%

Resources

CPU is judged in CPU-seconds per rep: the CPU time the framework's own processes used during one timed run (warm median), from per-process deltas of ps time. The sampled %cpu is shown last as a secondary number. Memory is the framework's own processes, sampled every 500 ms.

Host CPU-seconds per repHost CPU-seconds per rep: warden 9.1 s; Argent 2.8 s; agent-device 10.3 s; tester.army 17.0 s0 s5 s10 s15 s20 sHost CPU-seconds per repwarden: warden · 9.1 swarden · 9.1 sargent: Argent · 2.8 sArgent · 2.8 sagent-device: agent-device · 10.3 sagent-device · 10.3 stester-army: tester.army · 17.0 stester.army · 17.0 s
CPU time the framework's own processes used during one timed run (warm median), from per-process deltas of ps time. Host means the framework's own processes.
Host memory, peakHost memory, peak: warden 184.9 MB; Argent 261.8 MB; agent-device 2.4 GB; tester.army 2.0 GB0953.7 MB1.9 GB2.8 GBHost memory, peakwarden: warden · 184.9 MBwarden · 184.9 MBargent: Argent · 261.8 MBArgent · 261.8 MBagent-device: agent-device · 2.4 GBagent-device · 2.4 GBtester-army: tester.army · 2.0 GBtester.army · 2.0 GB
Sampled every 500 ms while the suite runs. Host means the framework's own processes, summed per process, so shared pages can be counted twice.
Host CPU-seconds, memory and %cpu
MetricwardenArgentagent-devicetester.army
Host CPU-s / rep9.1 s2.8 s10.3 s17.0 s
Host memory avg147.8 MB182.0 MB745.9 MB599.5 MB
Host memory peak184.9 MB261.8 MB2.4 GB2.0 GB
Host %cpu avg8.1%1.7%12.9%13.9%
Host %cpu peak59%40%533%508%
Simulator %cpu avg102.7%131.3%125.8%118.9%
Simulator %cpu peak293%788%380%560%

Host CPU-s / rep: warm median of the timed run. %cpu is a decaying average, inflated by a short suite; compare CPU-seconds.

Where the CPU goes

The same CPU-seconds split by process name, from the warm-median rep. A name keeps its colour in every bar, the six biggest names are shown and the rest are folded into other. The sampler ticks every 500 ms, so a process that lives between two ticks only shows up through the exit charge booked when its parent reaps it.

Host processes (the framework's own tree)

  • xcodebuild
  • warden-simd
  • simulator-server
  • bun cli.ts
  • snapshot-bridge
  • bun test
  • other
  • warden9.1 s
  • Argent2.7 s
  • agent-device10.2 s
  • tester.army17.0 s
Table
warden
ProcessCPU-sShareRSS avg
warden-simd7.0 s77.2%55.9 MB
bun test1.1 s12.6%92.2 MB
bun test (exit charge)0.7 s7.5%0 B
simctl0.2 s2.7%277.4 KB
(PlistBuddy)0.0 s0.0%0 B
(bash)0.0 s0.0%0 B
(simctl)0.0 s0.0%0 B
bun cli.ts0.0 s0.0%0 B
Argent
ProcessCPU-sShareRSS avg
simulator-server2.5 s92.0%96.6 MB
node argent0.2 s7.8%85.7 MB
node argent (exit charge)0.0 s0.2%0 B
(node)0.0 s0.0%0 B
node tool-server.cjs0.0 s0.0%0 B
simctl0.0 s0.0%0 B
system_profiler0.0 s0.0%0 B
agent-device
ProcessCPU-sShareRSS avg
xcodebuild7.5 s73.3%218.0 MB
bun cli.ts1.8 s17.3%268.7 MB
snapshot-bridge0.8 s7.5%116.3 MB
node agent-device0.1 s1.5%61.0 MB
ps0.0 s0.2%1.9 MB
simctl0.0 s0.2%20.4 MB
node agent-device (exit charge)0.0 s0.1%0 B
(simctl)0.0 s0.0%96.9 KB
DTServiceHub0.0 s0.0%16.7 MB
caffeinate0.0 s0.0%7.3 MB
(bash)0.0 s0.0%0 B
(clang)0.0 s0.0%0 B
other0.0 s0.0%0 B
tester.army
ProcessCPU-sShareRSS avg
xcodebuild14.3 s84.0%217.0 MB
node entry.js1.1 s6.2%84.9 MB
snapshot-bridge0.6 s3.7%116.2 MB
(node) (exit charge)0.6 s3.7%0 B
node e2e0.3 s2.1%109.4 MB
(node)0.0 s0.2%0 B
other (exit charge)0.0 s0.2%0 B
(ps)0.0 s0.1%27.9 KB
simctl0.0 s0.0%20.5 MB
DTServiceHub0.0 s0.0%16.8 MB
(pgrep)0.0 s0.0%0 B
(simctl)0.0 s0.0%0 B
other0.0 s0.0%0 B

Simulator processes

  • iOS
  • wardenexample
  • AgentDeviceRunnerUITests-Runner
  • bun cli.ts
  • SimulatorFrameworkBridge-iOS serve
  • CoreSimulatorBridge
  • other
  • warden116.3 s
  • Argent133.5 s
  • agent-device136.0 s
  • tester.army178.1 s
Table
warden
ProcessCPU-sShareRSS avg
iOS75.3 s64.7%34.8 GB
wardenexample30.6 s26.3%374.9 MB
SimulatorFrameworkBridge-iOS serve6.0 s5.2%197.7 MB
bun cli.ts2.0 s1.7%235.0 MB
CoreSimulatorBridge0.9 s0.8%83.7 MB
launchd_sim0.4 s0.3%52.2 MB
xpcproxy_sim0.3 s0.2%390.5 KB
mlhostd0.2 s0.2%129.7 KB
ps0.1 s0.1%1.9 MB
(launchctl)0.1 s0.1%93.2 KB
storekitd0.1 s0.1%127.9 MB
triald0.1 s0.1%96.6 MB
other0.0 s0.0%443.9 MB
Argent
ProcessCPU-sShareRSS avg
iOS98.8 s74.0%34.8 GB
wardenexample29.5 s22.1%375.5 MB
bun cli.ts2.8 s2.1%298.6 MB
simctl0.4 s0.3%363.8 KB
CoreSimulatorBridge0.4 s0.3%117.8 MB
launchd_sim0.4 s0.3%52.2 MB
ps0.3 s0.2%1.9 MB
(mlhostd)0.3 s0.2%222.5 KB
triald0.2 s0.1%96.7 MB
storekitd0.2 s0.1%128.4 MB
(managedappdistri)0.1 s0.1%214.5 KB
mlhostd0.1 s0.1%119.3 KB
other0.1 s0.0%444.5 MB
agent-device
ProcessCPU-sShareRSS avg
iOS89.3 s65.7%35.5 GB
wardenexample35.8 s26.3%371.9 MB
AgentDeviceRunnerUITests-Runner9.1 s6.7%268.2 MB
CoreSimulatorBridge0.5 s0.4%80.6 MB
simctl0.5 s0.4%676.7 KB
launchd_sim0.3 s0.2%52.4 MB
triald0.1 s0.1%96.7 MB
storekitd0.1 s0.1%128.3 MB
xpcproxy_sim0.1 s0.1%176.0 KB
mlhostd0.1 s0.1%34.2 KB
(wardenexample)0.0 s0.0%2.4 MB
assetsd0.0 s0.0%163.2 MB
other0.0 s0.0%274.3 MB
tester.army
ProcessCPU-sShareRSS avg
iOS107.5 s60.4%35.1 GB
wardenexample49.9 s28.0%380.4 MB
AgentDeviceRunnerUITests-Runner15.9 s8.9%271.0 MB
bun cli.ts2.6 s1.4%254.0 MB
CoreSimulatorBridge0.6 s0.3%80.6 MB
simctl0.5 s0.3%534.1 KB
launchd_sim0.5 s0.3%51.8 MB
mlhostd0.2 s0.1%135.3 KB
triald0.2 s0.1%96.6 MB
storekitd0.1 s0.1%128.2 MB
launchctl0.1 s0.1%36.7 KB
ps0.1 s0.0%1.9 MB
other0.1 s0.0%446.4 MB

Residue and footprint

Residue is what is left on the machine after teardown. Footprint is how much suite source you maintain and how large the runner binaries are.

Footprint and residue
MetricwardenArgentagent-devicetester.army
Suite source (lines)379161158307
Suite source (size)17.5 KB7.1 KB5.4 KB13.8 KB
Runner binaries on disk6.1 MB77.8 MB6.9 MB—
Leftover processes0000
Leftover driver apps0011
Leftover directories0111

Versions and run details

Framework versions and status
FrameworkVersionStatus
wardenbun 1.3.14 + warden-e2eran, all tests passed
Argent0.30.1ran, all tests passed
agent-deviceagent-device 0.21.31ran, all tests passed
tester.armye2e 0.20.0ran, all tests passed
Host
VirtualMac2,1, Apple M4 Pro (Virtual), 10 cores, 40.0 GB, macOS 26.5.2
Device
warden-iphone-17-1 iOS 26.5
App
nz.co.delacour.warden.example, 96.4 MB, build import:2d356, sha256 2d35643eda49
Tools
bun 1.3.14, warden 0.1.1
Run
5 runs per framework, 0 retries, load average 3.85 at start
Report
docs/bench/ios-2026-10-25.md

Fairness rules

  • Same .app for every framework, with its sha256 recorded.
  • Zero LLM calls.
  • Same assertions per canonical test id.
  • Same retry helpers: dropped first tap, dropped deep link, system alerts.
  • The iOS "Open in …?" sheet is answered once per boot by the harness before every framework's prepare (iOS asks it for the first custom-scheme link after a boot, not again).
  • Fresh app launch per test, retries=0.
  • Frameworks run sequentially with daemons stopped between them, or, on EAS, each on its own worker and simulator.
  • caffeinate -dims held for the run, host otherwise idle, load average recorded.
  • Warm medians exclude rep 1.
  • Machine-readable reporters only.
  • A framework with any failing test never sets the pace, so it is never the fastest.

Caveats per framework

FrameworkGap
wardenCopied from the example app, retries written with warden's own options: tap({ until }), a deep-link retry, systemAlerts: "dismiss". The hand-rolled helpers it replaced ran the published headline numbers; the idiomatic run is reported beside them.
ArgentRetries are nested when: guards capped at two retaps. Flow selectors read only the app's view hierarchy, never SpringBoard, so the flow cannot answer the "Open in …?" sheet itself. A checkbox's checked state is not readable, so the remaining-count assertion covers the effect.
agent-device.ad scripts have no retry or conditional, only wait and press, so the deep-link script cannot answer a sheet that may or may not show. Needs a runner prepare step and a daemon.
tester.armyHas its own copy of the hand-rolled helpers warden used before. Runs with a private agent-device state dir and Node 24 on PATH.

Each run is a snapshot on one machine class with few warm repetitions: read the ratios as a guide, not a verdict. The full Markdown report for each run is in docs/bench/ in the repo; the EAS runs also publish every worker's artifact on their run page.

On this page