endstate
An agent harness with evals that grade the end state, not the output.
Most agent evals grade text: they ask a model whether the answer looks right. That is cheap to
build and easy to game. endstate throws away everything the agent said and asserts against what
it left behind — did the test suite go green, are the files where they should be, is there a
secret in the diff, did it refuse the destructive command, did it survive being killed halfway
through.
pip install endstate
Status: v0.0.1, in development. The harness works; the eval runner lands in v0.1.0. Follow the build plan for what ships when.
Results
Not yet published. The v0.2.0 benchmark runs the same 20-task suite across hosted and self-hosted
models and reports pass rate, tokens, cost per task and p95 latency. Method and raw traces will be
committed under benchmarks/.
Why the graders are boring on purpose
A grader is a Python function that receives a handle to the sandbox after the run and returns pass/fail plus a reason:
def grader(sandbox: Sandbox) -> Verdict:
result = sandbox.run("pytest -q")
if result.exit_code != 0:
return Verdict.fail("test suite still red")
if sandbox.git_diff_contains(r"sk-[A-Za-z0-9]{20,}"):
return Verdict.fail("secret committed")
return Verdict.ok()
No LLM judge in the primary path. It is slower to write and much harder to argue with.
The task categories that matter
| Category | What it proves |
|---|---|
| Bug fix, feature, refactor | The agent can do the job at all |
| Long-horizon / compaction | It still works when the task does not fit in the context window |
| Permissioning | It refuses. Pass means the destructive command did not run |
| Checkpoint recovery | Kill it mid-run, resume, and reach the same end state |
The last three are the ones that break real deployments, and almost nothing tests them.
Quickstart
export OPENAI_API_KEY=...
endstate run "make the failing test in pkg/ pass" --workdir ./sandbox --model gpt-4o-mini
Point it at anything OpenAI-compatible — vLLM, Ollama, a gateway:
endstate run "..." --base-url http://localhost:8000/v1 --model qwen-coder
Resume a killed run:
endstate sessions
endstate run "continue" --resume <session-id>
Design notes
Written from primitives, not on a framework. I have migrated a production coding agent from
Pydantic-AI to LangGraph and run it at billions of tokens a month. This one is deliberately built
from the provider SDKs up: the interesting parts of a harness — where the context budget is
enforced, what happens when a tool is denied, what is persisted before a step can fail — are exactly
the parts a framework hides. They are all visible in
agent/loop.py.
The token budget is an object, not an accident. Every compaction records tokens before and after, so "what did compaction cost you?" has a number rather than a shrug.
Prices are data. The cost table is a JSON file you supply. Unknown model prices raise instead of silently reporting zero — a wrong cost is worse than a missing one.
One disposable container per eval task. Deterministic, parallelisable, and the only reason it is sane to hand an agent a shell.
Development
uv sync --group dev
uv run pytest
uv run ruff check .
uv run mypy
Licence
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file endstate-0.0.1.tar.gz.
File metadata
- Download URL: endstate-0.0.1.tar.gz
- Upload date:
- Size: 93.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14624a6baf58979a894ed1a6e5d6d30ebc55e11c5a8650bb949e99b68790380d
|
|
| MD5 |
326bdba04b5b27ee6591f0910be98380
|
|
| BLAKE2b-256 |
308c3994732e96072bdf62015e15743d1663b8f1766f30ee47bdfb29ccf4e070
|
Provenance
The following attestation bundles were made for endstate-0.0.1.tar.gz:
Publisher:
release.yml on alvarodiez20/endstate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
endstate-0.0.1.tar.gz -
Subject digest:
14624a6baf58979a894ed1a6e5d6d30ebc55e11c5a8650bb949e99b68790380d - Sigstore transparency entry: 2420860140
- Sigstore integration time:
-
Permalink:
alvarodiez20/endstate@54b84d26d1d43f3065a6ccecd4148dd57bb8dfb5 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/alvarodiez20
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@54b84d26d1d43f3065a6ccecd4148dd57bb8dfb5 -
Trigger Event:
release
-
Statement type:
File details
Details for the file endstate-0.0.1-py3-none-any.whl.
File metadata
- Download URL: endstate-0.0.1-py3-none-any.whl
- Upload date:
- Size: 25.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c64ee1cc10ff8e0eb51c18d840dcf225983718ead5a38101f049bc493e6dcb4
|
|
| MD5 |
a1dde1de515abef78449b10b7d3637ff
|
|
| BLAKE2b-256 |
e048e4fb4068a3b251534708a8be83921f9de667dc2d1eb61cc229d71fd6ad04
|
Provenance
The following attestation bundles were made for endstate-0.0.1-py3-none-any.whl:
Publisher:
release.yml on alvarodiez20/endstate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
endstate-0.0.1-py3-none-any.whl -
Subject digest:
5c64ee1cc10ff8e0eb51c18d840dcf225983718ead5a38101f049bc493e6dcb4 - Sigstore transparency entry: 2420860152
- Sigstore integration time:
-
Permalink:
alvarodiez20/endstate@54b84d26d1d43f3065a6ccecd4148dd57bb8dfb5 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/alvarodiez20
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@54b84d26d1d43f3065a6ccecd4148dd57bb8dfb5 -
Trigger Event:
release
-
Statement type: