Data, Results and Insights
Summarize runs, save the queries worth keeping, and move run data between your machine and the platform.
Individual runs tell you what one agent did once. To answer a product question you need them added up, so AX rolls a set of runs into a table: that table is a result.
Three entry points cover almost everything: ax experiment query for rollups across an experiment, ax run query for one run, and ax insight for a query you want to keep and share.
Two ways to query
Both ax experiment query and ax run query accept either style:
- SQL is the primary path: write it yourself, scoped to one experiment or one run.
- Flags are an experimental shorthand for common rollups. You choose metrics, filters, and grouping, and AX compiles the SQL.
With SQL
Add the sql subcommand. Start with --tables to see what is queryable, then write the query:
# What tables and columns exist?
ax run query <RUN_ID> sql --tables
ax run query <RUN_ID> sql --tables events
# Failing tests in one run
ax run query <RUN_ID> sql "SELECT test_name, exit_code FROM tests WHERE exit_code != 0" --table
# Across an experiment, from a file, saved as an insight
ax experiment query <EXPERIMENT_ID> sql @query.sql --save "Failing tests"See Runs for the tables remote SQL exposes.
With flags (experimental)
Flag-based modeled queries are experimental, so expect the surface to move. Three choices decide what comes back:
- Filters pick which runs count:
--filter dim=value, the axis flags (--agent,--prompt,--product,--environment), and--experiment-version. - Grouping splits those runs, one row per group:
--group-by variant|agent|model|product|environment|prompt|test. - Metrics decide what is measured for each group, one column each: test outcomes (
testPassRate,testsPassed,testsFailed), spend (cost,tokens), time (wallClockTime), and tool behavior (toolCalls,toolFailures). Seeexperiment queryfor the defaults and the full set.
# What can I group and measure on this experiment?
ax experiment query <EXPERIMENT_ID> --dimensions
# Pass rate per product
ax experiment query <EXPERIMENT_ID> --metric testPassRate --group-by product
# Cost and tokens per prompt, claude only
ax experiment query <EXPERIMENT_ID> --metric cost,tokens --group-by prompt --filter agent=claude
# Keep it as an insight
ax experiment query <EXPERIMENT_ID> --metric testPassRate --save "Pass rate by product"You can group and filter along any dimension the experiment defined (variant, agent, model, prompt, product, environment, experiment version) plus execution-derived fields such as run status and test success.
Each row averages or totals every run in that group, so check RUNS before trusting a comparison: a row backed by 50 runs means more than a row backed by one. --dry-run prints the compiled SQL without running it, and --json gives machine-readable output.
Query local runs
Pass --local to query a local run or downloaded Parquet. For raw local runs the CLI derives analytical Parquet under .axp/derived/<run-id>/query/ on demand; for downloaded runs it reads .axp/downloads/<run-id>/ directly.
ax run query <RUN_ID> sql "SHOW TABLES" --local --table
ax run query <RUN_ID> sql "SELECT * FROM runs LIMIT 10" --local --tableLocal query exposes physical tables (runs, agent_events, tool_calls, messages, harness_spans, tests, artifacts, experiment_runs), not the remote session_data_v1 logical tables. Write local SQL against whatever DuckDB reports; dialect and table parity with remote ClickHouse is out of scope. The local runs table includes axp_cli_version, so you can compare results by the CLI version that produced them.
Legacy ax results view, ax results query, and ax results scatter spellings still work (legacy commands); prefer ax experiment query and ax run query.
Saved insights
An insight is org-scoped saved SQL with a heading and an immutable slug. Create one from a query with --save, or directly:
ax insight create "Cross-experiment cost" --sql @query.sql
ax insight list
ax insight view <slug>
ax insight share <slug>
ax insight edit <slug> --heading "Updated title"
ax insight export <slug> out.csv --format csv
ax insight delete <slug>Insights re-execute live against your org's uploaded data on view and export. Listing returns metadata only and does not rerun SQL.
ax insight share prints a public capability URL. The first share publishes a frozen copy of the heading, description, query, data family, and execution scope. That page reruns the frozen query against live data, so rows can change while later edits to the source insight do not. Repeated shares return the same URL, and deleting the insight is the only way to revoke it in this release.
Where run data lives
| Path | What it is |
|---|---|
.axp/runs/<run-id>/ | The durable execution record for a local run. See run artifacts. |
.axp/derived/<run-id>/artifacts.parquet | Lossless copy of every raw run file, written by --local runs. This is what ax run upload sends. |
.axp/derived/<run-id>/query/ | Query-only Parquet, generated on demand by local SQL. |
.axp/downloads/<run-id>/ | Parquet tables pulled from the platform by ax run download. |
| Platform | Analytical tables the platform derives from uploaded artifacts. |
Derived files are a convenience, not the record: .axp/runs/<run-id>/ is the durable format.
Upload and download
Upload one completed local run to the platform:
ax run upload # most recent completed local run
ax run upload my-experiment-01HX...
ax run upload my-experiment-01HX... --force # replace a previous upload
ax run upload my-experiment-01HX... --org org_...Uploads need saved credentials from ax auth login and use the active CLI org. On a first upload, create an API key in Account settings, paste it when ax auth login prompts, then check ax auth status. Switch orgs with ax org switch, or pass --org for a one-off. If the run was already uploaded, the server rejects the duplicate; --force replaces it. Point at a different platform with AX_PLATFORM_URL.
The CLI reports success once artifacts are committed, while the platform continues publishing analytical tables. Derivation is best effort relative to that response, so an upload can report success while a follow-up derivation failure is logged on the platform.
Pull a run's Parquet tables back down:
ax run download my-experiment-01HX...
ax run download my-experiment-01HX... --forceFiles land in .axp/downloads/<run-id>/, verified against a byte count and SHA-256 trailer per file. With an explicit id the platform is the source of truth, so the run does not need to exist locally. If the run lives in another org your key can reach, the error suggests --org or ax org switch.
When a run needs a human rather than a query, ax send-debug packages it for support.