Repository navigation
Releases
Releases · NicolasBataille/MobileController
v0.3.0 — warm action daemon
Added
- The warm action daemon.
simprobe-daemonholds one gRPC connection toidb_companionopen,
andsimprobetalks to it over a newline-delimited JSON protocol on a per-UDID unix socket at
$TMPDIR/simprobe/<udid>.sock. Measured against the same simulator: a tap costs 16 ms of
wall clock instead ofagent-device press's ~1.0-1.5 s, a tree 82 ms instead of
snapshot -i's ~0.3-0.5 s, and a 20-iteration tap+tree loop 2.05 s instead of ~26-40 s. The
spike's mixed-loop measurement was 2.7x end to end with an XCUITest session live on the same
device. Design and caveats:docs/plans/05-warm-daemon.md. simprobe daemon start|stop|status.startspawns the daemon detached, waits for it to answer,
then smoke-tests both halves — a tree with at least one element and asimctlscreenshot,
because idb's own screenshot breaks once its companion outlives a simulator reboot.stopis the
only thing here that signals a process, and only one its own daemon wrote down whose executable
still matches; a recycled pid from a stale file is discarded, never killed.statusexits 0
either way: absence is a result.simprobe tap <#id | @index | x,y> [--wait-stable], which resolves a ref against a fresh tree
with the parserframesalready uses and taps the centre of the element's frame, and
simprobe tree [--interactive] [--json], which isframes' output from the warm path.- Exit-2 error kind
daemonUnavailable, carrying the exactsimprobe daemon startline.tapand
treedeliberately do not autostart a daemon: hiding a ~1.6 s cold start inside a tap makes
one iteration of a loop mysteriously slow. scripts/regen-idb-stubs.sh, which regenerates the vendored protobuf/gRPC stubs under
Sources/SimProbeDaemon/Generated/from the installed idb client's own descriptor rather
than from upstreamidb.proto— upstream has grown fields the released companion rejects, so
generating from the descriptor is wire-compatible by construction.
Changed
- Two executable products instead of one.
simprobekeeps its single dependency and its ~1-minute
clean build (58 s measured, 2.7 MB); gRPC's 22 transitive packages live insimprobe-daemon
alone (38.5 MB, 253 s for a first clean build of both), andswift build --product simprobe
never compiles any of them. Formula/simprobe.rbinstalls both binaries and asserts both intest do. The change takes
effect at the nextscripts/bump-formula.shtag; the pinned v0.2.0 tarball predates it.skill/SKILL.mdgains a "fast action path" paragraph and loses redundancy elsewhere to stay
within its line budget.
Security / hardening (from the pre-release reviews)
- Daemon: 20 s deadline on every companion RPC; accepted connections get 10 s socket timeouts
and a 64 KB request cap; the socket is bound (answeringping {"connecting":true}) before the
possibly slowidb connect, and the daemon exits by itself if the companion never answers. - Socket directory, socket, pidfile and log are created 0700/0600 with symlink and ownership
checks (O_NOFOLLOW); sockets and pidfiles are only unlinked when they are ours;daemon stop
waits for the process to exit (SIGTERM after 5 s) and removes the pidfile last. taprejects duplicate#idmatches, empty frames, centres outside the screen and non-finite
coordinates; daemon error kinds map back to the documented exit codes.
v0.2.0 — frames, Homebrew, patched agent-device build
Added
simprobe frames: the on-screen accessibility elements with their 1x coordinates — the
thing an agent-device snapshot never reports. Banded by vertical position, one line per
element,#accessibilityIdentifieror@indexas the ref, labels cut at 40 characters,
--interactive,--point x,yand--json. Reads frames throughidb
(brew install facebook/fb/idb-companion && pip3 install fb-idb), retrying once through
idb connectbecause the first call after a simulator boots fails by design.- Two exit-2 error kinds:
dependencyMissing(carrying the install line) andidbFailed. Formula/simprobe.rb: a Homebrew formula living in this repository rather than in a separate
tap —brew tap NicolasBataille/MobileController <url>,brew trust nicolasbataille/mobilecontroller,brew install simprobe. Builds from the release tarball
withswift build -c release --disable-sandbox. Verified end to end on Homebrew 6.0.19.scripts/bump-formula.sh <tag>: rewrites the formula's url and sha256 from the real tarball,
so a release cannot silently ship the previous binary.
Changed
bench/flows/demoapp-observe-act.sh: the step that reads the echo label back is now
get_echo_value(agent-device get attrs id=form.echoLabel, matching thevaluefield
exactly) instead ofis_echo_text(agent-device is text …), which compared against the
accessibility label (Echo) and so exited 1 by construction.- README: both measured tables regenerated on iPhone 17 Pro / iOS 26.5 with agent-device
0.20.11-mc.1, stated in the section heading. The digest rung measured 1515 B against
851 B forsnapshot -ion the same screen — larger than rung 2, where 0.20.10 read 447 B —
so the ladder prose and the skill's rung-1 cost now carry that caveat.
Docs
- docs: warm-daemon spike results
- README ▸ Optional: patched agent-device build: how to build and install
0.20.11-mc.1from
NicolasBataille/agent-devicebranchmobilecontroller/patched, and which of the five known
upstream limitations it fixes. 0.20.10 remains the documented baseline the skill is pinned to. skill/references/pitfalls.md: entries 2, 3, 4, 6 and 7 gained a Fixed in the patched build /
upstream PR #N line rather than being deleted — on the pinned 0.20.10 they are all still live.
Entry 3's claim thatsession list"shows what exists" is corrected: it filters by the caller's
scope on both builds.skill/references/pitfalls.md: two new entries — §14session listhides a session opened with
an explicit--session, and §15is text/get textread the accessibility label, not the
value (useget attrsand matchvalue). Both verified live on0.20.11-mc.1.
v0.1.0 — first public alpha
Changelog
All notable changes to this project are documented here. The format follows
Keep a Changelog; versions follow SemVer.
0.1.0 — 2026-08-26
First public alpha, measured on Xcode 26.6 / iOS 26.5 with agent-device 0.20.10.
Added
simprobeCLI (Swift, no private APIs):wait-stable,motion,shot,devices,diff,
with--jsonoutput and documented exit codes.- Claude Code skill (
skill/): agent-device conventions, observation escalation ladder,
session hygiene, pitfalls and a simprobe reference. - Benchmark harness (
bench/) recording wall time, bytes, estimated tokens, host load and a
control probe per step; Settings and DemoApp flows. DemoApp/: a public SwiftUI benchmark target (tabs, list, form, 300 ms transition).- CI with a public-repo hygiene gate and an 80 % coverage floor.
Known limitations
- Pinned to agent-device 0.20.10; see README "Known upstream limitations".
wait-stableneeds ≥ 3 captures (~1.5–4 s) with default--quiet-polls 3.