Signed-off-by: Andrew Barba <barba@hey.com>
e2e
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.
Harness config (@eve-e2e/config)
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).
The real-model tag
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.
Local
Run evals from the fixture directory:
cd e2e/fixtures/agent-basic-runtime
EVE_E2E_MODEL="openai/gpt-5.6-sol" pnpm exec eve eval --strict
Mock-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-model
Every 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:e2e
The root convenience command runs every fixture package with a test:e2e
script:
pnpm test:e2e
Vercel
Vercel 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 vc 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.
Run a fixture against Vercel from its directory:
vc link --yes --project "$VERCEL_PROJECT_ID"
vc 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="$(vc 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.
Redeploy suite
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 + vc 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-5.6-sol for local runs.
Fixture eval configs use the shared e2eJudgeModel() helper, which returns an OpenAI evaluation-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 evaluation API and is not supported. Deterministic judge coverage in agent-evaluate passes a fixture evaluation 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.
Fixtures
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.
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.
CI
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 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.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"
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="$(vc 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.