Skip to main content

The experiment viewer

Start the viewer from your project:
It serves the viewer at http://127.0.0.1:8000/ and opens it in your browser (--no-open only prints the URL). Pick a job from the menu above the minimap, or open a job’s link directly; the launcher prints one like http://127.0.0.1:8000/#job=<job id>. A job that’s still running updates live. For each job, the viewer shows:
  • the tree of workflow invocations, each a list of cards for its steps and child workflows, showing the function’s docstring, how it was mapped, and its progress;
  • the arrays each operation received and produced, with links to the entities they reference;
  • links from each card to the function’s code in your editor;
  • your project’s README.md, linked from the side rail.
Everything is shown with default renderers until you write your own, and simple dataclass entities display well without any.

Report results

Have the root workflow return one report entity that references every result worth presenting. The launcher then gets the whole run from one result, and a results overview can read everything from it:
Observing inside the workflow is fine here: nothing computes from the report, and each array it references is still a step output in the graph. In the launcher, load the report with await client.load(result.item(), as_type=Report), then each array with await client.load(report.scores).

Custom renderers

Renderers are React components, written in TypeScript in your project’s views/ package, that control how the viewer shows your entities and invocations. Write one when an entity holds a lot of data, or when some of its fields deserve more emphasis than others.

Register renderers

Register each renderer for a slot and a subject: Export the registrations from views/src/bundle.ts:
views/src/bundle.ts
Give each renderer an ID prefixed with your project’s name. Two renderers for the same slot and subject with the same ID, including a clash with the viewer’s own renderers, keep the whole bundle from loading. Inside a renderer, load an entity with unwrap(useEntity(id)). singleInvocation(View) loads the invocation an InvocationPanel is given and passes it to View; its inputs and output are array entity IDs to load in turn. The fxtr-view-kit package has shared building blocks for layouts and field lists.
Write every color as one of the viewer’s design tokens, such as var(--fg), var(--bg), or var(--select-accent), never a literal like #fff. The viewer has light and dark themes, and the tokens switch with it.

Build and reload

This builds the package into its view bundle. The viewer loads the bundle when the page loads, so reload the page after a rebuild. If the bundle is missing or fails to load, the viewer runs with its default renderers and says why in the side rail.

Results overviews

A results overview is an InvocationPanel renderer keyed on the root workflow’s registered name. The viewer offers it as a full-pane view of the run, in place of the trace, and it usually reads the experiment’s report entity. Some guidance for designing one:
  • Start from the question. Decide what someone most needs to see from this experiment. It may come from several steps, not just the last one.
  • Show distributions, not just averages, when there’s room, without making the chart too busy to read.
  • Keep axes consistent. Charts of the same kind side by side should share ranges and category order.
  • For two or more categorical variables, consider a table of X × Y, small multiples (a grid of tables or charts, one per value of a third variable), or a table with a small chart in each cell.
  • Link everything to its evidence. Anything in a chart that corresponds to an entity, such as a verdict or a conversation, should be clickable, so readers can check the data behind it.