Eyes for the Agent

How Amplifier learned to see and fix its own terminal UI

The Frame

You can't fix a screen the agent can't see

amplifier-tui — a Textual-based terminal UI for Amplifier, 284 commits, 282 by Sam Schillace — set out to make Amplifier usable from a rich terminal. The catch: the agent building that terminal could not look at the rendered layout it was supposed to fix.

First, the payoff of doing it right: one engine, everywhere.

One UI-agnostic core drives three real front-ends

Because the session logic was cleanly separated into a shared core, the same engine renders through a Textual terminal app, a FastAPI + WebSocket web app on port 8765, and a PySide6 desktop app.

"Works anywhere" is built, not aspirational. But building the first surface hurt.

3
entry-point scripts: amplifier-tui, amplifier-web, amplifier-desktop
17
shared command mixins over SharedAppBase
8765
default port of the web /ws WebSocket
11
desktop phases implemented (PySide6/Qt)
The Tension

The hardest part was blindness

The central pain of building the terminal UI: the agent could not see the rendered layout it was supposed to be fixing. app.py alone is 7,131 lines of tightly coupled widgets, actions, and CSS — and no eyes on any of it.

So the first move was to make the invisible screen capturable.

Render the app with no live terminal, export a Textual SVG

A headless capture pipeline (tools/ux_test.sh) runs the app without a live terminal and exports a Textual SVG of exactly what it looks like — injecting the app's real widget types so the screenshot reflects true rendering, not a simulation.

Now the screen exists as a file. Next: read it precisely.

# tools/ux_test.sh capture → tui_capture.py parse → svg_parser.py analyze → tui_analyze.py → YAML

SVG-over-OCR: read every character with no ML uncertainty

The design insight, recorded in the manual: Textual's SVG export contains every character with exact position, color, and style — making SVG parsing far superior to OCR. The parser uses only stdlib (xml.etree), so there's zero ML guesswork.

Precise enough to trust — and general enough to lift out.

The capture engine became a reusable package: textual-capture

The generic capture engine was extracted into ramparte/textual-capture, a standalone package the TUI now depends on — providing capture_svg / capture_png / capture plus parse_svg. When the TUI refactored onto it, all 263 tests still passed.

The fix outgrew the project. Now it closes the loop.

263
tests still passing after the refactor (commit 9b2232d)
4
public APIs: capture_svg, capture_png, capture, parse_svg

A self-seeing loop: the interface debugging its own interface

Amplifier captures its own screenshot, parses what it sees into structured YAML, spots the layout bug, fixes it, and re-captures. The blind agent from the frame now has eyes on its own work.

One pattern, reusable far beyond a terminal UI.

Capture — headless SVG screenshot
Parse — SVG → structured YAML
Spot & fix — the layout bug
Re-capture — verify the fix
The Takeaway

Give an agent eyes on its own output

Once it can see what it makes, an agent can close the build–see–fix loop itself. Here it was a terminal UI rendered to SVG — but the pattern reaches far beyond terminals.

Build it so the maker can look at its own work.

Sources

Sources & Research Methodology

Feature status: Shipped (web UI: MVP)

Data as of: Development spanned 2026-02-05 → 2026-04-23 (final local commit c967de0).

Primary sources: ramparte/amplifier-tui (PRIMARY, verified) and ramparte/textual-capture (extracted capture engine).

Commands run:

Primary contributor: Sam Schillace (282 of 284 commits, ~99%).

Gaps: textual-capture's local .git HEAD is a bad object, so its commit dates/counts are unverified; its facts are grounded on present files and on amplifier-tui commit 9b2232d. Manual's inline app.py/styles.tcss line figures are stale; current wc -l counts used. The web UI is an MVP.

More Amplifier Stories