Edit a running web app from inside the page: pick elements, preview changes, compare variants, and commit the approved one to source — driven by a local coding agent.
uitalk demonstrates strong tool design with clear, action-oriented naming (read_selection, capture, try_style, commit) and comprehensive descriptions (avg 180 chars, well above 10-char minimum). All 10 tools have documented input schemas with type definitions and parameter descriptions. Tool annotations (readOnlyHint) are present. However, output schemas are not explicitly documented in the visible code, responses are wrapped in generic text/error blocks without structured field definitions. Error handling is basic (generic 'page could not answer' messages). Parameter validation occurs at the tool boundary (badShowOptions, badAskChoice) but lacks actionable recovery guidance. The commit tool's 'also' parameter (additional CSS rules) lacks clear constraints on what constitutes valid rules.
Ask the user to pick one of several options. Returns the text of the option they chose, or null if they closed the panel without choosing.
Screenshot the current selection (or the page) and return it as an image, with an inventory of the elements inside the shot whose coordinates are relative to the image's top-left corner. A still frame cannot show motion: use frames for a strip, and delay to catch a state that exists only briefly. Call it again after a change to check the result. It never waits for the network — what had not arrived is named in the warnings.
The same element at several viewport widths, one image per width. This captures an element, not a rectangle, because a rectangle means something different at every width. Needs the split-screen shell, which owns the resizable frame.
Write the approved change to source. The change is identified by the snapshot taken when the user approved it: the file, the line, the old text, and the new text. If the file has changed since then, the bridge tries to find the old text elsewhere in the file and update that instead — a best-effort recovery from a concurrent edit. If it cannot find it, the change is refused and the user is asked to re-approve it against the current source.
Where an element came from in the codebase. Dev builds carry this: React and Svelte record the file and line of each element, Vue records the component's file. Failing that, the bridge searches the project's own source for the element's identifiers, and failing that, the HTML it actually served. The reply names the confidence of the answer — 'exact' (this element, file and line), 'component' (the right file, not necessarily the right line — always true for Vue), or 'candidate' (a text match, in source or served HTML) — and the evidence behind it. Treat anything short of 'exact' as a lead to confirm, not a location to edit blind. When the resolved component also appears elsewhere, a 'reuse' field breaks that into 'confirmedFiles' (other files that actually import this exact component) and 'possibleFiles' (a same-named tag whose import couldn't be verified) — see ask_choice for what to do with a confirmed one. Use this before hunting with grep.
Output schemas not documented. Tools return wrapped text/error blocks without explicit field definitions. LLMs cannot plan downstream operations or extract structured data reliably.
Error messages are generic ('The page could not answer: <err.message>') without recovery guidance. LLMs cannot determine if errors are retryable, user-fixable, or fatal.
commit tool's 'also' parameter (additional CSS rules) lacks constraints. Description says 'e.g. media queries or pseudo-classes' but does not specify format, validation rules, or limits on array size.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 63 | 2026-07-28+ | v2 |
Read the user's current element selection. Returns each selected element in the order it was picked (ref 1, 2, 3...) with its identifiers, geometry and box metrics, plus the layout context of their nearest common ancestor, the pixel deltas between them, and the viewport they are laid out in — which may be a simulated device size rather than the browser window. A ref whose element the app re-rendered away comes back marked 'stale' with no geometry — every other tool that takes a ref refuses one in that state the same way, rather than operating on a node no longer in the page. Read this before proposing any change, and before answering any question about position, alignment or spacing.
Undo all temporary style changes made by try_style or show_options, returning the element to its original appearance.
Mount a set of alternatives in the page so the user can see them side by side and pick one. Each option is a CSS declaration string (the same format as a style= attribute) that will be applied to the selected element. The page shows them in a split-screen or carousel, depending on how many there are and the viewport width. Returns the index of the one the user picked, or null if they closed the panel without choosing.
Apply a CSS declaration string to a selected element and see the result. The change is temporary: it is not saved to source, and it reverts when the page reloads or the element is re-rendered. Use this to preview a change before committing it, or to explore the effect of a property without the overhead of show_options.
Wait until the page is ready to look at, instead of guessing with a delay. Give a CSS selector or some text; set gone:true to wait for it to disappear, which is how you wait out a spinner. Returns as soon as the condition holds, with how long it waited.
wait_for tool accepts both 'selector' and 'text' parameters but does not document mutual exclusivity or precedence. LLMs may pass both, causing ambiguous behavior.
show_options and ask_choice validate inputs at tool boundary (badShowOptions, badAskChoice) but return generic error strings. Should return structured error with constraint details (e.g., 'need 2-10 options, got 1').