Self-Evolving Agent Harness
A fixed model cannot adapt its harness from experience unless updates persist; self-evolution uses execution feedback to revise and reload harness changes while retaining the ability to update again.
Read the paper ↗What it is
- Feedback-driven revision The system uses what happened during its own runs to propose or select changes to its prompts, memory, workflows, tools, or runtime, without changing the model itself.
- Persistent update loop Accepted changes are saved and loaded later, and the system still has a way to make another update from future experience.
- Mutation boundary A change may edit stored instructions or coordination, a callable component, broader runtime control, or how plugins are assembled.
Why it matters
This distinguishes continuing adaptation from static scaffolding or one-time editing. It also makes clear what is being changed and why a persistent revision can help—or carry a regression—into future runs.
Before getting into the machinery, the basic idea is simple: keep the model fixed, learn from the agent’s own executions, and revise the software and configuration that steer it. If a change is accepted, save it so the next run can use it and the next round can learn from new feedback. That matters because adaptation need not mean retraining the model.
-
Adaptation target: The harness is the surrounding software and configuration: instructions, memory, tool use, workflows, and runtime behavior. The canonical example is an agent that repeatedly makes the same tool-use mistake. You can change its instructions or reusable procedure while leaving its model weights alone. More broadly, harness changes reuse the existing model deployment and can be inspected as configuration or code; that does not mean every such change is safe or beneficial.
-
Feedback loop: A real update uses execution outcomes to diagnose a problem and propose or select a change. Think of a run that fails to verify a spreadsheet edit: the failure can inform a better checking procedure. The system may assess candidates itself or ask for human approval, but a log that merely records the failure is not yet an update. What decides whether the proposed change should be admitted?
-
Continuity and persistence: The accepted change has to survive beyond the current interaction, and the ability to update must survive with it. The canonical example is a revised tool procedure written to persistent state, then loaded by the next run, which can produce fresh feedback for another revision. It is like carrying a useful notebook from one town to the next; unlike a notebook, though, a stored procedure can execute and affect other components. If nothing is admitted, the incumbent can simply remain in place. What exactly counts as the harness state being revised?
The answer depends on the edited artifact’s job, not its programming language. Changing stored instructions, experience, or task-level routing among fixed capabilities is an interpreted-state update. A workflow encoded as code can still be interpreted-state if it only composes predefined operators. Changing an operator’s implementation or the runtime machinery that coordinates it is executable revision. For example, curating a memory entry changes what the agent remembers; changing the memory-management function changes how the harness handles memory. Component edits stay within a callable module boundary, repository-level edits expose interactions across the runtime, and plugin composition changes how services or components are bound. Those boundaries can overlap, and even a locally scoped change can affect shared state. So the important question is not only what changed, but what future runs inherit—and whether they can keep learning from what happens next.
Read the deep dive
Why People Wanted It
A deployed agent keeps encountering tasks and environments that change, but changing model weights is not the only way to adapt. The real question is whether execution experience can revise the software and configuration around a fixed model—and whether those accepted changes survive into later runs. Without both feedback-driven revision and persistence, you have either a static scaffold or a one-off edit, not a continuing adaptation loop.
The Core Move
Keep the task model fixed, use feedback from its executions to revise the harness, then store accepted revisions so later runs can use them and generate feedback for another update.
The harness is the software and configuration governing the model’s execution: prompts and context, memory, tools, orchestration, runtime control, and related infrastructure. The task model’s learned parameters remain outside that harness. A revision is not necessarily an improvement; “self-evolution” names the update process, while “self-improvement” requires a demonstrated gain.
Why Feedback and Persistence Must Both Hold
Now the version for readers who want the exact operational boundary: a qualifying update uses feedback from the system’s own executions to construct or select a revision algorithmically, while retaining an update mechanism for later experience. Feedback may come from an environment, an automated assessor, or a person; human approval can still be part of admission. If no candidate is admitted, the incumbent remains in place.
The second requirement is cross-run persistence: accepted revisions are stored and loaded in a subsequent run. A log appended under fixed rules, or context compacted under a fixed policy, does not by itself revise the harness. Learning reusable procedures or changing a memory policy can. A single observed update can demonstrate the lifecycle only when the system both persists the accepted change and remains able to update again.
Why the Edited Artifact Sets the Boundary
Here is the part that gets technical: classify a revision by the role of the artifact it changes, not by whether that artifact is written in code. Interpreted-state updates change instructions, stored experience, or task-level coordination over predefined capabilities. A workflow can be represented as code and still be interpreted-state if it only sequences or routes fixed operators through fixed coordination interfaces. Changing an operator’s implementation or the runtime that enacts coordination crosses into executable revision.
Executable targets have three useful boundaries. Component-level changes replace callable procedures or designated modules while surrounding orchestration stays outside the editable surface; stable entry points and input/output contracts make that boundary explicit, though changed outputs or shared state can still spread regressions. Repository-level changes expose interactions such as context construction, orchestration, execution hooks, recovery, and termination; the boundary is control over those interactions, not a count of edited files. Plugin composition binds or replaces components and runtime services, and can span both component and repository-level boundaries. These categories overlap rather than forming exclusive bins.
A final constraint matters: internal critics and provisional checks may be revised, but the final assessment that scores and verifies outcomes is not an editable target. Classification tells you what changed; it does not by itself establish feedback-driven continuity or persistence.
Minimal Causal Code
This loop exposes the state transition rather than optimizing it. The application-specific functions are placeholders; the key is that feedback informs a candidate, admission decides whether it replaces the incumbent, and the accepted state is loaded next time.
import json
from pathlib import Path
STATE = Path("harness.json")
def load_harness():
if STATE.exists():
return json.loads(STATE.read_text())
return {"prompt": "Solve the task carefully.", "memory": []}
def save_harness(harness):
STATE.write_text(json.dumps(harness))
def run_rollout(model, harness, task):
# Execute the fixed model under the current harness.
return execute(model=model, harness=harness, task=task)
def propose_revision(harness, feedback):
# Diagnosis and proposal are part of the update mechanism.
return revise_harness(harness, feedback)
def admitted(candidate, feedback):
# May include checks or human approval; final assessment stays fixed.
return assess_candidate(candidate, feedback)
def update_round(model, tasks):
incumbent = load_harness()
feedback = [run_rollout(model, incumbent, task) for task in tasks]
candidate = propose_revision(incumbent, feedback)
if admitted(candidate, feedback):
incumbent = candidate
save_harness(incumbent) # Persist for the next run and next update.
return incumbent
What You Gain, and What You Lose
You can adapt prompts, memory, workflows, tools, or runtime behavior while reusing a fixed model deployment; harness artifacts can also be inspected, compared, and tracked as software changes. That can avoid retraining and extra weight checkpoints, and permits updates through proprietary model APIs without access to weights.
But editable harness state creates its own propagation and repair burden. A local component change can affect shared state or downstream outputs; repository-level changes can alter assumptions across otherwise unchanged components. Persistence makes useful revisions available later, but also means an admitted regression can travel into future runs. Admission, validation, deployment boundaries, and independent safety controls therefore remain consequential. The update mechanism must survive deployment too: exporting a revised program without a way to revise it again breaks the continuing lifecycle.
A harness evolves only when execution feedback changes what later runs load—and the mechanism for changing it survives too.