Adds two explicit read-only operations for the context delivery
lifecycle: bounded raw source reads with reversible bytes and integrity
checks, and structural checking of the pinned AgentOps OKF page profile.
Source reads require independently selected context policy and enforce a
measured serialized-output bound before emitting content. Emitted bytes
do not establish host delivery or understanding; restricted-source
processing remains unavailable without native enforcement. The OKF
checker rejects missing status and incompatible profiles, and never
grants truth, disclosure, or usefulness approval.
Validation: focused tests and Linux/Windows source-reader builds passed.
The combined candidate is undergoing the required full repository checks
and fresh independent review before landing.
Add explicit, recoverable private context routing through `ao config
context`, binding native source, owner, task, model and destination to
existing policy and external storage. Recovery reads the original Beads
maintenance anchor; configuration reports native access enforcement as
unattested.
Add `ao provenance verify-judgments` to check required review profiles
against exact native transcript receipts, independent subject and
acceptance, distinct contexts, completion and permitted providers.
Requested identity and unreported effort do not count as runtime
evidence. The verdict schema is unchanged.
Repair the existing cleanup test: a 0.3-second budget could expire
during preparation before either fixture process started. A separate
controlled-delay test now proves preparation cannot renew that deadline.
The running-cleanup case requires parent/child readiness, preserved
partial output, the postlaunch cleanup result and both processes stopped
within its existing four-second bound. Production timeout behavior is
unchanged.
Validation: fresh author-distinct review passed the exact 55-path final
subject and all T05/T21 acceptance. The complete local Bats run passed
(1,333 passed, two existing skips), as did Go build/vet/test/race, all
72 full-mode gates, the aggregate and generated-output checks.
Ubuntu/Windows CI, security and both installation jobs passed on the
final commit. The final evidence scan found no new orphaned bindings; 73
historical bindings remain preserved. Earlier failed results and private
evidence remain outside the PR.
AO now performs intent snapshots, subject manifests, strict evidence
verification, atomic verdict storage, and orphan inspection through the
Go binary. The command handler keeps verification separate from
presentation so it meets the existing complexity limit. These operations
preserve the existing evidence formats, require explicit protected
storage where applicable, and run outside a checkout without Python. The
unchanged Python implementation remains a developer oracle; agents still
provide semantic judgment.
Codex and Claude skills now default to a fresh reviewer from the
author’s model family. Callers can explicitly request cross-model review
or pin its model. Reviewer adapters use a finite caller timeout or
remaining deadline instead of a fixed ten-minute default, while
retaining output limits and abnormal-termination cleanup.
Validation: Go build, vet, tests and race/shuffle tests; 1,334 shell
tests; aggregate runner; regeneration check; 72 full-mode gates.
Independent checks exercised 84 storage-boundary rejections and 21
evidence operations with an empty PATH. Both canonical and generated RPI
reference suites pass all 48 tests after updating the migrated oracle
import without weakening assertions.
Change-sensitive checks explicitly compare the final committed candidate
with the original PR base. Linux, Windows, installer, security, and
required summary checks are green.
> **Review findings closed.** The re-check's residue (app-seam family
count) is applied in `9a2790ae7` along with the full-tier CI
settlements: regenerated documentation index (generated file, hand-edit
drifted it), regenerated CLI-surface count fixtures (top=18 sub=44
all=62), `Test-Removal-Reason` trailer for the deliberate test
deletions, and the release-tag bats output list updated to the real
changes-job set. 67/67 full-tier gates green locally. Merging on Bo's
instruction.
## What
Deletes the provably-dead 28% of the `ao` CLI and every reference to it,
per the 2026-08-23 estate audit. −19.5K lines in the lane commit plus
integration fixups.
**Removed (each with zero live consumers, verified by consumer-grep +
`go list -deps`):**
- `ao eval` — 13 subcommands, ~10.9K LOC. Its would-be consumers were
already tombstones (`scripts/eval-agentops.sh` printed `RETIRED`),
`release.yml` hardcoded `--eval pass`, release evidence recorded
`suite_count: 0`, and three of its module tests exercised subcommands
that could never register (nil composition seats).
- `ao redact` — its only declared caller
(`skills/compile/scripts/compile.sh`) never existed.
- `cli/internal/types/memrl_policy.go` + the orphan cascade it and eval
left behind (`internal/scenario`, `internal/wiki`,
`internal/runtimecmd`, `internal/redact`) — all with zero importers,
verified before and after.
- `scripts/check-memrl-health.sh` +
`examples/schedules/feedback-drain-hourly.yaml` — a health check for the
feedback loop amputated on 2026-07-14; it exits 1 on main today and the
example instructs a verb (`ao feedback-loop`) that no longer exists.
- `corpus.secret-scan` gate — vacuous: its file filter excluded the
single tracked path its globs could match, so it scanned zero files;
secrets are covered by the pinned gitleaks steps in nightly and release
(validate's quick toolchain mode skips gitleaks).
- Docs for the deleted surface:
`docs/architecture/eval-architecture.md`,
`docs/code-map/eval-lid-primitives.md`; `contracts/eval-baseline-ab.md`
already carried a RETIRED banner and stays as history (delisted from the
live index).
**Kept, deliberately:**
- `ao robot-docs` — the audit's "duplicate of `doctor robot-docs`"
premise was false: they render different handbooks (whole-CLI vs
doctor-scoped). Verified before acting.
- `completion`, `demo`, `quick-start` — interactive human furniture, not
dead code.
- `corpus.witness-dolt-jsonl-crosscheck` gate — retargeted, not retired:
its backing script is a hermetic self-test over real tracked fixtures;
globs now point at the paths it actually exercises.
- `cli/internal/evalsubstrate` — Go-dead but it is the declared mirror
of `schemas/outcomes-rubric.v1.schema.json`; retiring it needs a paired
schemas/docs/scripts decision (package doc comment records this).
- `scripts/ci-local-release.sh` eval-evidence stanza — self-contained
honest bookkeeping (`status: not_applicable`), invokes nothing removed.
**Tombstones + migration:** `eval` and `redact` added to
`removed_command_hint.go` and `docs/MIGRATION.md`; the now-false "(`ao
eval` returned in 3.3 …)" parenthetical deleted; `go-cli.md` spine and
the "Eval — the Learn seat" section updated; the dated research snapshot
got a HISTORICAL banner via the docs-scope self-declaration mechanism
(history not rewritten).
## Why
v3.6.0 binary downloads: 4 darwin-arm64, 3 linux-amd64. Only 7 of 53
shipped skills invoke `ao` at all, and none of them touch this surface.
The eval family was the single largest command surface in the CLI with
zero live consumers — 28% of non-test Go maintained for nobody.
## Evidence
- `cd cli && go build ./... && go vet ./... && go test ./...` — exit 0
(previously-failing `TestGoCLIDocSpineMatchesApprovedSpine` and
`TestRemovedVerbsHaveMigrationRows` now pass)
- `scripts/check-docs-cli-snippets.sh` PASS ·
`check-cmdao-surface-parity.sh` PASS (54 leaf commands) ·
`check-corpus-path-guard.sh` PASS · `check-new-scripts-use-preamble.sh`
PASS · `ao gate check --dry-run` PASS
- Implemented by a worktree-isolated lane, independently validated by a
fresh context that re-ran the suite itself; the two failures it found
were doc files outside the lane's write scope, fixed in the integration
commit. Cross-family (Codex) review verdict included in the final
session report.
## Cross-family review (Codex, fresh context)
First pass: **FAIL** with two majors — (1) `quality.DeprecatedCommands`
still mapped five rewrite entries onto the removed eval family, so `ao
doctor --fix` would have introduced dead commands; (2) retained docs
(formal-verification research links, applied-ood README run block,
evalsubstrate hint strings) still prescribed removed commands. Both
repaired in `4da85a0d4` (one bounded round), plus its two minors
(types/AGENTS.md row, .gitignore unignore, family counts,
gitleaks-coverage comment). Re-verified: full suite green, snippets gate
PASS. Focused re-check: first-round findings confirmed closed; one new
residue (the family count above) stopped the loop under the spiral rule.
## Follow-ups (not in this PR)
- `cli/internal/quality/stale_refs.go` `DeprecatedCommands`: the five
eval-target entries are pruned here; the older pre-existing dead targets
(forge, inject, flywheel, ratchet, …) still need a map-wide
reconciliation against the live registry.
- `cli/internal/evalsubstrate` retirement decision (paired
schemas/docs/scripts change).
- `evals/scenarios/applied-ood/`, `evals/tier2-premortem/`,
`evals/_stats/` retain historical `ao eval` mentions in prereg/holdout
records — dated artifacts, left as history.
Summary:
- lands the audited current WIP lanes and excludes stale/process-only
material
- hardens prune path confinement, probe-v3 evidence binding,
codebase-recon identity, handoff/release/reverse-engineer behavior, and
Codex prompt handling
- truth-labels static skill scoring and regenerates all owning
projections
Validation:
- fresh independent PASS on commit
427098ed10
- full Go suite and full Go race suite
- quick local release CI
- focused Bats, scenario/linkage, native-skill, reverse-engineer,
Cathedral, Ruff, Python ratchet, projection, and diff checks
Residual boundaries:
- final-basename ABA remains unclaimed
- live skill-probe coverage remains honestly 0/12
- release-only cross-build, SBOM, vulnerability, and release-evidence
checks are left to delivery CI
Executes docs/plans/2026-08-07-agentops-operations-layer-alignment.md:
AgentOps is the operations layer for agentic engineering; the federated
integration graph is the topology, the semantic work-and-proof protocol
is the contract, and RPI is the standard one-experiment traversal.
Retires the ao flywheel command family and all knowledge-flywheel
product state, tombstones the seven-move operating-loop workflow,
narrows ao init and the .agents state writers to declared destinations,
renames the core architecture page to rpi-traversal.md with a
compatibility redirect, aligns AGENTS.md, 25 skills, public and package
copy, regenerates every owned projection, and strengthens the
conformance gates with planted-negative proofs.
Both the alignment subject and the follow-up gate-bookkeeping commit
carry fresh author-distinct validation PASS verdicts with empty
not_checked scope.
Test-Removal-Reason: dead knowledge-flywheel and session-store surfaces were deleted with their tests (operations-layer alignment)
## What
Ports `scripts/gc-maintainer-ops.sh` (425 lines of bash: prepare / check
/ recover-affinity for stock Gas City rigs) into the Go CLI as **`ao gc
prepare|check|recover-affinity`**, per ADR-0016 (skill logic ships in Go
via `ao`; shell stays thin glue).
**Why:** skills ship via plugin/npx as SKILL.md only — a user without a
repo checkout could not run the commands the shipped `using-gc` skill
teaches. The skill said "From an AgentOps checkout", which was disclosed
but weak.
## Changes
- **`cli/internal/gcmaintainer`** — full port: rig/import pin
verification, bundled pack-cache resolution, PyYAML-capable python
selection, atomic runtime staging, managed check wrappers, skill links
into city/rig Codex sinks, macOS LaunchAgent + doctor/status health
checks, bounded affinity recovery. Output and refusal-message parity
with the shell script (incl. refuse-before-mutation ordering).
- **`cli/internal/commands/gc` + `cmd/ao/gc_composition.go`** — cobra
module on the shared `clicontract.HostOptions` seam; global `--dry-run`
always overrides `--apply`.
- **Skills source resolution without a checkout**: `--skills-source` >
enclosing agentops checkout > installed skills root (`~/.agents/skills`,
`~/.claude/skills`). Existing rigs stay recognized: the `managed-by:
agentops gc-maintainer-ops` wrapper marker is unchanged.
- **Tests migrated**: `tests/python/test_gc_maintainer_ops.py` (7 cases)
→ Go L2 tests in `cli/internal/gcmaintainer` with the same fake-`gc`
harness, plus module wiring tests. `scripts/check-gc-executor.sh` no
longer runs the python suite.
- **`scripts/gc-maintainer-ops.sh`** reduced to a thin wrapper exec'ing
`ao gc`, pinning `--skills-source` to its checkout to preserve
historical semantics (`--ao-bin` now selects the ao binary).
- **Docs/projections**: `skills/using-gc/SKILL.md` now teaches `ao gc
...`; codex, gemini, and executor-pack projections regenerated via their
owning generators; spine/COMMANDS.md/surface artifacts regenerated.
## Verification
- `go build ./... && go vet ./... && go test ./...` — 2923 passed, 73
packages
- `golangci-lint run` on new/touched packages — clean
- `shellcheck -S warning` on wrapper + gate script — clean
- `bash scripts/check-gc-executor.sh` — OK
- Smoke: built `ao`, ran wrapper → `ao gc` delegation end-to-end
Workflows get the skills treatment (operator decision): canonical source
in the product tree, installed by a product verb, Claude-only labeled as
such.
**What moves:** all seven Claude workflow scripts + README migrate from
force-added exceptions inside the gitignored `.claude/` to a tracked
top-level `workflows/` (sibling of `skills/`) — the four existing
conveyors plus `audit-dimensions`, `verify-fixes`, `implement-wave`:
three thin, args-parameterized orchestration conveyors extracted from
this session's hand-rolled waves, contract-reviewed, and smoke-proven
through the real Workflow runtime (the smoke caught two contract gaps
static review could not: an `export default` wrapper the runtime never
invokes, and args arriving as a JSON string — both fixed, string-args
tolerance now built in).
**New verb:** `ao workflows link` / `unlink` mirror `ao skills link`
semantics — dry-run `--json`, refuse to replace real files or foreign
links, unlink only checkout-owned links — targeting the project-local
`.claude/workflows/` where Claude Code resolves named workflows
(`--into` overrides). Checkout identity reuses the skillsapp marker
discipline, fail-closed. Claude-only runtime adapter, same doctrine as
the Codex-only `skills-codex/`.
**Legacy surfaces repointed:** `install-workflows.sh` (user-global $HOME
installer), `check-workflow-drift.sh` + gate comment,
`check-bdd-foundry-markers.sh`; spine allowlist + YAML-probe excuse +
go-cli.md spine region gain the workflows group; COMMANDS.md,
cli-surface projections, and surface-count fixture regenerated; new
tests carry per-command git-env scrubbing (test-isolation ratchet back
at baseline).
**Built BY the workflow being canonized** — `implement-wave`
orchestrated its own canonization: two disjoint-ownership lanes plus a
seam-checking verifier that ran the real binary's link → resolve →
unlink cycle in the live tree (both lanes RESOLVED). The lanes correctly
*refused* to self-approve their command into the spine invariants and
handed integration three flagged edits instead.
**Expected local gate note:** `workflow.install-drift` correctly FAILS
on machines whose user-global `~/.claude/workflows` links still point at
the old location — that is the transition it exists to catch. CI stays
green (absent→skip). **Post-merge operator step:** `cd ~/dev/agentops &&
git pull && bash scripts/install-workflows.sh`.
**Verified:** full suite 63/63 pkgs; golangci-lint clean; `gate check
--full` over this range = 66/67 with only the documented install-drift
environment finding; workflows smoke-run evidence in session logs.
Wave 4 (residue) of the new-user happy-path arc. Three scoped
implementer lanes + fresh adversarial verifier (4 RESOLVED; 1 INCOMPLETE
= stale generated projections, closed in integration).
**Doctor**: the dev-version detector now reuses the Binary Freshness
resolution — a from-source build matching its checkout is healthy (a
novice building from source can finally see `ao doctor` exit 0);
findings fire only on genuine drift, shadowed duplicate `ao` binaries,
or an informational from-source note outside any checkout. `ao doctor
diff` gains `--only` so the fix-plan preview can be scoped the way
remediation text implies.
**Config**: the dead `ao config models` surface is removed end-to-end
(lane re-verified zero consumers before deleting; `--show` proven
byte-identical before/after; removed-child hint + MIGRATION row;
existing `models:` config sections still parse and are ignored).
**Dual-root stragglers**: learning-coherence gate globs,
`quality.CountConstraints`, and the eval sandbox corpus deny-list now
cover canonical `.agents/ao/<section>` alongside legacy roots.
**Doc-link hygiene**: the strict docs-link backstop's allowlist was 100%
stale (53/53 entries referenced Cathedral-Cut-deleted docs) — refreshed
to 10 verified accepted-class entries; ROADMAP dead links fixed;
documentation-index generator emits GitHub URLs for repo-root targets;
doc-skill references instruct only shipped scripts; codex twins +
CLI-surface projections + surface-count fixture regenerated.
**Deferred by design**: the `3.3.0-rc` fallback version bump belongs
inside the v3.3.0 tag-cut commit.
**Verified**: full suite 61/61 pkgs (2825 tests); golangci-lint clean;
`ao gate check --full` 67/67 over this range; Test-Removal-Reason
trailer covers the 6 deliberately deleted models tests.
flywheel compare direct-test coverage moved from cmd/ao into internal/flywheelapp;
mirror the provenance/skills carve-out allowlist pattern and regen cli-surface.
Registers the fully-built-but-never-wired eval module into the CLI spine
and repairs its one real instrument bug. Three commits, RPI-shaped: wire
+ fix, drift guards + docs, fixture counts.
## What
- **`ao eval` joins the spine** (cmd/ao/eval_composition.go):
deterministic suite runs, run-record
compare/baseline/scorecard/coverage, locked Tasks, holdout scenarios,
suite A/B verdicts with power-derived n-required, and the holdout-safe
Outcomes projection. This is the operating contract's *Learn* seat — a
read/measure consumer of evidence. It reports numbers and owns no retry,
scheduling, promotion, or lifecycle authority. The retired Aliases/Bench
seats stay nil and their subcommands are omitted.
- **Instrument bug fixed**: both scenario-ab arms were corpus-denied at
runtime — the with-gold treatment was only a prompt injection through
the retired `ao lookup`, so the A/B silently guaranteed a zero delta.
Treatment is now environment-shaped: the with-gold arm runs with the
corpus readable, the control arm stays sandbox-confined (the fail-closed
empty-deny guard is untouched), and judges are always corpus-denied.
- **Schema drift guards**: a run record persisted by the production
writer must validate against eval-run.v1.schema.json (and the minimal
suite against eval-suite.v1.schema.json) — closing the same silent-fork
class the verdict.v2 golden corpus closed.
- **Hermetic test builds hardened**: keep the real HOME's Go caches
(TestMain isolation was forcing module re-downloads) and skip VCS
stamping.
- docs/architecture/go-cli.md gains the eval section; MIGRATION.md notes
`ao eval`'s return; COMMANDS.md, cli-surface, and surface counts
regenerated; new leaves carry honest allowlist reasons; new cmd/ao L2
tests drive eval run/compare/help through the full production wiring.
## Evidence
- Full cli suite 2,801 green; race green on cmd/ao + the eval island;
vet clean
- Full-tier gate: 65/66 on the penultimate commit; the single failure
(surface counts) is the final fixture commit, re-verified PASS
standalone — no other check reads those fixtures
- Fresh independent validation (Codex, frozen subject 86022a3c6, clean
tree at start and end): **OVERALL PASS**, 6/6 — including a live
end-to-end `ao eval run` producing a passing run record
- Rubric-relocation decision honored: true holdout rubrics live in the
external measurement register; the repo keeps only leak-guarded
projections
Completes the Go CLI migration: one composition model, no tombstones, no
dead packages, hermetic tests, and a cross-language verdict contract
corpus. Net −88k lines.
## What
- **Tombstones + prune deleted**: the 21 registered 'Removed in the
Cathedral Cut' stubs, `zzz_default_spine.go`'s runtime prune, and the
~30 registered-but-pruned legacy command families are gone. The
registered tree IS the production tree; retired verbs fail with exit 1 +
a data-driven replacement hint pointing at docs/MIGRATION.md (now
covering nested verbs). Non-runnable parents reject unknown subcommands
instead of printing help with exit 0.
- **~35 unreachable packages deleted** (cliapp, canon, pawl-era verdict
parser, pool, harvest, knowledge, wiki engine, vibecheck, cli/embedded,
…) after import analysis + script/CI consumer verification. Retained
with named consumers: archcheck (arch gate scripts), eval island (rubric
schema drift guards), drwitness/drrebuild (witness-crosscheck).
- **Composition decision recorded**: single cmd/ao root +
internal/commands/<family> modules + clicontract; the never-adopted
cliapp.BuildRoot is removed. New overview: docs/architecture/go-cli.md
(repairs two broken links).
- **Hermetic tests**: flag_matrix_test.go builds the exec'd binary from
package source — the stale cli/bin/ao failure class is closed;
TestHermeticBinaryMatchesSourceSurface pins source↔binary
correspondence.
- **Verdict contract consolidated**: verification extracted from
status.go into cli/internal/verdictcheck; 19-case golden corpus
(tests/fixtures/verdict-contract) runs through Go + Python + JSON schema
via blocking gate `contract.verdict-corpus`. One divergence closed
(empty-string context ids now rejected by all three).
- **Fossil guard chains retired**: embedded-sync (mirror had zero
importers), retired-family compat baselines, dead
go_cli_compatibility.bats, stale gate globs/grandfather entries.
## Evidence
- Full-tier deterministic gate: **66/66 PASS** on the rebased tip (fresh
source-built binary)
- cli suite 2,795 tests green; race suite green on touched packages; vet
+ pinned golangci-lint clean
- Cathedral Cut conformance PASS; CLI reference/surface projections
regenerated and checked
- Independent cross-family validation (fresh Codex context, frozen SHA):
5/6 claims CONFIRMED; 6th NOT_PROVEN only due to sandbox networking (its
cached rerun of the same suite passed)
- Test-count decrease is deliberate and carried by a Test-Removal-Reason
trailer
## Summary
Closes the findings from the v3.3.0 release-viability audit of main.
**Surface truth (High):** `ao constraint`, `ao goals trace`, `ao session
memory`, and `ao skills edit` are production tombstones but
docs/cli-surface.md documented them as `public-tested`/`covered` (the
test binary keeps constraint live, and the generated doc reflected the
test build). Added `deprecated` allowlist rows, dropped the stale
constraint-subcommand rows, regrouped constraint with its tombstone
peers in the default spine, regenerated both surface projections, and
added `TestCathedralCutTombstonesSurvivePruning` pinning the invariant
that every Cathedral Cut verb keeps an executable tombstone.
**Installer hardening (Medium):** `install-bd.sh` now fails closed when
no published checksum exists for a release asset (explicit `--no-verify`
overrides), and the curl|bash path verifies the fetched
`installer-common.sh` against a pinned SHA-256 before sourcing it
(drift-guarded by a new install-bd.bats test).
**Docs (Medium/Low):** UPGRADING.md no longer links the MIGRATION-3.0.md
file the Cathedral Cut deleted; CHANGELOG 3.3.0 `### Removed` now names
`yield`, `constraint`, and the 3.2 `verify` front door and links the
MIGRATION.md map.
**Gate scripts (Low):** flywheel/provenance gate scripts build `ao` into
`mktemp -d` scratch dirs instead of fixed world-known /tmp paths
(symlink/TOCTOU on shared hosts).
**Bonus (surfaced by the push gate):** `scripts/lib/preamble.sh`
mis-resolved REPO_ROOT under git hook env (GIT_DIR without
GIT_WORK_TREE), which made `go.cli-architecture` refuse every
worktree-origin push touching `cli/cmd/ao/**`. Fixed by scrubbing the
hook-injected discovery env around the rev-parse.
## Validation
- `go build && go vet && go test ./...`: 5,085 tests green,
golangci-lint clean
- `ao gate check --fast`: 27/27 pass, including under simulated hook env
- bats install-bd suite 6/6 incl. new pin drift test; shellcheck clean
on all touched scripts
- markdownlint clean; doc-release gate passes; tombstone exit codes
verified on the built binary
Ship the Cathedral Cut on the 3.x line with the intentional semver deviation documented for v3.3.0. Includes the complete release rebadge, release-gate artifacts, removed-command tombstones, and a legacy config read fallback that preserves existing settings when saving the new canonical path.\n\nValidated by the full local Go/release suite and all required GitHub checks on head 78027b009c.
Add the uninstall/rollback twin for `ao skills link`: `ao skills unlink`
removes exactly the live-tier symlinks link minted — those whose target
resolves into this repo's skills/ tree — across every installed runtime
(~/.claude, ~/.codex, ~/.gemini, ~/.cursor, ~/.pi). Idempotent and
non-destructive: foreign symlinks pointing elsewhere and real directories
(a foreign corpus such as jsm) are reported as foreign and never removed;
stale owned links (skill since removed from the repo) are still cleaned up.
Supports --dest, --dry-run (persistent), and --json, mirroring skills link.
Document the uninstall path in docs/install-day2-ops.md: per-runtime plugin/
skill removal (Claude, Codex, AGY, OpenCode), `brew uninstall agentops`,
`ao skills unlink` for clone-linked skills, and an explicit 'what is kept'
note that .agents/ and quick-start artifacts (CLAUDE.md block, GOALS.md) are
user-owned data the uninstall deliberately never touches.
Regenerate the affected command-surface projections (COMMANDS.md, cli-surface
.{json,md}, the eval surface matrix + smoke fixture). The matrix/smoke counts
also absorb pre-existing origin/main drift (checked-in expected sub=120 vs
actual tree 112); regen brings them to the truthful 113 (112 + unlink).
Tests (L2 round-trip, t.TempDir): RemovesOnlyOwnLinks (foreign symlink + real
dir survive), DryRunWritesNothing, Idempotent, MissingDestIsNoop,
RemovesStaleOwnedLink, EmptySrcFailsClosed, ResilientAcrossDests.
F2 makes the verdict->edge emit fail-closed at WRITE time, but history + crash windows can
still leave a verdict FILE with no bound EDGE — a silent desync where 'ao done' (which reads
the LEDGER, not the file) refuses the close, discovered one-refused-close at a time. This
command scans .agents/pawl-verdicts/*.json and, for every CONFIRMED/REBOUND verdict, reports
whether a matching verdict->commit edge is bound, reusing the EXACT recognizer the push gate
and ao done use (hasConfirmedVerdictEdge — exact-token disposition, sha-bound, never substring).
--emit re-emits missing edges (idempotent — only the UNBOUND ones detected this pass, so a
second run is a no-op); --force allows a dirty ledger (default: refuse, age-7krl — never sweep
another lane's rows); --json for machine output. Exit 0 clean / 1 unbound-or-emit-failed / 2
usage. Report-only default is safe (no mutation).
Operational data (this repo, per the bead): 251 verdicts scanned, 1 unbound — and it is a
harmless orphan from this session's own messy F1 land (a dead sha 6cbcc0f5 reset away during
the concurrent-session recovery), NOT a systemic desync. Validates F2 (prevents new) + F3 (finds
existing). Tests: TestScanReconcileVerdicts (bound/unbound/REFUTED-skipped/malformed) + empty-dir.
Regenerated CLI surface (COMMANDS.md, cli-surface.{json,md}, eval matrix + smoke) for the new command.
Claude-Session: https://claude.ai/code/session_01RDWPYn4ZS2SyBkcBvAM18u
Scans skills/ against a destination live-tier dir (default ~/.claude/skills)
and symlinks every skill dir that has no entry yet. Idempotent and
non-destructive: existing symlinks are left as present, and a name owned by a
real dir (a foreign corpus like jsm) is reported as a conflict, never clobbered.
Honors the global --dry-run; --dest overrides the target.
The focused fix for 'a new skill landed on main but Claude cannot see it':
merging a skill dir mints no symlink and /reload-skills only re-reads existing
links. 5 L2 tests cover link/idempotent/dry-run/conflict/non-skill-dir; whole
cmd/ao package green (7853 tests).
Note: the regen also re-sorts a few eval-scenario/session cli-surface entries to
the current canonical (ASCII) order — latent sort drift on the base, benign, and
required for regen-check to pass.
Reviewed: fail-closed guard added per codex-fresh-review
buildAndonQueue gains a fourth pull-style source: a packet under
.agents/goal-design/ still in draft or validated is flagged kind=stale-packet
when a CONFIRMED provenance verdict edge names its slug or a driver candidate
bead resolves to a closed tracker bead. Fail-toward-silence by design: closed
or superseded packets and evidence-free drafts are never flagged, and bare
git-log slug mentions are deliberately not an evidence arm (self-triggering).
No daemon (ADR-0009) — recomputed at report time.
The one command a returning operator reads after hours of autonomy, no
transcript required (docs/architecture/the-flywheel.md — the human moves
from in the loop to ON it):
YIELD gate-verdict counts (CONFIRMED/REFUTED/ESCALATE/HOLD) since
the cutoff, catches recorded (DetectCatches over the windowed
ledger), beads closed in the window (tracker-agnostic).
ANDON QUEUE blocked beads, ESCALATE/HOLD pawl verdicts, and any REFUTED
verdict whose bead is still open (stalled slice) — id, why
parked, age; deduped, oldest-parked first.
--since accepts RFC3339 or a duration (default 24h); --json emits the full
struct. Honest empty-states (andon queue: empty — nothing parked). Beads
access reuses the ao beads exec internals (resolveTracker +
canonicalizeBDReadJSON, canonical br {issues:[...]} shape) behind an
injectable seam; tracker failure degrades to a reported beads_error, never
fatal. Executed-red TDD: seeded production-writer ledger + stubbed beads.
Flips the flywheel status-ledger row for the async governance surface to
landed.
Turns ON shipped-but-off-path land optimizations that the INSTALLED ao skips.
An installed ~/.local/bin/ao fails aoBinaryInside(repoRoot), so `ao pawl review`
on the user's own checkout takes the stranger/UNTRUSTED path (cold review,
PAWL_NO_SERVICE=1 + PAWL_UNTRUSTED_REPO=1, no verdict auto-bind). `ao land`:
- Step 0: builds a fresh cli/bin/ao and re-execs the whole verb through it, so the
driving binary is BOTH HEAD-fresh AND physically inside the checkout ->
aoBinaryInside() passes -> the review takes the LIVE (trusted) path (warm auto-up
+ deterministic preflight + verdict auto-bind).
- Step 2: pins AO_BIN to the fresh binary (VERIFIED GAP: the live path passes
extraEnv=nil, unlike the cold path, so it does NOT pin AO_BIN itself) so preflight
+ emit + the pre-push gate all share ONE fresh binary.
- Step 3: best-effort warm-service up; never hard-fails (cold review still works).
- Step 4: runs `ao pawl review <bead> --scope head` (auto-bind fires on CONFIRM);
REFUTED/NO-VERDICT stops the land, exits non-zero.
- Step 5: on CONFIRM hands off to scripts/pawl-land.sh (rebase -> restamp -> single
push through the gate) then scripts/post-land-provenance-emit.sh.
RCE SAFETY: reuses the SAME aoBinaryInside trust test (via a new streaming sibling
in the trusted_script.go chokepoint, runTrustedRepoScriptStreaming) — never forgeable
marker files. Every repo-script exec stays behind the aoBinaryInside boundary, so the
TestNoUngatedRepoScriptExec AST guard stays green.
Docs: AGENTS-WORKFLOW.md + docs/architecture/operating-loop.md repointed at
`ao land <bead>` as the canonical land verb; the manual `ao provenance emit-verdict`
+ `#trivial` bind ritual is removed (auto-bind now fires on the trusted path).
ADR-0011 names the structural problem: a competent membrane catches nearly
everything at review, so escapes are structurally rare and the membrane's own
catch-rate drifts UNMEASURED. Prior measurements (2026-06-22/23) were one-shots.
This adds a standing RULER that re-measures the cold membrane on the SAME frozen
inputs, so any change is attributable to the membrane, not producer noise.
- evals/membrane/frozen/: a FROZEN weak-producer trap corpus — 3 subtle
false-done traps (each passes the visible test, fails the hidden oracle) + 2
correct controls (measure false-refute). Overlaid onto the task scaffolds by
producers/frozen-trap-producer.sh (deterministic — no model, reproducible
byte-for-byte). Reuses the existing eval-membrane.sh machinery + task oracles.
- scripts/membrane-calibrate.sh: wraps eval-membrane.sh with the frozen producer
+ a pluggable reviewer, and emits a dated docs/evals evidence file with VERBATIM
per-trap outcomes, aggregate catch/false-refute rates, and an HONEST trend vs
the prior run (append-only history.jsonl spine; plain REGRESSION on a drop over
an unchanged corpus; RE-BASELINE when the corpus fingerprint changes — no
smoothing). Budget-bounded (<= #traps+1 reviewer calls; zero producer cost).
- ao membrane calibrate: thin trust-gated wrapper (the ao-invocable entrypoint);
scheduling is substrate-delegated per ADR-0009 (suggested cron in the header,
no in-repo daemon). Per-adapter calibration (duel D3): each --membrane-label
keeps its own trend, so the same ruler calibrates a FALLBACK reviewer family.
- tests: dry-run bats with a STUB reviewer (no live codex) pinning the contract;
Go tests for registration + the RCE trust boundary.
Baseline run (codex reviewer, cross-family): catch_rate=1.0 (3/3 traps caught,
0 escapes), false_refute_rate=0.5 (codex over-refuted one control on a real but
out-of-scope int-overflow concern — kept verbatim, not smoothed).
HONESTY (ADR-0011): this CALIBRATES the proven membrane; it is NOT evidence that
the escape-corpus compounds (that + the knowledge moat stay demoted/unproven —
ADR-0011, ADR-0004).
A deterministic "is this epic/wave actually done" verdict — the membrane's
"no verdict = not done" applied at group granularity, replacing agent
self-report. Native Go design-steal of gas city's convoy guards (no gascity
dependency, no daemon).
The pure predicate lives in cli/internal/epicstatus (table-tested); the
`ao beads epic-status <id>` command resolves the live br ledger (issues.jsonl,
via `ao beads dir` — worktree-safe), builds the member set as the union of
id-prefix children (<epic>.N) and parent-child dependency edges, and renders
the verdict (--json + human reason). With --terminal the verdict maps to the
exit code (0 terminal / 2 not-terminal / 3 skipped / 1 error).
Three guards (all must hold for a terminal/done verdict):
1. an unresolved/missing member (a dangling family reference) resolves to an
unknown-status placeholder that NEVER counts as done;
2. a group with a deliberately-open descendant — a human-gate/checkpoint bead
(label/type checkpoint|gate, or status deferred) — is NOT complete;
3. a zero-descendant, still-materializing group is skipped, NOT reported done
(tombstoned members are excluded from the live set, so an all-deleted
group is also skipped, never vacuously done).
Consumers: /crank wave close, /validate completion audits, drive-loop exhaust.
TDD: failing predicate table (12 cases) first, then implementation.
Install a sovereign LOCAL pre-push hook in any repo that makes no verdict = not
done MECHANICAL: it refuses any push to main/master whose commits lack a
commit-bound CONFIRMED cross-family verdict edge in docs/provenance/ledger.jsonl
(or the provenance-only #trivial waiver), and verifies the ledger hash chain.
- ao verify init [--remove]: install/refresh/uninstall; idempotent; chains a
pre-existing pre-push hook via a sidecar and restores it byte-identically.
- ao verify pre-push (hidden): the runtime gate — chain verify + per-commit
verdict-or-#trivial-waiver over the pushed range. Pure Go: NO repo-tree script
is trusted, so a repo cannot subvert its own gate.
- HOOKS-PATH RESOLUTION delegated to git (round-13, honest-mistakes fix):
resolveHooksDir asks git where the hook goes —
`git rev-parse --path-format=absolute --git-path hooks` (via trustedGit) —
instead of hand-classifying core.hooksPath absolute-vs-repo-relative. That
hand-split installed a ~-expansion value (core.hooksPath=~/ao-hooks) into
<repo>/~/ao-hooks while git ran hooks from $HOME/ao-hooks, so `ao verify init`
reported success but the ratchet silently never ran. git's own resolution
honors ~-expansion, absolute, repo-relative, and common-dir/worktree cases at
once; fail-closed if git returns no usable absolute path. (Distinct from the
parked adversarial repo-relative-hooksPath threat — this is a legitimate
operator config; that is the repo attacking itself, still out of scope.)
- TIP-TREE PROOF (round-2): chain verify + verdict-edge check read the ledger
blob AS COMMITTED at the pushed tip, never the working tree.
- COMMIT-RANGE, no tip-narrowing (rounds 3,7,10): creation / unknown-base derive
via git rev-list <tip> --not refs/remotes/*/<branch> (GATED TRUNK only); no
trunk ref for an absent non-zero base → refuse fail-closed.
- PARSING-DISCIPLINE SWEEP (rounds 11-12): every verdict-edge / ledger /
git-output recognition is EXACT and fail-closed. Verdict match requires
relation=="wasDerivedFrom" + shaBindsCommit + parseDisposition=="CONFIRMED"
(shared with `ao done`), never substring; the #trivial waiver uses diff-tree
-z NUL paths via the shared provenanceOnlyChangedFiles.
- CONVERGE-BY-DELETION of the planted-binary class (rounds 4-6): baked-only ao +
trustedLookPath git + install-time repo-internal-bake refusal.
- SCOPE (documented, parked): defends honest mistakes + misconfiguration, NOT an
adversarial repo subverting its own gate (PRODUCT.md).
- AO-VERSION FLOOR: the hook probes ao provenance ledger-reader-version.
- Config: init surfaces the effective verify policy via the age-rk3r.5 config.
Tests: 40 Go + 12 bats. RED-first proven for every refute, including round-13's
git-resolved hooksPath (core.hooksPath=~/aohooks → hook installed where git
actually runs it, not <repo>/~/aohooks).
# Conflicts:
# docs/cli-surface.json
# docs/cli-surface.md
# evals/agentops-core/cli-command-surface-matrix.json
# evals/agentops-core/fixtures/cli-command-surface-smoke.sh
Extend the ADR-0012 experimental-surface archival (h4y3 did RPI/factory) to the
three corpus/flywheel commands whose spine entanglement is a bounded, cleanly
separable extraction: corpus, curate, defrag. `defrag` is pulled in because it
calls corpus's createCorpusSnapshot for its pre-prune backup, so the two archive
together.
Spine-consumed symbols extracted to UNTAGGED files so the default build still
compiles after the command files move behind //go:build flywheel:
- corpus_scan_error.go: corpusScanExitError (root.go's Execute() switch
type-asserts it to map the fail-closed exit code).
- defrag_types.go: DefragReport / PruneResult / DefragDedupResult aliases
(goals_prune.go uses PruneResult; uat_smoke_test.go uses DefragReport).
Tagged behind //go:build flywheel: corpus*.go (12), curate*.go (3), defrag*.go
(3) including their _test.go files.
Spine test surfaces kept green:
- cobra_commands_test.go: corpus/curate/defrag dropped from both expectedCmds
lists (auto-regenerated) and corpus/fitness from parentExpectations.
- root_group_experimental_test.go: spine variant now asserts the 9 still-present
experimental commands; new root_group_experimental_flywheel_test.go asserts the
3 archived ones under the tag (together = the full 12-command demotion set).
- doctor_test.go TestDoctorStaleReplacementsExist: tolerates a deprecated-command
replacement absent from the spine build (e.g. "ao curate" → flywheel); the
archive-tag run is the strict check. ("curate → quality deprecation map".)
- uat_smoke_test.go TestUATSmoke_DefragDedup: skips in the spine build (it runs
`ao defrag`); runs under the flywheel tag.
Proof:
- default `ao {corpus,curate,defrag} --help` => unknown command; `ao buildtags`
=> spine.
- `-tags "flywheel legacy"` restores all three; `ao buildtags` => flywheel/legacy.
- both variants: build + vet + test ./... green (spine 11988, flywheel-legacy
11978 passed). make regen-all committed; make regen-check + verify-buildtags OK.
SCOPE NOTE: the bead's package archival (internal/wiki|pool|ratchet) and the other
9 commands are NOT included — proven infeasible as specified; see the bead report.
The 3 packages are spine infrastructure (validate.go's ratchet Validator engine,
gate.go's pool queries, inject/metrics citation ledger, transitive
internal/lifecycle + internal/search), and the other commands' runtimes are
spine-invoked (session_end runs dedup+maturity; flywheel_close_loop uses
pool-ingest+store-index; poolCmd/flywheelCmd host spine subcommands) or their
internals are tested by cross-cutting untagged spine tests.
# Conflicts:
# evals/agentops-core/cli-command-surface-matrix.json
# evals/agentops-core/fixtures/cli-command-surface-smoke.sh
Ship gen-membrane-receipts.sh + check-membrane-receipts-freshness.sh in the
embedded pawl bundle (make sync-hooks + //go:embed all:pawl) so a stranger repo
can render its own membrane-receipts proof page with no AgentOps checkout.
ao verify receipts mirrors the pawl review trust split: in-checkout dogfood runs
the live repo generator; anywhere else it extracts the EMBEDDED generator and
runs it against the user's OWN git repo under the sanitized cold env
(pawlReviewColdEnv) with AO_BIN pinned to the running binary — no ao-on-PATH
needed, no repo-local script trusted. The generator refuses the build-from-cli/
fallback when PAWL_UNTRUSTED_REPO=1 (compiling+running an untrusted repo's
cmd/ao would be RCE); the in-repo path keeps its fallback. Fail-closed
chain-verify-before-render and the count-parity check are unchanged.
Byte-identical to the current generator on this repo's ledger (behavior lock).
Bats acceptance in a throwaway repo with a production-writer-built ledger:
render + tamper-refusal + embedded==in-repo parity.
# Conflicts:
# docs/cli-surface.json
# docs/cli-surface.md
Archive the two remaining self-contained RPI/factory command clusters behind
//go:build legacy:
- orchestrate (orchestrate.go + _common/_preflight/_route/_shape/_status/_tools/
_verify + tests). The internal/orchestration LIBRARY stays untagged — spine
stamp_shape.go still uses it; only the command files are archived.
- loop (loop.go + loop_* subcommand cluster + tests). The internal/evolve
library it imports stays untagged.
With orchestrate now archived, the doctor's stale-command fixer can no longer
point at 'ao orchestrate': repoint DeprecatedCommands["ao work rpi"] to the
surviving spine loop driver 'ao converge' (stale_refs.go + fix_skills_test.go).
Default 'go build ./...' now omits codex/orchestrate/loop/tick/autodev; the
sibling spine commands (ready/close/verdict-gate/council-gate/guard-status/
install-guards/chaos-test/converge/gate) remain. make build-flywheel /
AGENTOPS_LEGACY=1 make build restore the archived set. regen-all swept all
surfaces; both build variants build+vet+test clean (spine 12018, legacy 12033);
regen-check ALL GREEN.
Archive the RPI/factory commands whose spine entanglement was decoupled first:
- codex lifecycle (codex.go, codex_schema.go + tests) — spine symbols already
extracted to untagged codex_artifacts.go / codex_task_schema.go.
- autodev (autodev.go + tests).
- tick: only the 'ao tick' command surface moves to tagged tick_cmd_legacy.go;
the tick ENGINE (tickRuntime, newTickRuntime, tickPassthrough, tickSmoke,
tickVerdictIdentity, tickExitCouncil) stays UNTAGGED in tick.go because the
spine consumes it (ao claim, ao converge, ao eval chaos, converge_canary), as
do the sibling spine commands ready/close/verdict-gate/council-gate/
guard-status/install-guards/chaos-test.
Cross-cutting test wiring:
- testutil_archived_globals{,_legacy}_test.go: build-tag-split delegate that
saves/restores/resets the codex+autodev cobra-flag globals only in the tagged
build, so the untagged (spine) test helpers (resetGlobalFlags, executeCommand)
never reference archived symbols.
- cobra_commands_test.go / tick_test.go: drop archived names from spine
expected-command lists; tick subcommand coverage moves to tick_cmd_legacy_test.go.
- flywheel_promoted_body_dedupe_legacy_test.go: the one codex-command test split
out of the otherwise-spine close-loop test file.
Default 'go build ./...' omits these commands; make build-flywheel /
AGENTOPS_LEGACY=1 make build restore them. regen-all swept the surfaces. Both
build variants build+vet+test clean; regen-check green.
ao done <bead-id> [--sha] [--force-no-verdict] [--json]: closes via the br CLI
on PATH with the close reason stamped [verdict:<sha7>:<disposition>]. CONFIRMED
ledger verdict -> CONFIRMED stamp; verdict-less provenance-only commit (the
pawl #trivial waiver class, fail-closed diff-tree) -> waived-trivial; otherwise
REFUSE naming ao verify / ao pawl review, with --force-no-verdict writing an
explicit greppable UNVERIFIED stamp. BEADS_DIR resolution reuses the
beadsTrackerCommandContext env path (no hardcoded ledger paths).
scripts/check-verdict-close-rate.sh: warn-only gate (threshold 0 baseline,
--strict --threshold N for the later ratchet) measuring the [verdict:...]
stamp fraction of the last N closes in the br issues.jsonl (last-wins per id);
skips cleanly when jq/BEADS_DIR/ao/ledger are absent.
Tests: 13 Go cmd-level tests (stub br on PATH + production-writer ledger
fixtures + t.TempDir git repos) + 14 bats over fixture JSONL. Narrow CLI-ref
regen (generate-cli-reference.sh) included to keep TestCobraConformance green.
The scenario-satisfaction layer's consumer (goalsfitness aggregator +
ao goals measure --scenarios-only) and contract (scenario-results.v1
schema/loader/writer) shipped long ago, but nothing ever wrote
.agents/rpi/scenario-results.json — a dead instrument reading
unknown/0%-evaluated for every directive. This lands the missing
producer, resolving the bead's decision rule to Option A (wire it,
writer-only, no council-judge dependency in v1).
ao eval scenario evaluate [--all|--directive <id>] [--json] [--timeout]:
- GATE-SHAPED scenarios (acceptance_vectors carrying a mechanical
"check" command; "gate:<id>" resolves through the GOALS.md Gates
table) run each check via goals.MeasureOne (sanitized bash, per-check
timeout, exit-77 skip convention). Score = fraction of checks passed;
verdict = score vs the scenario's own satisfaction_threshold, exactly
matching the aggregator's countSatisfied comparison.
- JUDGMENT-SHAPED scenarios (no mechanical check) are recorded as
verdict "skip" with attestation-needed evidence — the nearest
ValidVerdict for "cannot mechanically evaluate"; never a fabricated
pass (the anti-pattern GOALS.md's pre-production section forbids).
- A check that could not run (timeout, unresolvable gate ref) yields
skip, and missing/retired scenario links write NOTHING, so zero
evidence stays VerdictUnknown downstream.
- Results persist through the production scenarioresults.Writer.Append
(latest-judged_at supersede per scenario_id; iteration = prior + 1).
L2 tests prove the full producer->consumer round trip: the command
writes the artifact, the production loader accepts it strict, and the
real runScenariosOnly/EvaluateSatisfaction path reads back nonzero
evaluated counts (pass, fail, judgment/unknown, timeout, unresolvable
gate ref, supersede-on-rerun, threshold-equality lanes).
Nightly cadence wiring deliberately deferred to a follow-up commit.
Known: cli/docs/COMMANDS.md conformance regen deferred to landing.
Fold state, memory, rehydrate, handoff under `ao session` (zero-breakage via
hidden deprecated back-compat aliases for the three with external callers;
state gets none). `ao session bootstrap` is byte-identical — session_bootstrap.go
untouched.
Reparent rootCmd.AddCommand → sessionCmd.AddCommand and DELETE the GroupID lines
(stateCmd "knowledge", memoryCmd "config", handoffCmd "workflow") — cobra panics
at Execute if a child's GroupID isn't in the parent's groups, and sessionCmd
defines none. `ao --help` verified NO-PANIC.
Hidden aliases (Hidden + Deprecated→stderr, so COMMANDS.md is a pure move but
`ao handoff` / `ao memory sync --quiet` / `ao rehydrate` still execute) share the
same RunE + flag helpers; --quiet registered on both the session child and the
alias. cobra_commands_test parent map + a new TestSessionFoldedCommandsResolve;
stale_refs deprecation map. regen-all swept the surfaces (cli_commands 81->77).
go test = 7963 pass; surface-parity/smoke/cli-skills-map/regen-check all green.
Fold the top-level eval commands under `ao eval`, zero-breakage via dual-register
(old spellings kept Hidden, new eval subcommand shares the same RunE):
- retrieval-bench -> ao eval bench
- chaos-test -> ao eval chaos
- session-outcome -> ao eval session-outcome
- scenario subtree reparented under ao eval (add/init/list/validate follow)
`ao eval scenario-ab` preserved (ADR-0004 revival path).
Repointed inline `ao scenario` body-refs in skills/goals + eval-outcomes/flywheel
to `ao eval scenario` (+ mirrored the goals/eval-outcomes Codex twins + regen hashes)
so the FULL-tier skill.body-refs gate stays green. stale_refs.go deprecation map
updated; new eval_fold_surface_test.go (go.command-test-pair). regen-all swept the
command surfaces (cli_commands 84->81 as the 3 hidden leaves leave the public catalog).
go test ./... = 12046 passed.
Commands-only archive of the cleanly-separable RPI/factory commands behind
//go:build legacy: turn (turn_verify.go), harness (harness_cmd.go), operator
(operator_cmd.go + operator_adapter.go). Default `ao` surface drops them;
AGENTOPS_LEGACY=1 make build / make build-flywheel restore them; all four
build+test variants pass. regen-all swept the surfaces.
Scope note (mirrors .13): a leaf-audit found only turn/harness/operator archive
cleanly commands-only. The rest are spine-entangled: codex (context_ranked_intel
+ membrane use codexArtifactRef), evolve, orchestrate (multi-file cluster), loop
(cluster), tick (converge_canary uses tickExitCouncil), autodev (shared
testutil_test.go resets autodevFile/autodevForce). These need the same
spine-decoupling as the corpus/flywheel clusters — folded into a legacy spin-out.