codex-agy-worker

A Codex Agent Skill for bounded Antigravity CLI delegation with independent Git-scope checks and driver-owned verification.

Offline test workflow License: MIT

Use Codex CLI to delegate repository exploration, features, and project-scale coding to Antigravity CLI (agy). Codex—not the worker report—reviews the diff, runs build/test/lint checks, and decides whether the result is verified, partial, or blocked.

Quick start

Requires a POSIX-compatible environment with Bash, Python 3, git, Codex CLI, and agy on PATH. Native Windows is untested; WSL may work on a best-effort basis.

Install the Agent Skill from its Git-backed Codex marketplace:

codex plugin marketplace add cagdasyurekli/codex-agy-worker
codex plugin add codex-agy-worker@codex-agy-worker

Start a new Codex session after installation. The marketplace packages the same canonical skills/agy-worker/ bundle; it does not duplicate or download a second runtime when the skill runs.

Or review and install directly from GitHub:

git clone https://github.com/cagdasyurekli/codex-agy-worker.git
cd codex-agy-worker
./install.sh

Review the selected source commit before either installation path. The marketplace flow was tested from an immutable Git commit with isolated Codex state, including add, discovery, install, removal, and exact installed-skill byte parity. Installation does not authorize a provider dispatch or repository transmission.

Try the evidence boundary offline

./proof-demo.sh

The demo uses two private synthetic Git repositories, invokes no provider or network, and changes neither this checkout nor your credentials. It demonstrates two fixed gate cases only; it is not a security certification or proof of general correctness.

First real task

Before an agy-backed request, approve the exact repository/path content that may be sent through agy to Google/Gemini. Keep credentials and denied paths out of scope; read PRIVACY.md before use.

After installation, start a new Codex session and ask:

Use the agy-worker skill to add error-path tests for the parser modules under /absolute/path/to/project/src/. Allow changes only under tests/, verify with python3 -m pytest -q tests/test_parser.py, and preserve accepted work on a branch.

Codex creates an isolated worktree, asks for provider-transmission approval when it has not already been granted for that exact scope, inspects the resulting diff, and runs driver-owned checks. A worker can discover ordinary project structure; it is not limited to mechanical edits or a predeclared file list.

Learn how to verify an agent candidate without trusting its report.

The evidence pipeline

Bash + Python 3 + git. No Node and no MCP daemon. A deliberately started job may have one private, per-job local controller; it is not a shared service.

# Codex dispatches a bounded job to agy...
BASE="$(git -C "$WT" rev-parse HEAD)"       # capture before dispatch
echo "$TASK" | AGY_WORKER_MODE=accept-edits ./agy-worker.sh \
    --workdir "$WT" --add-dir "$WT" > envelope.json

# ...then independently verifies it, rather than believing the report.
./qa-gate.sh --envelope envelope.json --repo "$WT" --base "$BASE" \
    --only 'tests/**' --expect-edits \
    --verify "cd $WT && pytest -q"

Why another one of these?

There are already several Codex→agy delegators — codex-agy-delegator, codex-antigravity-bridge, agy-mcp, antigravity-cli-mcp, and antigravity-for-claude-code. Most are MCP servers; several are more featureful than this one. This project keeps one agy backend and does not claim validated native-Windows support.

Its differentiator is that Codex does not confuse a worker report with evidence. The worker's JSON report is a claim. The gate independently derives bounded facts from the repository, while Codex uses those facts and driver-owned checks to decide whether the result is verified or needs more work:

The worker... Gate Exit
edits files it never declared diffs the repo, compares to files_changed 10
declares files it never touched same check, other direction 10
reports commands or tests on a completed candidate treats them as untrusted data and executes none 11
returns a malformed envelope validates the complete checked-in schema 12
claims completion, changed nothing under --expect-edits diff is empty 13
makes a plausible but wrong fix runs the driver's own --verify command 14
asks for a human or reports partial/failed/blocked checks scope, then routes without accepting 15
changes files outside a driver-owned --only policy rejects even if the worker declared them 10

--verify is mandatory for acceptance. The gate never executes worker-supplied shell text, and it hashes the Git diff plus every nontracked path—including ignored files— before and after verification so a passing verifier cannot silently rewrite the candidate.

The forty offline suites need no agy provider call, network access, API key, or GitHub login.

GitHub Actions cost and quota fallback

For a public repository, standard GitHub-hosted Actions runners do not consume the owner's included minutes. A private fork or a future visibility change is different: macOS runners cost substantially more than Linux runners, so the workflow deliberately avoids a second full run after a normal merge.

The required test aggregate job verifies four fail-closed CI shards (dispatcher, dispatcher-remediation, other-a, other-b) on pull requests and exact-SHA manual dispatch. Each shard checks out the exact immutable commit (github.event.pull_request.head.sha or validated head_sha), enforces committed-range diff hygiene, and runs its registered stage subset. Every shard emits a mode-0600 receipt binding exact HEAD SHA, canonical inventory digest, expected/observed stage IDs, and outcome without recording paths, commands, environment, logs, or credentials. GitHub retains the uploaded privacy-safe receipt artifact for one day; it is repository workflow evidence, not an owner-private local file after upload. The required aggregate test job with if: always() downloads all receipts within the run and succeeds only if all four unique shard receipts exist, all producers succeeded, all match expected head/inventory, and every canonical stage ran exactly once. Lower CI wall time from parallelization does not mean lower total compute, provider usage, token usage, cost, or weaker verification. Normal squash merges preserve the tested tree; the post-merge commit has a new identity but does not need a duplicate full-suite run. The job is also available by explicit manual dispatch for an exact release comparison: supply committed base_sha and head_sha.

If a private fork's quota is unavailable, run the same fail-fast offline suite locally:

./scripts/ci-offline.sh

It runs the static checks and all forty offline suites without requiring a network or provider call and without intentionally inspecting account-HOME contents. Ambient local tools may still consult their ordinary user configuration. Keep the command's exact summaries together with the commit, tree, and git diff --check evidence. On a clean tracked/untracked worktree, an optional --timing-report <PATH> argument records ordered per-stage observational monotonic wall time in a mode-0600, no-overwrite JSON report bound to the exact HEAD SHA and canonical inventory digest; it contains no paths, commands, environment values, logs, credentials, provider data, timestamps, or host identity, and does not claim reduced compute, lower provider usage, or weaker acceptance. This is local evidence only: it never satisfies the protected GitHub test check. After availability returns, manually dispatch the exact comparison before publishing or releasing unless the repository owner explicitly changes the protection policy. The daily compatibility watch remains macOS-specific; the weekly metadata-only feedback watch uses Linux because it has no macOS contract. See GitHub's Actions billing guidance and workflow concurrency documentation.

See the evidence boundary in under a minute

./proof-demo.sh

This repository-only starter proof creates two independent private temporary Git repositories, exercises the maintained gate once on an exact synthetic edit and once on a plausible but incomplete synthetic envelope, then removes both repositories. It does not invoke agy, access the network, inspect credentials, or change the current checkout. The three-line result proves only that these two fixed cases produced the expected gate exits. gate-passed is not a human review, accepted candidate, general correctness claim, security certification, benchmark, or production validation.

Conformance v1: fixtures only

Integrations and forks can run the full public gate contract against their own entry point:

./conformance/run.sh --gate /path/to/their/qa-gate.sh

The versioned eleven-fixture kit requires exact exits for acceptance, scope, ignored-file, untrusted-claim, malformed-envelope, no-op, verifier-failure, verifier-mutation, human-required, mutable-base, and missing-verifier cases. Passing means fixture compatibility only—not security certification, real-job quality, Receipt v1 support, or human acceptance. The supplied gate executes with the current user's privileges; review it first. Its execution TCB includes the supplied gate and loaded code, the local owner and same-UID processes, and OS administrators. Cleanup holds no-follow directory descriptors and deletes contents relative to them while the original parent/root identities remain exact; final pathname removal trusts that TCB. Identity drift fails closed with a possible residual, and the runner never scans for or chases a moved directory. This is not same-user tamper resistance. See the bounded claim and fixture contract.

Roadmap

The product roadmap records dependency-ordered feature slices and their explicit implemented or deferred status. The published v0.6.0 release scope added the reviewed Gemini 3.7 Flash low/medium/high mappings and hardened the capture child mode and dispatch-state snapshot boundaries. The published v0.7.0 scope adds usability-first explore/task/project workflows and same-conversation repair. The published v0.8.0 scope adds explicit notifier maintenance/rebind handling, bounded annotated-tag resolution, version-drift observations, and the exact agy 1.1.13 quota-terminal classification. The published v0.9.0 scope activates the exact agy 1.1.16 version/source/distribution and unchanged 14-slug inventory binding, and accepts Codex 0.148.0 as an observational baseline. The published v0.10.0 scope includes the lifecycle, recovery, verification, and Codex-owned assurance scope, including the legacy notifier 18→21 file refresh migration, bounded lifecycle recovery, and driver-owned verification. Immutable historical v0.10.0 tag bytes cannot be rewritten; this source and package alignment establishes repository truth without retroactively altering that published tag. The published v0.5.0 scope added sanitized bug/improvement drafts with exact double confirmation, private-only security drafts, and the bounded metadata-only feedback aggregate and weekly/manual watcher. The prior v0.4.0 scope includes daily compatibility observation, private 30/60/90 measurement, the optional local notifier, version-drift-safe default/literal routing, bounded updater, gate-envelope, lifecycle-Git-output, Actions-checkout hardening, and the progress-aware per-job dispatch lifecycle. A source checkout alone is not proof of publication; verify the exact reviewed tag and release state separately. The approved v0.11.0 observation-only release scope records agy 1.1.22 as a non-activating observation, Codex 0.150.1 as observation-only, and pins actions/checkout v6.0.2 by commit. The required single no-retry 1.1.22 account inventory call failed without classifiable inventory evidence. The owner explicitly approved publication of this reduced scope; that decision does not activate 1.1.22, so the active agy baseline remains 1.1.16. Its bounded dogfood record includes accepted Flash-high task/explore and Pro-high task candidates plus a rejected Pro-high project candidate; Codex-owned review, tests, and exact-head CI remain the acceptance authority. This describes release scope, not proof that a v0.11.0 tag or GitHub Release exists. P2-B and P2-C remain deferred because their required live terminal-event and recurring-accumulation evidence does not exist. Source, tests, and this README remain the authority for current CLI behavior; every new slice still requires its own approval, tests, review, and pull request.


Installation details and compatibility

for suite in tests/test-*.sh; do "$suite"; done

The quick-start ./install.sh command installs the Codex skill only and touches nothing else. The loop above is an optional shell-suite smoke check.

It is not the complete offline gate. Run the full shell and Python command list in CONTRIBUTING.md before publication.

The GitHub repository is the source of truth. Review the commit you cloned before installation. For a released snapshot, check out the exact reviewed vMAJOR.MINOR.PATCH tag from the GitHub Releases page before running ./install.sh; do not substitute an unverified tag.

Requires agy (Antigravity CLI) on PATH, git, Python 3, and Bash. The core CLI has no Windows-specific denylist, but its maintained entrypoints require a POSIX-compatible Bash/Python/Git environment and some canonical evidence commands use fixed POSIX paths. Native Windows is untested; WSL or another compatible environment may work on a best-effort basis. The optional daily notifier is specifically a macOS LaunchAgent. The active reviewed model/effort matrix is bound to agy 1.1.22; its exact accepted evidence and pair-to-compound-slug mappings are reconciled in compat/reviews/agy-1.1.22-activation.md. The earlier 1.1.22 observation remains the unchanged historical failed-capture record. The complete 1.1.12 and 1.1.16 reconciliations remain historical, and the earlier 1.1.16 interface observation records the non-activating evidence that triggered the later capture and review. The agy-owned default and explicit literal pass-through remain version-independent. Codex 0.150.1 is the accepted observational Codex baseline; it does not grant agy dispatch or model-selection authority. See compat/reviews/codex-0.150.1.md.

Before spending provider quota, run the offline doctor against the repository you plan to delegate:

./doctor.sh --repo /absolute/path/to/target
./doctor.sh --repo /absolute/path/to/target --format json

The doctor is deterministic and read-only. It checks the bundled runtime, Bash 3.2, Python 3, git and worktree support, target Git worktree, exact semantic agy --version, and the checked-in agy version, reviewed-source, and review-date records. Source-revision failures are reported only as match, mismatch, or unavailable; the doctor never prints their bytes. It invokes no provider, network client, updater, dispatch, authentication probe, or personal-config scan, and it repairs nothing.

Exit Overall Meaning
0 ready All offline prerequisites match the checked-in evidence.
3 review-required Prerequisites work, but the agy version drifted or review is due.
3 not-ready A prerequisite, semantic probe, repository, bundle, or metadata check failed.
64 no report Invocation or format is invalid.

If the repository-root launcher cannot resolve a bounded symlink chain to the canonical doctor.sh, it emits one sanitized diagnostic, no report, and exits 3. The wrapper itself may be reached through that bounded chain, but the package-owned skills/agy-worker/runtime path and the runtime's scripts, agents, schemas, and compat parents must be real directories contained in the bundle, not symlinks. The doctor also ignores caller-provided temp paths, gives every child probe one private external workspace, and removes it before returning. HUP, INT, or TERM is forwarded to the active probe and its descendants; interruption emits only doctor: interrupted, no report, and exits 3.

Green covers only those offline prerequisites. It does not certify authentication, provider availability, Codex/agy sandbox permission, task quality, or a future dispatch. A due or drift result asks for human compatibility review; it never updates metadata. review-required is not a blanket dispatch lock: no selector or --tier default still delegates to agy's own default, and the explicitly approved --literal-model surface remains an unreconciled caller-owned pass-through. Reviewed --model/--effort resolution uses its reviewed 1.1.22 matrix evidence. Every direct selection uses a safe executable with bounded semantic --version and strict critical --help structure. An exact matrix-version match proceeds mechanically after that structural probe. Compatible version drift requires Codex's explicit --compatibility-disposition proceed --approve-help-sha SHA256 before dispatch; the SHA must be the exact raw help digest just reviewed. The caller's exact resolved slug is unchanged and the selection record reports model_availability: not_assessed; it never claims that a drifted installation offers a particular model. A structurally incompatible critical interface still blocks reviewed direct selection. Structural acceptance, including an exact-version match, is not semantic approval: before every reviewed direct dispatch, Codex inspects the current bounded raw agy --help and stops if the exact caller-selected model or effort cannot be honored. The controller never infers that decision from provider prose. not-ready still blocks all dispatch. For a folder-only skill copy, resolve PIPELINE as shown in skills/agy-worker/SKILL.md and run "$PIPELINE/doctor.sh"—no checkout or fetch is needed.

To approve compatible version drift without disclosing an executable pathname, inspect the bounded local agy --help bytes, then calculate their raw SHA-256 with LC_ALL=C agy --help 2>&1 | /usr/bin/python3 -c 'import hashlib, sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest())' and compare its digest to the sanitized raw_help_sha256 review output. Retry the same caller-selected --model/--effort request with --compatibility-disposition proceed --approve-help-sha set to that matching digest. A mismatch, changed help, or unavailable probe needs a fresh review; do not reuse an older digest.

skills/agy-worker/ is the one canonical, open-standard Agent Skill and contains its own Bash/Python/git runtime. A folder-only copy therefore works without the rest of the checkout and never downloads code when invoked. The repository-root commands are compatibility wrappers for clone users. install.sh copies the same bundle and writes a local pointer so checkout-only maintenance commands remain available; it does not rewrite the public SKILL.md.

The repository retains .codex-plugin/plugin.json and the root-source .agents/plugins/marketplace.json contract for the same Codex skills-only package. The marketplace and GitHub clone paths resolve the one canonical skill bundle; see the marketplace contract and verification boundary.

The portable Agent Skill can also be copied through the third-party skills CLI:

DO_NOT_TRACK=1 npx skills add cagdasyurekli/codex-agy-worker \
  --skill agy-worker --copy

npx is only an optional installer here; the installed skill has no Node runtime dependency. Review the copied files before use.

The public landing page source lives at docs/index.md. GitHub Pages configuration, repository About fields, topics, and search-engine verification are separate repository-owner actions; checked-in files do not change those settings.

Codex sandbox settings — required

agy starts a local language server and writes state under ~/.gemini. Under Codex's default workspace-write sandbox it fails with exit 5 and empty stderr. Add to ~/.codex/config.toml:

[sandbox_workspace_write]
network_access = true

and run Codex with --add-dir ~/.gemini. Both are needed — the writable dir alone still fails, because the blocker is the socket bind, not the file write.

With the config saved, launch an interactive session with:

codex --add-dir "$HOME/.gemini"

For a one-off codex exec invocation, pass both settings explicitly:

codex exec --sandbox workspace-write --add-dir "$HOME/.gemini" \
  -c 'sandbox_workspace_write.network_access=true' "<your task>"

Use it from Codex

After ./install.sh, start a new Codex session and ask in normal language:

Use the agy-worker skill to add error-path tests for the parser modules under /absolute/path/to/project/src/. Allow changes only under tests/, verify with python3 -m pytest -q tests/test_parser.py, and preserve accepted work on a branch.

For a larger request, the prompt can be equally direct:

Use agy-worker to build this application in /absolute/path/to/project/. Discover the existing structure and test commands, implement the requested behavior across the project, run the relevant checks, and repair failures in the same conversation.

Codex creates an isolated worktree, selects a workflow, dispatches agy, inspects the diff, runs driver-owned checks, and reports what is actually verified. You do not need to supply a final file list, a persona, or every test command before starting.

What you want Workflow Minimum input What Codex delivers
Understand, plan, or review a repository explore Repository and question A useful read-only report with stated coverage limits; not an exhaustive audit claim.
Implement a feature, refactor, or tests task Repository and desired behavior A worktree diff plus Codex-run relevant checks; failed checks can trigger a bounded repair.
Build an app, complete a project, or broadly audit-and-fix project Repository and outcome Repo-wide worktree changes, build/test/lint measurement, up to five total provider attempts (the initial attempt plus at most four same-conversation repairs), and an assurance label.
Follow a long job async lifecycle Job ID Local status/bounded wait, controlled extension, or cancel state; not remote-provider truth.

Assurance labels are intentionally practical: Codex uses verified only after its strict review policy is met, partially_verified for useful work with unresolved evidence, rejected for work it declines, and blocked for a genuine authority, repository-boundary, or execution block. After it validates the exact current candidate and Verification v2 binding, the controller persists Codex's declared label; it does not reinterpret check counts into a different disposition. A failed first check is a repair signal, not an automatic rejection or deletion.

Before the first dispatch for a repository, the skill identifies the paths in scope and requires explicit approval for sending that task and any worker-read repository content through agy to Google/Gemini, unless the user already approved that exact transmission. Read PRIVACY.md before use; support and project terms are in SUPPORT.md and TERMS.md.

Before every provider-launch attempt (initial run/start, resume, continue, and restart), the packaged skill requires Codex to tell the user in one or two concise user-facing sentences what task is being sent to AGY, the caller-selected model, caller-selected effort (when separately selectable), and the exact resolved model slug. For default selection where no model is selected or the default tier is used, state truthfully that the provider default model is used and that model or effort is unresolved, without inventing a resolved slug or thinking level. For fixed, compound, or literal models where effort is not separately selectable, that is stated accurately without inferring hidden backend reasoning or inventing a thinking level. The notice must precede every dispatch attempt and remain accurate afterward. If preflight fails before provider launch, Codex explicitly states that the task was not sent to AGY; if provider reach is genuinely uncertain, it states that reach is unverified rather than claiming success. Direct model and effort selection remain caller-owned, and routing recommendations are advisory.

Manual end-to-end example

Keep the pipeline checkout and target repository explicit. The job branch matters: it prevents accepted but uncommitted work from being destroyed during cleanup. bulk-test-writer is still experimental: it has been exercised on a real task, but has not yet produced an accepted real delivery.

PIPELINE=/absolute/path/to/codex-agy-worker
TARGET=/absolute/path/to/your-project
WT=/tmp/agy-job-12345
JOB_BRANCH=agy/tests-parser-errors-12345
ENVELOPE=/tmp/agy-job-12345-envelope.json
JOB_ID=parser-tests-12345
BASE="$(git -C "$TARGET" rev-parse HEAD)"

git -C "$TARGET" worktree add -b "$JOB_BRANCH" "$WT" "$BASE"

if ! echo "Add error-path tests for $WT/src/parser.py.
Edit ONLY files under $WT/tests/. Use file tools on absolute paths.
Do NOT run shell commands — they execute in a scratch directory, not this repo.
The driver runs every command. Return commands_run and tests_run as empty arrays." |
  AGY_WORKER_JOB_ID="$JOB_ID" "$PIPELINE/agy-worker.sh" \
    --workflow task --mode accept-edits --tier bulk --persona bulk-test-writer \
    --workdir "$WT" --add-dir "$WT" > "$ENVELOPE"; then
  echo "Dispatch failed; inspect the sanitized terminal state/result. Resume only a candidate-free failure; handle an ERROR candidate with Verification v2, and preserve/finalize or freshly restart a CANCELED candidate." >&2
  exit 1
fi

if "$PIPELINE/qa-gate.sh" --envelope "$ENVELOPE" --repo "$WT" --base "$BASE" \
  --only 'tests/**' --expect-edits \
  --verify "git -C '$WT' diff --check" \
  --verify "cd '$WT' && python3 -m pytest -q tests/test_parser.py"; then
  echo "Candidate passed the evidence gate; review the diff before preserving it."
else
  GATE_RC=$?
  echo "Gate rejected or routed the candidate (exit $GATE_RC)."
  exit "$GATE_RC"
fi

Exit 0 means the evidence gate accepted the current state; it does not merge it. Review and preserve the work before removing the worktree:

git -C "$WT" diff
git -C "$WT" add tests/
git -C "$WT" commit -m "test: cover parser error paths"
git -C "$TARGET" worktree remove "$WT"

# Integrate JOB_BRANCH only after your normal review/PR process.

If the gate rejects the job and you intentionally want to discard it:

git -C "$TARGET" worktree remove --force "$WT"
git -C "$TARGET" branch -D "$JOB_BRANCH"

Gate failure handling is deliberately small: exits 10–14 reject the candidate, exit 15 routes its questions to a human, and exit 64 means the driver invocation is wrong. A dispatch error starts no further provider call automatically; do not add a shell retry loop. A candidate-free failed state may be eligible for SHA-approved exact resume or explicit fresh restart. A terminal ERROR with a valid candidate goes to result, driver Verification v2, then continue or finalize. A terminal CANCELED candidate goes to result and preservation/finalization or an explicit fresh restart; it is never resumed or continued.

Read-only inventory example

Use plan for inventory and independently spot-check the report. Exit 0 can prove that no files changed and that the driver command passed; it cannot prove the worker's architecture prose is accurate.

An explore result is useful input for planning but does not prove that every semantic path was inspected. Codex should spot-check material claims before relying on them; that limitation does not make an otherwise useful broad exploration inadmissible.

if ! echo "Read repository-owned files under $WT using absolute paths. Report entry points,
test commands, and risky areas. Do not run commands. Return files_changed,
commands_run, and tests_run as empty arrays." |
  "$PIPELINE/agy-worker.sh" --workflow explore \
    --workdir "$WT" --add-dir "$WT" > /tmp/inventory-envelope.json; then
  echo "Inventory dispatch failed; do not pass its stdout to the gate." >&2
  exit 1
fi

"$PIPELINE/qa-gate.sh" --envelope /tmp/inventory-envelope.json \
  --repo "$WT" --base "$BASE" \
  --verify "git -C '$WT' diff --quiet '$BASE' --"

# Then open a sample of every claimed path and verify discovered commands against
# package/CI files yourself before using the inventory for planning.

Two rules that make it work

  1. Keep the worker off the shell. Under agy's sandbox, its shell tools run in ~/.gemini/antigravity-cli/scratch, not your repo — a worker asked to survey a repo will run ls and truthfully report an empty directory. Its file tools do reach the real target. Let the worker edit files; the driver owns every command.
  2. Absolute paths + --add-dir. agy has no reliable notion of "the current directory" in print mode. Name the absolute path in the task text and pass --add-dir. With only one, the worker works on the wrong thing.

Personas

--persona repo-inventory|diff-reviewer|bulk-test-writer optionally inlines a role brief from skills/agy-worker/runtime/agents/. repo-inventory measurably changed an under-specified job from a false survey into an honest escalation. bulk-test-writer has now been exercised on a real Playbook-Gemini test task: the gate caught a bad first test and rejected the retry on diff hygiene even though its focused tests passed. That proves the gate, not reliable first-pass quality from the persona. The first dispatch consumed about 251k input tokens and the corrective retry about 63k, reinforcing that this is for batched work, not cheap one-line edits. diff-reviewer remains unexercised on a real job.

Personas are injected as prompt text, not via agy's --agent flag, because --agent silently disables --json-schema enforcement (see below).

persona-evidence.sh validates the fixed shipped-persona registry and reproduces its documentation table. All three shipped personas remain offline-only: their records bind exact frontmatter/mode restrictions and the public P1-C contract bytes, but that synthetic candidate does not execute a persona. Historical real exercises lack the public Receipt/base/verifier/tool bindings needed to promote a registry state. Future upper states require immutable public Git blobs in three strict phases: evidence, separate approval/review, then registry transition. This validates protected-main sequencing and exact bytes/modes, not cryptographic reviewer identity or signatures; portable bundles reject upper states.

Persona Allowed modes Evidence status Public evidence
bulk-test-writer plan, accept-edits offline-only P1-C public contract; persona not executed
diff-reviewer plan offline-only P1-C public contract; persona not executed
repo-inventory plan offline-only P1-C public contract; persona not executed

Statuses are evidence levels, not trust labels or acceptance authority. The registry cannot rank, route, select, execute, promote, or dynamically register a persona.

Data-only workload profiles

profile.sh lists three fixed maintained skeletons without loading a repository or dispatching anything:

./profile.sh list
./profile.sh show bounded-test-backfill

show prints canonical JSON that may suggest one maintained mode, persona, and repo-relative path-policy shape. It is deliberately non-executable and explicitly requires the caller to provide approval, exact repository, exact path policy, selected tier, and verification commands. Profiles contain no repository path, model/tier/effort value, command, external root, authorization, routing, acceptance, dispatch, or Git action. Only the fixed hash-bound bundle is read; target repositories, environment variables, home directories, and caller-supplied profile paths are never profile sources.

Common options

Worker option Environment equivalent Meaning
`--workflow explore task project`
--max-cycles 1..2 explore or task total provider-attempt budget; default 2.
--max-cycles 1..5 project total provider-attempt budget; default 5. Legacy raw mode is exactly one attempt; --max-cycles requires an explicit workflow.
`--mode plan accept-edits` AGY_WORKER_MODE
`--tier cheap bulk hard
--model EXACT_MODEL AGY_WORKER_MODEL reviewed exact slug, or adjustable base used with effort
`--effort low medium high`
--literal-model EXACT_SLUG CLI-only caller-owned pass-through; no matrix claim. A bounded non-gating version observation may support exact diagnostics without changing the selected model.
--workdir DIR agy's workspace
--add-dir DIR repeatable file-tool root; must resolve inside --workdir
--persona NAME Optional bounded worker-role prompt; it does not authorize work or prove quality.
--idle-timeout DURATION AGY_WORKER_IDLE_TIMEOUT no valid progress for this long ends the attempt; default 10m
--hard-timeout DURATION AGY_WORKER_HARD_TIMEOUT; AGY_WORKER_TIMEOUT (deprecated alias) initial per-attempt deadline; default 2h
--max-runtime DURATION AGY_WORKER_MAX_RUNTIME caller-owned absolute cap across extensions; default 12h
AGY_WORKER_JOB_ID safe artifact directory name

Worker exits: 0 ok · 2 no prompt · 3 empty output · 4 schema invalid · 5 unclassified agy failure · 6 permission gate · 7 compatibility review required · 8 compatibility evidence unavailable · 9 idle timeout · 16 hard deadline · 17 provider timeout (reserved) · 18 authentication failure (reserved) · 19 provider unavailable (reserved) · 20 local status, binding, or verification-copy runtime unavailable · 21 resume failure · 22 cancelled · 23 output oversized · 24 provider quota exhausted · 25 provider terminal error with a preserved valid candidate · 26 direct-selection preflight failure · 64 invalid usage.

The reserved 1719 exits require an exact, version-bound reviewed signature. The active agy 1.1.22 baseline has no reviewed signature allowlist for these exits, so an unproven provider timeout, authentication error, or provider outage remains agy_failed_unclassified with exit 5; the supervisor does not infer a reason from free-form stderr.

Exit 24 is narrower than a general rate-limit classifier. It currently recognizes only the exact, structurally valid agy 1.1.13 terminal quota shape reviewed for Issue #59. Status exposes only a bounded, decreasing retry_after_seconds; it never prints the error text, conversation, prompt, model, path, envelope, or raw log. The worker does not sleep, retry, restart, or change the caller's model automatically. Wrong-version or altered quota terminals without a report remain invalid_envelope with exit 4 and failure_stage=missing_structured_output. The exact recognized 1.1.13 quota terminal remains provider_quota_exhausted with exit 24 when it has no report, with failure_stage=missing_structured_output.

Only provider init, step_update, and terminal result events can update v9 last_activity to provider_initialized, progress_signal, or terminal_received. They renew only an idle lease; they never prove success or extend the hard deadline or the caller-owned maximum. The supervisor forwards the maximum as agy's --print-timeout, owns the shorter local clocks and process group, and records only sanitized elapsed/progress-age/count, attempt origin, terminal reason, and resume availability. It never prints progress, prompts, raw stderr, or a conversation ID.

There is no automatic fresh retry or continuation. A candidate-free failed state may offer SHA-approved resume for the exact stored conversation or SHA-approved fresh restart. A valid provider ERROR (exit 25) candidate is unreviewed: obtain it with result, supply driver Verification v2, then continue or finalize. A valid provider CANCELED/CANCELLED (exit 22) candidate is preserved for result and finalization, or an explicit fresh restart; it is never resume- or continue-eligible. None of those outcomes is provider success. status, wait, result, extend, and cancel describe the local controller, not agy/provider status or proven remote cancellation. A locally cancelled job therefore reports remote_cancel_unverified.