Handles & reports

Agents prove the change works.

"Done!" is not evidence. Mark small C# methods as handles, and the agent plays the running game through them one step at a time and checks each result. Then it shows you a report.

// the agent calls your handles one at a time
unity_exec(code: 'Print(SaturaHandles.Call("StartPulse"));')
// {"status": "done", "value": 3}
unity_exec(code: 'Print(SaturaHandles.Call("WaitForBeats", 3));')
// {"run": 2, "status": "running"}
unity_exec(code: 'Print(SaturaHandles.Result(2));')
// {"status": "done", "value": 5.16}

// and shows you what it found
satura_report(path: ".sspace/reports/arena-pulse/report.tsx")

How an agent checks its own work

Compiling proves nothing about behaviour. So the agent runs the game and drives it through handles: small public static methods in your runtime code that set up a moment, do one action or read a state.

public static class ArenaPulseHandles
{
    [SaturaHandle("Adds ArenaPulse to the Monolith and returns the lamp count")]
    public static int StartPulse() { ... }

    [SaturaHandle("Waits for the given number of beats and yields the seconds they took")]
    public static IEnumerator WaitForBeats(int count) { ... }

    [SaturaHandle("Every point light: intensity and color")]
    public static string LampState() => ...;
}

The agent calls them through unity_exec on the Unity MCP server and checks the result after every call. SaturaHandles.List() gives it every handle with its signature and description.

Small steps, clear failures

Keep each handle to one job. A failure then names the step that broke and what came back, not "failed at line 212" of a long script.

Coroutines

A handle that returns IEnumerator can wait for things to happen. Call starts it, and SaturaHandles.Result(run) reads it later. Its value is the last thing it yielded.

Every player at once

For multiplayer, unity_exec(player="all") with SaturaHandles.StartAt(SameMoment(3), "Jump") starts a handle on every player, and each one runs it on its first frame after a shared moment. SaturaHandles.PlayerIndex is 0 on the primary.

Output an agent can read

SaturaLog.Log(tag, message) writes one file per tag, each line stamped with the frame number and the time. The files are cleared every time Play Mode starts. This line came from the run in the clips below:

[F:159 T:9.377] beat 1: 3 lamps up to x3, 40 motes

The agent reads them with unity_logs(source="tags", tag=...). Unity's console lands in the same place as _log, _warn and _error, so after a red run the agent reads _error first.

Where handles run

  • In the editor session you're streaming, with the game visible.
  • In Headless NoGraphics, where a long run finishes in seconds.
  • Across the multiplayer grid, on one player or all of them.
Reports

The proof, in one panel.

The agent records the run with unity_video, takes before and after shots with unity_screenshot, and puts everything in a report. satura_report opens it next to the agent's terminal.

What's in a report

A report is report.tsx, a React component the agent writes from the app's own parts:

  • Checks with pass, fail and skip, filters, the logs of a failure, and a link from each check to its moment in the video.
  • The run video in the app's frame player: step frame by frame, event markers on the timeline, a log beside it that follows the video, previews on hover and trackpad gestures.
  • Compare for before and after shots: wipe, side by side, flip or difference.
  • Stats, tables, logs, code and Markdown, plus any JSX the agent wants for a chart of its own.

satura_report compiles and type-checks the file and sends the errors back to the agent before you see anything.

Everything stays in the report

A file name with a line number, like ArenaPulse.cs:29, opens the code inside the report at that line. A frame link scrolls to the video and seeks it. Images enlarge in place, and web links are copied rather than opened. A tab switch keeps your scroll position, the video frames and the checks filter.

The specifics.

Surface

[SaturaHandle]On any public static method in your runtime code, coroutines included.

Per player

StartAt · PlayerIndexOne handle on every player, started at the same moment.

Logging

SaturaLogOne file per tag, stamped with frame and time.

Reports

report.tsxType-checked, and rendered in a panel next to the agent's terminal.

Straight answers

Handle and report questions.

How is this different from Unity Test Framework?

Handles run inside the session you're streaming, on every multiplayer player at once, and the agent checks after each step instead of waiting for one verdict at the end.

How does an agent read the results?

SaturaHandles.Call returns JSON with the status, the value, any error with its stack, and the log lines written during the call. unity_logs with source="tags" reads the SaturaLog files.

Where do I see what the agent found?

In a report next to the agent's terminal. The agent writes one at the end of every feature and for every failure.

Related

Make the agent show its work.

Every check runs in the game itself, and the report shows you what happened.

7-day free trial (no card required)macOS & Windows