evals/. Use veryfront eval to
run every discovered eval, or veryfront eval <eval-id> to run one.
Prerequisites
- A Veryfront project with an
agents/directory. - An agent target such as
agent:researcher. - A dataset with stable example IDs.
Quick start
Create an eval file:summary.json and results.jsonl to the report directory. If
--report-dir is omitted, Veryfront writes them under
.veryfront/evals/<run-id>/. Use --report only when CI also needs the full
raw report in one JSON file.
An all-eval run creates one suite directory and one child directory per eval.
The suite directory contains the summary, one JSONL result per eval, and the
markdown report. Use --junit to add a suite-level JUnit report. Evals run
sequentially, so a failing eval does not prevent the remaining discovered evals
from running.
--report, baselines, model overrides, and model comparison are single-eval
options. Name the eval when using them.
The report and summary artifacts include schemaVersion. New reports also
include dataset metadata with the dataset kind, optional path, example count,
and a stable SHA-256 hash when examples were loaded. The hash is based on the
loaded examples and dataset kind; the path is provenance and is not part of the
fingerprint. The summary artifact
includes pass/fail counts, metric aggregates, skipped metric or check results,
gate failures, failed examples, flake classification for repeated examples,
duration aggregates, and usage totals. Use results.jsonl when you need the
full input, output, trace, and per-record metric evidence.
Tool evals
UseevalTool when the target is one tool and the eval should avoid agent
routing noise:
input mapper is present, reports keep the original dataset example in
record.input and write the actual tool input to record.executionInput.
Direct tool execution is also recorded as a normalized entry in
record.trace.toolCalls, including the tool-call ID, input, output, status, and
duration metadata when available.
Use JSON mode for automation:
1 when the
current run introduces a regression against the baseline:
--baseline fails on any aggregate pass-rate drop, failed-count
increase, metric pass-rate regression, or newly failing example. Use threshold
flags only for intentional tolerance:
summary.json whenever both the
current report and baseline include those values. They fail the run only when
the matching threshold flag is set. A baseline is accepted only for the same
eval definition and target; a report from another eval is rejected instead of
being compared.
Update the baseline explicitly after reviewing the current report:
models/<model-id>/, plus comparison.json and comparison.md at
the report root. comparison.json keeps baselineModel and candidateModels
separate, then includes models[] for the per-model metric summaries. The
recommendation is conservative: a candidate is promoted only when it has no
failed runs, introduces no newly failed examples, satisfies the groundedness
threshold when measured, and improves cost, token use, or p95 latency. Otherwise
the comparison keeps the baseline or asks for review.
Gateway-backed runs add split input/output tokens, billable input/output tokens,
provider cost, Veryfront charge, credits, and cost source to the comparison
report. Direct local runs do not estimate prices in the framework; their cost
cells stay not measured unless a gateway supplies billing metadata.
Use a comparison policy when latency, cost, and quality tradeoffs depend on the
product. Constraints are hard gates. Objectives rank candidates that pass those
gates. Veryfront does not ship presets because each agent has different
requirements.
passRate, failed, gateFailures,
groundednessScore, inputTokens, outputTokens, totalTokens,
billableInputTokens, billableOutputTokens, costUsd, providerCostUsd,
veryfrontChargeUsd, veryfrontBilledUsd, costCredits, and p95Ms.
costUsd remains a backward-compatible cost objective and prefers gateway
Veryfront charge when it is available. Use min, max, and
maxRegressionPct for constraints. Use weight with direction set to
"minimize" or "maximize" for objectives.
Each report includes provenance metadata. Local runs record git SHA, branch,
dirty state, and a dirty hash. Cloud runs prefer release, deployment, or preview
identity when those values are present.
Datasets
Use inline data for smoke coverage:Metrics
Use deterministic metrics for stable requirements:jsonMatch compares JSON values, so object key order and insignificant whitespace do not affect the result. Agent text outputs and their string references are parsed only when the entire string is valid JSON; Markdown fences and surrounding prose are not accepted. Direct tool outputs are already values and are compared without reparsing.
Use agent and operational metrics for tool and budget quality:
metrics.ops.cost uses gateway veryfrontBilledUsd first, then
veryfrontChargeUsd, legacy costUsd, and finally providerCostUsd. It does
not maintain a separate pricing table inside the framework. Token and cost
budgets fail when the measurement required by their configured limit is
missing; absent usage evidence never passes a budget.
Use calledTool when the agent must call a tool. Add input when the tool
arguments must include specific fields. match: "partial" checks that the
expected fields are present and allows extra runtime fields. Use
match: "exact" when the whole captured input must match. Use notCalledTool
for dangerous side-effect tools, and toolCallCount for exact, minimum, or
maximum call budgets.
Use knowledge metrics when an agent should retrieve the right project knowledge
before answering. They read retrieved items from the search_knowledge tool
trace by default and compare them with expected sources or passages. For larger
datasets, put the expected knowledge on each example under
metadata.expectedKnowledge:
expectedFrom: "metadata.yourField" when examples store expected sources
under a different path. Pass tool: "your_tool_name" when the project exposes
knowledge through a custom retrieval tool. recallAtK measures how many
expected sources appeared in the top k, precisionAtK measures how many
retrieved top-k items were expected, and mrr measures the rank of the first
expected hit. citationPrecision measures whether answer citations point to
expected or retrieved sources. citationRecall measures whether expected or
retrieved sources are cited.
Adapters can expose structured RAG evidence directly on the record. Use
retrievedContext for the retrieved passages and citations for the answer
citations:
retrievedContext item must include a stable source such as a path, URL,
document id, or document key. Add content when groundedness judges or passage
matching should inspect the retrieved text. Each citations item must include
the cited source; add text or quote when reports should show the answer
marker or cited passage. When retrievedContext is absent, retrieval metrics
fall back to the configured knowledge tool trace. When citations is absent,
citation metrics read structured output.citations, output.sources, or
output.references.
Use rubric judges for semantic answer quality:
judge function
instead when evaluation must use project-specific logic or a non-LLM grader.
Use answer.groundedness when the judge should compare the final answer against
retrieved knowledge evidence:
search_knowledge by default and passes it to
the judge. The built-in LLM judge asks for structured JSON, fails closed when
the response is malformed, and checks semantic support instead of brittle string
overlap.
Checks
Usecheck for assertions that depend on the full record:
Mock tools for local agent evals
UsemockTools when a local evalAgent should run the real agent while
replacing its configured tools with deterministic eval doubles. The agent still
produces the answer and trace; mockTools only changes the request-scoped tool
set passed to agent.generate({ tools }).
mockTools can also be a resolver. The local CLI calls it once for each
example repetition so each record can receive fresh state:
mockTools result. Skills agents keep
only the read-only skill loader tools, load_skill and
load_skill_reference, so a skills agent can inspect skill instructions during a
mocked eval; execute_skill_script is not retained unless mockTools supplies
it explicitly. Loaded-skill allowed-tool policies and delegation overrides are
disabled while mock tools are active; the mock tool map is the complete tool
allowlist for that generate() request. There is no stream() equivalent for
request-scoped mock tools. Live AG-UI agent-service evals reject definitions
with mockTools before sending a request to the hosted endpoint.
Live agent-service evals
Use theveryfront/eval/agent-service subpath, documented under
veryfront/eval, when an eval should run
against a live AG-UI agent service. The adapter plugs into runEval, so reports
still use the standard EvalReport shape and the same metrics.
AG_UI_EVAL_PROJECT_ID when cases need project files, releases, or other
project-scoped API state. Set AG_UI_EVAL_PROJECT_SLUG or
VERYFRONT_PROJECT_SLUG when the AG-UI endpoint runs behind the project runtime
proxy. The adapter reads AG-UI events into record.trace.events, records tool
calls as record.trace.toolCalls, captures tool call IDs, status, streamed
arguments, result payloads, and denied/error state when the AG-UI endpoint emits
them, and puts the parsed text at record.output.text.
Live adapters and CLI helpers require a non-empty VERYFRONT_TOKEN. CLI case
filters cannot opt into mutation: a requested write case still requires
AG_UI_EVAL_WRITE=1, and an experimental write case requires both
AG_UI_EVAL_WRITE=1 and AG_UI_EVAL_EXPERIMENTAL=1. Unknown, duplicate, or
disabled case selections fail before any case runs. A run with no passing case
exits unsuccessfully instead of treating an all-skipped selection as evidence.
Projects with existing live AG-UI suites can also import reusable CLI, API, and
durable canary helpers from veryfront/eval/agent-service. Use those helpers
for product-specific canaries that are not yet expressed as evalAgent
definitions. Do not import from veryfront/agent/testing; that legacy testing path
is intentionally absent.
Export reports
Useveryfront/extensions/eval when reports need to flow to an external eval
platform. The registry supports multiple exporters, so Braintrust, Langfuse, and
LangSmith exporters can coexist behind the same contract. runEval can export a
completed report through selected exporters and includes export receipts or
failures in report.exports.
Veryfront bootstrap seeds the registry for project extensions. Standalone
scripts can create and register a local registry explicitly.
metadataAllowlist
only for metadata keys the destination is allowed to receive. Runtime monitoring
remains separate: use veryfront/extensions/observability and the OpenTelemetry
extension for spans,
traces, metrics, and service monitoring. When OpenTelemetry is active, runEval
adds the active traceId and spanId to export context unless you pass
context.trace explicitly.
Eval exports are explicit data exports, not ambient telemetry. Exporters receive
the completed EvalReport plus EvalReportExportContext only when the eval run
selects an exporter id or passes an export registry. This is the right hook for
Langfuse, LangSmith, Braintrust, or an internal gateway that translates the
redacted report into a vendor-specific API shape. Regular OpenTelemetry settings
such as OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_METRICS_ENABLED, and
OTEL_TRACES_ENABLED do not route eval reports to those vendors; they only
control runtime trace and metric export.
Use project metrics when an eval should also emit
aggregate dashboard signals such as vf_eval_result_total or
vf_eval_duration_ms. Keep report exports for rich per-case eval data, and keep
project metrics to low-cardinality counters, histograms, and gauges.
Use @veryfront/ext-eval-report-http when an eval gateway endpoint should
receive reports without adding a vendor SDK:
Gateway mapping strategy
Keep vendor-specific SDKs and schemas behind your HTTP gateway. Veryfront sends one redacted payload shape,{ report, context }, and the gateway maps that
payload to the destination API:
Gateways should treat
context.trace as correlation metadata. It is not span
export, does not include logs or metric streams, and does not replace ambient
OpenTelemetry export.
Use @veryfront/ext-eval-report-mlflow when completed reports should become
MLflow Tracking runs. The CLI path can be environment-only: set
MLFLOW_TRACKING_URI to activate the extension and select the default mlflow
exporter for the run.
MLFLOW_TRACKING_URI. Use MLFLOW_TRACKING_TOKEN for bearer auth or
MLFLOW_TRACKING_USERNAME / MLFLOW_TRACKING_PASSWORD for basic auth. Standard
OAuth client credentials are also supported through
MLFLOW_OAUTH_TOKEN_URL, MLFLOW_OAUTH_CLIENT_ID,
MLFLOW_OAUTH_CLIENT_SECRET, and an optional MLFLOW_OAUTH_SCOPE.
When MLFLOW_TRACKING_URI is configured, veryfront eval automatically exports
every completed eval report to MLflow. Set VERYFRONT_EVAL_EXPORTERS=mlflow
explicitly when CI should make that selection visible in its environment:
--export wins over VERYFRONT_EVAL_EXPORTERS when both are set. The legacy
singular VERYFRONT_EVAL_EXPORT is used only when
VERYFRONT_EVAL_EXPORTERS is unset. Without either selector,
MLFLOW_TRACKING_URI selects the fixed mlflow exporter automatically.
From the CLI, pass comma-separated exporter ids. Export failures are reported in
the JSON report and do not prevent local report or JUnit files from being
written. That best-effort behavior is the local default. CI can make a selected
export a quality gate with --require-export or
VERYFRONT_EVAL_EXPORT_REQUIRED=true; artifacts are still written before the
command exits non-zero.
Remote MLflow endpoints, OAuth token endpoints, artifact proxies, and optional
run URL templates must use HTTPS. Plain HTTP remains supported only for local
localhost or loopback MLflow development servers. Requests use bounded
timeouts and retry only safe operations. The exporter does not blindly retry a
run creation; it recovers a lost create response using the deterministic
veryfront.export_id run tag.
mlflow-artifacts:/... roots use the tracking server itself by default, so a
normal local mlflow server --serve-artifacts setup needs only
MLFLOW_TRACKING_URI. For a distinct artifact server or object-store-backed
root, configure MLFLOW_ARTIFACTS_URI; MLFLOW_ARTIFACTS_PORT derives it from
MLFLOW_TRACKING_URI for a local server on another port. v1 does not upload
directly to local filesystem roots or backend-specific schemes such as dbfs://,
gs://, wasbs://, or similar URIs. After upload, the exporter makes a
best-effort retrieval check through
MLflow artifacts/list for the veryfront-eval path and stores only the
sanitized verified/missing paths in the export receipt. The check is
non-fatal: because artifacts/list responses vary across MLflow deployments, a
mismatch or a failing listing endpoint is logged as a warning rather than
failing an export whose uploads already succeeded.
When a tracking service provides no HTTP(S) artifact proxy, set
MLFLOW_EXPORT_ARTIFACTS=false. Veryfront still sends the MLflow run’s
aggregate metrics, parameters, and tags, then skips report-artifact upload
without relying on a backend-specific storage API. This is not needed for a
normal local mlflow server --serve-artifacts setup.
The MLflow exporter logs generic aggregate metrics from the normalized
EvalReport; it does not know project-specific label formats. If a project
wants generic classification aggregates such as accuracy, macro precision,
macro recall, macro F1, per-category counts, or confusion counts, extract safe
labels inside the eval metric and place them in metric evidence:
@veryfront/ext-eval-report-* exporter, for example a future
@veryfront/ext-eval-report-braintrust, instead of being special-cased in
project eval definitions or the MLflow exporter.
Discovery
Eval files are discovered fromevals/:
ai.evals.discovery.paths in project config to use a different directory.
Studio editing
Studio can list eval definitions, show source location, and expose form fields for stable parts of the definition: name, target, dataset source, repetitions, tags, metadata, and metrics. If code is dynamic, including a tool evalinput
mapper, Studio should fall back to source editing for the same file.
Use createEvalSourceDocument(discoveredEval) to normalize a discovered eval
for Studio panels. The document exposes editableFields, dynamicFields,
source.filePath, source.exportName, dataset metadata, metric metadata, and
the eval capabilities required by the panel.
Use project.evals.read for listing reports and definitions. Use
project.evals.write for editing eval source definitions. Source documents that
can start durable runs also include project.evals.run. Triggering an eval run
records a canonical run with kind eval when the durable run API is used.
Verify it worked
List discovered evals:0 when all gate and budget checks pass. It exits
with status 1 when any gate or budget check fails.