Record a run

Turn a finished run into a short 1080p video of the real canvas, directed by you.

A recording plays a finished run back fast, on the real canvas, and writes it out as an MP4 you can drop into a blog post or a feed. The run is fixed: every step, timing, output, vote and cost in the video comes from the run's own history. What you direct is the camera: which steps it stops on and for how long. The waits in between are squeezed to a pause.

Only a finished run can be recorded (completed, failed or cancelled). The recording is made from its history after the fact.

Open the editor#

On a finished run's page (/runs/$id) the header has a Record button. It opens the recording editor at /runs/$id/record.

A run you have already directed shows Edit recording instead and reopens your storyboard.

The editor is three things around one preview:

  • The preview at the top left plays the recording. The transport under it scrubs, plays and pauses.
  • The list on the right is the run, one row per step in the order it ran. Each row offers two moments the camera can dwell on, the step's start and its result (a gate's waiting and its decision), and a beat is one of those moments switched on. Roscoe suggests the beats from the run itself (a human overriding a judge that passed, a step the run survived failing, a gate decision, the outcome) and says why beside each one. Turn a beat off, or turn any other moment into one. The rows themselves cannot be added, removed or reordered: that would be editing the run.
  • Select a beat and the inspector under the preview sets which rail tab it shows (inputs, outputs, exchange, trace) and how long it holds. With nothing selected the same box shows the pacing panel: the target length, the floor and ceiling a busy step may play for, and the pause left where a wait was skipped.

Every change saves on its own. The direction lives beside the run as <ROSCOE_HOME>/recordings/<runId>/storyboard.json. Nothing about the run is written there.

Export#

Export… in the editor's top bar opens the export dialog. It shows the video's length and a size estimate. The file is always MP4, H.264, 1920×1080 at 30 fps.

The Video switch picks the colour scheme. The video is made in the scheme the app is showing unless you pick the other.

Export renders it. The dialog shows the render's progress.

When the file is written the dialog offers Open and a reveal-in-file-manager action, with the file's name and a copy-path button. The file lands beside the storyboard, named <workflow>-<scheme>.mp4.

Two things to know before you post one:

  • The video is rendered with Roscoe's own engine, not the browser you are looking at, so text can sit a hair differently from the editor preview.
  • The video shows each step's output. If a step's output holds something you would not paste into a public post, it is in the frames. Watch the file before posting it.

The first export on a machine#

The first export downloads Roscoe's rendering engine, once, 99–120 MB depending on your platform (roughly twice that unpacked) into <ROSCOE_HOME>/browsers/. The dialog does not ask first: it says video export is being set up and shows the progress. Then it renders. Cancel during the setup and nothing is kept; the next export starts the setup over. Once the setup has finished it stays: cancelling or failing a render afterwards never removes it, and later exports go straight to rendering. To remove the engine, delete <ROSCOE_HOME>/browsers/.

The download honours HTTPS_PROXY (and https_proxy, HTTP_PROXY, http_proxy). Outside the web app, POST /api/recordings/:runId/export downloads nothing unless the body carries acceptDownload: true (see the REST API).

When export will not start#

The Export… button is greyed out, with the reason in its tooltip, only when this machine cannot render at all: Linux is not supported yet, there is no engine build for this kind of computer, the data folder cannot be written to, there is no room for the engine, or the engine on this machine cannot encode H.264.

An export can also fail partway. The ones you are likely to meet:

  • The web fonts did not load. The app loads its fonts from a CDN, and a render with the fallback font would look wrong in every frame, so it stops instead. Check the connection and retry.
  • The engine could not be downloaded: offline, or a proxy or firewall refusing storage.googleapis.com.

The dialog says what went wrong in one line and keeps the raw output under Details for a bug report.

What is in the file#

Everything on screen is run data. The run clock in the title bar shows real run time, and visibly jumps when a wait is collapsed, so a two-minute run that plays in thirty seconds never pretends to have taken thirty seconds. Node cards show their real status, attempts and cost. The rail shows the real input, output or trace of the step the camera is on. The closing card names the outcome, and the step it stopped on if the run failed or was cancelled.

Fan-out children (consensus, round-robin, map) are the one place the picture is coarser than the run: the store keeps no usable per-child timing, so every child's verdict lands when its parent does rather than staggered.

The fixture the recording is built from is an allowlist projection of the run: RunFixture in packages/schema/src/recording.ts carries the run row without its identity fields (no workflow path, project home, branch, commit, host or machine snapshot), plus the node rows as GET /api/runs/:id/nodes returns them, with each row's working directory removed. The playback masks each row's settled values until the moment the run reached them (apps/web/src/record/engine/project.ts).

Where to next#

View this page as Markdown

Predictable workflows from unpredictable AI