Skip to main content

EvalShift

Open-source LLM migration and regression testing for AI agents.

CI License: AGPL v3 Python 3.11+ Status: alpha

The SDK captures what your agent really did. The CLI replays it against a candidate model and tells you what broke. The hosted app keeps the history.

evalshift-sdk    captures real agent behavior in production
      ↓
evalshift CLI    replays it against a candidate model — scores, stats, report
      ↓
hosted (opt-in)  run history, diffs, PR gates

Migrating between LLM versions (say gemini-2.5-flashgemini-3.1-flash-lite-preview) means guessing which behaviors changed. EvalShift removes the guess. It runs both models over the same golden suite, scores the outputs with structural / semantic / LLM-as-judge / tool-call evaluators, and produces a single-file HTML report with defensible statistics: paired tests, Cohen's d, 95% CIs, and Benjamini-Hochberg correction across every (prompt x evaluator x slice) comparison.

An eval is only worth the examples in it. That is why the capture SDK is part of the product rather than an add-on: it records real production runs — model calls, tool calls, final outputs — to disk, and evalshift capture sync promotes them into golden suites. Hand-written suites are fully supported too, but captured traffic is the recommended starting point.

Local runs stay on your machine by default. Hosted private-alpha commands are available when you explicitly log in and push a run.

How EvalShift fits together

Four pieces, released and documented independently:

Piece What it does for you Reference
SDK — PyPI evalshift-sdk Records what your agent actually did in production — model calls, tool calls, final output — as capture files on disk. Those captures become your golden suite. docs/sdk.md
CLI — this repo, PyPI evalshift Replays the suite on two models, scores, analyses, reports, bundles, pushes. DOCS.md
GitHub Actionbabaliauskas/evalshift-action@v0 Runs the pipeline on pull requests, pushes the run, posts one PR comment, sets the evalshift/regression status. docs/github-action.md
Hosted serverapi.evalshift.dev, web app at evalshift.dev Optional. Stores pushed run bundles, diffs them across branches, drives PR comments and gating. docs/hosted.md

The SDK and the CLI never call each other — the interface is files under .evalshift/captures/, so either works without the other. Because both use the top-level import name evalshift, install them in separate virtual environments: the SDK in your agent's, the CLI wherever you run evaluations.

For AI coding agents

Point your coding agent at the dense, single-file reference for the piece it is working on:

Status

Alpha. Every command in the pipeline is shipped and the test suite covers 92% of the source. APIs may still change as feedback comes in.

Install

Requires Python 3.11+.

# Recommended
uv pip install evalshift     # or: pip install evalshift

And, in your agent's virtualenv — a separate one, see above — the capture SDK that feeds the CLI its suites:

uv pip install evalshift-sdk     # or: pip install evalshift-sdk

From source (for contributors):

git clone https://github.com/babaliauskas/evalshift-cli.git
cd evalshift-cli
uv venv --python 3.11
source .venv/bin/activate
uv pip install -e ".[dev]"

Quick start

Use it on your agent

This is the workflow: record what your agent really does, then hold a candidate model to it.

evalshift init                    # minimal capture-first evalshift.yaml

Instrument the agent with evalshift-sdk — installed in the agent's own virtualenv, stdlib-only, Python 3.10+:

from evalshift import capture


@capture.tool(name="issue_refund")
def issue_refund(order_id: str) -> dict: ...


@capture.agent(suite="support_agent", redact=True)
def handle(message: str) -> str: ...

redact= is required on every entry point that opens a capture session (SDK 0.3.0+) — @capture.agent, capture.agent_session, capture.agent_session_async, EvalShiftCallbackHandler: True masks emails, API keys and bearer tokens before anything reaches disk, False records verbatim, or pass your own (value) -> value callable. @capture.tool takes no redact of its own — tool spans are masked by the redactor of the agent session they run inside.

Nothing is recorded unless EVALSHIFT_CAPTURE=1 is set, so the decorators are safe to leave in production permanently:

EVALSHIFT_CAPTURE=1 python your_agent.py   # writes .evalshift/captures/
evalshift capture sync                     # captures → golden suites + wired config
evalshift all --suite-name support_agent --to <candidate-model>

See docs/sdk.md for the full capture contract. Can't instrument the agent? A hand-written golden.jsonl works just as well — see Getting started.

Driving the pipeline

evalshift all drives the full five-stage pipeline under a single Rich Live region — stacked status rows, an inline progress bar for the run stage, and a final verdict block that tells you whether the candidate is significantly better, regressed, or showed no significant change.

If you want to drive each stage by hand (useful in CI, or when re-running just one stage after fixing config):

evalshift doctor
evalshift run --yes
evalshift evaluate <run-id>
evalshift analyze <run-id>
evalshift report <run-id> --open

Every artefact lives under .evalshift/runs/<run-id>/state.json, raw.jsonl, scores.jsonl, analysis.json, migration_decision.json (when the config sets a migration_policy), report.json, report.html, and insights.json (when insights ran). None of it leaves your machine unless you opt in to hosted upload commands.

Hosted private alpha

Hosted EvalShift adds shared run history, web viewing, diffs, and GitHub PR comments. It is optional: local CLI usage does not require an account.

# Sign in through the hosted web app, then approve CLI login in the browser.
# Defaults to https://api.evalshift.dev; pass --host to target another server.
evalshift login
evalshift whoami

# Add a hosted project to evalshift.yaml:
# project: acme/model-migration
# thresholds:
#   pass_rate_min: 0.95

# Run locally, then package and push the result.
evalshift all --yes --push

You can also drive the hosted steps manually:

evalshift bundle <run-id>
evalshift push <run-id>
evalshift push --bundle .evalshift/runs/<run-id>/run_bundle.json.gz

Credential precedence is explicit CLI flags, then EVALSHIFT_HOST / EVALSHIFT_TOKEN, then ~/.evalshift/credentials.

What gets uploaded

Nothing, until you run push (or all --push) — and the CLI itself has no telemetry, analytics, or crash reporting. A push uploads one file, run_bundle.json.gz, whose full field-by-field contract is documented in docs/hosted.md — Privacy model. The short version:

  • Uploads: the run manifest (model ids, suite name, git SHA/branch/PR number, content hashes, CLI version); per-example rows — the example's template inputs and expected output verbatim, both models' full outputs, tool-call traces (names and arguments), scores, cost and latency; aggregate statistics, the analysis, the migration decision, economics, and the machine-written insights narrative.
  • Never uploads: provider API keys, prompt bodies and system prompts, suite conversation histories, tool definitions/schemas, raw.jsonl, the response cache, captures, and report.html. Prompt and dataset content is replaced by SHA-256 hashes so diffs still align across runs.
  • Can still be sensitive: inputs, expected outputs, model outputs, and traces carry whatever content your suite or your models put in them. Redact at capture time (see the SDK's redaction boundary) and inspect before pushing: evalshift bundle <run-id> writes the exact bytes a push would upload — gunzip -c .evalshift/runs/<run-id>/run_bundle.json.gz | jq ..

GitHub Action

evalshift init --ci scaffolds a production-shaped workflow: it discovers every committed suite under .evalshift/suites/, evaluates each on every pull request via babaliauskas/evalshift-action@v0 (one matrix job per suite), pushes the runs to hosted EvalShift, compares against the latest compatible base-branch run, posts one PR comment, and gates merges on your migration_policy through a single required evalshift gate check. The full setup checklist — secrets, committing suites, branch protection — is documented in the generated file itself.

evalshift init --ci

Then add repository secrets for EVALSHIFT_TOKEN and the provider keys your models use; until they exist the workflow no-ops green with a notice.

See docs/github-action.md for the workflow's shape, fail-on modes, and baseline behavior.

Agent migrations

Migrating an agent (a prompt that uses tools)? EvalShift detects regressions in which tools the new model calls, what arguments it passes, and how it sequences them. The killer scenario: a routing agent that silently stops calling notify_security_team after the migration — text-only eval reports green, EvalShift marks it CRITICAL.

Each golden-suite example carries its own toolset — recorded automatically by capture promote / capture sync from your production captures, or inlined by hand for a hand-authored suite.

See docs/agents.md for the full walkthrough and the examples/agent/ directory for a runnable customer-support example.

What the report looks like

Every run writes a single-file HTML report to .evalshift/runs/<run-id>/report.html — see Use it on your agent above, or the runnable walkthrough in examples/agent/. The report (single file, no external assets, works offline) has:

  • Migration verdict — the policy decision up top: which budgets failed, the top regression causes, and the recommendation.
  • Executive summary — one row per prompt with a severity badge.
  • What changed, in plain language — the verdict, the economics and the behavioural drift explained by defaults.insights_model. Every figure in it is copied from the computed statistics, never generated. Needs a provider key; skip it with --no-insights.
  • Per-prompt deep dive — aggregate stats, per-slice breakdown, top-5 worst regressions side-by-side.
  • Methodology appendix — every test, p-value, effect size, and CI is documented.

Why local-first?

Your prompts and suite stay local for doctor, run, evaluate, analyze, and report. The only outbound calls in local mode are to the LLM providers you configure (Anthropic, OpenAI, Google) using your own API keys.

bundle packages completed local artifacts into run_bundle.json.gz without uploading them. push and all --push upload that bundle to the hosted backend associated with your token.

Wiring the agent references into your project

The three references are listed at the top of this README. evalshift init wires these links into your project automatically: it writes EVALSHIFT.md and points existing agent files (AGENTS.md, CLAUDE.md, GEMINI.md, .cursorrules, .github/copilot-instructions.md) at it, creating AGENTS.md if none of those files exist. Disable with --no-wire-agents. In this repo the same three links live in AGENTS.md.

Documentation

Non-goals

  • General-availability hosted service or billing
  • Hosted provider-key storage
  • Multi-criterion judge in a single call
  • Custom evaluator plugin system
  • Comparing more than 2 models in one run
  • Auto-detection of LangChain / LlamaIndex prompt patterns

License

AGPL-3.0-or-later. Free for any use, including commercial, provided that derivative works — including network-hosted services — are released under the same license.

Versions 0.3.0 and earlier (published on PyPI before this change) remain available under the MIT License terms they were released with.

Commercial licenses without the AGPL share-back requirement are available; contact l.babaliauskas@gmail.com.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

evalshift-0.13.1.tar.gz (684.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

evalshift-0.13.1-py3-none-any.whl (375.1 kB view details)

Uploaded Python 3

File details

Details for the file evalshift-0.13.1.tar.gz.

File metadata

  • Download URL: evalshift-0.13.1.tar.gz
  • Upload date:
  • Size: 684.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for evalshift-0.13.1.tar.gz
Algorithm Hash digest
SHA256 63b0a6462f936b7275fd328b28d092b4e99029bb70f5eded7421edade0085e7d
MD5 3d4427f8349fc52cf4784946663fa4b5
BLAKE2b-256 16b6e864ed9f9fa45e60d346c8ece1874205977c4ba3e3c7c711fa89ab5439a9

See more details on using hashes here.

File details

Details for the file evalshift-0.13.1-py3-none-any.whl.

File metadata

  • Download URL: evalshift-0.13.1-py3-none-any.whl
  • Upload date:
  • Size: 375.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for evalshift-0.13.1-py3-none-any.whl
Algorithm Hash digest
SHA256 351f4f13aeaa7395f55a730caff2bf349d9a18c09ec7cbb03097352dec446aab
MD5 2314c8c6a29cae40c7ee464f668988e9
BLAKE2b-256 f285f262f4edbfd5cc1e6d8280be31c5e1e73c4d568ec48a0b98fdc7749bf289

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.13.1 This release

2 files

0.13.0

2 files

0.12.1

2 files

0.12.0

2 files

0.11.0

2 files

0.10.2

2 files

0.10.0

2 files

0.9.1

2 files

0.8.0

2 files

0.7.1

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.3.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page