Blolabel
← Notes
analysis 6 min read

ActionEngine's crawled map alone scores 73.1% on WebArena, 9.6 points under Claude Code; its 91.2% comes after a warm-up over the task templates

The map-then-program web agent matches Claude Code on three of four WebArena domains with its crawled map, trails it by 34 points on GitLab, and reaches its headline only after a template-driven warm-up whose cost the paper does not report.

ActionEngine's headline is 91.2% on 655 WebArena tasks, 8.5 points above Claude Code on the same Claude Opus 4.6 backbone. With only the map its crawler built, it scores 73.1%, which is 9.6 points below Claude Code and 34.0 below it on GitLab. The rest comes from a warm-up that runs one generated task for every WebArena task template and patches the map, and version 2 of the paper (arXiv:2602.20502, 28 September 2026) does not report what that warm-up costs.

Abstract technical illustration of a sparse node-and-edge map drawn over a grid, with a second pass adding and correcting a subset of the edges

What the paper changed and what it measures

ActionEngine is from Hongbin Zhong and Kexin Rong (Georgia Tech) with Fazle Faisal, Luis França, Tanakorn Leesatapornwongsa, Adriana Szekeres and Suman Nath (Microsoft). Version 1 was posted on 24 February 2026 and version 2 on 28 September. A crawling agent explores a web application offline and writes a state-machine graph: page templates as states, each with the operations available on it and the transitions they cause, serialised as YAML. At run time a planner reads that graph and writes a complete program in one call, which then executes without further planning. When a step breaks, a reactive fallback repairs it and a Patcher updates the graph.

The evaluation adds a warm-up between those two phases. The authors generate and execute one task per WebArena task template with the Patcher switched on, then switch it off for the scored runs, so each scored task is a single attempt on a fixed map. Warm-up tasks share templates with the evaluation tasks but not their instances or parameters. Failed tasks from every system were hand-reviewed, and answers that were correct but formatted differently from the reference were counted as passes.

DomainTasksClaude CodeCrawled map onlyAfter warm-upCrawl cost, timeBreak-even (tasks)States, operations after warm-upSource
Reddit (Postmill)10692.489.095.0$11.6, 36 min3957, 130 (+2)Tables 1, 2(a)
Shopping18779.780.787.0$16.9, 132 min4459, 105 (+2)Tables 1, 2(a)
Shopping Admin18274.274.095.3$37.2, 260 min101184, 1,182 (minus 4)Tables 1, 2(a)
GitLab18089.055.089.0$29.5, 230 min88219, 1,148 (+66)Tables 1, 2(a)
Overall65582.773.191.2$95.2, 658 min (our sum)not reportednot reportedTables 1, 2(a)

Success rates are percentages. Break-even is the paper's: tasks needed for ActionEngine's lower per-task cost to repay the crawl, relative to Claude Code. It does not include the warm-up, whose cost is not reported. The paper links no code repository that we could find.

The crawl gets you to parity on simple sites, and the warm-up does the rest

On three domains the crawled map alone lands within 3.4 points of Claude Code: 89.0 against 92.4 on Reddit, 80.7 against 79.7 on Shopping, 74.0 against 74.2 on Shopping Admin. GitLab is the exception, at 55.0 against 89.0. The warm-up closes that and more: GitLab's map gains 66 operations and reaches 89.0, and Shopping Admin goes from 74.0 to 95.3 while losing 4 operations to merges. The authors sort the repairs into three kinds: selectors that did not fire the page's JavaScript handlers, missing waits after asynchronous updates, and operation descriptions that needed behaviour learned by running them, such as a save that stays on the edit page.

WebArena success (%), same backbone (Claude Opus 4.6) Claude Code + Playwright ActionEngine, crawled map only ActionEngine, after warm-up 0 25 50 75 100 92.4 89.0 95.0 Reddit106 tasks 79.7 80.7 87.0 Shopping187 tasks 74.2 74.0 95.3 Shop. Admin182 tasks 89.0 55.0 89.0 GitLab180 tasks 82.7 73.1 91.2 Overall655 tasks Source: arXiv 2602.20502v2 Table 1 (Claude Code, refined) and Table 2(a) (crawler-only). Failed tasks were hand-reviewed for every system.

The efficiency numbers are large and hold after warm-up: 27 seconds per task against 87 for Claude Code and 787 for AgentOccam, 1.5 to 3.5 model calls against 7 to 16, and $0.05 per task against $0.40, of which prefix caching accounts for the step from $0.16 to $0.05. The success comparison is the part that depends on the warm-up. Our judgement is that "task-independent" fits the crawl but not the 91.2%, because the warm-up is steered by the benchmark's own templates. Nobody deploying this on a new site has a template list.

Map, patch, then execute: where each number in the headline comes from 1. offline crawl 36 to 260 min, $11.6 to $37.2 states + operations as YAML scores 73.1% alone 2. warm-up, Patcher on one task per WebArena template fixes selectors, waits, descriptions cost: not reported 3. scored runs, Patcher off 1 plan call, program executes 1.5 to 3.5 calls, 27 s, $0.05 scores 91.2% phoneshell has pieces of boxes 1 and 3, built separately and never joined crawl.py (no model) 1.2 s a step, deterministic traversal screen identity: layout fingerprint + content never types, never toggles a switch refuses 80 labels (send, pay, delete, allow) output: screenshots of screens memory.py (during agent runs) control on screen A led to screen B, n times settle time learned per screen (1.4 x mean) known after 2 visits up to 8 routes shown to the model as a hint no planner writes a program from it ActionEngine's largest warm-up gains were on form-heavy sites: Shopping Admin plus 21.3, GitLab plus 34.0. Forms need typing and toggles, the two things phoneshell's crawler is built never to do. Sources: arXiv 2602.20502v2 Sections 4 and 5, Tables 1 and 2; phoneshell/crawl.py and phoneshell/memory.py.

What it means for a phone agent with a memory

phoneshell has both halves of this design, built separately. phoneshell/crawl.py walks an iPhone's screens with no model in the loop at about 1.2 seconds a step, identifying screens by a layout fingerprint plus a content signature, and it never types, never toggles a switch and refuses 80 labels (send, pay, delete, allow, sign out and so on). phoneshell/memory.py records, during ordinary agent runs, which control on which screen led to which screen and how often. It treats a screen as known after two visits and shows the model up to eight remembered routes as a hint. Its docstring says a route walked enough times "becomes replayable outright, with no model in the loop"; in the code, memory only produces hints, and replay lives in the separate macro recorder.

ActionEngine's split of repairs maps onto that code. One of its three repair kinds, waits after asynchronous updates, phoneshell already handles by measurement: each remembered screen keeps a running mean of how long it took to settle and uses 1.4 times that, clamped to 0.15 to 2.5 seconds. The other two do not arise the same way on iOS, because phoneshell resolves controls against the live accessibility tree rather than stored selectors, and it has no operation descriptions to enrich.

The gap is the one the GitLab row shows. The crawled map was weakest where tasks go through forms, and the warm-up gains were largest on the two form-heavy domains, plus 21.3 on Shopping Admin and plus 34.0 on GitLab. A phoneshell crawl leaves out exactly the operations those forms need, by design, since a crawler that types and toggles on a real phone changes the user's data. Our judgement: on iOS a map-then-program agent would have to learn its input operations from supervised agent runs, the way memory.py already learns transitions. It could not get them from a crawl, and until it does, its crawl-only number is the one to expect.

The plan-then-execute limit also carries over. After warm-up, ActionEngine's remaining failures were mostly ambiguous intent (about 23 cases) and search-dependent tasks (about 22), where the planner has to pick search terms before seeing results. On a phone, search fields are the common entry point to Maps, Contacts, Settings and the App Store, all of which appear in phoneshell's 80 tasks.

Check it yourself

What would prove this wrong

Dated 31 March 2027. If ActionEngine, or a replication, runs the warm-up on half of WebArena's templates and scores only tasks from the other half, overall success will be below 85%. A held-out score at or above 88% would show the warm-up teaches reusable site knowledge rather than template coverage, and the 91.2% would stand as a deployment number. If a published follow-up reports warm-up cost, break-even including it will exceed 100 tasks on at least one of the four domains.

Sources

  1. Zhong, Faisal, França, Leesatapornwongsa, Szekeres, Rong, Nath (Georgia Tech, Microsoft), ActionEngine: From Reactive to Programmatic Web Agents via State Machine Memory, arXiv:2602.20502 v2, 28 September 2026 (v1 24 February 2026)
  2. ActionEngine v2 HTML: Section 5.1 (warm-up, manual review), Table 1 (success and latency), Table 2 (crawl cost, break-even, crawler-only success, caching), Figure 4
  3. Zhou et al., WebArena: A Realistic Web Environment for Building Autonomous Agents, arXiv:2307.13854, 2023
  4. phoneshell source: phoneshell/bench/openrouter.py, runner.py, schema.py, crawl.py, memory.py, environments/*.yaml (read 30 September 2026)