A fizzy plugin that lets an AI agent drive fizzy the way a person does, and fizzy-mcp, the MCP
server an agent (Claude Code, Codex, Grok's CLI, any MCP client) runs to reach it.
- Every command is a tool. Plugins' commands, with their parameters, are each plugin's API
to an agent:
fizzy_commandslists them, andfizzy_callruns one with arguments. - The screen as text.
fizzy_screenanswers what is drawn: one line per widget worth naming, with its role, name, tag and rect, read from the frame dvui just drew. Every window fizzy draws is in it — a dialog, a menu or a view popped out into an OS window of its own — each widget saying which, andfizzy_capturepictures any of them by its tag. - Scripts in one call.
fizzy_runruns a list of steps (input, commands with arguments, waits, expectations, settling, the screen, the profiler) across fizzy's frames and answers one report, with the step that failed and why. Turns are what an agent's iteration costs; a check that took six calls takes one. - Build, reload, check: one call.
fizzy_buildbuilds a plugin's directory, answers compile errors as data (file, line, column, message), waits for fizzy to reload the rebuilt binary, and runs afizzy_runscript against it. A warm loop is about a second. - The build loop in one call.
fizzy_buildbuilds a plugin, answers the compiler's errors as file, line and message, waits for fizzy to reload it, and runs a check script on what came back. Given fizzy's own repo instead, it builds fizzy and waits for the running fizzy to restart into the new executable (Settings > Restart when rebuilt), every open document kept, then runs the check there. The bridge does that half, since the plugin goes with the old fizzy. - Input as a person's.
fizzy_actclicks, types and presses keys through the same widgets a person uses, as a live tape. Everything shows on screen and lands in undo, and a person's own click stops it. - The profiler on request.
fizzy_profilemeasures for a while and answers fps, frame work, time per plugin and per scope, and why each frame came. It measures only the frames fizzy draws on its own, so an idle fizzy reads as idle;driveasks for every frame, to measure what drawing costs. A script'scomparestep measures, runs its steps, measures again, and answers what moved. Use it instead of adding logging.
Nothing here is a back door: an agent can do what a person at the keyboard can, and no more.
zig build # the plugin, into fizzy's plugins dir; fizzy-mcp into zig-out/bin
claude mcp add fizzy -- "$PWD/zig-out/bin/fizzy-mcp"Enable Agent in fizzy's plugin settings. For a sandbox beside your own fizzy, give both the same profile:
FIZZY_PROFILE=~/fizzy-sandbox zig build
fizzy --profile ~/fizzy-sandbox
claude mcp add fizzy-sandbox -- "$PWD/zig-out/bin/fizzy-mcp" --profile ~/fizzy-sandboxfizzy need not be running when the agent starts. The bridge connects on the first call, and again after fizzy restarts.
The tools are commands: agent.run, agent.act, agent.build, agent.capture, agent.tape,
agent.tapeOutcome, agent.profile, agent.claim, agent.release, and agent.call (another
command, as the agent's step: shown beside the person, recorded into the session's tape). Fizzy's
control server serves them as it serves every command, so an agent reaches them two ways:
agent ⇄ MCP (Streamable HTTP) ⇄ fizzy's control server (/mcp) ⇄ agent.* commands
agent ⇄ MCP (stdio) ⇄ fizzy-mcp ⇄ Unix socket (ZON lines) ⇄ agent.* commands
Each call is the caller's step (sdk.Author): the socket's connection, named by its MCP
client, or whoever the control server says is calling (one "An agent" until it says).
plugin.zig: registers the commands; on load, opens a Unix socket in the plugin's directory and writesconnection.zonbeside it (the socket's path and a fresh token, readable by this user only).src/commands.zig: the commands and their parameters.src/Server.zig: the socket's thread. It checks the token onhello, hands each request to the UI thread, and wakes the app to answer it.src/tools.zig: what the tools do, on the UI thread inbeginFrame, and the socket's routing to the commands. Some answer in the same frame; the rest (a snapshot, a tape, a measurement) wait across frames and ask for each frame they need.bridge/main.zig:fizzy-mcp, standard library only. It turns MCP calls into the plugin's requests, and JSON arguments into ZON. It goes oncefizzy mcpserves stdio onto the control server (plans/AGENTS_ANYWHERE_PLAN.md, step 3).
The socket is desktop only: a wasm side module cannot open one. On Windows, std's Unix sockets are
untested here.