AO2 is a local-first governed software-delivery system for running agent work with policy checks, exact-digest approvals, replayable evidence, evaluator closure, and release-readiness gates.
The first public workflow is the Risky PR Run:
objective -> workflow compile -> scoped plan -> policy-denied risky action
-> exact-digest approval -> patch/evidence -> reviewer concern
-> evaluator rejection -> correction -> evaluator acceptance -> evidence export
AO2 owns execution and evidence production. The optional
ao2-control-plane
repo is a separate self-hosted read-only observer for signed AO2 evidence.
This repository is part of the AO agent orchestration stack. Start with the central architecture guide at uesugitorachiyo/ao-architecture; the AO2-specific architecture page is ao2.
AO2 replaces the deprecated AO Operator / AO Runtime execution path for active
AO work. New execution, provider-free command, SDD command, runtime behavior,
and evaluator-closure work belongs here. Typed state, evidence readback,
retention, and observer workflows belong in
ao2-control-plane.
The runtime used by AO2 is the in-repo crates/ao2-runtime workspace crate;
AO2 does not depend on the deprecated standalone ao-runtime repository.
AO2's executable path uses the workspace ao2-runtime crate directly from
crates/ao2-cli; Cargo.lock must not contain standalone ao-runtime or
ao-operator packages. The Python guard
tests/test_ao2_native_runtime_platform_evidence.py enforces that boundary in
CI.
Pull request CI also builds and smokes AO2 release archives on Ubuntu, macOS,
and Windows through the hosted release archive smoke job. Native Windows release
downloads remain covered by .github/workflows/windows-release-smoke.yml.
AO2 currently supports bounded_governed_rsi: local-first Pulse continuation,
task generation, policy gates, replayable evidence, and operator-controlled
publish paths. AO2 does not currently prove
full_autonomous_self_mutating_rsi.
Run the local claim audit with:
npm run rsi:claim-readinessThe audit emits ao2.rsi-claim-readiness-audit.v1 under
target/rsi-claim-readiness/latest/summary.json. It allows the bounded claim
when the local Pulse evidence surface is present and denies the full
self-mutating claim until AO2 has mutation authority evidence, live self-change
evidence, rollback evidence for failed self-change, control-plane observer
readback, and Covenant approval to publish that higher claim. Each run also
emits blocker_delta with schema
ao2.rsi-claim-readiness-blocker-delta.v1, comparing the current full-claim
blocker IDs with the previous summary.json in the same output directory when
one exists.
Run the governed self-change dry-run evidence generator with:
npm run rsi:self-change-dry-runThe dry-run emits ao2.rsi-governed-self-change-dry-run.v1 under
target/rsi-self-change-dry-run/latest/summary.json, plus proposed and rollback
patch artifacts for the same change class. It also emits a
covenant.live-self-change-authority.v1 authority packet candidate at
target/rsi-self-change-dry-run/latest/live-self-change-authority.packet.json.
That packet is marked as a dry-run candidate and is not valid evidence for
claim publication until live self-change execution and observer readback exist.
The script applies and rolls back the patches inside a temporary workspace to
prove the rollback path restores the target file. It does not apply the patch
to the repository, mutate the repository, use the network, require provider
keys, or publish the full RSI claim. It is evidence for a governed self-change
rehearsal, not proof of live autonomous self-mutation.
Run the AO2 live-mutation dry-run execution packet with:
npm run live-mutation:dry-run-packetThe packet emits ao2.live-mutation-dry-run-packet.v1 under
target/live-mutation-dry-run-packet/latest/summary.json, plus proposed and
rollback patch artifacts for docs_only_single_file by default. It records the
exact changed-file list, verification plan, rollback patch, docs-only dry-run
apply result, forbidden-path checks, authority boundary, provider boundary,
session boundary, and an embedded ao2.bounded-patch-packet.v1. That bounded
patch packet names mutation_class, allowed_paths, forbidden_paths,
rollback_patch, verification_commands, expected_diff_limits, and
evidence_digests. AO2 validates the class before the isolated dry-run apply.
Setting AO2_LIVE_MUTATION_CLASS=test_only emits a one-test-file dry-run packet
with test-scoped verification and rollback evidence. Setting
AO2_LIVE_MUTATION_CLASS=low_risk_code emits a source-bounded dry-run packet
with max one source file plus one test file, rollback and verification-command
requirements, and explicit denials for scripts, CI, release, secret,
config-expansion, provider, and broad-refactor paths. It still does not grant
live production-code execution authority. Higher code classes remain denied.
The patch is applied and rolled back only inside a temporary isolated workspace
to prove the exact patch and rollback pair. It does not apply the patch to the
live repository, create a branch, push commits, upload artifacts, publish
releases, and does not call providers.
The packet is AO2 execution evidence for a future governed live-mutation chain; it is not self-authorizing. AO2 must not perform a live repository mutation unless the caller provides explicit exact-scope operator approval for the first docs-only class and the surrounding Foundry approval gate, Covenant ticket, Forge guard, Sentinel/Promoter boundary, rollback rehearsal, and Command readback all pass. Broad or fully unsupervised complex live mutation remains outside AO2's claimed authority.
Run the explicit live self-change rehearsal with:
AO2_RSI_LIVE_SELF_CHANGE_REHEARSAL=1 npm run rsi:live-self-change-rehearsalThe rehearsal emits ao2.rsi-live-self-change-rehearsal.v1 under
target/rsi-live-self-change-rehearsal/latest/summary.json, plus proposed and
rollback patch artifacts. The command is refused unless
AO2_RSI_LIVE_SELF_CHANGE_REHEARSAL=1 is set. When enabled, it briefly mutates
scripts/rsi-claim-readiness-audit.sh, verifies the changed script, and
rolls the file back to its exact pre-run SHA-256. This is operator-gated live
self-change evidence with local rollback proof; it still does not publish the
full RSI claim. The command does not publish the full RSI claim because
control-plane observer readback, Covenant claim-publish
approval, and retained claim-level evidence are still required.
After ao2-control-plane reads back that rehearsal, retain the readback
artifact in AO2's local evidence chain with:
npm run rsi:live-self-change-readback-indexThe index consumes AO2's ao2.rsi-live-self-change-rehearsal.v1 summary and
the control-plane
ao2.cp-ao2-rsi-live-self-change-rehearsal-readback.v1 summary, then emits
ao2.rsi-live-self-change-readback-evidence-index.v1 under
target/rsi-live-self-change-readback-index/latest/summary.json. It records
artifact names and SHA-256 values only. It does not mutate AO2, mutate
ao2-control-plane artifacts, publish claims, or approve RSI claims. It does not approve the full RSI claim. This retained readback evidence improves the claim audit input, but Covenant claim-publish approval and stronger claim-publish evidence remain required.
Run the local improvement evidence gate with:
npm run rsi:improvement-evidence-gateThe gate emits ao2.rsi-improvement-evidence-gate.v1 under
target/rsi-improvement-evidence-gate/latest/summary.json. It measures
workflow-hardening coverage as measured_improvement_percent for enforced RSI
evidence checks. The default target is 5%, and the current gate compares the
previous six-check RSI evidence baseline with nine enforced checks after the
AO Blueprint authorization prerequisite, the release-readiness dashboard
readback, and improvement gate are added. The summary also includes
control_surface_readback so operators can read the result without inferring
authority from the score: bounded_governed_rsi is supported when evidence is
passing, the improvement score can be target_exceeded, and
full_autonomous_self_mutating_rsi remains denied by design. This is
workflow-hardening coverage and evidence of stronger verification coverage, not
proof that the full RSI claim is publishable.
Persist the local improvement trend with:
npm run rsi:improvement-trendThe trend command reads the latest improvement gate summary, appends a local
JSONL record to target/rsi-improvement-trend/history.jsonl, and emits
ao2.rsi-improvement-trend.v1 under
target/rsi-improvement-trend/latest/summary.json. It records the current
measured_improvement_percent, the previous measurement when present, and
delta_from_previous_percent. The trend summary carries the same
control_surface_readback boundary as the evidence gate: bounded governed RSI
can improve while full autonomous RSI publication remains denied. It does not
publish or approve RSI claims.
Run the full local cross-repo RSI evidence chain with sibling
ao2-control-plane and ao-covenant checkouts:
npm run rsi:cross-repo-e2eThe E2E smoke emits ao2.rsi-cross-repo-e2e.v1 under
target/rsi-cross-repo-e2e/latest/summary.json. It runs the AO2 live
self-change rehearsal, ao2-control-plane readback,
rsi:live-self-change-readback-index, the release-readiness dashboard
readback smoke, rsi:claim-readiness,
rsi:blueprint-authorization-gate, and Covenant policy claim-publish-gate,
then runs the improvement evidence gate. Set
AO2_RSI_BLUEPRINT_AUTHORIZATION_SUMMARY to a real AO Blueprint
ao.blueprint.build-authorization.v0.1 output when replacing the local fixture.
The
expected final Covenant gate remains publish_authority=false with schema
covenant.rsi-claim-publish-gate.v1; the E2E summary also carries
ao2.rsi-improvement-evidence-gate.v1,
ao2.rsi-improvement-trend.v1,
ao2.rsi-blueprint-authorization-gate.v1,
ao2.rsi-control-plane-release-readiness-dashboard-smoke.v1,
release_readiness_dashboard_readback, dashboard_artifact,
control_plane_foundry_packet_readback,
ao.foundry.rsi-control-surface-packet.v0.1,
ao2.cp-ao-stack-rsi-chain-binding-readback.v1,
measured_improvement_percent, and
delta_from_previous_percent.
control_plane_foundry_packet_readback records that ao2-control-plane can
consume Foundry's RSI control-surface packet as observer-only readback; it does
not approve RSI claims, publish claims, or expand AO2 authority.
The smoke proves the denial chain and 5% workflow-hardening measurement are
wired end to end, not that the full RSI claim is publishable.
Compose the operator closure packet for the current AO stack RSI boundary with:
npm run rsi:operator-closure-packetThe packet emits ao2.rsi-operator-closure-packet.v1 under
target/rsi-operator-closure-packet/latest/summary.json, plus closure.md.
It reads the AO2 cross-repo E2E summary and the ao2-control-plane chain-binding
readback, then states the stable operator boundary in one place:
bounded governed RSI is supported; full autonomous RSI publication remains denied; and control-plane remains observer-only. It is local readback only; it
does not mutate repositories, approve RSI claims, publish claims, execute AO
work, or authorize AO Blueprint self-change.
Pulse next-task generation consumes this packet by default as bounded-governed
RSI readback. npm run pulse:generate-next writes
rsi_operator_closure_readback and rsi_claim_boundary into the eval loop,
task manifest, AI task board, generated task packet, and next-action readback;
those fields explicitly keep full_autonomous_self_mutating_rsi=denied and
operator_closure_is_publication_authority=false.
Compose the operator-readable RSI baseline packet from an existing cross-repo E2E summary with:
npm run rsi:baseline-packetThe packet emits ao2.rsi-baseline-packet.v1 under
target/rsi-baseline-packet/latest/summary.json, plus dashboard.html. It
surfaces the RSI trend, Blueprint authorization, Covenant denial, and
control-plane readback inputs in one compact packet, including the
release-readiness dashboard readback for
ao2-release-readiness-consumer/dashboard.html. It fails closed unless the 5%
workflow-hardening metric is met and the full autonomous RSI claim remains
denied with publish_authority=false. The packet reads local evidence only; it
does not mutate repositories, publish claims, approve RSI claims, or authorize
AO Blueprint self-change.
After two baseline packets exist, compose the repeated-run RSI eligibility packet with:
npm run rsi:eligibility-packetThe packet emits ao2.rsi-eligibility-packet.v1 under
target/rsi-eligibility-packet/latest/summary.json, plus dashboard.html. It
fails closed unless both baseline packets are ready, both preserve
claim_publish_decision=deny and claim_publish_authority=false, and both are
backed by tiered AO Blueprint authorization that is not self-authorized by RSI.
Both baselines must also carry the control-plane release-readiness dashboard
readback with dashboard_link_ready=true.
This is eligibility/readback evidence only; it does not publish claims, approve
RSI claims, mutate repositories, or authorize AO Blueprint self-change. CI
uploads it as ao2-rsi-eligibility-packet.
Most agent systems focus on doing work. AO2 focuses on making the work reviewable after the fact.
AO2 is built around local evidence:
- what objective was run;
- which policy and readiness gates executed;
- what commands, patches, and artifacts were produced;
- which evaluator concerns were rejected or accepted;
- what evidence supports a completed run;
- what can be replayed, audited, exported, or published to an observer.
That makes AO2 useful for autonomous or overnight work because the operator does not have to trust terminal scrollback or a vague "done" message. The run leaves behind structured records that can be inspected locally and, when desired, published to a read-only control plane.
This public export is prepared from AO2 0.4.81. It is intentionally
local-first:
- no provider API-key authentication paths;
- no bundled runtime evidence or generated release artifacts;
- no private git history;
- no control-plane mutation authority.
git clone https://github.com/uesugitorachiyo/ao2.git
cd ao2
npm run verify
npm run build:releaseRun the governed demo locally:
tmpdir=$(mktemp -d /tmp/ao2-demo.XXXXXX)
cp -R fixtures/discount-service "$tmpdir/discount-service"
cargo run -p ao2-cli --bin ao2 -- \
run examples/risky-pr-run/risky-pr.yaml \
--target "$tmpdir/discount-service" \
--run-id demo-runBuild a local release archive:
npm run package:local
tmpdir=$(mktemp -d /tmp/ao2-release.XXXXXX)
archive=$(ls dist/ao2-0.4.81-*.tar.gz | head -1)
tar -xzf "$archive" -C "$tmpdir"
sh "$tmpdir/verify-release.sh"Release archives also include Verify-Release.ps1 for native Windows
checksum verification before install.
The current stable public release is
v0.4.81.
It publishes release archives for macOS, Ubuntu/Linux x86_64,
Ubuntu/Linux aarch64, and Windows, plus SHA256SUMS, signed provenance, and
release-readiness JSON evidence.
The overview video is available at
https://youtu.be/p222b0iCpbg.
Download and verify a macOS archive:
mkdir -p dist-release
gh release download v0.4.81 --repo uesugitorachiyo/ao2 \
--pattern ao2-0.4.81-macos-aarch64.tar.gz \
--pattern SHA256SUMS \
--dir dist-release
(cd dist-release && grep 'ao2-0.4.81-macos-aarch64.tar.gz' SHA256SUMS | shasum -a 256 -c -)Use the same release base URL for Linux and Windows archives:
https://github.com/uesugitorachiyo/ao2/releases/download/v0.4.81/ao2-0.4.81-linux-x86_64.tar.gz
https://github.com/uesugitorachiyo/ao2/releases/download/v0.4.81/ao2-0.4.81-linux-aarch64.tar.gz
https://github.com/uesugitorachiyo/ao2/releases/download/v0.4.81/ao2-0.4.81-windows-x86_64.tar.gz
Run the Phase 1 promotion wrapper after starting a local ao2-control-plane instance and placing the control-plane bearer token in an environment variable:
export AO2_PHASE1_CONTROL_PLANE_URL=http://127.0.0.1:3000
export AO2_PHASE1_API_TOKEN_ENV=AO2_CP_API_TOKEN
export AO2_CP_API_TOKEN=<redacted-local-token>
npm run phase1:prepare-prerequisites
npm run phase1:promoteThe wrapper publishes through --api-token-env AO2_CP_API_TOKEN so the bearer
token stays out of process arguments, URLs, logs, and generated evidence. To
capture the read-only control-plane dashboard in the same local run:
AO2_PHASE1_DASHBOARD_SNAPSHOT=1 npm run phase1:promote
npm run phase1:dashboard-snapshotRun the native Windows release smoke on a Windows host after building or downloading the current archive:
powershell -ExecutionPolicy Bypass -File .\scripts\smoke-windows-release.ps1 `
-Archive .\dist-windows\ao2-0.4.81-windows-x86_64.tar.gzThe main CI workflow in .github/workflows/ci.yml runs on pull request and
main push, and can also be dispatched manually. Release workflows such as
release-gate.yml and public-release-build.yml remain manual operator gates.
Branch protection requirements and the scheduled/manual read-only drift check
are documented in docs/BRANCH-PROTECTION.md, including the full local audit
for stale required checks in active branch rulesets.
The canonical CI readiness signal is
ao2-release-readiness-final-closure-verifier. It only passes after the
upstream release-readiness artifacts have been produced, consumed, and checked
for publication closure.
ao2-release-readiness -> ao2-release-readiness-hosted-artifact-gate
-> ao2-release-readiness-consumer
-> ao2-release-readiness-final-closure-verifier
Use the final verifier artifact to decide whether the public AO2 release
readiness evidence chain is closed. Earlier artifacts remain useful for
debugging the specific gate that produced them. The consumer artifact also
includes dashboard.html, which gives operators an RSI eligibility readback
without granting autonomous RSI claim-publication authority.
Pulse auto-advance can continue local AO2 work without opening a pull request. Even in no-PR mode, it is not silent: it writes local evidence for each iteration so an operator can answer "what happened while I was away?"
The primary local evidence surfaces are:
target/pulse-auto-advance/latest/summary.json- current run status, completed iteration count, task results, direct-main publish status, and next-packet generation status.target/pulse-auto-advance/latest/task-executor/iteration-XX/summary.json- per-iteration task executor summaries.target/pulse-auto-advance/latest/logs/- per-command logs for task execution, PR/CI gate refresh, direct-main publishing, and next-task generation..ao2-local/pulse/latest/- the latest generated packet, board, eval-loop, operator prompt, resume metadata, and structured task manifest..ao2-local/pulse/pulse-auto-advance-ledger.jsonl- append-only local ledger entries keyed by eval-loop digest..ao2-local/pulse/pr-ci-gate.json- local PR/CI gate state when the loop is waiting on review, merge, or CI.
When direct-main publishing is enabled, Pulse also records
target/pulse-auto-advance/latest/direct-main-publish/summary.json. If there
are no source changes to commit, the publisher can exit successfully with
status=skipped; the local Pulse evidence still records the iteration, logs,
and generated next-task packet.
This keeps the MVP local-first: PRs and GitHub CI are useful review surfaces, but they are not required for AO2 to leave an auditable local record.
AO2 contains a typed, durable, cross-platform Pulse event-loop runtime in Rust. It can execute a bounded loop over a command, reading a decision file (supporting native AO2 and legacy-compatible decision schemas), and writing durable summary evidence:
ao2 pulse run-loop \
--command "npm run pulse:generate-next" \
--decision-file "target/pulse-next-recommended-tasks/ao2-event-loop-decision.json" \
--max-chain-runs 3 \
--max-runtime-seconds 2700 \
--out-dir "target/pulse-event-loop"- Install
- Architecture
- Product requirements
- Risky PR Run SDD
- Schemas and interfaces
- Implementation slices
- Security
- Verification
- Public release verification
AO2 is licensed under Apache-2.0. See LICENSE.
Third-party dependency license metadata is tracked in
docs/THIRD-PARTY-LICENSES.md.