Contributing to Proteus
August 21, 2026 · View on GitHub
Proteus is a harness-agnostic driver for measuring agent self-evolution. It knows nothing
about any specific agent framework — it talks only to a HarnessAdapter, and it scores
tasks through a BenchTask. The two highest-value contributions are therefore new
harness adapters (evolve another agent framework) and new benchmarks (measure under
more goals). Both are single-file, contract-checked, CI-gated additions. This guide shows
the path; see ROADMAP.md for what's wanted.
Dev setup
python -m pip install -e '.[dev]' # add ',dsh,pi' to work on those adapters
git config --global user.email you@example.com # snapshot tests need a git identity
git config --global user.name "Your Name"
The gate every change must pass (this is exactly what CI runs):
ruff check .
pytest tests/ -q
python tests/run_offline.py # the no-pytest path must stay alive (stdlib + python3)
Style: ruff with line-length = 100. A handful of pyupgrade rules are intentionally off
so tests/run_offline.py can import the package under a stock macOS python3 (3.9) — see
[tool.ruff.lint] in pyproject.toml. Don't reach for X | None / collections.abc in
code that path imports.
Adding a harness adapter
An adapter is one class implementing seven methods (see the fully-commented
proteus/examples/adapter_template.py and the contract in
proteus/core/adapter.py). The framework handles episodes,
snapshots, dispositions, goals, and measurement; you provide the harness-specific glue.
-
Scaffold a skeleton from the template:
python -m proteus.scaffold adapter MyHarness # -> proteus/adapters/myharness.py -
Implement the TODOs. In order of effort:
surfaces()— declare each persistent, agent-editable region (memory / skills / tools / code); the measurement layer iterates this manifest.seed()/install_disposition()/disposition_fingerprint()— provisioning and the removable perturbation. ReinstallingNEUTRALmust restore the fingerprint.run_episode()/read_trace()— run one context-fresh episode against your loop and emit a normalized action trace. This is the real work; for a containerized, rebuild-from-source harness copy the pattern inproteus/adapters/dsh.py/pi.py. For an offline reference, readproteus/adapters/minimal.py.- Optional attributes for advanced harnesses (all default safely if omitted):
continuity_mode("native"/"framework"/"none"— how fresh phases continue) and, for a harness whose own edited files change how it runs,staged_activation = Trueplus an optionalvalidate_candidate()so an edit only takes effect the next episode. See the notes inproteus/core/adapter.py.
-
Check the contract. Free static + provisioning checks run anywhere;
--episodeactually runs one neutral episode (may launch containers / call a model):proteus check --harness proteus.adapters.myharness:MyHarness proteus check --harness proteus.adapters.myharness:MyHarness --episode -
Gate it in CI.
-
If your adapter provisions offline (no Docker, no model, like
minimal/llm), add its name toPURE_ADAPTERSintests/test_conformance.py(andOFFLINE_EPISODE_ADAPTERSif its loop runs offline too). It's now checked on every push. -
If it's containerized or model-backed, it can't run on stock CI. Validate it locally through the same hook contributors use, and note in your PR that you ran it:
PROTEUS_CHECK_ADAPTER=proteus.adapters.myharness:MyHarness \ PROTEUS_CHECK_EPISODE=1 pytest tests/test_conformance.py
-
-
(Optional) register a short name in
proteus/cli.py::_adapter_factoryso users can write--harness myharnessinstead of themodule:Classform.
Prepared container images for a harness are a separate, optional step —
proteus env scaffold / proteus env build; see docs/ADAPTERS.md
and environments/README.md.
Adding a benchmark
A benchmark is a BenchTask: goal text, a setup(ws) that seeds the task workspace, and
a grade(ws) that returns an EvalResult. See
proteus/examples/benchmark_template.py, the contract in
proteus/bench/task.py, and the shipped
proteus/bench/local.py / polyglot.py / swe.py.
-
Scaffold:
python -m proteus.scaffold benchmark my_task # -> proteus/bench/my_task.py -
Implement
setupandgrade. The task workspace (<run>/task/) lives outside the harness snapshot — it is the exercise, not the subject, and only moves forward. Always degrade a broken/absent solution to a legible0.0, never raise: one bad episode is a recorded zero, not a crashed sweep.Security: graders execute agent-authored code. Declare a
sandboxparameter ongradeand Proteus injects the episode's grader sandbox (ctx.grader_sandbox); run the agent's code throughproteus/bench/sandbox.py(run_python), which never falls back to host Python — this is whatlocal.pyandpolyglot.pydo. A plain hostsubprocessis acceptable only for a trusted, local benchmark; see the note inproteus/examples/benchmark_template.py. -
Wire and test.
as_goal(TASK)conditions a run on the task;as_evaluator(TASK)scores without conditioning. Add a small grader test (solved →1.0, empty →0.0) next to the ones intests/test_conformance.py/tests/test_bench.py.
Pull requests
- One adapter or one benchmark per PR keeps review tractable.
- The three gate commands above must pass; say in the PR which heavy/opt-in checks you ran locally (Docker adapters, SWE-bench) since CI can't.
- New public behavior needs a test. New contract surface needs a line in the relevant doc
under
docs/.