Repository navigation
Releases
0.9.0 — platform surfaces, algorithms run, release/ops/tenancy
[0.9.0] — 2026-11-06
Added
-
RSIPlatform+PlatformConfig/PlatformReport: one bounded cycle that hands
compute allocation, the durable loop, trusted promotion, capability admission and
continual experience to each other.completeis false when a configured layer
does not produce a decision; a layer skipped by an upstream decision (for example
the foundry after a rejected promotion) is named inskippedanddetail.
Post-loop decisions are cached perrun_id, so re-running a terminal run returns
them instead of re-admitting or re-learning; a terminal run without a cache is
refused. A cycle that validates experience on its own rows marks
self_validated=True.Changed
LoopGenerationnow carries the observation's evidence, so the platform (and a
caller's own report) can see the compute action/option/features that produced a
generation without re-reading the event payload. -
CapabilityArchive: a quality-diversity archive, artifact graph and semantic
dedup kept in sync. A near-duplicate never occupies a QD cell or the graph; an
elite replacement removes the evicted graph node and fingerprint;addrolls
the QD cell back to the previous elite if the graph rejects the artifact;
prepopulated graphs seed the dedup fingerprints. Retrieval goes through the
graph and selection through the QD archive.Changed
ArtifactGraph.remove()removes an artifact and decrements document frequency
once per distinct token. Descendants keep their parent ids and treat the
removed node as external. -
CapabilityScout: packages failedTaskCandidates asToolSynthesisRequest
examples, runs the existingToolSynthesizer, and hands the selected candidate
to the caller'sCapabilityRequestbuilder beforeCapabilityFoundry.admit.
The report makesno-candidateandno-requestexplicit; only an admitted tool
reachespromoted. -
BudgetedSearch: runsSearchFabricat increasing UCT budgets and stops when
the value gain per expansion falls below a bar, using the existing
MarginalGainStopor a patience rule. The report keeps every round, the gain
it bought and why the search stopped, so compute spend is auditable rather than
hidden in one fixed budget. -
PromotionLedger: only an acceptedpromote()decision becomes a release. It
builds anArtifactManifestcarrying the evidence/decision hashes and reasons,
HMAC-signs it, verifies the signature, and writes a lineage node with the parent
artifacts, run id, manifest hash and key id. Refused promotions are not signed. -
CounterfactualExperience: turnsReplayLab.shapleystep credit into per-step
ExperienceRecordrewards and ingests it intoExperienceEngine. Credits below
min_creditare dropped and an empty reward map is refused, so a trace with no
attributable gain cannot silently become zero-information replay. -
PreferenceReplay: ranks storedExperienceRecords by a fitted
PreferenceModeland ingests the preferred slice intoExperienceEngine
without duplicating records. The preference model becomes the replay-selection
policy, so human pairwise feedback affects what the meta-policy learns from. -
A current
main-branch capability map covering the evolution loop, verification
and statistics, trusted promotion, durable operations, task/capability
discovery, archives and continual experience, with a staged path for evolving
Skills and Workflows. -
CapabilityLoop: composesTaskPipeline,CapabilityScoutand
CapabilityArchiveso production traces become a validated, admitted and
archived capability in one call. The report records the pipeline verdict, scout
outcome and archive result;admittedis true only when the archive added the
artifact (#677). -
BudgetedStep: composesSearchFabricandBudgetedSearchinto a durable
loop step that scales search budgets with the controller'sbudget_scale,
stops on marginal gain, and returns aLoopObservationwith round-by-round
evidence, risk and an artifact id (#678). -
curriculum_meta_rungains opt-in verified seeding:min_exam(via
verified_rules) excludes unexamined, flagged or audit-biased rules when set,
andoracle+audit_storeaudit a sampled slice of the
validation pairs and persist the verdict withaudited_n,oracle_gainand
gain_biasin the report. The generated-problem map is pruned to the live
frontier pool, and default run_ids get a random suffix so same-second
adoptions no longer collide (#679). -
release_evidenceandrelease_candidatecompose trust evidence, promotion
and thePromotionLedgerinto one fail-closed release seam. An accepted
promotion is signed and written to lineage; a reject or defer returns a report
without touching the ledger. An accepted promotion requires an artifact hash (artifact_hash=or
content_hash=); missing signing material or a missing/mismatched artifact
hash is refused rather than silently signed (#680). -
PlatformCampaign: runs severalRSIPlatformcycles under the existing
RSIControllerstop policy (target, cost, patience, cycle count), cloning the
platform with a fresh seed and run id per cycle while sharing the run store,
compute, foundry and experience. An exception or incomplete cycle is reported
as an error and stops the campaign, andPlatformCampaignReport.best_cycle
names the highest-reward cycle (#681). -
TenantPlatformwrapsRSIPlatform.run_cycleso each cycle routed through it
is a reserved, authorized and audited tenant action. A cycle reserves quota at
the stated tokens/cost (which enforcesrun:writeand the workspace limits)
and commits actual usage on success. An overrun or a recorded generation error
is charged the reserved amount before the refusal, so repeated overruns still
consume quota; only a platform call that produced no generation is released
without charge.TenantCycleReportexposes the platform report, reservation,
usage and a JSON-safe summary (#682). -
AdaptiveExperience: one cross-cycle composition that ingests counterfactual
credit throughCounterfactualExperience, selects validation anchors from a
fittedPreferenceReplay(or feature recall, recent history, or self-validation
on the first cycle), and delegates the guarded update toExperienceEngine.
Ingestion deduplicates byrun_id, and missing validation or bridge features
fail closed (#683). -
agentdescent.governed_harnesscomposes the capability gate, proof runner,
human approval store, canary/rollback plan and promotion rules into one governed
path for harness and code self-modifications. A denied gate, failed proof,
pending or rejected approval never reaches promotion, and approval keys are
content-bound so an old approval cannot be replayed for a different change. The
returned report is JSON-safe for manifests and decision logs (#684). -
CampaignOps+CampaignOpsReport: publish a sequence of finished
LoopReports into the control room in one call, recording each into the
console, lineage, telemetry and QD and returning the campaign metrics, alerts
and snapshot. Unknown statuses, duplicate run ids, malformed costs and invalid
thresholds fail closed before anything is recorded; fractional per-generation
costs are summed per loop and rounded up to integer calls (#685). -
meta_campaign_runturns continuous meta-learning into a bounded campaign:
RSIControllerstop conditions wrap repeatedcontinuous_meta_runsessions
that share one durableConsolidationStore, each in its own fresh ledger repo,
so every session seeds from the adopted rule the last one archived. A failed
session is reported and stops the campaign instead of being promoted
(#686). -
agentdescent releaseand the MCPreleasetool: one evidence-gated release
seam that builds trusted evidence from paired held-out scores, runs the
fail-closed promotion decision, and only on an accepted promotion signs an
ArtifactManifestand writes its lineage node. Signing material comes from an
environment variable or file (never argv); reject/defer leaves the lineage
untouched; the JSON result carriesschema_version: 1. Use--lineageto
persist and extend the receipt graph and--outto write the full report. -
Product surfaces for the four P1 capabilities, each with a CLI verb and an MCP
tool:platformruns a durable five-layer campaign from a JSON spec with a
runnable--demo;capabilityturns failure traces into an admitted, archived
capability;opspublishes terminal runs to the console/lineage/telemetry/
metrics with alerts; andexperiencereports, ingests, recalls, updates and
preference-replays an ExperienceStore. All returns carryschema_version: 1,
invalid input fails closed with a JSON{"ok": false, "error": ...}under
--json, and each command has a docs page and an offline demo or sample. -
agentdescent governed-harnessand the MCPgoverned_harnesstool: one
spec-driven surface for the existing safety-gate -> proof -> approval ->
canary/rollback -> promotion chain.init --demois runnable offline;plan
validates refs and scores without running the gates;runreturns the full
GovernedHarnessReport. A failed proof or pending/rejected approval never
reaches promotion; a conformal/sequential reject is never waived; MCP refs and
writes use the operator's surface allowlists. JSON results carry
schema_version: 1. Directgovern_harness_changecallers also get the
matching fix: optional conformalinsufficient/ sequentialcontinue
evidence is ignored when the rules do not require those tests, while a
conformal/sequential reject still fails the promotion. -
agentdescent meta-campaignand the MCPmeta_campaigntool: repeated
continuous_meta_runsessions over oneConsolidationStore, each in a fresh
ledger repo, withRSIControllertarget/cost/...
0.8.0 — hosts, RSI report, tournament & campaign
Added
-
agentdescent install grok-bot/uninstall grok-botscaffold a skill +
HOST.md+mcp.example.jsonunder~/.agentdescent/plugins/grok-bot/
(#165). Grok Bot has no public one-click plugin API for local skill+stdio
MCP yet, sodoctorreportsmcp n/awhen the scaffold is current rather
than pretending a host config was wired. Docs:plugins.md,
plugin-quickstart.md. -
agentdescent install opencodewrites/agentdescent/evolveunder
~/.config/opencode/command/agentdescent/evolve.md, andinstall codexwrites
/prompts:evolveas~/.codex/prompts/evolve.md— the same prompt body as
Claude Code's/agentdescent:evolve.uninstallremoves each only while still
stock (#165). -
agentdescent installwrites an/algorithmsslash entry beside/evolveon
Claude Code (commands/algorithms.md→/agentdescent:algorithms), OpenCode
(command/agentdescent/algorithms.md→/agentdescent/algorithms), and Codex
(prompts/algorithms.md→/prompts:algorithms). The body lists, shows, or
runs a named method through the same cards asagentdescent algorithms list|showand MCPlist_algorithms/describe_algorithm. Grok Bot's
HOST.mdnames the CLI/MCP discovery path;uninstallremoves each slash
file only while still stock (#384). -
rsi_report/agentdescent rsi/ MCPrsi: a read-only longitudinal view of
the consolidation archive. Per decision slot it reports the first and best
adopted reward, the adoption that set the best, the gain, adoptions since that
best, and the exam counts, and returns an overallimproving/stagnant/
mixed/insufficientverdict with the current portfolio reallocation. -
run_tournament/agentdescent tournament: run the same spec under several
registered algorithms (and seeds) with the same evolve budget, then report the
measured ranking and winner. The winner is aggregated per algorithm over seeds
(mean reward, fewer mean calls on a tie); a tie is reported as a tie. An errored seed counts as
reward 0 and is reported undererrors, so a crash cannot win by shrinking the
denominator;--dry-runprices every arm before a run.defaultis the spec's own recipe; each named arm
gets a deep copy, so the spec file is untouched. Ordinary
EvolveSpec -> compose() -> evolve()per arm, not a second engine or a claim to
reproduce the ports' published numbers. -
run_campaign/agentdescent campaign: run several evolution sessions on one
spec, each starting from the previous session's artifact. The campaign works on
a copy in a temporary workspace, applies only improving sessions, stops after
patiencenon-improving rounds, and reports the best artifact, workspace and
stopped_reason. Session 0 is the baseline (not a claimed improvement), the
split seed is fixed across sessions so rewards are comparable, andfinal_reward
is the last session whilebest_rewardis the artifact kept.--dry-runprices
the sessions first;policy_slotand inlinetexttargets are refused because
there is no file to carry, and--workdirmust be empty. -
MCP tools
safety,portfolioandaudit_trace: a host agent can now ask
whether an archive is safe to seed from, how its layers rank for the next
budget window, and where one adoption's evidence came from, without finding the
CLI verbs in the source. They return the same structure as the CLI's--json
(which now also carriesarchiveforsafety), write nothing, and treat a
missing archive as an error. The installedSKILL.mdsays when to use them, and
thedoctortool description now listsopencode(#505). -
LeakageGuard, a pre-evaluation screen and acceptance backstop that rejects a
candidate introducing a protected gold answer, task id or corpus string. It
checks diff keys and values before the held-out sweep and reports the existing
critic-rejectedoutcome, so a leak never crashes the aggregator or buys an
inflated score. The acceptance form only refuses newly introduced matches, so a
protected string already in the seed does not freeze the run. Matching is
case-insensitive and whitespace-collapsed, and short strings are ignored. -
ApprovalGate+ApprovalStore: high-risk self-modifications (blast radius or
diff size above a threshold) are not committed; a request is appended to a JSONL
store, and a human approval lets the same content through while a rejection
stays sticky. The key fingerprints target, ops and base version instead of the
producer'sdiff_id,needs-approval/approval-rejectedare real
MergeOutcomemembers, requests carry a reviewable summary, and malformed store
lines are skipped. Low-risk candidates delegate to the inner acceptance policy. -
MarginalGainStop, a statefulstop_whenpolicy: it watches the recent
reward/call slope and stops afterpatiencemeasurements whose per-call gain
is belowmin_gain_per_call. The per-call bar decides on its own under the
defaults, so a run that improves too slowly to pay for its calls now stops;
min_gainis an optional absolute-gain floor combined by OR. Thereason
names the measured gain and call delta, a round with no new calls never counts
as low, andreset()makes the object reusable across runs. This is an
economic stop for long self-improvement runs, not a safety verdict. -
VarianceSampler, aTaskSamplerthat prefers tasks whose recent reward
variance is high (flip-flopping tasks) over a lifetime pass-rate average, with a
UCB exploration bonus and round-index tie rotation. It is a drop-in
task_sampler=argument, thread-safe likeDifficultyWeighted. -
diagnose_payload/agentdescent diagnose/ MCPdiagnose: turnsshow's
samples, rejected candidates and outcome histogram into one actionable verdict
(solved,partial-improvement,running,cancelled,run-failed,
reflector-error,scoring-mismatch,gate-rejected,agent-failures,
no-improvement,unknown) with bounded evidence and the next step. A
committed-but-partial run is no longer called "no candidate adopted", gate
rejections win over the worst-sample rule, truncated samples do not claim a
scoring mismatch, and running/cancelled states are named. It reuses the same
read model as the CLI/MCP without building a discarded diff. -
GuardPipeline, one ordered acceptance gate that composes the checks a caller
supplies and names the ring that refused a candidate. It keeps the inner
guard's merge category (falling back tobelow-threshold) instead of inventing
a category the aggregator cannot decode, reports the first refusal even with
collect_all, and forwardsbind/configureplus checkpoint, restore and
screen-reject hooks to every guard. It imports no specific guard, so third-party
checks are first-class. -
DecisionRecord+DecisionLog: an append-only JSONL of immutable adoption and
session decisions with the guard category, evidence, cost and parent link.
Malformed lines (including non-object JSON) are skipped, a torn last line is
closed before the next append, duplicate record ids are refused, non-finite
floats become null, andchildren()exposes the decision tree a dashboard or
audit export needs. Writers in one process share a per-path lock. -
bootstrap_ci/is_significant/paired_gainandcontamination_overlap:
seeded paired-task bootstrap confidence intervals with an effect-size test, and
a contamination report between train and validation text. Paired keys are
sorted so the same seed is reproducible across processes, non-finite scores are
refused, normalized exact duplicates and CJK/short text are screened, and
"nothing to screen" isNonerather than a clean-looking0.0. Pure
standard-library functions for adoption gates, reports and external audits. -
KillSwitch,canaryandrollback_plan: a file-based global stop, a paired
exact sign test that recommends promote/hold/rollback from incumbent vs candidate
per-task scores, and a pure state diff for rollback. Missing candidate tasks
block promotion and are reported, significant losses use a separate
max_regressionbar, a delete-only rollback is not a no-op, and the switch
treats a directory at its path as engaged and writes atomically. These are
deployment operations separate from the acceptance gate, so a committed change
can still be canaried and reverted deliberately. -
run_guarded, one entry point for a session that cannot skip the kill switch or
the decision record. The injected acceptance is chained before the spec's
own acceptance policy or the shipped default statistical gate, so guards can
only tighten adoption; stateful checkpoint/restore/screen-reject hooks are
forwarded. The decision record says whether a candidate actually committed and
carries the error separately, a failing log does not hide the result, and an
aggregator_factoryalgorithm is called out innotes. The kill switch is an
explicit pre-flight check. -
RunManifest/build_manifest/verify_manifest/diff_manifest: a
content-addressed manifest of a run's spec, data files or directory tree, model
configuration (secret keys redacted), seeds, algorithm and code version. The
manifest id is stable for identical inputs, and verification names the fields
that changed. -
RiskPolicy/RiskRule/RiskContext: ordered, declarative rules that map a
change's tier, blast radius, diff size, capability domain and tenant to
allow/approve/canary/rollback/deny. First match wins, no match is
fail-closed (denyby default), and invalid actions or duplicate rule names are
refused at construction. -
evaluate/EvaluationReport: a deterministic, budgeted verifier-vs-oracle
pass. The verifier scores every task, the oracle only a seeded sample capped by
budget, and the report carries means, sign...
0.7.0 — named algorithm registry, self-improvement and verifier tooling
Added
-
A persistent-island population run now returns
EvolutionResult.lineages
(#150, semantics C): a read-only row per lineage (devplus each island) with
its candidate count, best archived version/score, selection count and lineage
tip. It is read from the archive the gate already scored, survivesfinalize,
and isNoneon a single-head run; the official artifact is unchanged. -
ACE's grow-and-refine playbook is now a named algorithm (
"algorithm": "ace",
kind: text) in the in-package registry (#384).ACEPlaybook, its
near-duplicate de-dup and theGrowAndRefineCurator moved fromexamples/ace
intoagentdescent/algorithms/ace.py; the example keeps its FiNER domain,
prompts and CLI and imports the one implementation. -
SkillOpt's skill-document training is now a named algorithm
("algorithm": "skillopt",kind: text) in the in-package registry (#384).
The bounded edit patch, strict held-out gate, rejected-edit buffer and annealed
textual learning rate moved fromexamples/skilloptinto
agentdescent/algorithms/skillopt.py; the example keeps its SearchQA domain,
prompts and CLI and imports the one implementation. -
EvoSkill's bounded skill-library frontier is now a named algorithm
("algorithm": "evoskill",kind: agent_dir) in the in-package
registry (#384). The two-role Proposer/Generator induction, the top-K frontier
and the best-member parent rule moved fromexamples/evoskillinto
agentdescent/algorithms/evoskill.py; the example keeps its OfficeQA domain,
prompts and CLI and imports the one implementation. -
Third-party packages can register a named algorithm through the
agentdescent.algorithmsentry-point group (Algorithmor a zero-argument
factory returning one). A plugin that fails to load is recorded in
agentdescent.algorithms.external_errors()and does not hide the shipped
registry; a name that duplicates a built-in is an error, not a shadow. -
DGM's keep-all capability archive is now a named algorithm
("algorithm": "dgm",kind: text) in the in-package registry (#384). The
sigmoid×novelty parent draw, the keep-all archive and the one-capability
proposal moved intoagentdescent/algorithms/dgm.py; the example keeps its
coding-agent/Docker domain and imports the mechanism. -
recursive_self_improve: the self-improvement loop now carries a
ReallocationPolicy, and each outer round evolves that rule with
portfolio_evolveon the archive the loop just wrote. The first round uses the same fixed rule asself_improve(config floor/min_samples),
each later round searches from and validates against the incumbent, and a rejected
policy round is reported with the previous rule kept; a cold archive is a reported rejection,
not a failure.SelfImproveConfig.min_examalso applies the verified-seeding bar
before an archived rule is used as a prior. -
CapabilityGuard, an acceptance policy that protects capabilities outside the
task being evolved: it scores the base artifact and the candidate on named task
suites and rejects a self-modification that misses a suite's absolute floor or
falls below the base by more than its tolerance, then delegates to the inner
acceptance policy. This is the anti-catastrophic-forgetting gate for recursive
self-improvement rather than a second verifier. -
VerifierCurriculumandVerifierAgreement: a curriculum that selects the
tasks where a verifier disagrees most with the oracle (abs / overestimate /
underestimate), feeds the selected oracle labels back into the verifier, and
reports the gap before/after (one oracle label per task per round); plus an
acceptance policy that audits a sample of commits and refuses a verifier-only
gain or an oracle regression (oracle-disagrees). This targets the
Goodhart failure mode of recursive self-improvement without adding a second
verifier. -
JEVModel, a dependency-free distilled Judge–Evaluator–Verifier student: a
linear logistic scorer over caller-supplied(artifact, task)features that
learns oracle labels online (observe), in passes (fit), predicts in[0, 1]
where a verifier is expected, and checkpoints as JSON. Intended to distil oracle labels from a disagreement-selected task loop, not to
replace the oracle; features are standardised online and the JSON checkpoint
carries the scaling state. -
safety_report/agentdescent safety: a read-only pre-flight check for an
archive that a recursive loop is about to seed from. It combines exam coverage,
whether each slot's best eligible rule is trusted, and the worst oracle-vs-
verifier gain bias from an optionalMetaAuditStoreon the seedable set, returningsafe/
caution/unsafewith the named checks and reasons.--min-exammirrors
verified_rules; CLI exit codes are 0 safe, 1 caution, 3 unsafe, 2 usage. No
model calls, no writes. -
agentdescent uninstall <dsh|claude-code|codex|opencode>(--dry-run,--home)
reversesinstall(#165): it removes the skill files and the plugin directory,
the marker-delimitedcordis.patch.ymlblock, the[mcp_servers.agentdescent]
table and the pinnedmcp.agentdescententry, and nothing else. A Codex table
is removed even when Codex has appended other tables after it. Anything that is
no longer exactly whatinstallwrites (an edited launcher, a bare
opencode mcp addentry, a hand-written table) is kept and reported with exit
status 1, a commentedopencode.jsoncis never rewritten, and the run store is
untouched. Newintegrations.uninstall(). -
Genesis (
examples/genesis): a blind mode in which the acceptance suite lives
outside the repository and the agents see the requirement and the assertion's
name rather than its source,own_review/own_test_failuresso a child's own
tests are run and implementation code with no test under its node is sent back
(a test file istest_*.pyor*_test.py; package markers,conftest.pyand
generated modules owe none), theflydomain (onlyREQUIREMENTS.mdis frozen),
a containerised session sandbox that forwards credentials by name rather than by
value, and theclaude-cliprovider with--max-tokens/--timeoutin
examples/_common.py.agentdescent/itself is untouched (#188). -
Multi-artifact evolution —
extra_artifacts=onevolve()andasync_evolve()
(#197): register any number of artifacts beside the primary; the worker loop
proposes against each (PP stages name them;PipelineParallellifts once
extras exist), the aggregator merges bydiff.target, and a contract-breaking
diff lands atomically viaLedger.commit_atomicwith exact dependent-adapter
coverage (missing-adapterswhen incomplete) and CAS retry that refuses a
stale adapter.Contract.depends_ondrives dependent cache eviction
(MemoryCache/FileCache.invalidate). Sync/async rollout records attribute
extras to the extra's artifact id. Default path without extras is unchanged. -
RRSI wired into
evolve()(examples/rrsi/rrsi_policies.py, #254 / #221):
build_rrsi_bundle()assembles the three regularizers --RRsiCritic
(pre-evaluation screen: annealed edit-budget gate + deterministic leakage
screening + optional model reviewer),RRsiProposalPolicy(injects budget,
measured per-edit history, pruning targets and stall exploration into the
reflection), andRRsiAcceptance(the pinned Algorithm-2 floor + both
cost-rule branches + novelty, with monotoneS*) -- into onePolicies
bundle sharing a checkpointableRRsiState. New engine seam
Policies(screen=...)(ScreenPolicy) runs before measurement, so a
leaking or over-budget card is settled and reported ascritic-rejected
without a held-out sweep; new outcomesnoise-floor/cost-rule; new
counterscritic_checked/critic_rejected; the aggregator's checkpoint
now carries an acceptance policy's optional state, so a resumed run does not
loseS*. The selection core and schedule fixtures are reused, not
rewritten; declared deviations (one-candidate-per-round judging, per-merge
anneal on the barrier-free path, configurednoise_band) are recorded in
docs/algo-rrsi.md. Default behaviour unchanged -- a run without the bundle
reports zeros. -
Verifier bootstrap flywheel (
agentdescent/audit/boost.py, #273):
VerifierBoostwraps any verifier and learns a monotone calibration curve
(isotonic_fit, numpy-only PAV) from the audit's IMPROVEMENT pool, then
activates it only if it provably reduces residual error on a held-out slice
of that pool (the bootstrap gate). When active it corrects the cheap and
learned layers the aggregator uses to rank candidates and the audit uses for
its trust signal;eval_counts/full_evalare delegated raw, so the
commit gate keeps the oracle's authority over what commits. It trains on the
IMPROVEMENT pool only (never the CALIBRATION pool that measures it), filters
to the current verifier version, and declares itself as a new verifier version
(version_tag) soattach(boost=...)/Audit.recompute()refresh the audit
fingerprint andVerifierWatchwithdraws the old calibration. Default
behaviour unchanged -- no boost means no fitting and no correction. -
examples/textgrad/: amechanism_microportof TextGrad
(zou-group/textgrad@75e912e2) as a reflection / propose seam. A proposal is a
textual-gradient call (the base-case backward prompt) followed by a TGD rewrite
read from<IMPROVED_VARIABLE>tags, applied to one prompt slot whose diff id
hashes the text (an unchanged rewrite is a counted no-op). Acceptance is the
default held-out gate, so no core contract changes; it is stricter than
upstream'srun_validation_revert(a tie is kept upstream, rejected by the
Beta-posterior gate), which is a declared departure. Registered in
bench.candidate_methods, with `docs/algo-textg...
0.6.0 — multi-head, allocator, trajectories, governance
Everything merged since 0.5.1: multi-head ledger forks, value-directed allocation, L-traj resume, trajectory ledger, governance contracts, CladeThompson, skill_dir structural gates, RRSI building blocks, changelog fragments, and a large set of crash-safety / overflow / parser fixes.
Highlights
- Multiple live heads —
Ledger.fork/live_heads/discard_headso workers can expand different candidates in parallel without serialising ondev. - Value-directed budget allocation —
evolve(allocator=...)learns which candidates are worth the expensive self-verify rollout. - L-traj resume —
async_evolve(resume_queue=...)re-runs stragglers against a newer head instead of only counting them. - Rollout trajectory ledger — opt-in
record_trajectories=Truepersists versioned trajectories for process supervision and audit replay. - Governance invariants —
evolve(contract=Contract(invariants=(...)))enforces machine-checkable rules before measurement. - CladeThompson selection, skill_dir structural
SKILL.mdgates,Diff.rationale, and RRSI component / history / schedule fixtures. - Changelog fragments — PRs add
changelog.d/<n>-<slug>.mdinstead of editingCHANGELOG.md. - Hardening across AuditStore, CostEfficient/FlatPuct/Archive softmax, rewards number parsing, runstore/FileCache/Ledger write contracts, and AdaptiveTrustRegion caps.
Upgrade notes
- Install with
pip install "agentdescent[mcp]==0.6.0"(MCP extra needs Python >= 3.10). DSH package isdsh-agentdescent@0.6.0. - Research examples remain in the source checkout. Clone
v0.6.0for the matching tag. - Trajectory recording, contracts, allocator, and resume_queue remain opt-in; defaults match 0.5.1 behaviour.
Validation
Release commit on main: d0cbc268c0104c29520ed79b313a37754c7eca96. Required checks build + test (3.9–3.13) were green on the release PR before squash auto-merge.
Full detail: CHANGELOG.
Added (from CHANGELOG)
Ledger.fork/live_heads/discard_head— multiple live heads (#75).- Value-directed budget allocation —
evolve(allocator=...)/async_evolve(allocator=...).BudgetGovernordegrades optional spend (fusion tournaments, the self-verify rollout) against global floors: oncespent / max_tokenscrosses a threshold, every candidate stops getting the expensive part. The EvoAlloc line of work measures the cost of that fixed allocation when evaluation is the scarce resource — this replaces it with a per-candidate decision learned from the run's own merge history. - **
async_evolve(resume_queue=...)— the L-traj resume half, the straggler CladeThompsonselection policy (#276): HGM's expansion rule, Thompson- Add the RRSI component vocabulary (
examples/rrsi/components.py) and per-edit kind="skill_dir"now gates candidates structurally before any rolloutDiff.rationalecarries the FileTree reflector's reason into the ledger- Add the RRSI cosine-annealed L0 edit-budget schedule (
examples/rrsi/schedule.py) - Add an offline RRSI round-selection mechanism fixture adapted from Google's
- Rollout trajectory ledger.
evolve(record_trajectories=True)(and - Governance invariants.
evolve(contract=Contract(invariants=(...)))(and - Changelog fragments (#295): a PR now adds one file
changelog.d/<number>-<slug>.md
Fixed (from CHANGELOG)
audit.AuditStorekeeps its crash-safety contract (#274). A torn tail leftFlatPuct/CostEfficient/MCTS/Beamno longer crash or silentlysigmoid_novelty_weights/Archive(sampling='sigmoid_novelty')no longerrunstorerounds/status no longer break on a non-finite reward or a torn- HuggingFace row-cache filenames sanitize split names and bound their
TrajectoryStore.record()no longer raises when a record cannot be encodedFileCachewrite failures no longer leave orphan*.tmpsiblings, and- A failed
Ledgerwrite no longer corrupts the ledger (#265). Payloads are runstore._write_jsonencodes before creating a sibling tmp and alwaysmeta.cached_completionis best effort and never costs the caller a paid call: a cache-write failure (OSError, unencodable or non-strresponse) returns the response uncached and leaves no*.partialsibling, the entry is encoded before the disk is touched, and a corrupt or non-strentry (including a JSON list, which used to raiseTypeError) is counted once, as a miss, instead of as both a hit and a miss (#269).TrajectoryStore.get/path_forround-triptrace_ids whoseartifact_idcontains a colon by parsing withrsplit(":", 1)(#257). The key is always a hex digest; a leading split treated a namespaced id as part of the key and returnedNonefor a record that was on disk.dataloadercache entries are written atomically (temp file +os.replace),- Container sandbox allowlisted env vars are forwarded as
--env NAMEso CallBudgetdefault floor is capped atbase, so a configured ceiling belowhf_rows_modelscope(cache=False)now bypasses an existing on-disk cache andAdaptiveTrustRegionwidens when a window is dominated byOVERSIZED- Allocator A/B comparisons now use the same fully scored seed pairs for
- The
OVERSIZEDmerge report now quotes the trust region that actually BudgetGovernor's diminishing-returns stop skips a non-finite (NaN/inf)PopulationAggregatorrecordsCandidate.parentand backpropagates
… and 4 more in CHANGELOG.
0.5.1 — reliable host installs and a clearer first run
Everything merged since 0.5.0, including the host-launch repair and the updated website, quickstart and documentation.
Highlights
- Machine-local MCP launchers and session hooks use the installing Python, so a later agent process does not need the pip scripts directory on PATH. Reinstalling repairs stock legacy and stale pinned Codex/OpenCode entries while preserving custom configurations and wrappers.
- The README now leads to the website and interactive demo, installation guide and documentation. Mobile navigation keeps the demo reachable; responsive layout checks cover the desktop menu, disclosures and install command.
- Token budgets, cost-aware selection, graceful degradation and optional diminishing-returns stopping; checkpointed search state can survive a restart.
- Sparse verifier auditing and calibration, opt-in priority-ordered audit draining, and replay-aware sampling and proposals.
- Policy-slot evolution, Genesis skill extraction and read-only investigation, and the porous-molecule tree-search example.
- More actionable spec/dataset errors, policy-slot scaffolds, demo restart-race fixes and clean installed-wheel CLI/MCP gates.
Upgrade notes
- Python >=3.9; the MCP extra requires Python >=3.10. NumPy >=1.20 is now an installed dependency.
- Install the release with
pip install "agentdescent[mcp]==0.5.1". The DSH package isdsh-agentdescent@0.5.1; registry workflows run after this GitHub release is published. - Research examples remain in the source checkout, outside the installed wheel. The website's one-command setup installs current main, not a pinned release.
- Use
ThreeLayerVerifier.full_evalandfull_eval_matches_counts. The old oracle aliases remain; their planned removal stays at 0.7. - Checkpointing, replay weighting and audit draining remain opt-in. Token budgets use adapter-reported usage and are not provider-side hard spending limits.
Validation and limits
The merged release commit is 75688466483c162982adb7d5108f1c208a1263cb. Python 3.9–3.12 full suites and clean-wheel gates, production docs and JavaScript regressions are checked for this exact commit. Fresh wheel and sdist installs were exercised outside the checkout, including empty-PATH host configurations and session hooks.
Native Windows/macOS host sessions and paid-model runs were not exercised. The local sandbox has 19 known environment failures that also reproduce on unchanged main; hosted CI is the full-suite release gate. Registry publication is verified separately after the publishing workflows run.
Full detail: CHANGELOG.
0.5.0 — the plugin surface
0.5.0 — the plugin surface
AgentDescent as a plugin for Claude Code, Codex, OpenCode and DeepSeek
Harness: a shared skill, an MCP server over doctor / plan / start / status /
show / apply / cancel / resume, a run store so a run started from an agent can
be inspected from a shell, and plugin as an evolvable kind.
Merging is the default now wherever a model is reachable to merge with, so
several workers merge their edits rather than one winning and the rest being
dropped.
v0.4.6 — two benchmarks this repository did not build
Two benchmarks this repository did not build, and a prior that steers the search.
ERA on LLM-SRBench (#159)
examples/era/era_llm_srbench.py — the same flat-PUCT tree, aggregator, sandbox
and governance layer, scored on somebody else's published problems, metrics and
leaderboard. On LSR-Transform (111 Feynman equations rearranged so the closed
form is not one a model memorised), under the benchmark's own per-problem
protocol:
| LSR-Transform, all 111 | SA | Acc(0.1) | median NMSE | budget |
|---|---|---|---|---|
| LaSR (paper, best backbone) | 6.31% | 50.45% | 0.0011 | millions of GP mutations |
| LLM-SR (paper, best backbone) | 31.53% | 39.64% | 0.0091 | 250 prompts |
here, deepseek-v4-flash |
41.4% | 56.8% | 2.15e-08 | 16.5 calls |
Five protocol settings are stricter than the benchmark's own, so those are floors.
ERA on AlgoTune (#160)
examples/era/era_algotune.py — 147 of AlgoTune's 154 tasks, one tree each,
scored in speedup rather than accuracy, with the task's own reference as the
root node and its own is_solution as the oracle.
A model prior in PUCT's P(s,a) (#160)
--prior-exponent (default 0.0, upstream's uniform 1/N to the
floating-point bit) asks the mutation reply for a PROMISE: <n> rating of the
approach after tuning, and uses p^k / Σp^k as the prior. Read out of a reply
the port already pays for, so it costs no extra call.
Over 250 rated nodes, 60 of the 137 rated ≥8 reached 2x against 3 of the 93
rated ≤6 — Fisher one-sided p=2.2e-13. Against validity it is worth
nothing (Spearman 0.046), which is the right division of labour when the sandbox
already measures correctness.
On the eight tasks AlphaEvolve, MetaEvolve and OpenEvolve all publish, one run
each: harmonic mean 2.195x against AlphaEvolve's 1.392x and MetaEvolve's
2.045x, ahead on five of eight against each; 1.440x with the uniform prior.
Three caveats travel with that number and are in
bench/results/era-algotune-model-prior.md
— chiefly that lu_factorization's 4.464x skips the reference's .tolist()
rather than factorising faster (discounting it gives 1.782x), and that it is one
run per task on a benchmark whose spread on polynomial_real alone covers
0.983x to 962x.
Fixed
- The AlgoTune sandbox capped the reference's threads and not the
candidate's. None of the BLAS variables reach numba, which reads
NUMBA_NUM_THREADS, so an@njit(parallel=True)candidate was timed on every
core against a one-core reference. Neither side is capped now — writing a
parallel implementation is an optimisation — and--cpu-secondsscales with
the core count. - A rejected answer could be told its numbers were correct. The note
attached to anis_solutionrejection flattened both sides before comparing,
so right values in the wrong container looked identical to it.
Full notes: CHANGELOG
v0.4.2 — where those fifteen rows actually came from
A follow-up to 0.4.1, which fixed a dropped flag but left the wrong attribution
in place. Full detail in
CHANGELOG.md.
Fixed
-
A run reported what it reached and nothing about how it was set up, so fifteen recorded rows attributed themselves to the wrong lag budget. Every
bench/results/*.jsonwritten from a MethodPolicy port pairs acellslist with a hand-typedconfigblock; the cells were transcribed from the linestandard_mainprints, which states results only. Fifteen blocks recordedasync_ratio: 2for runs that tookrun_port's default of 1, and the attribution namedbench.candidate_methodsas the source.It was not. That harness has no
--stalenessand never passesstaleness=torun_port, so every run through it isguarded— and all fifteen blocks recordfull. The transcribed line is what produced them, and that is checkable rather than argued: it formats qualities at.3f, seconds at.1fand calls as an int, and across all 45 cells not one value carries more precision, while the one filebench.candidate_methodsdid write has 198 of 198 wall/engine values at full float precision. Those files now record 1, with a note, and the elevenRun itcommands pass--async-ratio 1. -
run_portrecordsstalenessinframework— the one setting a run could not state about itself, and the one that made those blocks impossible to attribute either way.
Added
examples._method_runner.run_configand theconfig:line. A live run prints its resolved configuration as one JSON object, in the key names those results blocks already use, so a block is copied out of a run instead of remembered about it.tests/test_results_provenance.pykeeps the forensic invariant executable: a future results file whose cells carry more precision than that print line came from somewhere else, and its config block cannot be read as describing a command-line run.
v0.4.1 — flags that were declared and never read
Everything that had accumulated since 0.4.0. Full detail in
CHANGELOG.md.
Fixed
- Four shared flags reached the MethodPolicy runner and were dropped.
--async-ratio,--eval-concurrencyand--eval-cachewere declared by the shared parser and never passed torun_port, so on all eleven declarative ports a run that set every one of them was byte-identical to one that set none;--val-capparsed and moved nothing, because those ports freeze their splits inbuild(). All three are threaded and recorded now,--val-capis withdrawn, andtests/test_method_runner_flags.pyenumerates the parser and fails on any flag with nowhere recorded that reads it. (#143) - A work-budget stop on the async path abandoned the evidence it had paid for. When
max_rolloutstripped, up ton_workers - 1rollouts were still in flight with their model calls already billed, and the merger drained the intake once and returned. Measured on an 8-worker GEPA run: 8 cards produced, 7 abandoned. evolve(policies=..., aggregator_factory=...)silently ignored the merge-side policies. It now warns, naming the dropped ones.
Added
Usage.failure_seconds— model time spent inside calls that ultimately failed, kept apart fromsecondssowall - failure_secondsis the wall-clock net of endpoint weather.bench.matrix_run— the parallelisation-matrix runner: one row per port, serial vs N-wide arms,--budget-rolloutspinned on both, results written after every cell.- GEPA
--reflective-mergemerges the round's diffs into one pool candidate. At equal budget (16 rollouts, seed 0, net of failures): serial 1424s/97 calls, sync N=8 1022s/70 calls (−28%), test EM within noise across arms. - Shared port flags:
--eval-concurrency,--val-cap,--reflective-merge, GEPA's--seed-instruction.
Changed
- The fusion tournament is off by default; the union goes straight to the acceptance gate. Measured on the multi-key fixture: 88 → 48 task evaluations, same
final_reward=1.000.evolve(fusion_tournament=True)restores ranking. cheap_eval_tasks=Nonenow means 8, or the whole held-out set when smaller —ThreeLayerVerifier.rule_subset's own default, whichevolve()had been overriding. Passlen(held_out)for the old behaviour.- OpenEvolve's
--serialnow means the shared thing (one worker).
v0.4.0 — one engine
One engine. 0.3.0 made the numbers readable; this release removes the second
implementation they were being measured against.
AgentDescent and AsyncAgentDescent each had their own round barrier, worker
dispatch, snapshot staggering, merger thread, published head and backpressure.
docs/architecture.md called that "a known wart rather than a design intent", and
it kept costing: two measured fixes that had to be hand-ported between the loops, two
early-stop epsilons nobody chose, and three mechanisms the general engine
re-derived — and got wrong — because the reference stack already had them.
Both are adapters over evolve() now. The public surface is unchanged, the
sequential barrier is preserved so a seeded run stays reproducible, and the
reference table still reads first 0.604, final 1.000, against a fork baseline of
0.379.
Highlights
- One engine, two runtimes. The reference domain is expressed in the vocabulary
evolve()/async_evolve()speak, andWorkeris gone. The three things the
translation does not preserve exactly are listed indomains/router.pyrather than
left to be discovered. - An execution-and-resource plane, with a page of its own. Sandbox leases with an
owner, a ceiling and a way to be reclaimed; a real container boundary verified
against both podman and docker; a ledger and an evaluation cache that survive more
than one writing process;ClusterParalleland the feedback channel a scheduler
needs. - The executor seam is actually wired. A supplied
Policies(executor=...)used to
run nothing while the run reported that it had gone fine — on both paths. - Replaceable policies. Each merge, staleness, retirement and early-stop decision
is a contract you can swap without changing any of the defaults. - Evolving a directory — a skill folder, an agent folder, or its code — with
FileTree(frozen=[...])enforced twice. - Ports share one tested CLI contract, each owns a directory, and the results
table now marks which rows survive a change of model. - Docs rebuilt as a reference, with a generated API page and one table of every
primitive that is provided, tested, and not in any engine path.
Breaking
- Removed:
agentdescent.worker.Worker,AsyncConfig.aggregator_interval,
AsyncConfig.worker_pause,EvidenceCard.version_annotations, the
domains.router.Taskalias. full_evalis no longer part of theEvolvableprotocol (implementations keep
theirs).Evolvable.cheap_eval→evidence_eval;cheap_evalremains an alias, and the
moved strategy import paths still work.
Each entry in the changelog says what replaced it.
Not claimed
Two of the five re-measured port results are knob-dependent — --hard and
--top-k are calibrated against the published model — and docs/results.md marks
those rows ⚠︎ rather than presenting them as reproductions.
Full detail: CHANGELOG