Skip to main content

evalstand

Status: 1.0.0. All 8 phases complete. Install with pip install evalstand.

Evaluating an LLM application should feel like running a test suite.

evalstand is a local-first LLM evaluation tool for Python. You write an eval file, run a watch command, and results stream into a live terminal UI — scores, nested call traces, token counts, latency, and cost. Everything runs on your machine and persists to a local SQLite database, so you can compare a run against the one before it.

60 seconds

git clone https://github.com/MiltonKlun/Evalstand && cd Evalstand
uv sync
# qa_eval.py
from evalstand import Case, evaluate, llm
from evalstand.scorers import exact


async def answer(question: str) -> str:
    reply = await llm.acall("gpt-4o-mini", [{"role": "user", "content": question}])
    return reply.text.strip()


evaluate(
    name="capitals",
    cases=[
        Case(id="france", input="Capital of France? City only.", expected="Paris"),
        Case(id="japan", input="Capital of Japan? City only.", expected="Tokyo"),
        Case(id="peru", input="Capital of Peru? City only.", expected="Lima"),
    ],
    task=answer,
    scorers=[exact],
)
export OPENAI_API_KEY=sk-...
evalstand watch          # the live view, re-running when you edit
evalstand run            # one pass, prints a summary
evalstand serve          # browse past runs in a browser (needs the web extra)
pytest qa_eval.py        # the plain test runner; same runner underneath

Three things, and only three: Cases are the inputs, the Task is your function under test, and Scorers judge what it returned.

What you get

Live results rows appear as each case finishes, not in one batch at the end
Trace trees a call made inside another call is its child, so you can see which step went wrong
Cost and tokens per call, per case, per run — and marked as a lower bound when a call could not be priced
History every run recorded locally; history, show, compare
Watch mode edit a prompt, the eval re-runs within a second
CI gates --threshold and --fail-on-error, with documented exit codes
CI artifacts --html writes one self-contained report: full outputs, whole trace trees
Ten scorers exact, normalised, contains, regex, levenshtein, ratio, close-to, JSON fields, judge, factuality
Runs under pytest each (case, repeat) is one test item, so -k, -x, --lf all work
A web UI, optionally evalstand serve browses history in a browser and streams a running eval into it

Full capability list in PLAN.md §2. Three capabilities go beyond the tool that inspired this one:

  • Nested traces. The reference implementation's traces are a flat list.
  • Response caching. It has none, so iterating re-buys every answer.
  • Stable case identity. It matches cases by position, so inserting one silently re-pairs every later case with the wrong history.

Docs

  • Quickstart — install, write an eval, run it
  • Writing evals — cases, tasks, repeats, custom columns
  • Scorers — the library, and writing your own
  • Traces — what your task did, and what it cost
  • Watching — the live view and watch mode
  • CI — thresholds, exit codes, pull-request comments
  • Web UI — serve, the JSON API, and how to read its numbers
  • Architecture — how the pieces fit, for anyone changing them
  • Decisions — why the design is the way it is

In CI

evalstand run --threshold 0.85 --fail-on-error

0 met the bar, 1 fell below it, 2 something did not run. --output markdown produces a body for a pull-request comment. See docs/ci.md for the workflow and the full table.

Why

Existing Python options are either heavyweight platforms that push you toward a hosted service, or bare metric libraries with no runner, no persistence, and no live feedback loop. evalstand is the middle: a real runner with a real UI that stays on your machine.

Limitations

Stated up front, and kept accurate as the project grows.

A delta is not a verdict. compare reports the arithmetic difference between two runs' means. There is no significance testing, so a difference between two runs of a stochastic system may be noise. Nothing here will call a change a regression.

LLM judge scorers are unvalidated. judge and factuality work, but nobody has calibrated their verdicts against human labels on your data. Treat them as a signal, not a measurement.

The showcase example has no published baseline yet. examples/pdf_extraction/ generates a 30-invoice corpus from a fixed seed with ground truth written at generation time, and baseline.py will produce the numbers from a stored run — but that needs a real model, and no such run has been made. The file says so rather than carrying plausible-looking figures, because a baseline is the number people quote.

No demo GIF yet. examples/demo/ holds an offline eval and a VHS tape ready to record; the recording tooling is not installed here.

Cost figures are lower bounds when a model is not in LiteLLM's pricing table. Unpriced calls are counted and declared, never silently treated as free.

The web UI has no authentication. evalstand serve binds localhost by default for that reason. The database holds every prompt and completion your evals sent and received, so --host 0.0.0.0 publishes all of it to anyone who can reach the port. There is no login, and adding one is not planned — put it behind something that does auth if it needs to leave the machine.

Development

uv sync --all-extras --dev
uv run pytest                       # the suite
uv run python scripts/mutate.py     # 279 mutants, all killed
uv run mkdocs serve                 # the docs site

The mutation harness is the real quality measure here. Every defect this project has found ships with a mutant that reintroduces it, so a test that stops catching its bug fails loudly rather than passing quietly. tests/unit/test_mutation_harness.py holds the harness itself to the same standard — a stale anchor reports as a broken probe, not as a survivor.

Licence

MIT. See LICENSE.


Inspired by evalite (MIT), which showed that local LLM evals could feel like running tests. evalstand is an independent Python implementation.

Release files for evalstand 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for evalstand 1.0.0
File Size Uploaded
evalstand-1.0.0.tar.gz 396.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for evalstand 1.0.0
File Interpreter ABI Platform
evalstand-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 551.0 kB

Release files / evalstand-1.0.0.tar.gz

Download URL evalstand-1.0.0.tar.gz
Size 396.4 kB
Tags Source
SHA-256 checksum
How to use checksums
308923f7af255132e5ada7e21f79679bd873217de5fdce4c00701b5f2c0115a5
BLAKE2b-256 checksum
How to use checksums
71e3520e02f26a181a00a9dd59989beea4160d0aa1c516c6a4814a1430857fdd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / evalstand-1.0.0-py3-none-any.whl

Download URL evalstand-1.0.0-py3-none-any.whl
Size 154.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
36a0656bd3f9a2fafda9bb6607e3da503af31b88c60de9aea72586a57ee3b129
BLAKE2b-256 checksum
How to use checksums
272a59a61130ad5bbbced54b03bd79023713d193e248db426b91e6b94243bfdf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.2

2 release files

1.0.1

2 release files

This release

1.0.0 This release

2 release 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