Skip to content

Releases

0.9.0 — platform surfaces, algorithms run, release/ops/tenancy

Choose a tag to compare

@Birfy Birfy released this 06 Nov 08:25
426a1f5

[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. complete is 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 in skipped and detail.
    Post-loop decisions are cached per run_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
    LoopGeneration now 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; add rolls
    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 failed TaskCandidates as ToolSynthesisRequest
    examples, runs the existing ToolSynthesizer, and hands the selected candidate
    to the caller's CapabilityRequest builder before CapabilityFoundry.admit.
    The report makes no-candidate and no-request explicit; only an admitted tool
    reaches promoted.

  • BudgetedSearch: runs SearchFabric at increasing UCT budgets and stops when
    the value gain per expansion falls below a bar, using the existing
    MarginalGainStop or 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 accepted promote() decision becomes a release. It
    builds an ArtifactManifest carrying 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: turns ReplayLab.shapley step credit into per-step
    ExperienceRecord rewards and ingests it into ExperienceEngine. Credits below
    min_credit are dropped and an empty reward map is refused, so a trace with no
    attributable gain cannot silently become zero-information replay.

  • PreferenceReplay: ranks stored ExperienceRecords by a fitted
    PreferenceModel and ingests the preferred slice into ExperienceEngine
    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: composes TaskPipeline, CapabilityScout and
    CapabilityArchive so production traces become a validated, admitted and
    archived capability in one call. The report records the pipeline verdict, scout
    outcome and archive result; admitted is true only when the archive added the
    artifact (#677).

  • BudgetedStep: composes SearchFabric and BudgetedSearch into a durable
    loop step that scales search budgets with the controller's budget_scale,
    stops on marginal gain, and returns a LoopObservation with round-by-round
    evidence, risk and an artifact id (#678).

  • curriculum_meta_run gains opt-in verified seeding: min_exam (via
    verified_rules) excludes unexamined, flagged or audit-biased rules when set,
    and oracle + audit_store audit a sampled slice of the
    validation pairs and persist the verdict with audited_n, oracle_gain and
    gain_bias in 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_evidence and release_candidate compose trust evidence, promotion
    and the PromotionLedger into 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 several RSIPlatform cycles under the existing
    RSIController stop 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, and PlatformCampaignReport.best_cycle
    names the highest-reward cycle (#681).

  • TenantPlatform wraps RSIPlatform.run_cycle so each cycle routed through it
    is a reserved, authorized and audited tenant action. A cycle reserves quota at
    the stated tokens/cost (which enforces run:write and 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. TenantCycleReport exposes the platform report, reservation,
    usage and a JSON-safe summary (#682).

  • AdaptiveExperience: one cross-cycle composition that ingests counterfactual
    credit through CounterfactualExperience, selects validation anchors from a
    fitted PreferenceReplay (or feature recall, recent history, or self-validation
    on the first cycle), and delegates the guarded update to ExperienceEngine.
    Ingestion deduplicates by run_id, and missing validation or bridge features
    fail closed (#683).

  • agentdescent.governed_harness composes 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_run turns continuous meta-learning into a bounded campaign:
    RSIController stop conditions wrap repeated continuous_meta_run sessions
    that share one durable ConsolidationStore, 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 release and the MCP release tool: 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
    ArtifactManifest and writes its lineage node. Signing material comes from an
    environment variable or file (never argv); reject/defer leaves the lineage
    untouched; the JSON result carries schema_version: 1. Use --lineage to
    persist and extend the receipt graph and --out to write the full report.

  • Product surfaces for the four P1 capabilities, each with a CLI verb and an MCP
    tool: platform runs a durable five-layer campaign from a JSON spec with a
    runnable --demo; capability turns failure traces into an admitted, archived
    capability; ops publishes terminal runs to the console/lineage/telemetry/
    metrics with alerts; and experience reports, ingests, recalls, updates and
    preference-replays an ExperienceStore. All returns carry schema_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-harness and the MCP governed_harness tool: one
    spec-driven surface for the existing safety-gate -> proof -> approval ->
    canary/rollback -> promotion chain. init --demo is runnable offline; plan
    validates refs and scores without running the gates; run returns 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. Direct govern_harness_change callers also get the
    matching fix: optional conformal insufficient / sequential continue
    evidence is ignored when the rules do not require those tests, while a
    conformal/sequential reject still fails the promotion.

  • agentdescent meta-campaign and the MCP meta_campaign tool: repeated
    continuous_meta_run sessions over one ConsolidationStore, each in a fresh
    ledger repo, with RSIController target/cost/...

Read more

0.8.0 — hosts, RSI report, tournament & campaign

Choose a tag to compare

@Birfy Birfy released this 30 Oct 10:50
ac103ca

Added

  • agentdescent install grok-bot / uninstall grok-bot scaffold a skill +
    HOST.md + mcp.example.json under ~/.agentdescent/plugins/grok-bot/
    (#165). Grok Bot has no public one-click plugin API for local skill+stdio
    MCP yet, so doctor reports mcp n/a when the scaffold is current rather
    than pretending a host config was wired. Docs: plugins.md,
    plugin-quickstart.md.

  • agentdescent install opencode writes /agentdescent/evolve under
    ~/.config/opencode/command/agentdescent/evolve.md, and install codex writes
    /prompts:evolve as ~/.codex/prompts/evolve.md — the same prompt body as
    Claude Code's /agentdescent:evolve. uninstall removes each only while still
    stock (#165).

  • agentdescent install writes an /algorithms slash entry beside /evolve on
    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 as agentdescent algorithms list|show and MCP list_algorithms / describe_algorithm. Grok Bot's
    HOST.md names the CLI/MCP discovery path; uninstall removes each slash
    file only while still stock (#384).

  • rsi_report / agentdescent rsi / MCP rsi: 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 overall improving / stagnant /
    mixed / insufficient verdict 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 under errors, so a crash cannot win by shrinking the
    denominator; --dry-run prices every arm before a run. default is 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
    patience non-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, and final_reward
    is the last session while best_reward is the artifact kept. --dry-run prices
    the sessions first; policy_slot and inline text targets are refused because
    there is no file to carry, and --workdir must be empty.

  • MCP tools safety, portfolio and audit_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 carries archive for safety), write nothing, and treat a
    missing archive as an error. The installed SKILL.md says when to use them, and
    the doctor tool description now lists opencode (#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-rejected outcome, 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's diff_id, needs-approval / approval-rejected are real
    MergeOutcome members, requests carry a reviewable summary, and malformed store
    lines are skipped. Low-risk candidates delegate to the inner acceptance policy.

  • MarginalGainStop, a stateful stop_when policy: it watches the recent
    reward/call slope and stops after patience measurements whose per-call gain
    is below min_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_gain is an optional absolute-gain floor combined by OR. The reason
    names the measured gain and call delta, a round with no new calls never counts
    as low, and reset() makes the object reusable across runs. This is an
    economic stop for long self-improvement runs, not a safety verdict.

  • VarianceSampler, a TaskSampler that 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 like DifficultyWeighted.

  • diagnose_payload / agentdescent diagnose / MCP diagnose: turns show'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 to below-threshold) instead of inventing
    a category the aggregator cannot decode, reports the first refusal even with
    collect_all, and forwards bind/configure plus 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, and children() exposes the decision tree a dashboard or
    audit export needs. Writers in one process share a per-path lock.

  • bootstrap_ci / is_significant / paired_gain and contamination_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" is None rather than a clean-looking 0.0. Pure
    standard-library functions for adoption gates, reports and external audits.

  • KillSwitch, canary and rollback_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_regression bar, 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_factory algorithm is called out in notes. 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 (deny by 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...

Read more

0.7.0 — named algorithm registry, self-improvement and verifier tooling

Choose a tag to compare

@Birfy Birfy released this 23 Oct 12:48
a7d020a

Added

  • A persistent-island population run now returns EvolutionResult.lineages
    (#150, semantics C): a read-only row per lineage (dev plus 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, survives finalize,
    and is None on 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 the GrowAndRefine Curator moved from examples/ace
    into agentdescent/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 from examples/skillopt into
    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 from examples/evoskill into
    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.algorithms entry-point group (Algorithm or 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 into agentdescent/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_evolve on the archive the loop just wrote. The first round uses the same fixed rule as self_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_exam also 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.

  • VerifierCurriculum and VerifierAgreement: 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 optional MetaAuditStore on the seedable set, returning safe /
    caution / unsafe with the named checks and reasons. --min-exam mirrors
    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)
    reverses install (#165): it removes the skill files and the plugin directory,
    the marker-delimited cordis.patch.yml block, the [mcp_servers.agentdescent]
    table and the pinned mcp.agentdescent entry, and nothing else. A Codex table
    is removed even when Codex has appended other tables after it. Anything that is
    no longer exactly what install writes (an edited launcher, a bare
    opencode mcp add entry, a hand-written table) is kept and reported with exit
    status 1, a commented opencode.jsonc is never rewritten, and the run store is
    untouched. New integrations.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_failures so a child's own
    tests are run and implementation code with no test under its node is sent back
    (a test file is test_*.py or *_test.py; package markers, conftest.py and
    generated modules owe none), the fly domain (only REQUIREMENTS.md is frozen),
    a containerised session sandbox that forwards credentials by name rather than by
    value, and the claude-cli provider with --max-tokens / --timeout in
    examples/_common.py. agentdescent/ itself is untouched (#188).

  • Multi-artifact evolution — extra_artifacts= on evolve() and async_evolve()
    (#197): register any number of artifacts beside the primary; the worker loop
    proposes against each (PP stages name them; PipelineParallel lifts once
    extras exist), the aggregator merges by diff.target, and a contract-breaking
    diff lands atomically via Ledger.commit_atomic with exact dependent-adapter
    coverage (missing-adapters when incomplete) and CAS retry that refuses a
    stale adapter. Contract.depends_on drives 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), and RRsiAcceptance (the pinned Algorithm-2 floor + both
    cost-rule branches + novelty, with monotone S*) -- into one Policies
    bundle sharing a checkpointable RRsiState. New engine seam
    Policies(screen=...) (ScreenPolicy) runs before measurement, so a
    leaking or over-budget card is settled and reported as critic-rejected
    without a held-out sweep; new outcomes noise-floor / cost-rule; new
    counters critic_checked / critic_rejected; the aggregator's checkpoint
    now carries an acceptance policy's optional state, so a resumed run does not
    lose S*. 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, configured noise_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):
    VerifierBoost wraps 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_eval are 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) so attach(boost=...) / Audit.recompute() refresh the audit
    fingerprint and VerifierWatch withdraws the old calibration. Default
    behaviour unchanged -- no boost means no fitting and no correction.

  • examples/textgrad/: a mechanism_microport of 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's run_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...

Read more

0.6.0 — multi-head, allocator, trajectories, governance

Choose a tag to compare

@Birfy Birfy released this 16 Oct 08:22
d0cbc26

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_head so workers can expand different candidates in parallel without serialising on dev.
  • 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=True persists 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.md gates, Diff.rationale, and RRSI component / history / schedule fixtures.
  • Changelog fragments — PRs add changelog.d/<n>-<slug>.md instead of editing CHANGELOG.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 is dsh-agentdescent@0.6.0.
  • Research examples remain in the source checkout. Clone v0.6.0 for 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=...). BudgetGovernor degrades optional spend (fusion tournaments, the self-verify rollout) against global floors: once spent / max_tokens crosses 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
  • CladeThompson selection 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 rollout
  • Diff.rationale carries 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.AuditStore keeps its crash-safety contract (#274). A torn tail left
  • FlatPuct / CostEfficient / MCTS / Beam no longer crash or silently
  • sigmoid_novelty_weights / Archive(sampling='sigmoid_novelty') no longer
  • runstore rounds/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 encoded
  • FileCache write failures no longer leave orphan *.tmp siblings, and
  • A failed Ledger write no longer corrupts the ledger (#265). Payloads are
  • runstore._write_json encodes before creating a sibling tmp and always
  • meta.cached_completion is best effort and never costs the caller a paid call: a cache-write failure (OSError, unencodable or non-str response) returns the response uncached and leaves no *.partial sibling, the entry is encoded before the disk is touched, and a corrupt or non-str entry (including a JSON list, which used to raise TypeError) is counted once, as a miss, instead of as both a hit and a miss (#269).
  • TrajectoryStore.get / path_for round-trip trace_ids whose artifact_id contains a colon by parsing with rsplit(":", 1) (#257). The key is always a hex digest; a leading split treated a namespaced id as part of the key and returned None for a record that was on disk.
  • dataloader cache entries are written atomically (temp file + os.replace),
  • Container sandbox allowlisted env vars are forwarded as --env NAME so
  • CallBudget default floor is capped at base, so a configured ceiling below
  • hf_rows_modelscope(cache=False) now bypasses an existing on-disk cache and
  • AdaptiveTrustRegion widens when a window is dominated by OVERSIZED
  • Allocator A/B comparisons now use the same fully scored seed pairs for
  • The OVERSIZED merge report now quotes the trust region that actually
  • BudgetGovernor's diminishing-returns stop skips a non-finite (NaN/inf)
  • PopulationAggregator records Candidate.parent and backpropagates

… and 4 more in CHANGELOG.

0.5.1 — reliable host installs and a clearer first run

Choose a tag to compare

@Birfy Birfy released this 10 Oct 13:43
7568846

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 is dsh-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_eval and full_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

Choose a tag to compare

@Birfy Birfy released this 07 Sep 13:05
e9951b7

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

Choose a tag to compare

@Birfy Birfy released this 28 Aug 15:32
8ea8ca8

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-seconds scales with
    the core count.
  • A rejected answer could be told its numbers were correct. The note
    attached to an is_solution rejection 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

Choose a tag to compare

@Birfy Birfy released this 10 Aug 13:46
f11a84a

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/*.json written from a MethodPolicy port pairs a cells list with a hand-typed config block; the cells were transcribed from the line standard_main prints, which states results only. Fifteen blocks recorded async_ratio: 2 for runs that took run_port's default of 1, and the attribution named bench.candidate_methods as the source.

    It was not. That harness has no --staleness and never passes staleness= to run_port, so every run through it is guarded — and all fifteen blocks record full. The transcribed line is what produced them, and that is checkable rather than argued: it formats qualities at .3f, seconds at .1f and calls as an int, and across all 45 cells not one value carries more precision, while the one file bench.candidate_methods did write has 198 of 198 wall/engine values at full float precision. Those files now record 1, with a note, and the eleven Run it commands pass --async-ratio 1.

  • run_port records staleness in framework — 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_config and the config: 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.py keeps 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

Choose a tag to compare

@Birfy Birfy released this 10 Aug 13:06
7fede50

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-concurrency and --eval-cache were declared by the shared parser and never passed to run_port, so on all eleven declarative ports a run that set every one of them was byte-identical to one that set none; --val-cap parsed and moved nothing, because those ports freeze their splits in build(). All three are threaded and recorded now, --val-cap is withdrawn, and tests/test_method_runner_flags.py enumerates 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_rollouts tripped, up to n_workers - 1 rollouts 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 from seconds so wall - failure_seconds is the wall-clock net of endpoint weather.
  • bench.matrix_run — the parallelisation-matrix runner: one row per port, serial vs N-wide arms, --budget-rollouts pinned on both, results written after every cell.
  • GEPA --reflective-merge merges 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=None now means 8, or the whole held-out set when smaller — ThreeLayerVerifier.rule_subset's own default, which evolve() had been overriding. Pass len(held_out) for the old behaviour.
  • OpenEvolve's --serial now means the shared thing (one worker).

v0.4.0 — one engine

Choose a tag to compare

@Birfy Birfy released this 05 Aug 14:23
40486b2

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, and Worker is gone. The three things the
    translation does not preserve exactly are listed in domains/router.py rather 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; ClusterParallel and 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.Task alias.
  • full_eval is no longer part of the Evolvable protocol (implementations keep
    theirs).
  • Evolvable.cheap_eval → evidence_eval; cheap_eval remains 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