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.
AgentDescent puts the deep-learning training stack on top of agents. The "parameters" are a library of evolvable artifacts (skills, prompts, harness modules, verifiers); the "gradients" are diffs carrying evidence cards; the "optimizer step" is a merge decision. N workers propose diffs in parallel, and a barrier-free asynchronous merger aggregates them into a shared, version-controlled artifact library — targeting O(N / T_iter) improvement throughput, where serial self-improvement is bounded at 1 diff / T_iter.
The one place the analogy must break defines the whole system: gradients add, diffs do not. Aggregation is therefore not averaging but conflict resolution + statistical acceptance + transactional commit.
Highlights
- One entry point —
evolve(). Describe what evolves (aStrategy) and the rules of evolution (run/reward/propose); the parallel, merge-based loop (ledger → workers → aggregator → commit) runs for you. - Parallel and asynchronous. Concurrent workers within a round
(
max_concurrency) and a barrier-free async runtime across rounds (asynchronous=True) — a ROLL-Flash-style lag budget plus Full / Guarded / Reflective staleness policies keep stale diffs safe. - The aggregator is a discrete-space optimizer. Staleness filter → conflict
resolution → fusion tournament → Beta-posterior acceptance → transactional
commit — and fully swappable via
aggregator_factory. - Governed by blast radius. Skills (L2) merge freely; harnesses/verifiers (L1) are forced through an oracle; safety/permissions (L0) are frozen.
- Provider-agnostic. Any
prompt -> textis a completion — Claude, OpenAI-compatible endpoints (GLM / DeepSeek), or a tool-using agent (OpenHands). - Faithful algorithm ports. Runnable, offline-tested examples of ACE, GEPA, EvoSkill, SkillOpt, ADAS, and DGM — faithful to each repo's algorithm and dataset choice.
Install
pip install -e ".[dev]" # from source · PyPI name: agentdescent · Python ≥ 3.9
The core engine has zero required dependencies; [dev] adds pytest, [docs]
adds MkDocs Material.
Quickstart
from agentdescent.evolution import evolve, LLMAgent
from agentdescent.agents import claude
result = evolve(
tasks, reward, # your task set + scorer
agent=LLMAgent(claude(model="claude-haiku-4-5")),
rounds=15, n_workers=4, max_concurrency=4, # parallel workers
# asynchronous=True, async_ratio=3, # ...or barrier-free async
)
print(result.rendered) # the evolved artifact
print(result.final_reward) # held-out reward
📖 Documentation
Full docs live in docs/ and render as a website via MkDocs Material:
| Page | What's in it |
|---|---|
| Home | Overview and 30-second tour |
| Architecture | Components, data-flow diagram, the two runtimes, concurrency model |
| Concepts | The training↔RSI analogy, staleness, the aggregator, the three long tails, governance |
| Usage & extending | Running the demos, config reference, plugging in your own Evolvable domain |
| Evolving anything | The general engine — evolve any artifact by writing its Strategy + run/reward/propose |
| Connecting agents & LLMs | The provider-agnostic completion layer |
| Loading datasets | The agentdescent.dataloader data layer — HF datasets-server + raw-file fetch, cached, dependency-free |
| Customizable parallelism | Pluggable DP / TP / PP strategies — or write your own |
| Duration-aware scheduling | Estimate rollout cost from task size; LPT dispatch + straggler checkpointing |
| Efficiency experiments | Measured parallel scaling and async tail-hiding |
| Example: skill evolution | One complete run — real dataset, real LLM, every module |
| Self-evolution algorithms | Faithful ports of ACE, GEPA, EvoSkill, SkillOpt, ADAS, DGM |
pip install -e ".[docs]"
mkdocs serve # live preview at http://127.0.0.1:8000
mkdocs build # static HTML into ./site
A GitHub Actions workflow (.github/workflows/docs.yml)
builds and deploys the site to GitHub Pages — enable it under Settings → Pages
→ Source: GitHub Actions.
Evolve anything — the general engine
The core is the ledger + aggregator + schedulers + governance.
agentdescent.evolution is the domain-agnostic engine on
top: describe what evolves (a Strategy) and the rules of evolution
(run / reward / propose), and it runs the parallel, merge-based loop.
from agentdescent.evolution import evolve, AppendRules
result = evolve(
tasks, reward,
agent=my_agent, # or run=/propose= plain functions
strategy=AppendRules(), # or KeyedRules / your own
blast_radius=0.2, # 0.2 = L2 skill; 0.6 = L1 harness/verifier
rounds=15, n_workers=4,
)
print(result.rendered, result.final_reward)
The strategy maps a proposal into diff ops, so distinct edits fuse and
conflicting edits are resolved on held-out score — for free. blast_radius
picks the governance layer (a skill is L2; a harness/verifier at 0.6 is L1,
where merges are forced through the oracle). Same evolve call for either —
only the artifact, strategy, and blast radius differ.
Connect any agent/LLM — agentdescent.agents is the
separate provider layer; any prompt -> text is a completion (claude(...),
openai_compatible(...) for GLM/OpenAI-style endpoints, from_callable(...),
with_retries(...)).
The one complete end-to-end run — real dataset, real LLM, every module — is
examples/skill_evolution.py
(python -m examples.skill_evolution --dry-run for the no-API preview).
Guides: the engine · skill example
· agents.
Faithful ports of the latest self-evolution algorithms
To show the engine is faithful to the field, AgentDescent ships one runnable example
per representative skill and harness self-evolution algorithm — each
faithful to the original repo's algorithm and dataset choice, each with a
--dry-run (no-API) mode and an offline test suite. Every one loads its benchmark
through the shared agentdescent.dataloader data layer
(HF datasets-server + raw files, cached, dependency-free). Full guide:
docs/self-evolution-examples.md.
| Algorithm | Kind | Dataset | Example |
|---|---|---|---|
| ACE (Agentic Context Engineering) | skill / context | FiNER-139 | ace_context_evolution.py |
| GEPA (Reflective Prompt Evolution) | skill / prompt | HotpotQA | gepa_prompt_evolution.py |
| EvoSkill (Automated Skill Discovery) | skill library | OfficeQA | evoskill_skill_discovery.py |
| SkillOpt (ReflACT) | skill document | SearchQA | skillopt_skill_training.py |
| ADAS (Meta Agent Search) | harness | MGSM | adas_meta_agent_search.py |
| DGM (Darwin Gödel Machine) | harness | SWE-bench Verified | dgm_self_improve.py |
python -m examples.ace_context_evolution --dry-run # skill/context self-evolution (ACE)
python -m examples.dgm_self_improve # harness self-evolution (DGM), offline
Fidelity is to the released code, not just the paper (e.g. EvoSkill's frontier is top-K aggregate, not per-instance Pareto — the example follows the code and says so); where a full setup needs heavy infra (SWE-bench Docker, gated data), the boundary is documented, never hidden.
Efficiency (measured)
examples/efficiency.py — parallel scaling is
near-linear (efficiency ≥ 0.99 through 8 workers, 7.9× speedup), and the
async pipeline is 2.5× faster than a sync barrier under heavy-tailed
rollout latency (100% vs 40% worker utilization). See
docs/efficiency.md.
The central analogy
| Model training | AgentDescent (parallel RSI) |
|---|---|
| parameter tensor θ | library of Evolvable artifacts |
| gradient g | Diff + EvidenceCard |
| parameter server | git-backed, version-vectored Ledger |
| optimizer step | Aggregator merge decision |
| per-param adaptive LR (Adam) | per-artifact Beta-posterior test |
| staleness / decoupled PPO | per-diff η + rebase re-verify |
| partial rollout | turn-level checkpoint / ResumeQueue |
| EMA (weight averaging) | stable/dev dual branch |
| training code (not self-modifiable) | L0 frozen layer |
Running the examples
# RQ1 — merge vs fork, end to end (synchronous DP)
python -m examples.run_demo
# Async stage orchestration — Full/Guarded/Reflective policies + async_ratio sweep
python -m examples.run_async
# The flagship: evolve a skill on a real dataset with a real LLM (--dry-run: no API)
python -m examples.skill_evolution --dry-run
# Efficiency: parallel throughput scaling + async vs sync-barrier tail-hiding
python -m examples.efficiency
# Customizable parallelism: DP / TP / PP (+ a custom strategy)
python -m examples.parallelism
# Duration-aware scheduling: online estimator + LPT dispatch + straggler checkpointing
python -m examples.duration_scheduling
# RQ2 — staleness tolerance sweep (alpha in {0,1,5,inf})
python -m examples.rq2_staleness
# tests
pytest
No external services or model APIs are required: the reference domain
(agentdescent/domains/router.py) is a fully
deterministic keyword-router skill, so the entire parallel loop runs in-process
and is unit-tested — while still producing genuine diffs that measurably improve
a held-out metric.
Architecture → code map
Every module cites the design section it implements.
| Component | Module | Design § |
|---|---|---|
Evolvable unit, Diff, EvidenceCard, version vectors |
evolvable.py |
3.2, 3.3 |
| Git-backed Ledger: version vectors, CAS, 2PC, dual branch | ledger.py |
3.1, 4.5 |
| Aggregator: staleness → conflict → fusion → Beta accept → commit | aggregator.py |
4 |
| Staleness policies: Full / Guarded / Reflective | staleness.py |
4.2 |
Async stage-orchestration runtime + async_ratio |
async_runtime.py |
3.1 |
| Parallel paradigms: DP / TP / PP | parallel.py |
8 |
Statistics: Beta posterior, P(Δ>0), annealed δ, UCB |
stats.py |
4.4, 5.2 |
| Three schedulers: UCB task / audit / resume queue | scheduler.py |
5 |
| Three-layer verifier (rule / learned / oracle) | verifier.py |
3.1, 5.3 |
| Layered governance by blast radius (L0/L1/L2) | governance.py |
6 |
| Worker: rollout + propose | worker.py |
3.1 |
| Orchestrator (sync DP) + fork baseline | orchestrator.py |
3.1, RQ1 |
| Agent/LLM connection layer (provider-agnostic) | agents.py |
— |
General evolution engine + pluggable Strategy |
evolution.py |
3.2 |
How aggregation works (the Aggregator pipeline)
Cards are bucketed by artifact. When a bucket triggers (batch size B, or a
T_max timeout so cold artifacts don't starve), the aggregator runs one
optimizer step:
- Staleness filter (§4.2) — per-diff
η = max(head − base)over touched artifacts.η = 0proceeds;0 < η ≤ αis rebased and cheaply re-verified (does the delta still hold on the new head?);η > αis discarded and its evidence settled back into the pool.αadapts to artifact heat; contract-breaking diffs forceα = 0. - Conflict resolution (§4.3) — syntactic (hunk overlap) and semantic (contradictory ops) detection; contradictions are projected out PCGrad-style, keeping the better of the pair on a shared subset.
- Fusion tournament (§4.3) — complementary diffs are fused (model-soup analogy) and run against the individual candidates on held-out data.
- Statistical acceptance (§4.4) — commit only if
P(Δ > 0) > 1 − δunder a per-artifact Beta posterior, not a point threshold.δanneals with version (LR decay); a trust-region caps diff size. - Commit (§4.1) — compare-and-swap on
dev(2PC for contract-breaking multi-artifact diffs). - Dual-branch promotion (§4.5) —
dev → stableafter K regression-free rounds (EMA-style confirmation). - Audit (§5.3) — the merge decision is itself submitted to the
AuditScheduler; high-blast-radius / low-trust merges are forced through the oracle. The optimizer audits itself.
Parallelism & asynchrony
AgentDescent ships two execution runtimes and a set of pluggable strategies, so a run can be moved along the sync↔async and DP↔TP↔PP axes without touching the merge pipeline.
Two runtimes
- Synchronous DP (
orchestrator.py) — a round barrier: all workers step, then oneaggregator.step(), then the next round. Deterministic; the RQ1/RQ2 baseline. - Asynchronous stage orchestration (
async_runtime.py, FlashEvolve-style) — no barrier. Worker threads keep producing evidence while a dedicated aggregator thread keeps merging, connected by the thread-safeEvidenceBuffer. The rollout/propose and aggregate/commit stages overlap instead of stalling.
Staleness policies (staleness.py, FlashEvolve Full/Guarded/Reflective)
The active policy is the only thing that changes between async regimes — the
aggregator asks it ACCEPT / REBASE / DISCARD from each diff's η and α:
| Policy | Behaviour | Cost |
|---|---|---|
| Full | use stale diffs directly (η ignored) | max throughput, min safety |
| Guarded | version-gated: accept η=0, rebase η≤α, discard beyond |
AReaL bounded-staleness |
| Reflective | always rebase + re-verify; discard only if the delta no longer holds | recovers otherwise-wasted proposals |
async_ratio — the ROLL Flash lag budget
A worker refreshes its snapshot only once head has drifted more than
async_ratio versions ahead of it. Small ratio → near-synchronous, few stale
diffs; large ratio → highly asynchronous, many stale diffs the policy must
handle. A backpressure signal forces a global sync if the pipeline stalls
(evidence keeps arriving but nothing commits).
python -m examples.run_async shows the trade-off — all three policies converge
to 1.000, but at async_ratio=4:
| policy | rollouts | stale discarded | wall-clock |
|---|---|---|---|
| Full | ~8k | 0 | ~3.2s |
| Reflective | ~7.8k | ~0.7k | ~3.3s |
| Guarded | ~20k | ~17k | ~5.1s |
DP / TP / PP (parallel.py, §8)
- DP (data parallel) — same snapshot, task-sharded, diffs merged. The default the async runtime runs.
- TP (tensor parallel) — split one hot artifact into disjoint sections;
each worker owns a section, so edits are conflict-free by construction and
the merge is concatenation + a consistency reviewer (
TensorParallelMerge). - PP (pipeline parallel) — artifacts form a dependency chain; a downstream
failure back-propagates blame to the earliest failing upstream stage
(
PipelineChain.blame, shared with the §7 counterfactual-replay attribution).
The three long tails (§5)
AgentDescent treats "the long tail" as three separate problems:
- L-traj (system): heavy-tailed rollout durations → turn-level checkpoint +
ResumeQueue, resumed against the latest ledger (a free cross-version A/B signal). - L-task (data): Zipfian artifact triggering → UCB over (cluster × artifact) so starved tail artifacts get an exploration bonus, plus a difficulty filter and a tail canary set.
- L-value (signal): most diffs are marginal →
AuditSchedulerspends the scarce oracle budget onblast_radius × uncertainty / trust.
Governance (§6)
Artifacts sort into layers automatically by blast_radius:
- L2 fast — local skills/prompts → full async merge.
- L1 slow — harness/verifier → serialized in-flight changes + staged rollout.
- L0 frozen — oracle, audit budget, merge permissions, safety constraints → read-only to the loop. Without a frozen layer, the self-referential loop eventually pollutes itself (a verifier that learns to pass itself).
Scope & honesty
This is a research reference implementation, not a production system. It is faithful to the design's mechanisms and runs end-to-end on a synthetic domain so the mechanisms are observable and testable. AgentDescent's novelty is a narrow, defensible engineering synthesis — concurrent, staleness-bounded, conflict-resolved diff-level merge over a git-backed versioned ledger — and its throughput premise is a testable engineering hypothesis, not community consensus (cf. FlashEvolve / SkillClaw / CoEvoSkills).
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 agentdescent-0.1.0.tar.gz.
File metadata
- Download URL: agentdescent-0.1.0.tar.gz
- Upload date:
- Size: 86.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e16733c181869e160e10712b0d40966d25cc3dd61c0bb7e1797e931043fa959d
|
|
| MD5 |
0bf1c573c3fb5355c4de7becc136ebaf
|
|
| BLAKE2b-256 |
a9898f154b011c09494387937d8832c90e83e354c91d50fac30bcaf3cd604570
|
Provenance
The following attestation bundles were made for agentdescent-0.1.0.tar.gz:
Publisher:
publish.yml on Birfy/agentdescent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentdescent-0.1.0.tar.gz -
Subject digest:
e16733c181869e160e10712b0d40966d25cc3dd61c0bb7e1797e931043fa959d - Sigstore transparency entry: 2256313434
- Sigstore integration time:
-
Permalink:
Birfy/agentdescent@c2ef3644fd996d3022e70e9919cd3f98e358da7d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Birfy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c2ef3644fd996d3022e70e9919cd3f98e358da7d -
Trigger Event:
release
-
Statement type:
File details
Details for the file agentdescent-0.1.0-py3-none-any.whl.
File metadata
- Download URL: agentdescent-0.1.0-py3-none-any.whl
- Upload date:
- Size: 68.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f2b9e716c3438ddc4207ebc6554e04147773587895638824007f5400d726b44
|
|
| MD5 |
ea0d416eab1dc0d8e66f9e8c2f8c461d
|
|
| BLAKE2b-256 |
14e0ee63bde3073efaff331f43397cbd60e26907bcb41ee6e07870eab7302adc
|
Provenance
The following attestation bundles were made for agentdescent-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Birfy/agentdescent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agentdescent-0.1.0-py3-none-any.whl -
Subject digest:
9f2b9e716c3438ddc4207ebc6554e04147773587895638824007f5400d726b44 - Sigstore transparency entry: 2256313442
- Sigstore integration time:
-
Permalink:
Birfy/agentdescent@c2ef3644fd996d3022e70e9919cd3f98e358da7d -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Birfy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c2ef3644fd996d3022e70e9919cd3f98e358da7d -
Trigger Event:
release
-
Statement type: