Admission Gates
Central Agentic Ops admits a run only when its checked-in control policy authorizes the workflow identity and requested limits. Admission happens in the gh-aw pre-activation job, before activation and before any agent executes.
The hosted Go server also supports the separate
gh-aw cooperative activation-admission protocol
at POST /api/admission. That optional OIDC-authenticated cost gate does not
replace the control-policy checks described here and cannot enable campaigns,
widen target scope, or grant writes.
Once that authority is deployed and the repository is explicitly enrolled, configure the participating workflow’s repository variables with the native CLI:
# Preview without changing variables.gh cao setup admission --repo OWNER/REPO --url https://cao.example.org/api/admission --dry-rungh cao admission setup --repo OWNER/REPO --url https://cao.example.org/api/admissiongh cao admission status --repo OWNER/REPO --jsongh cao admission disable --repo OWNER/REPO --dry-rungh cao setup admission and gh cao admission setup configure the same
non-secret variables; no workflow secret is needed for OIDC authentication.
Setup and disable apply changes unless --dry-run is supplied.
Setup uses the URL as the default audience and defaults outages to block.
After initial setup, omit --url to reuse the target’s configured server or
the current control repository’s configured server for fleet rollout/recovery.
See Set up the admission gate for authority preparation,
local readiness checks, a live canary, rollout, and troubleshooting.
--audience and --on-outage ignore are explicit overrides. Status includes
inherited organization settings; disable shadows them with an empty repository
URL instead of deleting the override. These commands neither deploy the
authority nor enroll repositories, compile workflows, or alter CAO policy.
For bulk rollout, replace --repo with one of these mutually exclusive selectors:
gh cao setup admission --all-repos --url https://cao.example.org/api/admission --dry-rungh cao setup admission --org acme --org engineering --url https://cao.example.org/api/admission --dry-rungh cao setup admission --enterprise company --url https://cao.example.org/api/admission --dry-runRemove --dry-run to apply. --all-repos uses the validated local CAO global
scope: exact repository allowlists, or the visible repository inventory of each
allowed organization. Personal owners require exact repository lists.
--org provisions variables with visibility all, including future
repositories. Enterprise rollout enumerates organizations and configures each
organization’s variables; there is no enterprise variable scope. Existing
repository overrides still take precedence. Enterprise read access does not
substitute for organization Variables write permissions.
status and disable accept the same selectors. Bulk preflight reads all
targets before mutation; write failures report completed targets and stop
without automatic retry or rollback. The limit is 1000 targets per command.
trigger -> pre-activation admission -> authorized-run precompute -> activation -> agent | denied | blocked +----------------------+-> no agent executionAdmission queries the GitHub rate-limit API and uses the returned core limit, remaining capacity, and reset time directly. It does not read or write a repository variable to coordinate capacity decisions across runs.
The former CAO_GITHUB_API_GATE repository variable is not an authority or integrity input and is no longer used. Capacity is checked directly with the job-local credential, so there is no shared mutable gate or concurrent gate writer.
There is no .github/cao/src/report.mjs in the current control runtime. Admission reporting is emitted by .github/workflows/shared/control.mjs; dashboard reporting is the separate modular pipeline under dashboard/report/.
What Admission Gates
Section titled “What Admission Gates”The shared control component keeps one canonical runtime under .github/workflows/shared/. The exact-github.workflow_sha shared checkout contains that runtime and .github/workflows/cao.json; authorized runs execute precompute from the same checkout.
| Check | Admitted when |
|---|---|
| Runtime revision | github.workflow_sha is an exact commit and the policy and both CAO modules are readable at that revision. |
| Policy document | The JSON has supported keys, types, ranges, unique names, no duplicate keys, and no GitHub Actions expressions. |
| Control plane | control-plane exists. |
| Workflow identity | The workflow declares orchestrator, worker, or standalone; workers declare an exact worker identity, while standalone workflow slugs must match the actual compiled workflow reference. |
| Campaign | The campaign, or standalone workflow under control-plane.workflows, is declared and not disabled. |
| Worker | A worker is declared under that campaign and not disabled. |
| Target input | A supplied target_repo uses exact owner/repository form. Scope and access are checked later during precompute. |
| Mode input | review or live does not exceed the checked-in ceiling; request-only debug passes the manual worker and human authorization gates below. |
| Run limits | max_repos and rollout_percent are valid and do not exceed checked-in policy. |
| GitHub API capacity | The credential used for precompute has enough primary REST API capacity for the run. |
A manual dispatch can narrow a run, such as changing an authorized live run to review or reducing max_repos. It cannot promote mode, add scope, enable a standalone workflow, campaign, or worker, or increase a limit.
Standalone workflows use these same gates without campaign records or worker discovery. Precompute admits a deterministic repository set through the shared scope, inventory, percentage, and repository limits; each candidate carries its effective mode and output route. The workflow executes its own mission directly on that set and cannot discover additional targets or dispatch work. Required inventory failures prevent activation. See standalone workflow configuration.
Manual Debug Admission
Section titled “Manual Debug Admission”debug is accepted only for a directly launched workflow_dispatch worker,
not an orchestrator, scheduled run, or bot dispatch. Admission verifies the
authoritative event inputs and human sender, rejects a different rerun actor,
and checks that the sender still has write, maintain, or admin permission on
the control repository. Missing event or permission evidence denies the run.
Precompute repeats that check before producing the worker handoff.
Debug retains exact-SHA policy validation, campaign and worker enablement, target scope, request limits, credential requirements, and API-capacity checks. It replaces only dispatcher-envelope requirements: correlation ID, central repository, and originating-run URL inputs must be empty. The output repository must equal the explicit target; no review destination is resolved because gh-aw stages every declared output. Debug cannot be persisted as a policy mode or dispatched by an orchestrator. See Local Worker Debugging for launch commands, staging behavior, and the local-origin limitation.
Worker Dispatch Trust Boundary
Section titled “Worker Dispatch Trust Boundary”workflow_dispatch authenticates the caller as the GitHub App bot that holds the write-App credential. Allowlisting that bot preserves safe-output worker dispatches, but its login alone is not cryptographic proof of a particular orchestrator run, App installation, or dispatch envelope: a holder of the same App credential can submit equivalent workflow-dispatch inputs directly.
CAO therefore treats the write-App credential, its control-repository secret, and its selected installations as part of the trusted control-plane boundary. A worker independently fails closed unless the policy at its exact workflow SHA declares its campaign and worker, keeps both enabled, accepts the requested mode and output route, and accepts the target owner and any exact repository allowlist. The target repository cannot widen, narrow, or veto this authority through its own files. These checks prevent a dispatch from widening policy, campaign, target, or mode, even when the caller has the allowlisted bot identity.
The correlation ID and control-plane run URL provide audit linkage only; they are dispatch inputs and cannot establish provenance by themselves. A deployment that requires proof that only a particular orchestrator run issued a worker dispatch needs a signed, replay-resistant envelope generated outside the agent-visible dispatch inputs (or a GitHub-provided source-run attestation). Do not treat the App login, installation access, or a matching run URL as a substitute for that stronger guarantee.
What Precompute Gates
Section titled “What Precompute Gates”Admission is deliberately lightweight and repository-local. Once admitted, .github/workflows/shared/control.md runs deterministic precompute checks that need credentials, repository metadata, inventory, or usage evidence.
| Admission | Authorized-run precompute |
|---|---|
| Validates policy and workflow identity | Resolves repository inventory and allowlists |
| Rejects disabled or undeclared campaigns and workers | Verifies target and review-repository access |
| Prevents manual inputs from widening policy | Binds live workers to centrally authorized targets and output routes |
| Computes policy ceilings | Applies repository, rollout, and dispatch limits |
| Uses only the control repository revision | Confirms installed worker workflow availability and binds output routing |
Failure in either phase prevents agent execution. Admission denial skips activation; precompute fails closed when an authorized run cannot establish a required remote fact. Successful precompute uploads only control-precompute.json; the agent job restores and validates that non-secret artifact before checkout or model invocation.
Connect Setup and Policy
Section titled “Connect Setup and Policy”Setup creates one atomic control-plane revision:
- Install the gh-aw campaign from an immutable CAO tag or commit.
- Verify that campaign installation copied
.github/workflows/shared/control.mjsand.github/workflows/shared/policy.mjs. - Declare the installed campaign and its worker-to-workflow mapping in
.github/workflows/cao.json. - Commit the workflows, generated locks, campaign records, and policy together, then push before running the campaign.
The Bash installer installs the explicit CAO root package and creates the consumer-owned policy. The package provides one runtime copy under .github/workflows/shared/. Controlled workflows receive it through their existing exact-SHA shared checkout; they do not fetch another copy from the CAO repository. Follow Set Up CAO to bootstrap the repository and configure its exact scope interactively.
Control-plane installation does not declare an operational campaign in consumer-owned policy or grant admission. The CAO setup procedure and checked-in control policy own those decisions.
The Configuration Reference defines every policy field. The phase that uses each group is:
| Configuration | Admission effect | Precompute effect |
|---|---|---|
control-plane.campaigns and workers | Declares and enables the exact workflow identity. | Resolves installed worker workflow paths. |
control-plane.workflows | Declares and enables the exact standalone workflow identity. | Admits its bounded repository set without worker workflow discovery. |
mode, target mode, and worker max-mode | Establishes the maximum mode a dispatch may request. | Re-resolves the central ceiling before worker execution. |
max-repositories and rollout-percent | Rejects a wider manual request. | Bounds selected repositories. |
scope | Validates and returns the configured owners and repositories. | Filters inventory and rejects out-of-scope targets or review destinations; workers also reject targets outside a configured exact repository allowlist. |
inventory | Validates scan, cell, and batch limits. | Performs bounded discovery and deterministic batching. |
Diagnose a Skipped Run
Section titled “Diagnose a Skipped Run”Open the run summary and expand Central Agentic Ops admission. An authorized run names its campaign and role, and every check in the list is marked ✅. A denied run records a reason, marks every check before the failing one ✅, marks the exact failing check ❌, and leaves activation skipped. The ❌ marker identifies which row of the table below to consult; later checks are left unmarked because admission stopped before reaching them.
| Reason | Check marked ❌ | Configuration or setup to check |
|---|---|---|
| Cannot read or execute CAO runtime | Runtime revision | Verify that the CAO root package installed .github/workflows/shared/control.mjs and policy.mjs and that both exist at the workflow revision. |
control policy validation failed | Policy document | Validate policy keys, types, ranges, unique names, and expressions in .github/workflows/cao.json. |
control-plane-absent | Control plane | Add control-plane to .github/workflows/cao.json. |
role must be orchestrator, worker, or standalone, worker identity is required, worker identity is forbidden for orchestrators | Workflow identity | Fix the role and its workflow or worker identity. |
standalone workflow identity must match GITHUB_WORKFLOW_REF | Workflow identity | Set the standalone import’s workflow to its exact compiled filename slug. |
workflow-undeclared, workflow-disabled | Campaign | Review the standalone entry under control-plane.workflows and its enablement. |
campaign-undeclared | Campaign | Add the installed campaign under control-plane.campaigns. |
campaign-disabled | Campaign | Review the campaign, then remove enabled: false when it is safe to resume. |
worker-disabled, unknown worker: <campaign>/<worker> | Worker | Review the worker, then remove enabled: false or declare it under control-plane.campaigns.<campaign>.workers when it is safe to resume. |
target_repo must use owner/repository form | Target input | Fix the target_repo manual input to the exact owner/repository form. |
safe_output_mode exceeds checked-in policy, safe_output_mode must be review or live | Mode input | Narrow the requested safe_output_mode, or raise the checked-in campaign, target, or worker mode/max-mode ceiling. |
debug ... | Mode input | Launch a worker manually as a write-authorized human, use an in-scope target as the output repository, and omit dispatcher-envelope inputs. Inspect the exact reason for missing event or permission evidence. |
max_repositories exceeds checked-in policy, rollout_percent exceeds checked-in policy, or an integer-range message | Run limits | Narrow the requested max_repos/rollout_percent, or raise the checked-in max-repositories/rollout-percent. |
github-api-capacity-insufficient, github-api-capacity-unavailable | GitHub API capacity | Follow the remediation guidance in the run summary and wait until the reported reset time before retrying. |
Fix the checked-in setup or policy, commit and push the new revision, then start a new run. Do not bypass admission by editing a generated .lock.yml file or by widening manual inputs.