NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev
Runtime probe that exposes a Flutter app's widget tree to QA agents over the Dart VM service. Pairs with agent_wires_mcp.
Last release 24 days ago
14 Sep 2026
Release timing varies
gaps range from 9 days to 4 months
Nearly every release is documented
notes for 8 of 8 stable releases
Nothing withdrawn
no release was ever pulled
4 months old
8 releases · first in 2026
One column per month.
fix(probe,mcp): real swipe deltas, visible-only scroll, offscreen gua…
fix(probe,mcp): real swipe deltas, visible-only scroll, offscreen gua…
Gesture and targeting fixes surfaced by driving a production cart flow.
swipe never scrolled. Synthesized PointerMoveEvents carried the
default delta: Offset.zero, so drag recognizers never cleared the touch
slop and a plain ListView under the finger stayed put while tap worked
fine. Moves now carry the real per-step delta.scroll (no element_id) picked a list the user could not see. The
largest-viewport heuristic happily drove the home list buried under a pushed
route. Selection now runs the snapshot's occlusion pass and only considers
scrollables that are neither hidden nor off-screen; when none qualify it
returns success: false instead of scrolling hidden content.tap / long_press refuse targets outside the viewport. Dispatching a
pointer event whose center lies off-screen "succeeded" silently and nothing
happened. Both now return success: false with an outside the viewport ... scroll it into view first error and the computed at point. (A target that
is inside the screen but clipped by its own scroll viewport is not detected.)snapshot flags offscreen: true on laid-out elements whose center lies
outside the viewport (rows further down a scrollable column) — the same rule
the tap guard uses — so an agent can tell "listed" from "tappable".wait_for_element gains match: "substring". Labels are inferred from
descendant text, so callers rarely know the exact string; with
match: substring a case-insensitive, word-boundary match is accepted
("Domains" finds "Domains · Manage your domains", "OK" does not find
"Book now"). The default stays exact. The response now echoes the matched
label and match: "exact" | "substring" | "role".agent_wires_probe 0.1.9 — scroll ( #12 ) + screenshot ( #13 ) reliability…
Fixes screenshot returning a stale frame — most visibly "one navigation
behind": a freshly-navigated, fully idle screen captured the previous route,
byte-identical across repeated calls (#13).
RepaintBoundary was captured. Flutter wraps every
Navigator route in its own RepaintBoundary (_ModalScope). The capture path
selected the first boundary in pre-order traversal — the bottom/oldest route
in the stack, which the current route covers. Its retained layer still holds
whatever it last painted (the previous screen, or a mid-transition frame), and
the Overlay never repaints it — which also made '!debugNeedsPaint' assert on
that covered route even when the binding was idle.debugNeedsPaint is deliberately not part
of the selection — the visible route can be transiently dirty (e.g. a blinking
text cursor); that case is still handled by the existing settle-and-retry.Adds an on-screen action overlay — a narration layer for a human watching the agent drive the app. Debug-only (like the rest of the probe) and on by d
Adds an on-screen action overlay — a narration layer for a human watching
the agent drive the app. Debug-only (like the rest of the probe) and on by
default; it never appears in the agent's screenshot or snapshot.
enter_text/clear_text and
inspect/point-at, and a brief border flash + badge for screenshot and
snapshot.IgnorePointer overlay inserted into the app's topmost
Overlay; effects auto-expire and are capped so a burst can't accumulate. The
host is never installed while the overlay is disabled, so it can't perturb the
app's element layout when off.ext.qa.set_overlay extension (paired with the
MCP set_action_overlay tool); compile-time opt-out via
AgentWiresProbe.install(actionOverlay: false).Docs-only release. No code or API changes — refreshes the README so the pub.dev page reflects the 0.1.5 screenshot and ping version-reporting behaviou
Docs-only release. No code or API changes — refreshes the README so the
pub.dev page reflects the 0.1.5 screenshot and ping version-reporting
behaviour and bumps the install snippet to ^0.1.6.
Screenshot reliability + version reporting from a real LLM-agent driving session. No breaking API changes; AgentWiresProbe.install() is unchanged.
Screenshot reliability + version reporting from a real LLM-agent driving
session. No breaking API changes; AgentWiresProbe.install() is unchanged.
TextField is focused. RenderRepaintBoundary.toImage
asserts !debugNeedsPaint in debug builds, so a focused text field — whose
blinking cursor repaints every frame — kept the root boundary perpetually
dirty and screenshot always failed mid-edit
('!debugNeedsPaint': is not true). Capture is now optimistic with a
settle-and-retry: on failure it commits a frame (which also defeats stale
captures) and retries across the windows between cursor blinks where the
boundary is clean.endOfFrame unbounded, which could block the call indefinitely when
no frame is being produced. The frame wait is now bounded (a live app lands
one in ~16ms; the timeout is only a safety net), and the
no RepaintBoundary found error explains the cause and points at
wait_for_idle.ext.qa.ping now returns {"ok": true, "probe_version": "0.1.5"}. The MCP
server reads this to warn on probe/server version skew, since protocol drift
between the two has been observed to cause odd hangs. probeVersion is
exported from the package and pinned to the pubspec version.Perception-accuracy fixes from real LLM-agent driving sessions. No API changes; AgentWiresProbe.install() is unchanged.
Perception-accuracy fixes from real LLM-agent driving sessions. No API
changes; AgentWiresProbe.install() is unchanged.
InheritedTheme.captureAll
(_CaptureAll). They fill the viewport geometrically but paint
nothing, so the containment cover test treated them as a covering page
and occluded the real route beneath — every text-field screen
(DomainRegisterRoute, etc.) came back with an empty snapshot. The
cover test now ignores transient overlays (a _CaptureAll with no
_ModalScope/ModalBarrier in its subtree); only opaque routes and
modal barriers occlude.IgnorePointer/AbsorbPointer, so a tap can't reach
them. Elements under an ignoring/absorbing wrapper are no longer
surfaced as actionable. Opacity is deliberately not used as the
signal — a transparent widget still receives taps in Flutter, so
hiding by opacity would diverge from real tap behaviour.Post-launch iteration driven by real LLM-agent driving sessions. No breaking API changes; the public AgentWiresProbe.install() / AgentWiresProbe.route
Post-launch iteration driven by real LLM-agent driving sessions. No
breaking API changes; the public AgentWiresProbe.install() /
AgentWiresProbe.routeTracker.createObserver() shape is unchanged.
DomainDetailsRoute would include the home
screen's FAB, stats cards, and bottom nav (shifted left ~146px by
parallax but still in the tree). Now per-Navigator overlay
introspection drops any entry buried under a topmost
viewport-covering page. Covering is judged by containment of the
owning theater's box (not the global window), so device_preview
and nested navigators are scoped against their real viewport.state field: "on" / "off" for Switch / SwitchListTile /
CupertinoSwitch; "checked" / "unchecked" / "indeterminate" for
Checkbox / CheckboxListTile; "selected" / "unselected" for
Radio / RadioListTile; the value for Slider / RangeSlider. A
post-pass hoists state from a contained child to the smallest
containing labelled parent, so a labelled SwitchListTile reports
state: "on" directly without the agent inspecting the inner Switch.unresolved[] is now omitted and replaced by
unresolved_count unless the MCP caller passes include_unresolved: true — cuts snapshot size by ~60% on real screens._debug.occlusion
block: {theaters_found, entries_processed, entries_dropped, viewport_found, theaters: [...]}. Lets the agent verify the
route-scoping pass ran and (when it didn't drop anything) see per-
theater entry descriptions so the failure mode is debuggable
without instrumenting the probe.ext.qa.inspect now returns a
descendants[] array with {depth, widget_type, visible_text?} for
every element up to descendant_depth (default 3, capped at 500
entries). Lets the agent answer "what's inside this Card?" without
re-snapshotting.CustomPaint metadata. Descendant entries for CustomPaint
surface painter (the painter's runtime type, e.g.
"PrecisionReactiveSliderPainter"), foreground_painter if set,
and rendered size. Tells the agent "this region is drawn pixels,
not addressable widgets" — the integrator can wrap with
Semantics(button: true, label: '…') or attach a Key to make it
targetable. README has an integrator note covering this.ext.qa.wait_for_idle returns a structured IdleStatus JSON:
{idle, blocked_by, in_flight_http, has_scheduled_frame, in_transient_callback}. On timeout, blocked_by lists what's still
active (scheduled_frame, transient_callback, in_flight_http:N)
so the agent knows whether to wait, retry, or proceed.ignore_animations: true param drops the scheduled-frame and
transient-callback checks; waits only for HTTP. Use on screens with
continuous spring animations (custom sliders, looping animations)
that never visually settle.Navigator.pages from the
live Element tree at snapshot time. AutoRoute / GoRouter / any
page-based router gets full route_stack coverage with zero
observer wiring — createObserver() becomes optional (still
available as a fallback for imperative Navigator.pushNamed apps).["UserProfileRoute", "AccountRoute", "MainRoute"] instead of just
the leaf.RepaintBoundary is found on the first call (cold start, no
frame has rasterized yet), awaits one endOfFrame and retries
before failing. Eliminates the spurious "no RepaintBoundary found"
the agent used to hit on the first screenshot of a session.VM-service extensions for an LLM agent to introspect and drive a running Flutter app: ext.qa.snapshot, inspect, screenshot, tap, long_press, swipe, en
Initial public release.
ext.qa.snapshot, inspect, screenshot, tap,
long_press, swipe, enter_text, clear_text, scroll,
press_back, wait_for_idle, wait_for_route, wait_for_element,
get_logs, get_network, ping."Sub Total · 9,709.50 LYD · Unpaid · 342844").routeStack surfaces every observed
navigator's top route so tab apps (AutoRoute, nested Navigators) can
be told apart.get_network returns method / url / status / duration
per exchange, drained incrementally via a since cursor.get_logs tees debugPrint, FlutterError.onError,
and PlatformDispatcher.onError into a 500-entry ring buffer.kReleaseMode; the probe never ships to your users.Your coding agent can read these notes before it upgrades. Set up the MCP server →