End-to-end coverage is fixture-owned eve eval runs. The suite only runs
fixture eval files from the fixture directory.
CI splits the coverage into two suites so live-model flake never gates world-infrastructure coverage (and vice versa):
- Model suite (
e2e-local.yml): every fixture runs against the local workflow world with real matrix models. Fixtures whose behavior varies per provider declare"e2e": { "modelMatrix": "full" }inpackage.jsonand run on every matrix model; all other fixtures run once on the default model. - World suites (
e2e-vercel.yml,e2e-postgres.yml, and one workflow per additional workflow world): every fixture builds, deploys, and runs once with deterministic mock models (EVE_E2E_MODEL=mock), proving the world's infrastructure — build, deploy, boot, streaming, durability — without live models. Evals whose assertions need a real model carry thereal-modeltag and are excluded there via--exclude-tag real-model.
Fixture agents author their harness-owned configuration through the private
@eve-e2e/config workspace package (e2e/fixtures/e2e-config):
e2eAgentConfig({ mock? })— spread into the rootdefineAgent: resolves the matrix model fromEVE_E2E_MODEL, and applies the workflow-world override fromEVE_E2E_WORKFLOW_WORLDwhen set.e2eSubagentConfig({ mock? })— the same model resolution for subagents, without root-only settings.e2eModel({ mock? })— a bare model handle for nested slots such as compaction models and dynamic selections.
When EVE_E2E_MODEL=mock, all of these return a deterministic mockModel()
instead of a gateway model id. The default responder echoes the last user
message; fixtures whose evals need tool calls pass a scripted responder via
the mock option (see agent-tools-sandbox/agent/agent.ts).
An eval tagged real-model asserts behavior only a live model produces
(judge scoring, provider cache metrics, free-form tool planning). The world
suites exclude it; it still runs in the model suite. Untagging an eval is the
migration unit for world-suite coverage: script the fixture's mock responder
until the eval passes under EVE_E2E_MODEL=mock, then remove the tag. Prefer
untagging over new real-model tags — deterministic evals make every world
suite stronger.
Run evals from the fixture directory:
cd e2e/fixtures/agent-basic-runtime
EVE_E2E_MODEL="openai/gpt-6.1-sol" pnpm exec eve eval --strictMock-model runs work anywhere with no provider credentials, which makes them the fastest way to validate world-suite behavior locally:
EVE_E2E_MODEL=mock pnpm exec eve eval --strict --exclude-tag real-modelEvery retained e2e eval is deterministic and self-contained. Coverage that needs external services or injected env is intentionally not part of this suite. Most fixtures use the shared model-provider credentials; dedicated runtime stress fixtures may use an authored deterministic model instead.
Each retained fixture package also exposes the same command as:
pnpm --filter agent-basic-runtime test:e2eThe root convenience command runs every fixture package with a test:e2e
script:
pnpm test:e2eVercel e2e uses the same fixture evals against immutable preview deployment
URLs. All fixture deployments link to the same Vercel project id; isolation
comes from the deployment URL returned by vercel deploy --prebuilt.
One-time project setup:
- Configure the shared Vercel project for Node.js 24.
- Provide the model-provider credentials needed by
EVE_E2E_MODELin the project's Preview environment. - Provide
VERCEL_TOKEN,VERCEL_ORG_ID, andVERCEL_PROJECT_IDin CI.
The repository does not install the Vercel CLI. Locally, any global vercel
install works. CI installs it with pnpm:
pnpm add --global vercel@latestRun a fixture against Vercel from its directory:
vercel link --yes --project "$VERCEL_PROJECT_ID"
vercel env pull --yes --environment=preview
VERCEL=1 VERCEL_ENV=preview VERCEL_TARGET_ENV=preview \
VERCEL_PROJECT_ID="$VERCEL_PROJECT_ID" \
pnpm exec eve build
DEPLOYMENT_URL="$(vercel deploy --prebuilt --yes --target=preview \
--env "EVE_E2E_MODEL=$EVE_E2E_MODEL" | tail -n 1)"
npx eve eval --strict --url "$DEPLOYMENT_URL"Do not set VERCEL_TEAM_ID at build: sandbox template keys must derive
identically at build and runtime, and Vercel has no team variable at runtime.
agent-tools-sandbox/evals/sandbox/redeploy.eval.ts proves sandbox semantics
across deployment updates as they behave on preview targets. A delivery to an
idle parked session hands ownership to the exact deployment that accepted the
request while preserving the public session stream. The eval verifies that an
instruction-only redeploy preserves the sandbox workspace, a resource-changing
redeploy rotates it, and a new session loads the new deployment's skill.
The eval redeploys from inside its test body: it mutates the agent source,
runs eve build + vercel deploy, and repoints a run-scoped Vercel alias at
each new deployment, polling /eve/v1/info until the alias serves it.
Because immutable deployment URLs never change what they serve, the eval
must run against the alias — the e2e-vercel workflow sets
EVE_E2E_REDEPLOY_ALIAS, aliases the deployment, and runs --tag redeploy
evals as a second eve eval invocation after the main suite. Without the
alias env (local matrix, plain eve eval --strict) the eval skips.
Most fixture agents resolve EVE_E2E_MODEL
through @eve-e2e/config, defaulting to openai/gpt-6.1-sol for local runs.
Fixture eval configs use the shared e2eJudgeModel() helper, which returns an OpenAI decision-model instance for openai/gpt-5.6-luna until CI has access to Jev. The adapter uses Gateway's Responses endpoint and AI_GATEWAY_API_KEY, independently of the agent matrix. A bare Luna string targets Gateway's native decision API and is not supported. Deterministic judge coverage in agent-decide passes a fixture decision model explicitly.
agent-workflow-stress uses eve's mockModel fixture helper so its 100-turn
runs stay fast and deterministic. Its concurrent and sequential evals cover
high-volume session execution and repeated session resumption respectively.
Its parallel-tool-calls eval scripts ten tool calls into one model step and
proves the durable runtime executes them concurrently, which a live model
cannot guarantee because it may split the calls across steps.
The agent-self-modification
fixture contains source-generation and repair examples using eve eval. It
checks generated tools through real calls in fresh sessions and restores source
after retiring the parent and child sessions. Routing-only self-modification
coverage stays in agent-subagents.
agent-tasks is the real-model gate for how models plan around tasks: waiting
for a needed result, fanning out, keeping or correcting tasks after a new
message, and ordering a side effect after the result it depends on. Every eval
in it is tagged real-model. Deterministic task coverage lives with the
surfaces it exercises, in agent-workflow-tools and agent-subagents.
agent-deferred-tools owns the catalog: about 40 deferred tools (20 of them
under the ledger namespace), agents, skills, and a connection, reached only
through search and execute. Its mock-model evals cover dispatch through
execute; its real-model evals gate prompt-cache reuse after discovery and
that web questions go to web_search.
agent-tool-discovery is the real-model gate for how models use the catalog
tools: a catalog of 70 deferred tools (60 in the sre, d0, index, and
support namespaces), a deferred skill, and a deferred agent, with no
connections, beside the default web_search and bash. Its evals check that
models find deferred tools with eve__search and run them with eve__tool,
send web and shell requests to web_search and bash instead, and leave the
catalog alone for questions they can answer themselves. Every eval in it is
tagged real-model.
E2E fixtures live under e2e/fixtures/*. Fixture discovery also accepts
apps/fixtures/* apps with an evals/ directory, but shared development apps
should stay out of the e2e matrix unless they intentionally own evals.
When adding e2e coverage:
- Put the eval in the fixture app's
evals/directory. - Keep it runnable with only
eve eval --strict. - Keep it deterministic: no external service startup or injected env requirements (beyond model-provider credentials).
- If the behavior cannot fit that shape yet, leave it out and rebuild it later as a first-class eval story.
The matrix models and worlds are registered in e2e/matrix.json
— edit that file to add either. .github/scripts/discover-e2e-fixtures.mjs
discovers every fixture with an evals/ directory and emits the suite
matrices from the registry:
model_matrix— fixture × model legs fore2e-local.yml. The first registry model is the default that every fixture runs on; the rest run only on fixtures with"e2e": { "modelMatrix": "full" }in package.json. A fixture can sete2e.localOnly: truewhen it requires local-runner hardware or daemons and must not enter world deployment matrices. A fixture can add a narrowly scoped leg withe2e.additionalModelsentries shaped as{ "name": "short-check-name", "id": "provider/model" }.e2e.optionalModelscan name selected model legs that should still run and report failures without blocking the aggregate check. Fixtures can definee2e.modelShardsas named, non-empty eval-ID partitions; discovery requires the partitions to assign every discovered eval exactly once and expands each selected model into one job per shard. This partitions only the local model suite; world matrices remain one leg per fixture.world_matrix_<world>— one leg per fixture for that world's suite workflow. A fixture can sete2e.worldsto a subset of registered world names, or to[]when its evals require local dev behavior; omitting it selects every world. A registered world'spackagereaches the job asEVE_E2E_WORKFLOW_WORLD(worlds without one, likevercel, use the deploy target's default).
The short model name is the stable Actions check identifier; the full id
selects the provider model. Updating a model version does not rename required
checks. Each workflow also publishes one stable aggregate check —
e2e-local, e2e-vercel, or e2e-postgres — which succeeds only when every
leg succeeds. Require those aggregate checks in the repository ruleset so
newly added fixtures and models become required automatically. Add a new
aggregate to the ruleset only after its workflow lands on main: a required
check nothing reports blocks every PR as permanently "expected".
.github/workflows/e2e-local.yml (the model suite) builds the eve package
once per leg, then runs one fixture directory with the leg's real model:
pnpm --filter eve run build
cd "$FIXTURE_DIR"
pnpm run --if-present e2e:prepare
EVE_E2E_MODEL="$MODEL" pnpm exec eve eval --strict --junit "$JUNIT_PATH"For a sharded fixture, the workflow passes that shard's eval IDs as positional
arguments to eve eval. Each matrix leg has its own checkout, server, JUnit
file, and failure-artifact name.
Fixtures with generated source can define an e2e:prepare script. The local
model suite runs it before starting the eval server; the self-modification
fixture uses it to copy the checkout's standard registry scaffold.
Always build with the full build script (not build:js); only the full
build stamps the package version into dist.
.github/workflows/e2e-vercel.yml (the Vercel world suite) links each
fixture directory to the shared Vercel project id, builds Vercel output
locally with EVE_E2E_MODEL=mock, deploys that output, and runs the
mock-compatible evals:
pnpm exec eve build
DEPLOYMENT_URL="$(vercel deploy --prebuilt --yes --target=preview \
--env "EVE_E2E_MODEL=mock" | tail -n 1)"
npx eve eval --strict --exclude-tag real-model \
--url "$DEPLOYMENT_URL" --junit "$JUNIT_PATH".github/workflows/e2e-postgres.yml (the Postgres world suite) starts a
PostgreSQL service container, bootstraps the @workflow/world-postgres
schema, builds each fixture with EVE_E2E_WORKFLOW_WORLD=@workflow/world-postgres,
runs the mock-compatible evals against a local production server
(eve start), and asserts the traffic produced Postgres-backed workflow
runs. Every fixture carries @workflow/world-postgres as a dependency so
the world module resolves at build time.
A world suite for another workflow world follows the same shape: register
the world in e2e/matrix.json, add an e2e-<world>.yml that consumes its
world_matrix_<world> output (the registered package arrives as
matrix.world_package for EVE_E2E_WORKFLOW_WORLD), set
EVE_E2E_MODEL=mock (plus any backing services), and run with
--exclude-tag real-model.
TUI smoke scripts are not e2e. They live under
packages/eve/test/tui-client and run through pnpm test:tui.