Repository navigation
🍰 Highlights
- TV apps on LG webOS and Samsung Tizen: new optional provider plugins
@agent-device/webos(#4098) and@agent-device/tizen(#4168) drive web apps on TVs. They supportopen,snapshot, remote keys, pointer, text, scroll,screenshotandlogs. - Limrun iOS runs on the shared XCTest runner (#4224, #4182). It uses the same snapshot and interaction paths as a local Simulator. Local app installs sync to the instance (#4225), and boot and shutdown map to instance leases (#4275).
- Parallel web sessions (#4191): each web session is its own device, so sessions with different
--sessionnames run side by side on one host. Web device ids now include the session (agent-browser-chrome:session:...). - Pin a workspace to a device (#4384) with
devicePininagent-device.json. Commands select within the pin, and conflicting selectors fail withdevice_pin_conflict. - Safer presses on iOS:
backis now a verified left-edge swipe (#4460). A synthesized gesture that may already have run is never repeated (#4474). Press and click wait for a moving target within the request's deadline and cancellation (#4461). - Deterministic iOS screenshots:
screenshot --screen-mask blackmasks the simulator outline for stable visual baselines (#4206), and--capture-backend runnerselects the XCTest runner capture (#4184). - More accurate snapshots: iOS 27 system toolbars no longer cover their own controls (#4494). Android alert titles and messages stay in
snapshot -i(#4493). Empty text fields show their placeholder (#4467). Zero-area iOS nodes are marked unmeasured and point atscroll --until(#4495). - macOS context menus open on a native secondary click (#3962).
- Hardening from the November audit across the daemon, remote transport, replay, capture and providers (#4355, #4358, #4360, #4362, #4363, #4366 and more).
Breaking changes (MCP)
- Tool results are text by default (#4466).
agent-device mcpreturns compact text, with no output schemas and nostructuredContent. To get the previous structured results and output schemas, start the server withagent-device mcp --structured. AI SDK tools keep their structured results. - UI targets are top-level fields (#4459).
press,click,fill,longpressandhovertakeref(with an optionallabel),selector, orx+y.gettakesreforselector. The nestedtarget: { kind, ... }object is rejected with a message that shows the new form. This also applies tobatchsteps, so update savedbatch --stepsfiles andclient.batch.runsteps. The typedclient.interactions.*API is unchanged.press {"ref":"@e6"} click {"selector":"id=\"home/products\""} press {"x":201,"y":160} - Operator-only inputs left the tool schemas (#4468).
tenant,runId,leaseIdandandroidDeviceAllowlistare refused as tool input in MCP and AI SDK tools. Set them in the server environment (AGENT_DEVICE_TENANT,AGENT_DEVICE_RUN_ID,AGENT_DEVICE_LEASE_ID) or in config.tools/listshrank from 268 KB to 216 KB, and every input schema is now 5 KB or less. - Stricter server arguments and session lock (#4355).
agent-device mcpaccepts only--structured,--helpand--version. Configure the server withAGENT_DEVICE_*variables orAGENT_DEVICE_CONFIG. The session lock now comes only from the serving process (AGENT_DEVICE_SESSION,AGENT_DEVICE_SESSION_LOCK,AGENT_DEVICE_PLATFORM), never from tool input. The stdio server also no longer stalls on blank or malformed lines, keeps answeringpingandtools/listduring a call, and cancels the daemon request onnotifications/cancelled.
What's Changed
- feat(provider-webos): add LG webOS TV provider plugin by @alimek in #4098
- fix(ios): report an unreadable system prompt as ALERT_UNRESOLVED, not absence by @thymikee in #4149
- fix(ios): report keyboard focus from the private-AX snapshot bridge by @thymikee in #4154
- refactor(providers): share one lease table across cloud providers by @thymikee in #4158
- chore: report only minor and corroborated review findings by @thymikee in #4178
- fix(daemon): cancel artifact preparation and refresh failed builds by @thymikee in #4175
- fix(record): bound a cold video-validator compile by the stop's finalize budget by @thymikee in #4150
- fix(android): preserve labels across snapshot action boundaries by @andrewfree in #4180
- fix(android): retry a refused helper start once, and scope the session fake's stall to its helper by @thymikee in #4156
- .github/workflows: Migrate workflows to Blacksmith runners by @blacksmith-sh[bot] in #4185
- fix(ios): size sole-display gestures from XCTest screen metrics by @thymikee in #4157
- chore: print alert corpus surfaces through the Swift owner by @thymikee in #4186
- refactor(apple): support managed XCTest runner launchers by @muvaf in #4174
- docs: credit Blacksmith for CI in the README by @thymikee in #4193
- fix(ios): book every surface on the lit panel, not the first window by @thymikee in #4122
- fix(daemon): retain Apple runners for leases kept on close by @muvaf in #4195
- refactor(android): allow providers to install prepared app artifacts by @muvaf in #4194
- fix(ios): count the keyboard leaving as a post-gesture change by @kdy1 in #4207
- feat(screenshot): add a per-request iOS simulator screen mask by @sync in #4206
- perf(ios): check surface hosts inside the snapshot bridge, not with pgrep by @thymikee in #4172
- fix(ios): report devices CoreDevice cannot reach as not booted by @gronxb in #4210
- fix: retain third-party license notices in distributions by @thymikee in #4070
- fix(ios): keep failed alert reads unresolved by @thymikee in #4187
- docs: point to NoMac's agent-device plugin by @gergomiklos in #4198
- fix(ios): give simulator AX bridge captures a tree-bound keyboard fact by @kdy1 in #4217
- refactor(apple): share simulator tools and runner operations by @muvaf in #4213
- refactor(ios): bind surface geometry and synthesis orientation by @thymikee in #4189
- perf(ios): reuse current focus for native text replacement by @damian-kolasinski in #4192
- fix(android): accept a dispatched am start timeout once the app is foreground by @zerone0x in #4143
- fix(ios): refuse observe-only snapshots that find a system alert by @airowe in #4219
- fix(limrun): isolate recordings with recording session IDs by @muvaf in #4196
- fix(limrun): stop answering appstate for an unreachable iOS instance by @airowe in #4176
- fix(daemon): run find focus through the shared touch-point decisions by @airowe in #4223
- fix(ios): deliver simulator edge swipes as screen-edge touches by @gronxb in #4211
- feat(lease): name the iOS simulator mode in a proxy lease device spec by @vitalyiegorov in #4183
- fix(cli): one five-minute idle TTL for remote device leases by @thymikee in #4220
- fix(ios): release snapshot bridge exit watchers after each round trip by @kdy1 in #4232
- feat(limrun): replace iOS AX automation with the shared XCTest runner by @muvaf in #4224
- feat(screenshot): select the XCTest runner capture with --capture-backend runner by @vitalyiegorov in #4184
- fix(daemon): settle orphaned recording records when a recording starts by @sylvain-abadie in #4218
- feat(apple): serve the Simulator AX bridge from the XCTest runner by @thymikee in #4182
- fix(record): warm the MP4 validator without blocking capture by @thymikee in #4248
- refactor(apple): make runner surface policy explicit by @thymikee in #4251
- feat(limrun): sync local iOS and Android app installs by @muvaf in #4225
- fix(ios): keep the runner alive when XCTest cannot snapshot the app by @thymikee in #4221
- feat(web): make each web session its own device by @kacper-mikolajczak in #4191
- refactor(limrun): drop the unused iOS app-alias seam and stale AX-backend wording by @thymikee in #4243
- feat(client): let callers opt out of post-gesture stabilization by @kdy1 in #4253
- docs(capture): correct stale Limrun and Revyl capture comments by @thymikee in #4254
- docs(help): route stale React Native state to reads, not UI navigation by @thymikee in #4231
- docs(adr): accept 0038 snapshot capture source routing by @thymikee in #4255
- test(ios): give the post-probe type its own commandId by @thymikee in #4261
- fix(capture-kit): don't let an identifier-only Android leaf paint over sibling layers by @pcbeingused333 in #4266
- fix(limrun): recover when the Limrun instance ends under a held lease by @thymikee in #4257
- fix(mcp): return compact text for untyped tools and bound settle removals by @thymikee in #4246
- fix(apple): recover runner snapshot bridge after a wedge or restart by @thymikee in #4256
- fix(release): publish to npm from a GitHub-hosted runner by @thymikee in #4259
- fix(conformance): wait for Settings to detach before the tap-retry baseline by @thymikee in #4260
- refactor(apple): give the foreground probe one result shape by @thymikee in #4267
- refactor(apple): name the foreground reading type by @thymikee in #4271
- fix(apple): keep runner bridge test hooks out of the shipped package by @thymikee in #4272
- feat(limrun): share Android text and performance reads by @muvaf in #4268
- fix(android): clean recording evidence after its pid is reassigned by @thymikee in #4245
- fix(daemon): keep a session closable while close withholds its device claim by @thymikee in #4263
- feat(limrun): map boot and shutdown to instance leases by @muvaf in #4275
- refactor(ios): walk the lit windows once per multi-type element read by @thymikee in #4250
- fix(cli): name the state dir when daemon stop finds no daemon by @strzhao in #4280
- docs: record the HarmonyOS clipboard limitation by @strzhao in #4281
- refactor(apple): simplify snapshot route settlement by @thymikee in #4278
- docs: slim remote device leases ADR by @thymikee in #4277
- docs(adr): slim ADR 0004 to a decision record by @thymikee in #4279
- fix(snapshothelper): preserve TalkBack during Android helper automation by @mvanhorn in #4222
- fix(ios): preserve simulator app accessibility after runner teardown by @thymikee in #4276
- fix(apple): stop runner connect retry on signal exit or session drain by @twotnguyen in #4273
- docs: apply the wording follow-ups from #4277, #4278 and #4279 by @thymikee in #4299
- fix(ios): prepare snapshot helpers within a shared readiness budget by @andrewfree in #4181
- refactor(contracts): own snapshot provenance by @thymikee in #4306
- fix(limrun): start the iOS runner under the hosts' Xcode 27 by @thymikee in #4305
- docs(agents): prefer runner images and small fixes over selection code by @thymikee in #4312
- ci(release): build the Limrun runner on the macos-27 image by @thymikee in #4311
- fix(limrun): list only the connection's instance in devices by @thymikee in #4310
- refactor(capture-kit): lift the iOS snapshot route into the capture-kit router by @thymikee in #4308
- refactor(capture-kit): state each snapshot source's circuit scope by @thymikee in #4313
- fix(daemon): refuse a lease-less provider request as unallocated by @thymikee in #4307
- perf(ios): skip the simulator accessibility write when this host's preferences already allow it by @thymikee in #4300
- feat(macos): open context menus on native secondary click by @janicduplessis in #3962
- fix(macos-helper): skip the window-sharing indicator when choosing the front window by @janicduplessis in #3965
- fix(cli): treat device status and release selectors as explicit-only by @twotnguyen in #4315
- fix(android): delete characters with KEYCODE_DEL when typing backspaces by @twotnguyen in #4269
- fix(daemon): enforce device claim for commands with explicit selector by @twotnguyen in #4270
- refactor(contracts): derive snapshot producer facts from one registry by @thymikee in #4309
- docs: route the management command family in the skill and install help by @strzhao in #4282
- test(ios): answer the panel fixture's label through KVC by @thymikee in #4320
- ci(vitest): annotate failing tests on the GitHub check by @thymikee in #4316
- fix(cli): guide screenshot callers to the session prerequisite by @strzhao in #4289
- docs: slim scroll clip authority ADR by @thymikee in #4327
- docs: slim collocation decision record by @thymikee in #4328
- docs: slim Apple platform consolidation ADR by @thymikee in #4325
- docs: slim daemon runtime coupling ADR by @thymikee in #4324
- docs: slim interactive replay ADR to a decision record by @thymikee in #4331
- docs: slim request-bound runtime ADR by @thymikee in #4330
- docs: slim proposed event journal ADR by @thymikee in #4329
- docs: slim screen recording proposal by @thymikee in #4326
- fix(cli): print failures as a recoverable summary line by @thymikee in #4302
- feat(cli): render scoped snapshot refs in their pinned form by @strzhao in #4284
- test(android): wait on the InputMethod window before comparing keyboard pixels by @thymikee in #4319
- test(daemon): pin that sessionless screenshot refusals never capture by @thymikee in #4335
- fix(interaction): omit changedFromBefore when no verify baseline was captured by @strzhao in #4338
- docs(adr): slim ADR 0023 to a decision record by @thymikee in #4323
- fix(platform-apple): simplify alert action retry budgets by @pcbeingused333 in #4123
- test(repo-guards): fail when an ADR cites a missing repository file by @thymikee in #4336
- chore(gates): typecheck every scripts/ TypeScript file by @thymikee in #4364
- refactor: align ADRs with the code and delete unreachable command-runtime families by @thymikee in #4361
- fix(daemon): report failed close/disconnect, cancel shutdown timers, scope daemon diagnostics by @thymikee in #4357
- test: drive coverage-flaky timing tests by timer order and events by @airowe in #4353
- fix(android): return framework share sheets as a system surface by @mwolson in #4349
- fix(contracts): normalize rejected cleanup in durable resource disposal by @yuminn-k in #4346
- fix(interaction): disclose label-fallback when the native-ref preflight recovers by label by @airowe in #4352
- fix(cli,mcp): reliable MCP stdio, cancellation, shared session lock, strict mcp args by @thymikee in #4355
- fix(remote): correct fill recording recovery guidance by @nikitabhagat2307-prog in #4351
- fix(daemon): harden command input handling for type, alert, push, clipboard, paths and artifacts by @thymikee in #4360
- fix(selectors): keep downgraded target annotations under the payload ceiling by @airowe in #4354
- chore(gates): make test guards and CI selectors fail on the violations they exist for by @thymikee in #4356
- feat(provider-tizen): add Samsung Tizen TV provider plugin by @alimek in #4168
- fix(daemon): contain session artifact paths by @thymikee in #4389
- fix(remote): reject invalid artifact responses and settle interruptions by @thymikee in #4385
- docs(agents): correct context and prefer proven integration coverage by @thymikee in #4380
- fix(daemon): bound materialized-path retention by @thymikee in #4383
- fix(daemon): private launcher state and strict integer env parsing by @thymikee in #4369
- feat(harmonyos): report the keyboard band in snapshot responses by @strzhao in #4285
- fix(replay): escape recorded interpolation, run scripts off the event loop, harden Maestro and test flows by @thymikee in #4363
- fix(host-kit): one async process-identity reader and one identity-checked stop escalation by @thymikee in #4359
- fix(apple-runner): guard XCTest build cleanup paths by @thymikee in #4382
- fix(cli): classify cloud failures by HTTP status by @thymikee in #4381
- fix(providers): secure web text entry, harden WebDriver transport and buttons, honor --relaunch by @thymikee in #4362
- fix(capture): audit remediation for redaction, capture lifecycle, contract validation and snapshot performance by @thymikee in #4366
- fix(ios): clear a secure field with deletes before the caret tap by @TanmayOG in #4350
- fix(remote): harden transport (redirects, artifact paths, upload hash, socket cap, proxy RPC errors) by @thymikee in #4358
- fix: review follow-ups (web text-entry hint, recorder echo names, mutation report on cancel) by @thymikee in #4394
- refactor(apple): remove redundant cleanup platform state by @thymikee in #4393
- ci: install the Android SDK through one setup-android-sdk action by @thymikee in #4400
- fix(selectors): make only value rewrites live recorded placeholders by @thymikee in #4398
- fix(maestro): run child entrypoints through symlinked paths by @thymikee in #4397
- test(daemon): assert daemon exit with the predicate retirement confirms by @thymikee in #4404
- fix(kernel): rank visionOS below iPhone and iPad by @thymikee in #4410
- fix(release): continue publishing plugins after failures by @thymikee in #4409
- fix(daemon): allow idle recovery after failed relaunch by @thymikee in #4408
- fix: fit target annotations after echo redaction by @thymikee in #4406
- fix: scroll until through virtualized content by @thymikee in #4407
- fix(open): boot a stopped Android AVD named by --device before claiming it by @thymikee in #4396
- build(check): run every locally runnable catalog gate in pnpm check by @thymikee in #4401
- fix(coverage-changed): refuse stale or foreign reports via the coverage stamp by @Huyvux12 in #4387
- fix(daemon): authenticate before recording idle activity by @thymikee in #4430
- fix(aws): evaluate the final readiness observation by @thymikee in #4429
- ci: run iOS and macOS smoke on parallel Blacksmith runners by @thymikee in #4418
- fix(test): prevent an untracked child in the mutation baseline by @thymikee in #4416
- ci: speed validation and fix daemon exit detection by @thymikee in #4417
- chore: apply review notes from #4406, #4408 and #4410 by @thymikee in #4415
- fix(capture): exempt floating chrome above bottom tabs by @thymikee in #4405
- docs(harmonyos): apply the keyboard band follow-up review notes by @strzhao in #4436
- fix(wait): run duration waits without device discovery by @thymikee in #4433
- fix(upload): constrain forwarded ticket schemes by @thymikee in #4431
- fix(web): scope implicit browser sessions to workspaces by @thymikee in #4414
- fix(capture): enforce network scan merge bounds by @thymikee in #4386
- fix(release): treat asset tags as data by @thymikee in #4390
- fix(ios): refuse snapshot-derived input without a screen origin by @shamilovtim in #4439
- fix(daemon): anchor repeated gesture overlays to each execution by @thymikee in #4447
- feat(lease): name a backend baseline in a proxy lease device spec by @V3RON in #4236
- feat(config): pin workspace devices with explicit selectors by @Rutvij97 in #4384
- fix(mcp): accept digest settle results in the interaction output schema by @thymikee in #4458
⚠️ MCP breaking: feat(mcp)!: take UI targets as top-level ref, selector, and x/y by @thymikee in #4459- fix(device-selection): keep host env out of the request device cache key by @thymikee in #4464
- test(device-pin): cover existing-session admission and error sources by @thymikee in #4465
⚠️ MCP breaking: feat(mcp)!: advertise only agent inputs in MCP tool schemas by @thymikee in #4468- fix(daemon): put non-takeover options first in DEVICE_IN_USE hints by @thymikee in #4469
- fix(android): keep scroll target taps outside system bars by @thymikee in #4446
- fix(ios): own idle snapshot bridge socket errors by @thymikee in #4463
- feat(interaction): pre-dispatch admission owner for runtime press/click by @thymikee in #4461
- fix(apple): preserve simulator boot observation freshness by @thymikee in #4445
- docs(adr): pre-dispatch admission for resolved targets by @thymikee in #4457
- fix(journal): bound writes and recover rotation failures by @thymikee in #4470
⚠️ MCP breaking: feat(mcp)!: return text-only tool results by default; add mcp --structured by @thymikee in #4466- test: enforce declared launches for daemon fixtures by @thymikee in #4432
- fix(snapshot): print an empty text field's placeholder in snapshot -i by @shahjahanpak in #4467
- fix(test-kit): reject companion exit gates and tolerate deleted sources by @thymikee in #4473
- fix(journal): clarify failure diagnostics by @thymikee in #4472
- perf(test): walk only possible daemon fixture family files in the launch guard by @thymikee in #4475
- fix(android): recognize exited screenrecord processes by @shamilovtim in #4450
- fix(wait): ignore an editable field's typed value in wait text by @thymikee in #4489
- fix(android): keep alert dialog title and message in snapshot -i by @thymikee in #4493
- fix(snapshot): stop iOS 27 system toolbars from covering their own controls by @thymikee in #4494
- ci(android): reuse cached system images across emulator workflows by @thymikee in #4490
- fix(capture): publish cropped screenshots atomically after scaling by @thymikee in #4478
- fix(ios): never repeat a synthesized gesture that may have run by @thymikee in #4474
- fix(ios): mark zero-area nodes unmeasured and point their press refusal at scroll --until by @ruizemanuel in #4495
- fix(ios): make back the verified left-edge swipe by @thymikee in #4460
New Contributors
- @alimek made their first contribution in #4098
- @andrewfree made their first contribution in #4180
- @blacksmith-sh[bot] made their first contribution in #4185
- @kdy1 made their first contribution in #4207
- @sync made their first contribution in #4206
- @gronxb made their first contribution in #4210
- @gergomiklos made their first contribution in #4198
- @damian-kolasinski made their first contribution in #4192
- @vitalyiegorov made their first contribution in #4183
- @sylvain-abadie made their first contribution in #4218
- @pcbeingused333 made their first contribution in #4266
- @twotnguyen made their first contribution in #4273
- @mwolson made their first contribution in #4349
- @yuminn-k made their first contribution in #4346
- @nikitabhagat2307-prog made their first contribution in #4351
- @TanmayOG made their first contribution in #4350
- @Huyvux12 made their first contribution in #4387
- @Rutvij97 made their first contribution in #4384
- @shahjahanpak made their first contribution in #4467
- @ruizemanuel made their first contribution in #4495
Full Changelog: v0.21.36...v0.21.37