跳到正文
GitHub·· 10 天前AI 评分60

EvolvingAgentsLabs 开源 agentvcs:为运行时自我演化的智能体做版本控制

EvolvingAgentsLabs/agentvcs

AI 导读

EvolvingAgentsLabs 开源 agentvcs,定位为面向智能体的 git,把代码、目标、模型、trace 与子智能体集群作为一次提交的多个维度一起版本化,并支持把运行时演化合并回发布分支。

正文

Two branches diverge and merge, sealed once the eval passes

CI Python Tests Dependencies License

Version control for software that evolves while it runs.

The open-source "git for agents": version an agent's code, skills, goals, models, traces & sub-agent swarm together — and merge its autonomous evolution back into your releases, intelligently.

Rust core (v0.1, in progress)

The revival rebuilds agentvcs around a frozen protocol (spec/) as a Rust core, CLI and MCP server (ADR-0001). The Python implementation documented below stays the released one until the plan moves it to legacy/.

cargo build --release                       # target/release/agentvcs
python3 conformance/run.py --cli "$PWD/target/release/agentvcs"   # 103/103
cargo test --workspace
agentvcs init --json
agentvcs snapshot manifest.json --json                  # -> manifest_id
agentvcs run start --manifest b3:… --run-id r1 --json
echo '{"agent_id":"x","inputs":[],"outputs":[],"started_at":"…","ended_at":"…",
       "tokens":{"in":1,"out":1},"latency_ms":3,"metrics":{"f1":0.4}}' \
  | agentvcs step record r1 --json
agentvcs patch propose r1 --from b3:… --to v2.json --rationale "…" --json
agentvcs gate run b3:<patch> --suite suite.yaml --json  # suite: command + thresholds
agentvcs patch apply b3:<patch> --json                  # refuses ungated patches (exit 5)
agentvcs export audit r1 -o r1.audit.json --json
agentvcs verify r1.audit.json --json && agentvcs blame r1.audit.json --metric f1 --json
agentvcs mcp                                            # the same commands as MCP tools

Crates: agentvcs-core (canonical JSON, BLAKE3, manifests, store, ledgers), agentvcs-diff, agentvcs-query (verify, blame, bisect), agentvcs-merge, agentvcs-cli, agentvcs-mcp, agentvcs-py (the Python SDK, below). Implementation decisions: ADR-0006. Numbers: docs/BENCHMARKS.md.

Merge (v0.2 draft)

Two lines of a harness that diverged from a common manifest merge three-way, dimension by dimension (spec/MERGE.md). agentvcs merges what is mechanical and hands each real conflict to an agent with the evidence a run observed — the patches that touched that dimension, their gates and their blame deltas. The agent writes a resolution; agentvcs checks it, stores the merged manifest (parent_ids: [ours, theirs]) and a merge record, and gates it. It never decides a conflict by itself.

agentvcs merge prepare --base b3:… --ours b3:… --theirs theirs.json \
    --ours-run r1 --metric f1 --json            # auto results + conflicts with evidence
# the agent writes resolution.json: per conflict {"take": "ours"|"theirs"|"base"|"delete"}
# or {"kind", "content"}, plus a rationale (spec/MERGE.md §3)
agentvcs merge commit --base b3:… --ours b3:… --theirs theirs.json \
    --resolution resolution.json --suite suite.yaml --json   # exit 1 if the gate fails
agentvcs patch propose r1 --from b3:<ours> --to b3:<merged> --rationale "merge:b3:<record>" --json

Applying a merge to a running system is an ordinary gated patch, so blame attributes what the merge changed. Same commands over MCP (merge_prepare, merge_commit) and in the SDK (avcs.merge_prepare, avcs.merge_commit). Decisions: ADR-0008.

Resolve a merge with Claude Code

agentvcs has no model of its own: when a merge needs judgment, merge resolve hands the conflicts to Claude Code and keeps every guarantee on its side (spec/MERGE.md §6).

agentvcs merge resolve --base b3:… --ours b3:… --theirs theirs.json \
    --ours-run r1 --metric f1 --suite suite.yaml \
    --model claude-opus-5-5 --budget-usd 1 --max-turns 20 --json
agentvcs merge resolve … --dry-run --json      # write the workspace, print the claude command

No conflicts: it commits mechanically and never starts the agent. Otherwise Claude Code runs headless in a fresh temporary workspace that holds only prepare.json, the three manifests and BRANCHES.md, with Read and two MCP tools bound to this merge (agentvcs mcp --merge-session <dir>: prepare, and commit, which validates and stages the resolution). After the session agentvcs audits the transcript — any other tool, or a Read outside the workspace, even a denied one, is E_RESOLVER_ESCAPED (exit 5) and nothing is committed — then commits the staged resolution exactly as merge commit does and adds a resolver object to the merge record (Claude Code version, model, cost, turns, and the transcript as a blob). Over MCP it is the merge_resolve tool; in the SDK, avcs.merge_resolve(...). Inside an interactive Claude Code session, the agentvcs-merge skill covers both ways to ask for a merge.

Python SDK (v0.1, Phase 2)

crates/agentvcs-py is the Python package agentvcs — a thin PyO3 binding over the Rust core plus harness ergonomics (ADR-0007). Not on PyPI yet; build it locally:

crates/agentvcs-py/dev.sh test        # venv + maturin develop --release + pytest
import agentvcs as avcs

with avcs.run("manifest.json", store=".") as run:          # run_start ... run_end(status)
    run.on_patch(lambda ev: print("reload", ev.changed_dimensions))
    run.checkpoint(lambda step: save_kv_state(step.step_index))   # -> checkpoint_ref

    @avcs.step(agent_id="extractor")                     # one StepRecord per call
    def extract(doc):
        prompt = run.manifest["extract.prompt"]["template"]   # always the active manifest
        avcs.current_step().metric("f1", score(...))
        ...

python -m agentvcs (and the agentvcs console script of the wheel) is the Rust CLI in-process; it passes the same 103/103 conformance cases. Model wrappers for OpenAI-compatible servers (llama.cpp, vLLM, Ollama) and Claude live in agentvcs.integrations; the end-to-end example is examples/toy_pipeline.

Name clash. The legacy pure-Python package documented below also imports as agentvcs. Use one per virtualenv: the root pyproject.toml is the legacy one, crates/agentvcs-py/pyproject.toml the SDK.

Apple Silicon with an x86_64 rustup (Rosetta). If rustc -vV says host: x86_64-apple-darwin but your Python is arm64, a plain build links the extension for the wrong architecture (symbol(s) not found for architecture x86_64). dev.sh detects this and builds with --target aarch64-apple-darwin (rustup target add aarch64-apple-darwin). The permanent fix is a native toolchain: reinstall rustup from an arm64 shell, or rustup toolchain install stable-aarch64-apple-darwin && rustup default stable-aarch64-apple-darwin. cargo build at the root skips the binding (it is not a default workspace member); cargo clippy/test --workspace still cover it.

The problem: your agent evolves, git never sees it

An autonomous agent doesn't just run your system. In the field it rewrites it — a new skill, an edited tool, a spawned sub-agent, a redirected goal, a prompt tuned against production experience. Git tracks static text, so none of that exists as far as your repository is concerned.

Then the team ships the next release, and it overwrites every field-learned adaptation and the reasoning behind it. The agent starts over.

agentvcs's goal is to make that run-time evolution first-class and trustworthy:

  1. Capture every iteration as one commit across code + goal + models + trace + swarm.
  2. Prove & freeze what works into a deterministic, replayable recipe.
  3. Reconcile the agent's run-time line back into your git releases instead of losing it.
  4. Measure whether the self-modification is actually improving — not just changing.

It complements git — it doesn't replace it (how it compares). Git stays the system of record for what your team designs; agentvcs is the persistent episodic memory of what the agent became at run-time.

 design-time line   ●──────●──────●   what your team develops & releases under git
                     \              \
                      \              ▼  agentvcs merge --reconcile <agent>
                       \            ◆  one reconciled history
                        \          ▲
 run-time line          ●────●────●   what the autonomous system changed about itself

One commit: four dimensions plus a state

A commit here is not a text diff. It is an atomic snapshot of four simultaneous dimensions — and, when the agent has them, a sub-agent swarm and the runtime frame:

Dimension What it holds
code the files as usual — tools, scripts, markdown skills
goal the intent or directive the agent was pursuing
models which LLM ran, with which params (temperature, …)
trace the chain of thought, tool calls and real results that caused the change
            ┌─────────── one commit ───────────┐
   code  →  │  tree     goal     models   trace │   state: fluid | crystallized
            └───────────────────────────────────┘

And every commit carries a state:

  • fluid — the agent is still iterating, searching probabilistically: high-temperature models, code/skills/prompts/goals mutating between iterations. Powerful, expensive, non-deterministic. This is where new problems get solved.
  • crystallized — a solution you trust, frozen. Once the agent passes its evaluation (agentvcs eval), agentvcs freeze pins the models to temperature 0 and compiles the iteration into a replayable recipe: cheap, stable, deterministic.

agentvcs diff tells you which dimension moved — a goal redirect and a code change are distinguishable events, not one opaque text diff:

705b2fb..1d4bd90
  code
    ~ app.py
  goal
    from: Resolve refund requests autonomously
    to:   Resolve refund requests with fraud checks

What it does that a code VCS can't

Semantic merge — merge --reconcile

The flagship feature. When the design-time line (your team's codebase) and the run-time line (what the agent learned in production) diverge, a plain git merge clobbers the field adaptations or buries them in conflict markers — and it has no idea what the goal or the reasoning should become.

agentvcs merges each dimension appropriately: three-way merge for code/skills (the eval-winner auto-resolves conflicting hunks first), union for model pins, node-by-node for the swarm — then hands the semantic decision to an agent you trust. It writes {base, ours, theirs} goals, traces, code diffs and eval/cost metrics to a subprocess's stdin and reads back {goal, trace, notes, resolved_files}:

agentvcs merge runtime/main --reconcile "nanoloop reconcile"

That is the whole interface. The core has no LLM dependency and no opinion about what sits on the other end — the reconciler synthesizes unified knowledge and can even return the conflict-free files agentvcs then writes.

Multidimensional rollback — the panic button

When an iteration goes wrong, agentvcs rollback restores not just the code but the exact prior goal, model pins and memory, and records why in a durable ledger:

agentvcs rollback --reason "v3 collapsed routing; urgency flag regressed"

It is itself reversible.

Evolutionary diagnostics — is the self-modification working?

AI-generated code suffers regressions a code review won't see. Because agentvcs owns the whole recorded lineage — a population of variants over time, each with an eval score — it can measure things a code VCS can't. These are exact, standard-library computations over the commit graph, with no extra LLM calls:

Diagnostic Model Question it answers
price Price equation w̄·Δz̄ = Cov(w,z) + E[w·Δz] Is improvement from selecting between branches, or editing within a lineage?
price (threshold) Eigen error catastrophe (μL < ln σ) Is self-editing losing information faster than selection recovers it?
health Critical slowing down (lag-1 autocorrelation + variance) Is a collapse coming before the mean score moves?
health / branch Muller's ratchet Is an unmerged branch a decaying asexual lineage that needs recombination (merge)?
infobits Kelly / Kussell–Leibler & channel capacity (I(context; action) in bits) How much can more context retrieval actually buy — where's the compression headroom?
contain Branching process R₀ = n·p Will one poisoned entry in shared memory spread across the swarm, or die out? What verification rate contains it?

The honest scope: these measure a population of variants across time — the object a version control system owns. Controller/fleet math (throughput control, sampling, scheduling) belongs to a live harness and is deliberately out of scope. Full derivations, mappings and the scope boundary: docs/EVOLUTIONARY_DYNAMICS.md.

Real demos

Runnable, narrated, and on the web — every number comes from a real agentvcs eval, nothing faked. Live demos ↗ · reproduction guide docs/DEMOS.md.

  • Business cases — plain English, no math on screen (bash examples/business-cases/run.sh). Five everyday situations, each ending in a one-line call: a support bot that quietly gets worse every week (roll back), a client fork nobody merged (merge it before it rots), a prompt stuffed with context that changes nothing (trim it, save cost), one bad fact poisoning a shared-memory fleet (verify N% of reads).
  • Evolution diagnostics — the technical companion (bash examples/evolution-diagnostics/run.sh). The same five with the real numbers and the theory; every claim asserted against --json.
  • Self-evolving eve merge (bash examples/eve-evolve-merge/demo.sh). A Vercel eve agent rewrites its own skill and spawns a sub-agent at run-time while the team evolves the same files in git — and merge fuses both. Offline, no API key.
  • The full agent loop (bash examples/agent-loop-demo/run.sh). A simulated autonomous agent driving commit → eval → rollback (with a recorded reason) → freeze end to end.

More in examples/README.md.

Architecture & ecosystem

Zero dependencies. Everything is built on the Python standard library alone — deliberate, for maximum auditability and drop-in integration. The data model underneath is a git-style content-addressed object store with typed objects (commit / tree / goal / modelpin / trace / crystal), a per-commit fluid ↔ crystallized state machine, and a three-way semantic merge over the merge-base (docs/SPEC.md). Model pins are provider-agnostic (Anthropic, Google, Qwen, …); "auto" fills the pin from the model that actually ran, so it can't drift.

Passive trace capture (providers). You don't instrument your code to record traces. agentvcs reads what the runtime already writes — local session files or events — through built-in providers: claude-code, qwen-code, anthropic-managed, vercel-eve and odyssey. Declare one in agent.json and commits capture reasoning automatically. Secrets are [REDACTED] by default.

Built for agents. Every command accepts --json and emits a single parseable object with stable error.codes, so an agent recovers programmatically instead of parsing English. An MCP server ships too — claude mcp add agentvcs -- agentvcs-mcp (zero-dependency, stdio JSON-RPC) — exposing the same capabilities to Claude, Cursor or any MCP client so the agent can version itself autonomously. agentvcs new scaffolds an AGENTS.md so the next agent learns the workflow.

Optional Web3 identity — Souls of Silicon. Off by default, zero crypto surface otherwise. agentvcs init --with-soul gives each instance an Ed25519 Soul, signing every commit (forge-proof provenance). Every verified freeze mints a Soulbound Token, building a verifiable CV of what the agent has actually proven — reputation that can't be cloned. Fleets are selected with DeSoc correlation discounting for maximum diversity. Full vision: docs/papers/souls-of-silicon.md. A separate opt-in corporate/legal layer (agentvcs init --corporate) adds an audit log and signed human approvals for governed deployments.

Install

Not on PyPI yet — publishing waits for the v0.1 protocol.

Zero runtime dependencies — standard library only, with a test that walks the AST and fails if that ever stops being true. Nothing is pulled in behind you.

From source:

git clone https://github.com/EvolvingAgentsLabs/agentvcs
cd agentvcs && pip install -e .

avcs is a built-in shorthand for agentvcs — every command works with either name.

Quickstart

agentvcs new my-agent          # scaffold a project pre-wired for agents (agent.json, AGENTS.md, CC skill, MCP)
cd my-agent
agentvcs commit -m "initial fluid agent"
agentvcs diff                  # dimensional diff: code vs goal vs models vs trace
agentvcs eval && agentvcs freeze   # prove it, then crystallize (freeze is gated on the eval)
agentvcs price                 # is the self-modification net-positive?

Declare the non-code dimensions in agent.json:

{
  "goal": "Resolve refund requests autonomously",
  "models": [{ "provider": "anthropic", "model": "claude-opus-4-8", "params": { "temperature": 1.0 } }],
  "trace": { "provider": "claude-code", "auto": true },
  "swarm": { "refund-verifier": { "role": "verify a refund", "skill_file": "agent/subagents/refund-verifier.md" } },
  "eval": { "command": "pytest -q", "runs": 3 },
  "state": "fluid"
}

freeze refuses to crystallize a commit that hasn't passed its eval (EVAL_FAILED); freeze --force past a failure marks the recipe verified: false — never a silent lie. "Crystallized" means "proven", enforced in code rather than in the README.

Commands

command what it does
agentvcs new DIR / init scaffold / create a repository (--claude-code / --qwen-code / --eve wire trace capture)
agentvcs commit -m MSG snapshot code + goal + models + trace
agentvcs log / status / show / diff history / working-tree changes / one commit / dimensional diff
agentvcs branch / checkout REF list/create a live branch / restore the working tree
agentvcs merge BRANCH multidimensional merge; --reconcile CMD hands goal+trace+conflicts to an agent; --target-goal directs it
agentvcs rollback [REF] --reason TEXT undo: restore the full prior state, with a recorded justification (the panic button)
agentvcs eval / freeze / replay / recall the trust gate: prove → crystallize → re-run → find
agentvcs price / health is the evolution working: selection-vs-transmission + error-catastrophe & ratchet warnings
agentvcs infobits / contain information value of context (bits) · shared-memory poisoning containment (R₀)
agentvcs runtime / budget / context / statusline / watch the operational frame your runtime hides
agentvcs ui serve a local web dashboard to watch the evolution
agentvcs soul / verify / fleet optional Soul/DeSoc layer (see above)

Learn more

Scope

agentvcs does not try to replace git. Git stays what your human team builds and releases with at design time; agentvcs is the agent's persistent episodic memory at run-time, closing the gap between MLOps, LLMOps and ordinary DevOps — purely locally.

This repo is the local protocol and runtime — complete on its own, offline, forever. It complements your existing stack (git, LangSmith/Langfuse, MLflow/W&B) rather than replacing any of it. Hosted collaboration and fleet observability at scale are a separate concern, not part of this open-source core.

Before you trust it: the bundled demo reconciler is a deterministic bullet-union stub — honest in its docstring, but not intelligent; the LLM reconciler is a separate piece. Test coverage is lopsided: the optional cryptographic layer has 20 tests while the core object store has 5. 212 tests pass across Python 3.10–3.13.

License

Apache-2.0. See LICENSE.

来源:GitHub · github.com