Self-evolution for any agent harness.
Plug in. Evolve. Measure.
Quick Start • Harnesses • How It Works • The Episode Loop • Onboard Your Harness • Recipes • Bring a Benchmark • Add a Measurement • Environments • Measurement
Plug in any agent harness × any model, let it rewrite its own harness over many context-fresh episodes, and measure how the harness changes — under a goal, many goals, or no goal at all.
Named for the sea-god who changes shape at will: Proteus watches a harness reshape itself, and gives you the ruler to measure the change.
🔭 Why Proteus is different
Agent self-improvement is moving from the weights to the harness — the prompts, memory, skills, tools, and control loop the model runs on. Recent systems evolve a harness to raise a benchmark score. Proteus asks a different, complementary question: what does a self-evolving harness actually do, and does an initial condition leave a permanent mark?
Three things set it apart from every existing harness-evolution system:
- Harness-agnostic. Others evolve harnesses built from their own primitives. Proteus
evolves yours: implement one small
HarnessAdapterand your agent — the bundled offlineminimalharness (the CLI default), DeepSeek Harness, Pi, Aki, or your own — plugs into the same framework, sandbox, and measurement. - Goal and no-goal, with visible or hidden evaluators. Others hard-code a single
regime: one benchmark verifier, agent blind to the score, goal mandatory. Proteus spans
the space —
no-goal | one goal | many goals, and evaluators the agent either sees (in the observe phase) or never sees. No-goal, unpressured evolution is a first-class mode. - A measurement instrument, not just a score. Others report task pass-rates. Proteus ships the ruler for the harness itself: structural distance between harness states (per surface, path length), a crystallization / swap test (remove the disposition, read the harness back), and behavioural distance with a permutation test (the action-preference statistic). Every condition is read with the same ruler.
🚀 60-second demo (no API key, no Docker)
pip install proteus-evolve # no model SDK; Python 3.10 adds only a TOML compatibility package
The bundled minimal harness runs fully offline, so you can see the whole pipeline before
wiring up a real agent:
proteus run --harness minimal \
--arm neutral --arm review:notes --arm review:tools \
--seeds 4 --episodes 8 --out runs/demo
proteus measure --harness minimal --out runs/demo
arm seeds notes tools (mean units built)
neutral 4 3.5 4.0
review_notes 4 13.0 0.0
review_tools 4 3.8 8.0
behavioural R (between/within arms, last episode): 3.075 p=0.0150
An installed action preference measurably shifts what the harness grows — and the same
measure reads a no-goal run and a goal run identically.
🧩 Harnesses in the box
| adapter | what it is | needs |
|---|---|---|
minimal |
offline reference harness (mock policy) | nothing |
llm |
the same harness driven by a live model — any OpenAI-compatible endpoint, DeepSeek by default | an API key |
dsh |
DeepSeek Harness, headless profile, in a prepared container | Docker + a DeepSeek key |
pi |
Pi — Mario Zechner's minimal coding harness (4 tools, native AGENTS.md + skills) | Docker + a DeepSeek key |
aki |
the Aki research harness (the paper's apparatus) | the research checkout |
| yours | --harness <module>:<Class> — no registration |
your adapter |
dsh and pi are the source-evolving third-party integrations. At seed time each adapter
extracts the pinned harness's real TypeScript source into harness/src/; every later phase
boots that copy, rebuilding it when its content changes. The source is therefore a measured,
snapshotted loop surface alongside instructions, notes, tools, and skills. The adapters
still leave the upstream repositories untouched: they arrange the run copy, launch one
prepared container per phase, and parse the harness's own session logs.
🏗️ How it works
flowchart LR
U["Run config<br/>harness × model<br/>goal + evaluators<br/>arms + seeds"] --> F["Proteus framework<br/>assemble phase prompts"]
F --> A["HarnessAdapter<br/>run one episode"]
A --> H["harness/<br/>evolving, snapshotted subject"]
A --> T["task/<br/>optional benchmark workspace<br/>outside the snapshot"]
A --> L["native harness logs"]
L --> E["evaluators<br/>hidden or observe-visible"]
E --> S["selection + snapshot<br/>accept or preserve-and-restore"]
S --> F
Every seed runs N context-fresh episodes; only files cross the episode boundary. One
episode is four phases:
observe → propose → act → reflect
- observe — take stock; if you configured a visible evaluator, its score on the last episode is shown here.
- propose — list ways to improve your own harness.
- act — carry one out by editing the harness (the goal, if any, is announced here).
- reflect — decide what to keep.
The framework owns everything that is not the harness (prompts, goal text, evaluator routing, snapshotting, selection, measurement). The adapter owns everything that is (how the four phases actually execute). That split is what makes Proteus harness-agnostic.
The core objects
| Concept | What it is |
|---|---|
HarnessAdapter |
the contract a harness implements: its surfaces, how to run an episode, how to read the action trace, how to install/remove a disposition |
Surface |
one editable, persistent region (memory / skills / tools / code / …), declared as data so the measurement layer needs no hard-coded names |
Disposition |
the action-preference perturbation — a single, removable change at t=0 (prompt suffix, config value, or code patch) |
GoalConfig |
goal / no-goal / multi-goal, each evaluator HIDDEN or OBSERVE-visible, plus outer-loop selection (accept_reject) |
Sandbox |
where an episode runs; LocalSandbox (trusted) or DockerSandbox (OS-level isolation, tunable network) |
Action preference
An action preference is installed as a Disposition and is guaranteed removable, so the
crystallization test can take it away and read what the harness built on its own:
from proteus.core import review, record, NEUTRAL
review("memory") # each phase: review your memory, act or not
record("tools") # keep your tools current as you work
NEUTRAL # the control, F0 — no perturbation
Goals and evaluators
from proteus.core import EvaluatorSpec, GoalConfig, Visibility
GoalConfig.no_goal() # unpressured evolution
GoalConfig.of(text="Become more reliable.") # stated goal, no evaluator
GoalConfig.of(
text="Become more reliable.",
evaluators=(EvaluatorSpec("reliability", my_eval,
visibility=Visibility.OBSERVE),),
) # agent sees the score next episode
GoalConfig.of(text="Pursue A and B together.",
evaluators=(EvaluatorSpec("a", eval_a),
EvaluatorSpec("b", eval_b)),
selection="accept_reject") # outer loop rejects regressions
An evaluator is any callable (trace, ctx) -> EvalResult; bring a benchmark verifier, an
LLM judge, or one of the built-ins (proteus.core.evaluators).
Sandbox
from proteus.sandbox import SandboxConfig, DockerSandbox
DockerSandbox(SandboxConfig(network="none")) # no egress
DockerSandbox(SandboxConfig(network="host", # needs an LLM endpoint
env_passthrough=("OPENAI_API_KEY",),
mem_limit="4g"))
A self-editing agent writes and runs its own code, so an application-level file sandbox cannot contain it — Proteus runs real harnesses in a container whose filesystem holds the harness and nothing else.
🔌 Onboard your harness
The input is a repository — a git URL or local path:
proteus env scaffold --from https://github.com/org/their-harness --name theirs --ref v1.2.0
proteus env build theirs # pinned image, resolved sha recorded in the manifest
# write the adapter (7 methods), then:
proteus check --harness mypkg.theirs_adapter:TheirsHarness --episode
proteus run --harness mypkg.theirs_adapter:TheirsHarness --arm neutral ...
proteus check machine-verifies the contract (removable disposition via fingerprint
round-trip, snapshot-ability, trace shape). The full guide: docs/ADAPTERS.md.
📦 Prepared environments
environments/ contains two environment shapes. Manifest-backed environments pair a
Dockerfile or prebuilt image with environment.toml; the built-in dsh-src/ and
pi-src/ images are instead built from pinned upstream source checkouts, because the image
must contain the exact source and toolchain that the adapter later extracts and rebuilds.
In both shapes evolving state lives in mounts, never in a per-run image. Conventions:
environments/README.md; design notes:
docs/ENVIRONMENTS.md.
📏 Measurement
from proteus.measure import distance, stream, crystallize
distance— structural distance per surface (added / dropped / revised), path length (proteus measure --travel).stream— behavioural distance (frequency / order / procedure) and the between/within permutation testR.crystallize— mount an evolved state under a neutral disposition and test whether it reads back as its own endpoint (two-stage fidelity + arm-shift).
To add a per-episode measurement evaluator, a post-run statistic, or an adapter-native counter, see docs/MEASUREMENTS.md. The guide covers their different contracts, artifact boundaries, CLI/report integration, statistical rules, and tests.
📤 Outputs
Every run's primary artifact is its evolution history as a git repository — one commit per episode. Keep it local, browse it, or push it wherever you like (never automatic):
proteus repo export runs/demo/runs/run-<id> my-evolution # normal repo, `git log` = the trajectory
proteus repo push runs/demo/runs/run-<id> git@github.com:you/my-evolution.git
Every sweep also ships a live tracking page — per-run progress, per-surface growth curves, evaluator scores — updating while the sweep runs:
proteus watch --out runs/demo # http://localhost:8300/report.html
Tracking data (condition labels, hidden scores) lives at the sweep level, outside run roots, so the evolving agent can never read its own condition.
📊 Status
v0.1 (research preview). Working today: the offline minimal harness; the live llm
harness; pinned, source-evolving DeepSeek Harness and Pi adapters with exact-tree boot,
rebuild caching, viability gates, turn budgets, and task mounts; the Aki research adapter;
local, Polyglot, and SWE-bench task integrations; resume-safe sweeps; the full measurement,
audit, reliability, report, and repository-export paths; and adapter/environment tooling.
CI covers Python 3.10–3.14. The separate release-smoke workflow runs two episodes across
the public release set (minimal, llm, dsh, pi), exercises the benchmark path, and
requires both container harnesses to edit their own source and boot the edit; releases use
pinned upstream versions, while the weekly upstream canary is advisory. As a
cross-implementation check, Proteus's
behavioural ruler applied to the research runs independently reproduces their headline
dynamics: arms separate at episode 1 (R = 1.63) and converge by episode 30 (R = 0.93).
📖 Citation
See CITATION.cff. A paper reference will be added when the preprint is public.
License
MIT.
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 proteus_evolve-0.1.0.tar.gz.
File metadata
- Download URL: proteus_evolve-0.1.0.tar.gz
- Upload date:
- Size: 96.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
773ca2a9975c2b4964dff46aa68e5e7520412a74afca063bb5b3d70ca0f9b3c3
|
|
| MD5 |
e62567d7a0dd2851e63c31d141bf47b0
|
|
| BLAKE2b-256 |
a993db6040ed0f99cda0cb236a3e3dd3584e6e35f717b56f09e786fbb4227ab8
|
Provenance
The following attestation bundles were made for proteus_evolve-0.1.0.tar.gz:
Publisher:
publish.yml on proteus-evolve/Proteus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proteus_evolve-0.1.0.tar.gz -
Subject digest:
773ca2a9975c2b4964dff46aa68e5e7520412a74afca063bb5b3d70ca0f9b3c3 - Sigstore transparency entry: 2528719363
- Sigstore integration time:
-
Permalink:
proteus-evolve/Proteus@d445fe0645c5621062621d5f5c9b7c19a94c47de -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/proteus-evolve
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d445fe0645c5621062621d5f5c9b7c19a94c47de -
Trigger Event:
release
-
Statement type:
File details
Details for the file proteus_evolve-0.1.0-py3-none-any.whl.
File metadata
- Download URL: proteus_evolve-0.1.0-py3-none-any.whl
- Upload date:
- Size: 93.3 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 |
44314f67298d764bec4e05b692731a90082437f8d0df2e94838ef60560ef9002
|
|
| MD5 |
0147f639130246f045c586286d3e1806
|
|
| BLAKE2b-256 |
6d0e928f43e2a014e2d64e866de2c08e895b2bc90464efe16111a7558d79fce6
|
Provenance
The following attestation bundles were made for proteus_evolve-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on proteus-evolve/Proteus
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
proteus_evolve-0.1.0-py3-none-any.whl -
Subject digest:
44314f67298d764bec4e05b692731a90082437f8d0df2e94838ef60560ef9002 - Sigstore transparency entry: 2528720116
- Sigstore integration time:
-
Permalink:
proteus-evolve/Proteus@d445fe0645c5621062621d5f5c9b7c19a94c47de -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/proteus-evolve
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d445fe0645c5621062621d5f5c9b7c19a94c47de -
Trigger Event:
release
-
Statement type: