Skip to content

API reference

Every name agentdescent exports, grouped by the module it comes from. Generated from the package's own signatures and docstrings by python -m tools.gen_api_docstests/test_api_reference.py fails if this page and the code disagree, so a signature here is the signature you get.

Each section links to the page that explains why the module is shaped the way it is; this page is the what.

164 public names across 30 modules.


The loop

evolve(), the artifact, the actor, and what a run returns.  ·  agentdescent.evolution  ·  guide

Agent

Convenience actor: bundles running a task and proposing an improvement.

EvolutionResult(...)

method what it does
cost_summary() -> str One line: what the run cost. Complements outcomes(), which says why it went as it did.
cost_to_quality(target: float) -> Optional[int] Rollouts spent up to the first round that reached target.
duplicate_rate() -> float Cache hits as a fraction of lookups -- work that did not have to be redone. In one process this is memoisation working; across processes it is the figure that says how much a shared cache would be worth.
outcomes() -> Dict[str, int] Merge outcomes for the whole run, by category -- why it went as it did.
save(path: str) -> None Write the evolved artifact and its run summary to a JSON file.
stale_rate() -> float Discarded evidence as a fraction of evidence considered; 0.0 if none.
time_to_quality(target: float) -> Optional[float] Wall-clock at the first round whose held-out reward reached target.
write_to(...) Install a file-tree artifact back into a real directory.

EvolvingArtifact(...)

An Evolvable: flat state + a strategy.

method what it does
cheap_eval(evidence: EvidenceCard) -> float Score this artifact on the trajectories an evidence card carries.
evidence_eval(evidence: EvidenceCard) -> float Score this artifact on the trajectories an evidence card carries.
full_eval(task_set: Sequence[Task]) -> Dict[str, float] Score on a task set. No longer part of the Evolvable protocol -- the engine reaches ground truth through the verifier's eval_fn -- and kept because it is a convenient thing for a caller to have.
score(tasks: Sequence[Task]) -> float Mean reward over tasks, evaluated concurrently.

LLMAgent(...)

Adapt a Completion (from agents) into an Agent.

ProposalContractError

propose returned something that is not text (or None).

RewardContractError

The caller's reward returned something outside the documented contract.

RoundInfo(...)

Task(id: str, prompt: str, meta: Dict[str, Any] = <factory>) -> None

One unit of work the artifact is evaluated on.

claude_agent(model: str = 'claude-opus-4-8', max_tokens: int = 1024) -> LLMAgent

Convenience: LLMAgent(claude(model)) (provider code lives in agents).

evolve(...)

Evolve an artifact. Provide either agent (with solve/propose) or the run / propose callables directly.

reflector(...)

Use any model as the reflector for an agent you already have.

tasks_from(...)

Turn a list of dicts -- a dataset -- into Task objects.


One-call skill evolution

The shortest path from a dataset to an evolved instruction.  ·  agentdescent.skill  ·  guide

evolve_skill(...)

Evolve one instruction (a "skill") against a dataset, in one call.


One-call directory evolution

The same, for a skill folder, an agent folder, or its code.  ·  agentdescent.skilldir  ·  guide

evolve_agent_code(...)

Evolve agent code: the tree is executed, and a test gate guards it.

evolve_agent_dir(...)

Evolve an agent directory (subagent definitions, tool config, harness).

evolve_skill_dir(...)

Evolve a skill directory, executed by a real agent that reads it.


Agents and models

Any prompt -> text is a completion; a WorkspaceAgent also has a directory.  ·  agentdescent.agents  ·  guide

AgentError

A tool-using agent failed; the message carries its stderr / exit status.

Usage(...)

What a run cost: calls, tokens, and wall-clock spent in the model.

method what it does
estimated_cost(per_1m_prompt: float, per_1m_completion: float) -> float Cost at the given per-million-token prices (both provider-specific).

WorkspaceAgent

A Completion that can additionally be bound to a directory.

claude(...)

A Claude-backed completion (requires pip install anthropic + creds).

claude_code(...)

Claude Code in non-interactive print mode, as a Completion.

cli_agent(...)

Run any command-line coding agent as a Completion.

codex(...)

OpenAI Codex CLI in non-interactive exec mode, as a Completion.

echo(transform: Optional[Callable[[str], str]] = None) -> Completion

A deterministic, no-network completion for tests and dry runs.

from_callable(fn: Completion) -> Completion

Identity adapter -- documents that any prompt -> text callable works.

metered(completion: Completion, usage: Usage) -> Completion

Count calls and model wall-clock for any completion.

openai_compatible(...)

A completion for any OpenAI-compatible chat endpoint (GLM/Zhipu, proxies, local servers, OpenAI itself).

with_retries(...)

Wrap a completion with exponential-backoff retries on any exception.


Directories as state

Load a directory into state, materialise it back, serialise it losslessly.  ·  agentdescent.filetree  ·  guide

TreeError

A directory could not be represented as evolvable state, or vice versa.

TreeSpec(...)

Which files make up an evolvable tree, and how big it may get.

method what it does
validate_against(trust_region_chars: int) -> None Fail now if the loader admits files the optimizer can never accept.

canonical(state: Mapping[str, str]) -> str

A lossless, stable serialisation of a file tree.

load_tree(path: str, spec: Optional[TreeSpec] = None) -> Dict[str, str]

Read a directory into {relpath: text}.

materialize(...)

Write a tree into dest (optionally under prefix); return the paths.

parse_tree(rendered: str) -> Dict[str, str]

The inverse of canonical.

tree_summary(state: Mapping[str, str], limit: int = 40) -> str

A human/LLM-readable listing (paths + sizes), for prompts and logs.


The file-tree strategy

One state key per file, plus the multi-file proposal protocol.  ·  agentdescent.treestrategy  ·  guide

FileTree(...)

The artifact is a directory; each state key is a relative file path.

method what it does
frozen_files(source: Mapping[str, str]) -> Dict[str, str] The pristine content of every frozen path, for the runner's overlay.
keys() -> Sequence[str] The declared key space, for TensorParallel.
writable(path: str) -> bool May the loop write this path? frozen beats editable.

parse_edits(proposal: str) -> Dict[str, Optional[str]]

Parse a reflector reply into {path: new_content} (None = delete).

tree_reflector(...)

A propose callable that asks complete for multi-file edits.


Runners

Give a real agent the candidate directory, one workspace per rollout.  ·  agentdescent.runners  ·  guide

code_runner(...)

Run candidate code on a task: materialise, gate, execute.

tree_runner(...)

Build a run(rendered, task) that gives agent the evolving directory.


The data model

What a unit of evolution is, and what a gradient looks like here.  ·  agentdescent.evolvable  ·  guide

Contract(...)

The externally-visible interface of an artifact.

ContractError

The caller's own code broke a documented contract.

Diff(...)

A proposed change to an artifact's state.

method what it does
size() -> int A crude "number of edited lines" proxy used by the trust-region cap (design doc, section 4.4).

EvidenceCard(...)

The "gradient metadata" carried by every diff (design doc, section 3.3).

method what it does
rebased_onto(head: VersionVector) -> 'EvidenceCard' Return a copy whose base is advanced to head for touched keys.

Evolvable

The single interface every unit of evolution must satisfy.

stable_hash(key: Any) -> int

A process-independent hash for seeding and partitioning.

vv_dominates(a: VersionVector, b: VersionVector) -> bool

Return True if a is at least as new as b on every shared key.

vv_staleness(head: VersionVector, base: VersionVector) -> int

Per-diff staleness eta (design doc, section 4.2).


The aggregator (the optimizer)

Staleness filter, conflict resolution, fusion, acceptance, commit.  ·  agentdescent.aggregator  ·  guide

Aggregator(...)

Per-artifact optimizer step over the ledger.

method what it does
finalize() -> None Publish the current dev head to stable at the end of a clean run.
step() -> List[MergeReport] Fire every artifact bucket that is ready and return per-artifact reports.

AggregatorConfig(...)

AggregatorContractError

A custom aggregator returned something step() may not return.

AggregatorProtocol

The contract a custom aggregator must satisfy to plug into evolve.

EvidenceBuffer() -> None

Cards bucketed by target artifact (design doc, section 4.1).

method what it does
settle(cards: List[EvidenceCard]) -> None Keep discarded-diff evidence addressable, under a hard bound.

MergeOutcome

The vocabulary of category.

member value
COMMITTED 'committed'
BELOW_THRESHOLD 'below-threshold'
ALL_STALE 'all-stale'
OVERSIZED 'oversized'
ORACLE_REJECTED 'oracle-rejected'
CAS_CONFLICT 'cas-conflict'
UNKNOWN_ARTIFACT 'unknown-artifact'

MergeReport(...)

diffs_conflict(a: Diff, b: Diff) -> bool

Syntactic overlap: do two diffs edit an overlapping set of keys?

diffs_contradict(a: Diff, b: Diff) -> bool

Semantic contradiction: same key, different proposed value.

fuse_diffs(diffs: List[Diff]) -> Diff

Merge complementary (non-contradicting) diffs into one candidate.


The ledger

The git-backed, compare-and-swap artifact store.  ·  agentdescent.ledger  ·  guide

CASConflict

Raised when a commit's declared base version is stale.

ContractRejected

Raised when a commit would change an artifact's contract major.

GitError

A git command failed; the message carries git's own stderr.

Ledger(...)

A git-backed, version-vectored artifact store with dual branches.

method what it does
close() -> None Refuse further use of this ledger. Idempotent.
commit(...) Compare-and-swap commit of a single artifact.
commit_atomic(...) Two-phase, all-or-nothing commit of several artifacts.
promote_to_stable(artifact_id: str) -> Optional[int] EMA-style confirmation: copy dev's current artifact onto stable.
register(artifact: Evolvable, branch: str = 'dev') -> None Add a brand-new artifact at version 1 on both branches.
snapshot(branch: str = 'dev') -> Snapshot Materialize every artifact on branch into live Evolvables.

Snapshot(artifacts: Dict[str, Evolvable], version: VersionVector) -> None

An immutable view of one branch at one point in time.


The verifier

Rule / learned / oracle, and the budget that bounds the expensive one.  ·  agentdescent.verifier  ·  guide

ThreeLayerVerifier(...)

Rule / learned / oracle backend for the aggregator.

method what it does
cheap_eval(artifact: Evolvable) -> float The signal used everywhere a budget-free score is needed.
eval_counts(artifact: Evolvable) -> Tuple[float, float] Return (successes, failures) on the full held-out set.
learned_eval(artifact: Evolvable) -> Tuple[float, float] Noisy proxy that also returns an uncertainty estimate.
oracle_eval(artifact: Evolvable) -> float Ground truth on the full held-out set. Consumes audit budget.
rule_eval(artifact: Evolvable) -> float Cheap, deterministic-ish check on a tiny subset.

VerifierBudget(oracle_calls_remaining: int = 200, oracle_calls_used: int = 0) -> None

Oracle call budget, consumed by oracle_eval.


Governance

L0 frozen / L1 slow / L2 fast, assigned by blast radius.  ·  agentdescent.governance  ·  guide

GovernanceError

Raised when the evolution loop tries to mutate a frozen (L0) artifact.

L1SerialGate(_in_flight: Dict[str, str] = None, _lock: threading.Lock = <factory>) -> None

Enforces "at most one L1 diff in evaluation at a time" (section 6).

Layer

member value
L2_FAST 2
L1_SLOW 1
L0_FROZEN 0

assert_mutable(artifact: Evolvable) -> None

Guard invoked before applying any diff (design doc, section 6, L0).

classify(artifact: Evolvable) -> Layer

Assign an artifact to a governance layer.


Staleness policies

What to do with a diff proposed against a version that has moved.  ·  agentdescent.staleness  ·  guide

FullStaleness()

Use stale diffs directly regardless of eta (max throughput).

GuardedStaleness()

Version-gated with rebase in the middle band (AgentDescent's default).

ReflectiveStaleness()

Always rebase + re-verify; discard only if the improvement no longer holds.

StaleAction

What the aggregator should do with a (possibly stale) evidence card.

member value
ACCEPT 'accept'
REBASE 'rebase'
DISCARD 'discard'

StalenessPolicy

get_policy(name: str) -> StalenessPolicy


Parallelism methods

How a round's work is split across workers: DP / TP / PP.  ·  agentdescent.parallel  ·  guide

ClusterParallel(...)

DP over task clusters, leased by UCB instead of sharded round-robin.

method what it does
observe(unit: WorkUnit, task_id: str, score: float) -> None Feed one rollout's outcome back into the cluster's UCB estimate.

DataParallel(name: str = 'DP') -> None

DP -- every worker holds the same artifact; the tasks (keys) are sharded across workers and their diffs are merged. Coverage rotates each round.

ParallelMode

member value
DP 'data_parallel'
TP 'tensor_parallel'
PP 'pipeline_parallel'

ParallelStrategy

How a round of work is partitioned across n_workers.

PipelineChain(stages: List[str]) -> None

An ordered artifact dependency chain, upstream -> downstream.

method what it does
blame(stage_success: Dict[str, bool]) -> Optional[str] Back-propagate blame to the earliest failing stage.
counterfactual_pairs(stage: str) -> List[Tuple[str, str]] The {old x new} version swaps to replay for minimal factor analysis.

PipelineParallel(stages: Sequence[str], name: str = 'PP') -> None

PP -- artifacts form a dependency chain; each worker drives one stage, and a downstream failure back-propagates blame to the earliest failing stage (via PipelineChain).

SectionViolation

Raised when a worker's diff touches a key outside its section.

TensorParallel(...)

TP -- one hot artifact is split into n_sections disjoint sections; each worker owns a section, so edits are conflict-free by construction and the merge is a union (concatenation + a consistency check).

method what it does
section_map() -> Dict[str, int] artifact key -> section. Empty when no key space was declared.

TensorParallelMerge(n_sections: int, keys: Optional[Sequence[str]] = None) -> None

Merge section-scoped diffs into one artifact (concatenation + review).

method what it does
merge(base: Evolvable, section_diffs: List[Tuple[int, Diff]]) -> Tuple[Evolvable, bool] Return (merged_artifact, consistency_ok).
owner_of(key: str) -> int Which section owns key -- via the declared partition when there is one.

WorkUnit(worker: int, keys: List[str], stage: int = 0, section: Optional[int] = None) -> None

What one worker is responsible for in one round of a parallel plan.

assign_key_sections(keys: Sequence[str], n_sections: int) -> Dict[str, int]

Partition a known artifact key space into balanced, disjoint sections.

assign_sections(worker_ids: Sequence[str], n_sections: int) -> Dict[str, int]

Authorize each worker for exactly one section (round-robin).

section_of(key: str, n_sections: int) -> int

Hash an artifact key to a section id.

shard_round_robin(items: Sequence, n_shards: int) -> List[List]

Split a task list into n_shards disjoint shards, round-robin.


Task sampling

Which task a worker rolls out next.  ·  agentdescent.sampling  ·  guide

DifficultyWeighted(...)

UCB over tasks, weighted by how much learning signal each one carries.

method what it does
stats() -> Dict[str, Tuple[float, float]] Copy of the per-task (passes, trials) counters -- for inspection/tests.

RoundRobin()

Cycle through the shard in order -- the deterministic default.

TaskSampler

Chooses the next task id for a worker, and learns from the outcome.

method what it does
pick(keys: Sequence[str], round_index: int) -> str Return one task id from keys (never mutate keys).
record(task_id: str, score: float) -> None Report the reward a rollout of task_id achieved (0..1).

Scheduling and audits

Duration-aware dispatch, straggler handling, and the oracle audit queue.  ·  agentdescent.scheduler  ·  guide

AuditScheduler(max_queued: int = 4096, collect: bool = False) -> None

Allocates oracle budget by estimated value G-hat (design doc, 5.3).

method what it does
force_oracle(blast_radius: float, artifact_id: str) -> bool High-impact or low-trust changes are forced through the oracle.
update_trust(artifact_id: str, oracle_agreed: bool) -> None Raise trust when cheap eval agreed with the oracle, lower it when not.

DurationEstimator(...)

Predicts a rollout's wall-clock cost from a task's size (e.g. prompt length), calibrated online from observed rollouts.

ResumeQueue(p90_multiplier: float = 2.0) -> None

Turn-level checkpoints of timed-out rollouts (partial rollout).

TaskCluster(...)

TaskScheduler(clusters: List[TaskCluster], c: float = 1.4) -> None

UCB over task clusters, with a difficulty (zero-advantage) filter.

method what it does
lease_one() -> TaskCluster Atomically pick the single highest-UCB cluster (async worker pull).
lease_round_robin() -> TaskCluster Async worker pull that spreads concurrent workers across clusters.
select_batch(k: int) -> List[TaskCluster] Lease k clusters to workers, UCB-ordered, cycling if k exceeds the number of clusters.

fifo_makespan(weights: List[float], n_workers: int) -> float

Makespan of naive round-robin dispatch (the baseline LPT improves on).

lpt_schedule(weights: List[float], n_workers: int) -> Tuple[List[int], float]

Longest-Processing-Time-first assignment of items to workers.


The data layer

Datasets, splits, and cached fetches from HuggingFace or raw URLs.  ·  agentdescent.dataloader  ·  guide

Dataset(...)

A dataset partitioned into train / val / test splits.

method what it does
map(fn: Callable[[Any], Any]) -> 'Dataset' Apply fn to every item in every split, returning a new Dataset.

split_dataset(...)

Partition items into a Dataset by ratios (train, val, test).


Barrier-free evolution

evolve() without the round barrier.  ·  agentdescent.async_evolve  ·  guide

async_evolve(...)

Evolve an artifact without a round barrier.


The async orchestrator

The reference barrier-free runtime and its statistics.  ·  agentdescent.async_runtime  ·  guide

AsyncAgentDescent(...)

Barrier-free reference runtime, on the general engine.

method what it does
buffer_pending() -> int Cards waiting in the aggregator's buckets, or 0 before a run.

AsyncConfig(...)

AsyncStats(...)


The reference orchestrator

The round loop the research results were measured with.  ·  agentdescent.orchestrator  ·  guide

AgentDescent(...)

The merge-based parallel self-evolution system, on the general engine.

RoundStat(...)

run_fork_baseline(...)

DGM-style archive/fork control: parallel but never merged (RQ1).


Document backends

A tool-using agent over a document that is too big for a prompt.  ·  agentdescent.backends  ·  guide

AgentBackend

A base agent that answers a question about a document, possibly using tools.

document_agent(...)

Turn any Completion into an AgentBackend for document questions.

openhands(...)

A real OpenHands agent (SDK v1.x) as a workspace-bindable Completion.

openhands_backend(...)

document_agent(openhands(...)) -- the document task on OpenHands.

tool_loop_backend(...)

A dependency-free grep/read ReAct loop over the document.


Ready-made scorers

The reward functions everyone writes, with the details right.  ·  agentdescent.rewards  ·  guide

contains(gold_key: str = 'gold', *, normalise: bool = True) -> Callable

1.0 when the gold answer appears anywhere in the output.

exact_match(gold_key: str = 'gold', *, normalise: bool = True) -> Callable

1.0 when the output equals the gold answer.

last_number(gold_key: str = 'gold', *, tolerance: float = 0.0) -> Callable

1.0 when the last number in the output matches the gold number.

numeric_close(gold_key: str = 'gold', *, tolerance: float = 0.01) -> Callable

last_number with a relative tolerance -- for rounded answers.


Type aliases and constants

Values rather than classes or functions.

AcceptDecision

Commit or not, and -- when not -- which of the merge categories it was.

AcceptancePolicy

Whether a candidate is committed.

AggregatorFactory

(ledger, verifier, audit, config, policy) -> AggregatorProtocol — how a custom optimizer is installed.

AppendRules

Accumulate a deduped list of rules/lessons (append-only, content-addressed).

CacheProtocol

Somewhere to keep evaluations. In one process, across many, or on disk.

Completion

Callable[[str], str] — the one contract every model and agent satisfies.

ConflictPolicy

Which of a batch of mutually contradictory changes survive.

EDIT_PROTOCOL

The multi-file proposal format a FileTree reflector is told to emit.

Executor

Runs rollouts somewhere. Threads here, processes and hosts later.

FAST_MAX

The L2/L1 blast-radius boundary (0.30).

FROZEN_IDS

Artifact ids the loop may read but never mutate (L0).

FileCache

A directory of evaluations, so separate processes can share them.

FusionPolicy

How complementary diffs become one candidate.

KeyedRules

One entry per category: competing proposals contradict and are resolved.

LAYOUTS

Where a runner writes the evolving tree inside a workspace (claude_skill, skill_library, claude_agent, root).

LedgerFailure

The exception tuple a caller catches to treat any ledger problem as recoverable.

LedgerProtocol

Seven methods: four the aggregator calls, three more the engine calls.

LocalWorkspaceSandbox

A throwaway directory on this machine -- what a rollout has always got.

MemoryCache

In-process, single-flight, counted.

MergeContext

Everything an AcceptancePolicy is allowed to look at.

Policies

Every replaceable piece, in one argument.

ProcessExecutor

Persistent worker processes, with re-dispatch when one dies.

Promotion

One artifact the PromotionPolicy believes stable should hold.

PromotionPolicy

Which artifacts dev has proved well enough to copy onto stable.

ProposalContext

What a ProposalPolicy is given for one rollout.

ProposalPolicy

How a rollout becomes candidate changes.

Ref

A callable named rather than sent: "module:attribute" plus config.

RefError

A reference could not be resolved, and why -- never a bare ImportError.

Result

What one rollout produced, or why it did not.

RolloutSpec

One rollout, described completely enough to run somewhere else.

SOLVED

Reward at or above which a task counts as solved (0.999). Lower it for a graded scorer, or every rollout asks the reflector to fix an answer that was already good.

Sandbox

One acquired execution environment.

SandboxPool

The single gate on how many sandboxes exist at once.

SandboxProvider

Where sandboxes come from and go back to.

SandboxSpec

What environment one rollout needs. Must survive JSON: it crosses processes.

SharedSandboxPool

A pool whose ceiling is the machine's, not this process's.

SingleSlot

The artifact is one value, and each accepted proposal replaces it.

Strategy

Defines what evolves and how -- the representation and the merge rule.

TEST_FAILURE_MARKER

Prefix of the output code_runner produces when the frozen gate fails, so the failure scores 0 and the reflector can read it.

ThreadExecutor

The default: a bounded pool of threads in this process.

VerifierProtocol

Four methods, from grep 'self\.verifier\.' agentdescent/aggregator.py.

VersionVector

Dict[str, int] — artifact id to version.

WorkspaceProvider

Provisions LocalWorkspaceSandbox -- mkdtemp, plus a lease file.

backends

Agentic backends -- a base agent that navigates documents with tools, not just maps a prompt to text.

dataloader

Dependency-free dataset loading -- the data layer for examples/experiments.

rule_id

Content-address a proposal so identical proposals dedupe automatically.