Skip to main content

AgentDescent

Gradient descent — but the parameters are agents. A parallel, asynchronous framework for self-evolving agents (skills, prompts, harnesses) where diffs are the gradients and the aggregator is the optimizer.

DOI PyPI tests docs python license

N workers propose edits to a shared artifact in parallel; a barrier-free aggregator merges them into one version-controlled library. Serial self-improvement is bounded at one accepted change per iteration, and merging concurrent edits is the attempt to lift that bound.

The place the analogy has to break is the whole design: gradients add, diffs do not. So aggregation is not averaging but conflict resolution, fusion, statistical acceptance and a transactional commit.

What it measures

Every row names the setting that produced it, and the full results page also reports the runs where there was nothing left to learn.

measured setting
An artifact held in one key, where a keyed union can never fuse keyed union fuses 0 of 48 merges · reflective merge 42 of 48 BBH dyck_languages, GLM-5.2, N=4, 4 seeds
What that costs, at a pinned rollout budget 40% fewer model calls (95% CI 27–54%, same direction on every seed) the same runs
Wall-clock against a faithful serial control median 6.8× (three seeds, 3.1–9.5×) GEPA on HotpotQA, N=4, 16 rollouts pinned
The one-call path, end to end held-out exact match 0.167 → 0.583 40 HotpotQA items, 12 held out

Quality is claimed only where the design can support it. The paper reports intervals rather than p-values where a comparison cannot reach significance, and says so.

How it works

AgentDescent architecture: N workers roll out against ledger snapshots and emit diffs with evidence cards into a buffer; a single aggregator thread runs the five-stage merge pipeline and commits to a git-backed ledger; four pluggable seams sit under the components they select; the L0 governance layer gates the audit step.

Solid, top: the fixed data path. N workers roll out tasks against ledger snapshots and emit diffs with evidence cards; one aggregator thread runs the five-stage merge and commits winners; the green edge is the only feedback path, bounded by the lag budget.

Dashed, bottom: the seams, each selected by one keyword argument of evolve(). Red: the governance layer, deliberately not a seam — a self-modifying system must not be able to replace its own evaluator.

Stages 1–5 are one optimizer step over a discrete space. Whether that step has anything to do at all is decided upstream, by the key space your strategy writes — edits on disjoint keys fuse, edits on the same key conflict. That is why the table above starts with a one-key artifact.

The figure is the paper's, rendered from its TikZ source by tools/gen_architecture_figure.py so it cannot drift from what the paper shows.

Install and run something in 30 seconds

pip install agentdescent

The core engine has zero required dependencies and needs only Python ≥ 3.9. The examples are research artifacts kept outside the installed package — they would otherwise squat the top-level examples name — so clone the repo to run them:

git clone https://github.com/Birfy/agentdescent && cd agentdescent
pip install -e ".[dev]"
python -m examples.run_demo      # no API key, no network

A terminal recording of python -m examples.run_demo: the evolution loop runs to completion in under half a second, printing a per-round table of held-out accuracy and the aggregator's commit, fused, stale and conflict counters.

That is the whole run — no API key, no network, under half a second. Three rounds commit, then the gate stops accepting because there is nothing left to improve; commit, fused, stale and confl are the aggregator's own counters, and every run prints them.

Quickstart — a dataset to an evolved skill

One entry point, evolve(), and three building blocks that turn a dataset into its arguments. The decisions that are actually yours — your data, how to score it, which model — are the ones you still make.

from agentdescent import SingleSlot, evolve, openai_compatible, reflector, scorer, tasks_from
from agentdescent.dataloader import hf_rows

rows = hf_rows("hotpotqa/hotpot_qa", "validation", config="distractor", limit=40)
model = openai_compatible(model="deepseek-v4-flash")

tasks = tasks_from(rows, prompt="question", gold="answer")     # rows -> Task objects
run = lambda skill, task: model(f"{skill}\n\n{task.prompt}")   # the skill meets the question

result = evolve(tasks, scorer("exact"), run=run, propose=reflector(model),
                strategy=SingleSlot(initial_value="You are a helpful assistant."),
                rounds=8, n_workers=8, max_concurrency=8, held_out_frac=0.3,
                patience=3, target_reward=0.98)

print(result.rendered)        # the skill it learned
print(result.final_reward)    # held-out reward
print(result.outcomes())      # why it went that way

That run is the last row of the table above. It learned "Respond with only the requested answer, omitting any extra explanation or restatement."

The same thing without a dataset. Runnable as-is — no API key, no dependencies.
from agentdescent import Task, evolve

tasks = [Task(id=f"t{i}", prompt=f"item {i}") for i in range(12)]

def reward(task, output):                  # must return [0, 1]
    return 1.0 if "2026" in output else 0.0

def run(rendered, task):                   # your solver
    return "answer" + (" 2026" if "year" in rendered else "")

def propose(rendered, task, output, reward):   # what to add on a failure
    return "always state the year"

result = evolve(tasks, reward, run=run, propose=propose,
                rounds=6, n_workers=3, max_concurrency=3)
print(result.rendered, result.final_reward, result.error)

Swap in a real model or agent by passing agent= instead of run/propose:

from agentdescent import LLMAgent, claude, openai_compatible, claude_code

evolve(tasks, reward, agent=LLMAgent(claude(model="claude-haiku-4-5")))
evolve(tasks, reward, agent=LLMAgent(openai_compatible(model="deepseek-v4-flash")))
evolve(tasks, reward, agent=LLMAgent(claude_code()))     # Claude Code CLI
# ...or run barrier-free: evolve(..., asynchronous=True, async_ratio=3)

Use it from your agent — Claude Code, Codex, OpenCode, DeepSeek Harness

The same engine as a plugin. A shared skill teaches the host when to reach for it, an MCP server exposes doctor / plan / start / status / show / apply / cancel / resume, and the CLI mirrors them, so a run started from an agent can be inspected from a shell.

bash scripts/setup-hosts.sh   # installs it and wires up whichever agent CLIs you have
agentdescent demo             # a complete evolution, offline, no key, ~10s
agentdescent doctor           # which CLIs and keys this machine has

Say "improve this prompt against these examples" inside the agent. It runs doctor, writes a spec, quotes the call count before starting, waits for your yes, runs detached, and asks again before it writes anything back.

No cases yet is not a blocker. Drafting them is step one of the procedure, not a prerequisite: point it at the file and it writes 8–20 for you to check first.

kind is text, skill_dir, agent_dir, agent_code — or plugin: the host plugins themselves are evolvable, each rollout loaded into an isolated copy of the host, hooks and permission config frozen, with a recursion guard so a plugin evolving itself cannot start a nested run.

The plugin in three commands → · set it up and test it →

What you can replace

Two seams carry the algorithm, and both are typing.Protocols — nothing to inherit from, and the contracts are re-derived from the engine's own call sites by a test, so the published interface cannot drift from what runs.

The strategy — what evolves. Three methods over a flat {key: value} state. Its key space is what decides whether concurrent proposals can fuse at all.

strategy the artifact is concurrent proposals
AppendRules a deduped list of lessons, keyed by content almost always fuse
KeyedRules(categories) one entry per named category contradict within, fuse across
FileTree(files) a directory, one key per path contradict per file
SingleSlot one value — a prompt, an instruction always contradict

Eight policy slots — the rules of evolution. Each is one field of a Policies bundle, each defaults to the shipped rule, and filling one leaves the other seven alone. A driver refuses a field it cannot honour rather than ignoring it — a policy that installs but never runs is the one failure a caller cannot detect from a completed run.

selection task_sampler proposal staleness
conflict fusion acceptance promotion

Mechanisms that need state the pipeline does not keep — an archive, per-instance score rows, an island pool — take the aggregator_factory exit instead. How to fill a slot →

Nineteen algorithm ports

Published self-evolution algorithms run as plug-ins rather than forks, under serial, synchronous or barrier-free scheduling without touching the engine — which is what makes the scheduler a controlled variable instead of a property of each paper's own loop.

Benchmark-faithful (8): ACE · GEPA · EvoSkill · SkillOpt · ADAS · DGM · OpenEvolve · ERA Microports and analogues (11): PromptBreeder · AFlow · Self-Refine · Reflexion · SICA · Gödel Agent · Voyager · SkillWeaver · Absolute Zero · R-Zero · Agent0

Fidelity is declared per port, follows each project's released code where it diverges from its paper, and analogues are not to be cited as benchmark reproductions. Every port has a --dry-run mode that needs no API key. All nineteen, with their measured results →

Documentation

Full docs render at birfy.github.io/agentdescent.

Start here
Quickstart — dataset to skill One call: your data, how to score it, which model
Measured results Every empirical claim with the setup that produced it
Architecture Components, data flow, the two runtimes
Concepts The training↔RSI analogy, staleness, governance
Going further
Evolving anything · Strategies Evolve any artifact by writing its Strategy
Choosing policies · Using the slots The decision plane, and how to write for it
Agents & LLMs · Datasets The provider layer and the data layer
Parallelism · Execution · Sandboxes Where rollouts run, and how they are isolated
Use it from your agent · Testing it The plugin surface, and how to verify each host
Efficiency · Runtime matrix Measured scaling and the scheduler comparison

Citing

The paper — AgentDescent: Asynchronous Parallel Self-Evolution of LLM Agents by Merging Conflicting Edits — gives the design, a closed-form condition for when merging can fire at all, and a live-model evaluation with every generating script named.

@article{chen2026agentdescent,
  title  = {{AgentDescent}: Asynchronous Parallel Self-Evolution of {LLM} Agents
            by Merging Conflicting Edits},
  author = {Chen, Danyang},
  year   = {2026},
  doi    = {10.5281/zenodo.22348027}
}

LaTeX source and the built PDF live on the paper branch, not here: the write-up and the code change on different clocks. Per-result raw data is in bench/results/ for most results; the merge-versus-selection sweeps are re-measurable from the command the paper names rather than recomputable, because their per-run data was not retained — the paper says so too.

Scope

A research reference implementation, not a production system. The novelty is a narrow engineering synthesis — concurrent, staleness-bounded, conflict-resolved diff-level merge over a git-backed versioned ledger — and its throughput premise is a testable hypothesis rather than community consensus. Contributions welcome: CONTRIBUTING.md. The suite is offline and deterministic, so pytest -q needs no API key.

Release files for agentdescent 0.5.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 agentdescent 0.5.0
File Size Uploaded
agentdescent-0.5.0.tar.gz 678.0 kB Details

Built distribution (wheel)

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

Total release size: 1.0 MB

Release files / agentdescent-0.5.0.tar.gz

Download URL agentdescent-0.5.0.tar.gz
Size 678.0 kB
Tags Source
SHA-256 checksum
How to use checksums
318df7566f96c950dc2a64b63c0f43c9ef67745a622dc13bb74b84feefe72514
BLAKE2b-256 checksum
How to use checksums
6408fb52cb11a5b39839ce15604ba682198b4819909a95227695f721480ec30f
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 7, 2026.

Transparency log

Release files / agentdescent-0.5.0-py3-none-any.whl

Download URL agentdescent-0.5.0-py3-none-any.whl
Size 361.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d252fc2bcd95e888828427074daebdedf140d15dc174e7028848742e6efb74a9
BLAKE2b-256 checksum
How to use checksums
86f5400aefe19c992aa814287c6fe50ae6fa1b65f27f84a67676142b7e3cca3f
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 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

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