Skip to content

Snapshots and review

A snapshot is the evidence a command retains. It might be a browser screen, a terminal’s output or a set of database rows. Your agent compares that evidence with an earlier run and checks the change against your application’s rules.

Ask your agent:

Add snapshots at the points that explain this journey. Run it, inspect the changed screens and outputs, and fix regressions within the scope of my change. Show me the evidence and anything still unresolved before preparing the PR.

Use a named browser snapshot after the relevant assertion:

site.expect selector="[data-testid=invitation-form]"
site.snapshot name="team-invitation" selector="[data-testid=invitation-form]"

The name identifies the checkpoint across runs. Omit selector for the viewport, or select one visible element with stable bounds. Missing or ambiguous targets fail without a viewport fallback. See the Browser plugin for all capture arguments, timeouts and animation behavior.

Here the invitation form still exists, so the assertion passes. The screenshot shows that its role selector disappeared during a copy change.

reflow / Team invitationsIllustrative example
Change Summary

Update invitation copy

1 changed screen
invite-memberPassed
team-invitation/settings/team
Beforemain
AcmeWorkspace Invite a teammate Add someone to your workspace. Email address sam@acme.test RoleEditor Send invitation
Afterthis change
AcmeWorkspace Invite a teammate Add someone to your workspace. Email address sam@acme.test Role selector removed Send invitation
The test passed. The screen changed.site.snapshot
Agent reviewOutside scope

The role selector disappeared.

This PR changes invitation copy. Owners still need to choose a role before sending an invitation.

team-invitationteam-access.md

LocalBash and DockerUbuntu retain command results, including standard output, standard error and exit status. Wrap an application CLI command in a flow:

worker.bash command="./bin/fulfill order-1042"

Command output is retained automatically, without a terminal screenshot command. Here both versions exit successfully, but one stops returning tracking information. See LocalBash or DockerUbuntu for connection settings, command arguments and file capture.

Bash · fulfillment workerIllustrative example
fulfill-order.mdLocalBash
worker.bash
command="./bin/fulfill order-1042"

Your application command. Its result becomes a snapshot.

Beforeexit 0
stdout.txt order: 1042 status: dispatched tracking_number:
TRK-1042
stderr.txtempty
Afterexit 0
stdout.txt order: 1042 status: dispatched
tracking_numberMissing from output
stderr.txtempty
State and evidence changed
Exit code
0 → 0
Standard output
Changed

Both commands succeeded. The saved output differs.

Agent’s review note

“The worker still reports ‘dispatched’, but no longer returns a tracking number. Can the shipment notification still include a tracking link?”

Evidence: before + after / stdout.txt

A query can capture the business state behind the screen:

db.query sql="SELECT id, status, refunded FROM orders ORDER BY id" key="id" checkpoint="orders"

Use a unique, non-null key for stable row ordering. The snapshot retains query rows; your agent relates the difference to the application’s refund rules. See the PostgreSQL plugin for setup, limits and write controls.

reflow / PostgreSQL · refund checkIllustrative example
verify-refund.mddb: PostgreSQL
db.query sql="SELECT id, status, refunded
FROM orders ORDER BY id"
key="id" checkpoint="orders"
orders / rows.jsonEarlier runCurrent run
id keystatusrefunded
1041paid0.00
1042refunded25.0020.00
1043paid0.00
3 rows retained · amounts in USD
Retained before → after1042
refunded25.0020.00
Agent review · examplerefunds.md

Full refunds return the entire $25.00 payment.

The order says refunded. $5.00 is missing. The captured rows show $20.00 returned. Check the refund amount before merging.

CommandRetained evidence
site.snapshot name="…" selector="…"A named screenshot of one element; omit selector for the viewport.
worker.bash command="…"Command output, errors and exit status.
db.query … checkpoint="…"Query result rows.
Custom plugin commandThe state and artifacts declared by that provider.

These are command excerpts. Declare aliases and binding names in your flow, and initialize the application plugin lock; see Write a flow. Use list_plugins to inspect the installed command schemas. Every plugin invocation returns a terminal snapshot, but only some commands capture a screen or a named review checkpoint. A click’s result does not replace an intentional screenshot of the outcome.

All visual examples on this page are illustrations. Reflow retains the exact originals from your actual execution; a comparison must not substitute an illustration or silently overwrite them.

Terminal window
reflow plan
reflow apply
reflow status
reflow dashboard

When earlier steps or covered source files change, the next plan automatically includes affected steps and their dependents. Apply runs that work. An unchanged, completed step can reuse its evidence; you do not need to taint it after every edit.

If the external application changed without a source or input change, request fresh evidence with reflow taint flow-name, then plan and apply. Your agent can select flow-name#step-name to start from a particular step; Reflow also includes affected dependents and the steps needed to reconstruct a browser session.

A difference is a question for your agent to investigate. It can update an obsolete test or fix a product regression, rerun the affected work and show the resulting delta. See Repair and rerun for that workflow.

For a deliberate approved-image contract, the RFL snapshot checkout threshold="2%" command also compares against an approved baseline using SSIM. It reports new without one; a mismatch fails that checkpoint. The default threshold is 1%. This is a separate contract from comparing two executions.

Assert application readiness first. settle="500ms" bounds waiting for finite animations; the default is two seconds, maximum ten seconds. A timeout retains the capture and fails without comparing an unsettled image. Looping animations are not frozen or masked. See the snapshot reference.

Neither a visual difference nor a new image is permission to change the baseline. Review originals before an authorized owner accepts an expectation. Agent repair preserves the original failure; it does not turn a mismatch into a passing result by approving it. A PR can compare changed evidence without adopting a baseline.

flowKey is the exact key declared in the comparison inventory: inspect base.checks[].key or head.checks[].key (and matching runs[].key). It is not implicitly a flow slug, UUID, file path or display name. An inventory can use login-smoke as its key; use that string only when the inventory actually declares it.

For a storyboard screen bound to that check, set flowKey: "login-smoke" and checkpoint: "org-home" only if that check captures a snapshot named org-home. checkpoint uses the authored snapshot name (the capture’s displayName in comparison reads), not the step label. Provider captures also expose a retained internal name, such as provider_snapshot:<hash>; an exact internal name is accepted too. The name must identify at most one capture on each side of the selected flow. A step move can change the internal key between sides; the storyboard retains both originals as a before/after pair. Repeated names within one side, or a name that also matches another capture’s internal key on that side, are ambiguous. Use unique snapshot names or an unambiguous internal key; Reflow never picks the first matching capture.

The review distinguishes a flow outside the comparison, a checkpoint missing from a selected flow, an ambiguous name, and an unavailable retained screenshot.

Omit both fields when no existing inventory check and named capture are known. A storyboard binding maps review evidence; it does not create a test or prove the flow ran.

get_run_evidence lists provider screenshots using the authored checkpoint name, step and invocation number when the retained Browser manifest contains the name. Multiple captures with the same name still have separate evidence IDs. This also works for older retained runs; it does not require a new execution. Missing or unreadable metadata falls back to a step/call label without preventing image access. Labels do not change image identity, approval or checksum verification.

For volatile timestamps or branch labels, author a CSS mask on site.snapshot. See Browser snapshots for exact syntax and pixel behavior. Direct plugin captures support explicit comparisons and agent review; masking does not automatically approve a baseline or a difference.

A change comparison uses the frozen knowledge reviews explicitly selected as knowledge.base and knowledge.head; the application’s current knowledge root is not attached automatically. Include the storyboard document in each review’s selected paths to show it alongside the retained captures.

Each selected knowledge review must have a repository label matching the comparison and a non-null gitCommit matching that side’s exact revision commit. When base and head commits differ, publish two knowledge reviews with their respective labels, even if both select the same unchanged corpus revision. One shared review with gitCommit: null does not satisfy either side. The labels are caller-supplied context; they do not prove Git ancestry or execution.

Inspect these labels before publishing the comparison. A published comparison’s selection is immutable: changing the current knowledge root cannot attach a map or repair its selected Git labels. A new comparison is needed to change those selections. Resolving an existing snapshot name does not require editing the map or republishing the captures.