Prefix: AGV- Catalog: v1.1 (new pillar). What it measures: the
contract between agent autonomy and human intent — policy-as-code, approval
gates, and explicit bounds on what an agent may change, merge, or deploy
unattended.
Without governance, agent-driven delivery is unbounded authority. This pillar is
how an organization states, in artifacts an assessor can read, where the agent
stops and a human starts. There is no v1.0 AGV catalog; IDs in the AGV-1xx
band are the first published criteria for this dimension.
Criteria in this pillar
AGV-100 — Autonomy bounds published
- Level: 2 · Scope: portfolio · Check: deterministic
- The portfolio publishes a machine-readable policy stating which paths and actions (edit, merge, deploy, secret read, production write) an agent may perform unattended. Each application in the subject is covered, or is listed as an owned exception. Absence of a bound is not an implicit grant.
- Rationale: an agent given a repository and a token will use both. Bounds that live only in chat are not a contract an assessor — or the next agent — can read.
- Evidence expected: a committed policy file, ruleset, or equivalent structured record; actions and path (or application) scopes enumerated; default-deny or an explicit default stated; exception list owned.
AGV-110 — Privileged actions require an approval gate
- Level: 3 · Scope: application · Check: deterministic
- Merge to a production-shipping ref, production deploy, and use of secrets or long-lived credentials require a recorded approval — a human review, a named policy exception, or a two-party check. An agent MUST NOT be the only actor on those actions unless AGV-100 explicitly allows that action on that path.
- Rationale: autonomy without a gate on merge, deploy, and secrets is production write access with extra steps. The gate is how a human remains in the loop for blast-radius actions.
- Evidence expected: branch protection, deploy approval, or equivalent on the production-shipping ref; secret use is not available to the unattended identity without the gate; a sample of recent privileged actions shows the recorded approval.
AGV-120 — Policy-as-code enforced in the pipeline
- Level: 4 · Scope: repository · Check: deterministic
- Autonomy bounds (AGV-100) are enforced in CI or the merge and deploy pipeline, not only documented. A change or action that exceeds the bound fails the job. A wiki policy with no failing check does not satisfy this criterion.
- Rationale: documentation is advice. Agents follow the pipeline. Policy that cannot fail a job cannot bound an unattended operator.
- Evidence expected: a pipeline job or required check that evaluates the bound; a failing fixture or recorded incident where an out-of-bound action was blocked; the check is required on the production-shipping ref.
AGV-130 — Agent identity is distinct and attributable
- Level: 4 · Scope: repository · Check: deterministic
- Agents act under a named identity distinct from any human personal account. Commits, merges, deploys, and tool calls that the agent performs record that identity. Shared human tokens, forwarded personal credentials, or an anonymous bot account used by several agents do not satisfy this criterion.
- Rationale: when something merges at 03:00, the first question is "who". If the actor is a person's token, governance cannot tell agent action from human action, and revocation hits the wrong principal.
- Evidence expected: a named machine or workload identity per agent (or per agent class); audit or SCM records showing that identity on agent-authored commits and deploys; human personal tokens absent from unattended paths.
AGV-140 — Portfolio exception register
- Level: 4 · Scope: portfolio · Check: manual
- Exceptions to autonomy bounds are enumerated per application, owned, and
time-bounded. A newly added application inherits the published default (deny,
unless AGV-100 states otherwise) within one review cadence or is marked
not_applicablewith a one-line justification. An unbounded "just this application" carve-out does not satisfy this criterion. - Rationale: portfolio scoring (CSPC-31) fails closed when one slice is exempt forever. The exception list is how an assessor sees where the agent is still unbounded.
- Evidence expected: a committed exception register; owner and expiry (or
review date) on each entry;
k/napplications under the default bound; cadence stated.
Machine-readable artefacts
The deterministic scanner reads one JSON object per criterion, from
docs/governance/ (or docs/agv/, or an agv-*.json file at the root). Each
file is validated against a closed schema. Unknown fields, aliases, duplicate
entries, and values outside the vocabulary below are schema errors. An object
that declares the same key twice is rejected, because JSON.parse would
silently keep only the last value. A leading UTF-8 byte-order mark is ignored. A
file that is not a JSON object (YAML, JSONC, or free text) fails closed: a
keyword scan cannot prove that a bound or gate is actually enumerated.
Every free-text field, required or optional (owner, cadence, version,
description, justification, expiry, production_ref), must be a string
with at least one visible letter or digit. Whitespace and invisible characters
such as U+200B, U+2060, and U+FEFF do not count.
Dates are calendar dates in YYYY-MM-DD form and are evaluated in UTC against
the scan time. An expiry stays in force through the end of its UTC day.
Action vocabulary
Each token names exactly one action family. A token marked privileged states
the production-reaching form of its family. AGV-110 must gate merge:main,
deploy:production, and secret:use. Narrowing variants are valid tokens, but
they never cover their family.
The actions list in AGV-100 enumerates what the bound governs. Under
default: deny it is the set of actions the policy speaks to, not a grant: an
action is permitted unattended only where the bound or an owned exception says
so. AGV-100 must list every privileged token so that none is left ungoverned.
| Token | Family | Kind |
|---|---|---|
edit | edit | privileged |
merge:main | merge | privileged |
merge:preview | merge | narrowing |
deploy:production | deploy | privileged |
deploy:preview | deploy | narrowing |
secret:use | secret | privileged |
secret:rotate | secret | narrowing |
production:write | production | privileged |
Path scopes
Application paths are relative, /-separated literal segments. Each segment
starts with a letter, a digit, _, or @, and continues with letters, digits,
_, ., @, or -. A single trailing / is allowed. The scanner rejects the
following.
- Globs and pattern characters are rejected:
*,?,[ ],{ },!,( ), and+. .and..segments, a leading/, an empty segment (//), and backslashes are rejected.- Hidden segments such as
.githubare rejected, because a segment cannot start with.. Bound the parent directory instead. - Next.js route groups and dynamic segments such as
(marketing)or[slug]are rejected. Bound the enclosing literal directory instead, for exampleapps/site/src/app.
Files and fields
- AGV-100
autonomy-bounds.json:- Required:
default(deny),owner,actions(tokens above),applications[], andexceptions[]. - Each application has an
idand concretepaths, plus an optionaldescription. - Each exception has an
applicationand anowner, plus an optionaljustificationand an optionalexpiry. When present, the expiry must be a real calendar date that has not passed. If any exception is past its expiry, the whole file fails AGV-100. - Optional at the top level:
versionanddescription.
- Required:
- AGV-110
approval-gates.json:- Required:
gates[]. Optional:version,description, andproduction_ref. - Each gate has exactly an
action(a token above) and anapproval, which is one ofhuman_review,required_review,codeowners,two_party, ornamed_exception, plus an optionaldescription. - Any other gate field, such as
required,enabled,approver, orrequired_approvals, is a schema error, so a gate cannot be switched off or delegated through a sibling field.
- Required:
- AGV-120
policy-as-code.json:- Required:
required_checkandon_violation, which is one offail,block, orreject. - Optional:
enforced_in(one ofci,merge-queue, ordeploy),production_ref,version, anddescription. - Without the file, a source file named
agv-guard,autonomy-check, orpolicy-as-codeundersrc/counts.
- Required:
- AGV-130
agent-identity.json:- Required:
agents[], each with anid, anidentity, and akind, which is one ofworkload,machine,github-app,service-account, orbot. Each agent may also have adescription. - Optional at the top level:
versionanddescription. - An
identitytakes one of three forms:- The general form starts with an ASCII letter or digit, contains only ASCII
letters, digits, and
: . _ @ / + = , -, and may end in[bot]. It coversgithub-app:wentzel-carl, GitHub App bot logins such asdependabot[bot], and IAM names such asrole/carl+builder. - A GKE Workload Identity, such as
my-project.svc.id.goog[carl/carl-scanner], optionally prefixed by an organization domain (example.com:my-project.svc.id.goog[…]). - An Azure resource ID that starts with
/subscriptions/.
- The general form starts with an ASCII letter or digit, contains only ASCII
letters, digits, and
- An
identityis at most 2,048 characters, the AWS IAM ARN maximum. - The identity is rejected in any of these cases:
- It is a shared or public principal:
bot,shared,everyone,allUsers,allAuthenticatedUsers, orsystem:authenticated, ignoring case and trailing separators. - It names a set of principals rather than one: a
principalSet:ordomain:identifier, Kubernetessystem:serviceaccounts(with or without a namespace), orsystem:masters. - Its final segment (after the last
:or/) is exactlyeveryone, as ingroup:everyone. A named app such asgithub-app:everyone-notifieris still accepted. - It has an
anonymous,unauthenticated, orpersonaltoken, or anAWSReservedSSOtoken (an IAM Identity Center session, which is always a person). Tokens are split on every non-alphanumeric character, sogithub-app:personalization-svcis still accepted. - It contains both
@andpersonalanywhere, so a role session named after a personal email address is rejected. - It contains
ghp_orusers/anywhere. It also fails when agho_,ghu_, orgithub_pat_credential prefix appears at the start or after any non-alphanumeric character. - It contains
@and is not a service-account email (exactly one@, followed by a domain that ends in.gserviceaccount.com) or an AWS IAM role ARN in theaws,aws-us-gov, oraws-cnpartition. A role or session name in such an ARN may contain@(role/svc@build), but an email-shaped name (assumed-role/ci-deployer/ryan@gmail.com) is still rejected.
- It is a shared or public principal:
- Each
idand eachidentityappears at most once, so one agent's actions cannot be confused with another's.
- Required:
- AGV-140
exceptions.json:- Required:
cadence, ak/nview (integerk≤n, orapplications[]with anidand a booleanin_bound), andexceptions[]. - Optional at the top level:
default(deny),version, anddescription. - Each entry is either an
applicationwith anownerand anexpiry(plus an optionaljustification), or anapplicationwithnot_applicable: trueand ajustification. - An
expirymust be a real calendar date that has not passed and is at most 366 days ahead. The expiry day itself is still in force.
- Required:
Related
- v1.1 pillars — draft catalog, including these AGV-1xx criteria.
- Cost & FinOps — spend ceilings an unattended operator must honour.
- v1.0 specification — the published standard.