Search documentation

Search the Fumadocs-backed documentation index.

Reports

Write up what an experiment showed as a markdown document that embeds live insights, experiments, Context and run evidence.

A report is a document your organization writes together: a title, a description, and a markdown body that embeds live insights, experiments, Context objects and excerpts from runs. Members edit it in the web app; agents and scripts write the same document through ax report, the HTTP API and the report_* MCP tools. Whatever surface wrote a paragraph, everyone with the report open sees it appear.

OperationWhat it does
listThe org's reports, most recently changed first, without bodies.
getOne report with its body as markdown.
createA new report from a title, an optional description and an optional body.
appendAdd markdown after the current body.
editReplace the title, description and/or whole body, guarded by the updatedAt you last read.
deleteRemove the report and its body.

The document format

A body is CommonMark. Headings, paragraphs, lists, tables and code blocks are what you expect. Three conventions carry everything Fiveonefour-specific, so a body survives any markdown editor and reads back exactly as written.

Blocks

An embedded block is a fenced code block whose info string is ax-block and whose body is one JSON object. kind names the block; the other keys are that kind's fields.

```ax-block
{"kind":"insight","experimentId":"<EXPERIMENT_ID>","block":"scatter","scope":{},"view":{}}
```
KindShowsFields
insightOne view from an experiment's Results tab, read live at the scope you set.experimentId, block (scatter, tests, metric), scope, view
experimentAn experiment's live card (name, run count, last activity), or its definition at the pinned version. version is a fingerprint or an ordinal such as v3; omit it to follow the latest registered version.experimentId, show (card, definition), version
context-objectA product, use case, persona or other Context object, as its card with its current name and description.contextKind, id, show: "card"
evidenceThe quoted excerpt with the run's status, the object it came from and an "Open in run" link to that tool call, span or entry.runId, evidenceKind (run, tool_call, timeline_entry, span, prompt), targetId, excerpt, seqStart, seqEnd, id, findingId
evidence-chartOne metric across the runs of the experiments it cites, read live and grouped by the axis you choose.id, variant (bar, box, coverage, line), experimentIds, metric, groupBy, title, caption
evidence-tableA table of figures the author states, with its caption.id, columns, rows, title, caption
experiment-linksLinks to experiments with their live run counts.id, experimentIds, label
related-objectsThe experiments, products, use cases, agents and personas the report touches.id, groups
action-cardA recommended product change, investigation or follow-up experiment.id, actionType, title, description, target, experimentIds
study-mapWhat went into a study, which experiments ran, and what came out.id, title, inputs, experimentIds, categories

The exact field types are published as a JSON Schema in the report_append_blocks tool description. A fence whose payload does not match its kind is kept verbatim and shown as code; nothing is dropped or rewritten.

Every block accepts an optional layout object that says how it sits in the flow. Omit it for the default: the full column width, in line with the text.

layout keyValues
width0.25, 0.333, 0.5, 0.667, 0.75, 1 as a fraction of the column, or "wide" / "full" to break out of it
alignleft, center, right
floatleft, right (text wraps around the block)
heightPixels; honored only by kinds that draw at a height, such as insight views and charts

Callouts

A callout is a blockquote whose first line is a tag and a title. Three tags exist: FINDING for what the evidence showed, ACTION for what to do about it, and NOTE for anything else. Any other tag reads as a note.

> [!FINDING] Checkout is slower on Fridays
> The p95 doubles between 16:00 and 18:00 UTC across all three models.

Mentions

A mention is a link whose target is an ax:// address. The app shows the object's current name and links to it, so a renamed product or experiment stays correct in every report that cites it.

TargetPoints at
ax://experiments/<EXPERIMENT_ID>An experiment
ax://context/<KIND>/<ID>A Context object, where <KIND> is the plural type from ax context objects (products, use-cases, personas, ...)
The [checkout flow](ax://context/use-cases/<USE_CASE_ID>) regressed in [Model sweep 12](ax://experiments/<EXPERIMENT_ID>).

What the app reads from the body

The report page shows two rows above the body, both derived from it as it changes. Contents lists the headings and scrolls to the one you pick. Referenced names every experiment, Context object and run the body cites, whether through a block or a mention, with each object's current name linked to its page. Nothing needs declaring: cite an object where you discuss it and it appears in Referenced.

Columns

Side-by-side content is an HTML block: a <div data-ax-columns> holding one <div data-ax-column> per column, each with an optional data-width fraction. Separate the tags from the markdown inside them with blank lines.

<div data-ax-columns>

<div data-ax-column data-width="0.5">

Left column.

</div>

<div data-ax-column data-width="0.5">

Right column.

</div>

</div>

Editing in the web app

Open a report from Reports and write into the page. Members with the report open see each other's edits as they type, and the document autosaves. Everything below writes the format above: a block you place from the menu is the same ax-block fence a script would append, so the two ways of writing never diverge.

Type / at the start of a line or after a space to open the insert menu. Keep typing to narrow it; the arrow keys move, Enter chooses, Escape closes. The menu has three groups:

GroupEntries
TextHeadings, bulleted, numbered and task lists, a quote, a code block, a table, a divider, and a FINDING, ACTION or NOTE callout wrapped around the current line
BlocksOne entry per block kind. Insight opens a picker: choose an experiment, then arrange its Results view (block type, filters, version, axes) and choose Use this view; the block reads that view live at the scope you pinned. A kind that cannot be added from the menu yet says so and stays put.
MentionsAn experiment, or a Context object of any kind you can open; choosing one opens a search and inserts a chip with the object's current name

Type @ to open the mentions group on its own.

Every block has a toolbar above it while you edit. It moves the block up or down, sets its width (a fraction of the column, Wide or Full width), aligns or floats a block narrower than the column, opens the block's settings, and duplicates or deletes it. Drag the block's edge to resize it to the nearest fraction. Kinds that draw at a height take one in their settings. An insight block's settings switch between the scatter, test results and metric views and set what each shows; the block re-reads its data as you change them.

Drag a block by its handle to move it. Drop it in the flow to reorder, or drop it onto the left or right edge of another block or paragraph to put the two side by side as columns. Drag the gutter between columns to change their widths; when a column empties, it is removed, and a row left with one column unwraps back into the flow. Rows never nest.

Readers who cannot edit see the same page: blocks render their live views and chips show current names, with no toolbar and no menu.

Adding evidence from the app

Wherever the app shows something a report can embed, Add to report… puts it into one. Pick a report from the list, or start a new one titled after what you are adding, and the block is appended after the report's current body. The report opens from the confirmation.

WhereWhat is added
The Results tab, beside a block's Share menuAn insight block of that block, at the filters, version and view shown. It reads live, so it follows the experiment.
An experiment page's action menuThe experiment's card.
A Context object's pageThe object's card.
A run page's test rows and setup logAn evidence excerpt quoting the test's outcome and script, or the setup log, linked to the run. An empty log offers nothing to add.

A new report starts with a section heading naming what was added; an existing report receives the block alone. Blocks take the default layout; arrange them in the editor afterwards.

Writing from the CLI, API and MCP

The three programmatic surfaces take and return the same shapes: a report row (id, title, description, createdBy, updatedBy, createdAt, updatedAt) and, for a single report, its bodyMarkdown.

Two writes exist. Append adds markdown after the current body, after a blank line, and is the usual way to add a finding or a chart from a script. Edit replaces the title, the description and/or the whole body and requires the updatedAt you last read; when the report changed since, the write is refused and nothing is written, so a stale copy never overwrites a newer body. Read the report again and retry with its new stamp. Append accepts the same stamp optionally.

# Create a report and add a finding from stdin
ax report create "Checkout latency" --description "Where the p95 went"
printf '> [!FINDING] Slower on Fridays\n> The p95 doubles after 16:00 UTC.\n' | ax report append <REPORT_ID>

# Rewrite the body from a file, guarded by the stamp you last read
ax report get <REPORT_ID> --json | jq -r .report.updatedAt
ax report edit <REPORT_ID> --body-file report.md --expected-updated-at <UPDATED_AT>
SurfaceReference
CLIax report
HTTP API/api/v1/reports
MCPreport_* tools

Deleting a report removes its body and the links from findings to it. The findings and the Context objects it cited stay.