Policy rules
Describe what one runtime may do, in one JSON file.
The configuration file
{
"runtime": {
"human": "[email protected]",
"agent": "coding-agent",
"runtimeId": "local-development",
"task": "bootstrap"
},
"repositories": [
{
"name": "acme/payments",
"id": 123456789,
"installationId": 12345678,
"allowWorkflowWrites": false,
"protectedBranches": ["main"]
}
],
"rules": [
{ "id": "read-repository", "action": "git.read", "repository": "acme/payments", "effect": "allow" },
{ "id": "feature-branches", "action": "git.push", "repository": "acme/payments", "ref": "refs/heads/agent/*", "effect": "allow" },
{ "id": "review-main", "action": "git.push", "repository": "acme/payments", "ref": "refs/heads/main", "effect": "approval", "approvals": 2, "reviewerSources": ["oidc"] },
{ "id": "protect-tags", "action": "git.push", "repository": "*", "ref": "refs/tags/*", "effect": "deny" },
{ "id": "protect-deletions", "action": "git.push", "repository": "*", "ref": "*", "operation": "delete", "effect": "deny" }
]
}Evaluation
- Unmatched actions are denied.
- Deny beats approval, approval beats allow.
- Repository reads (
git.read) are required for both fetch and push discovery. - Each push is inspected before forwarding. If any ref is denied, none of the request is forwarded.
Rule fields
| Field | Values |
|---|---|
id | Unique rule name, recorded in audit |
action | git.read, git.push, git.lfs.upload, github.pr.read, github.pr.create, github.pr.comment, github.pr.merge, github.actions.read |
repository | OWNER/REPO or * |
ref | Exact ref, trailing-* prefix (refs/heads/agent/*), or * |
operation | Optional: create, update, or delete |
effect | allow, deny, or approval |
approvals | 1–5 distinct reviewers (approval rules) |
reviewerSources | Subset of local, oidc (approval rules) |
requires | Entitlement requirements |
A push touching several approval-gated refs takes the maximum approvals across matching rules.
Repository options
Workflow files
To allow pushes that edit .github/workflows, grant the App Workflows: write and set allowWorkflowWrites: true. This defaults to false and only applies to Git write tokens.
Push options
git push -o <option> is forwarded only when the option is listed in allowedPushOptions (exact strings or a prefix* wildcard; up to 32 entries; default none). A bare * allows any value. Disallowed options get 403 PUSH_OPTION_DENIED.
Option values are agent-controlled free text, so they are never stored — only a count and a SHA-256 digest, which binds the exact set into any approval.
Unicode ref names
Refs are ASCII-only by default. allowUnicodeRefs: true accepts NFC-normalized names without control characters, whitespace, bidirectional overrides, or zero-width characters. Rule patterns and protectedBranches stay ASCII-only, so a Cyrillic homoglyph of main can never match the rule written for the real main.
Content scanning
See Content scanning.
Reloading
Send SIGHUP to reload (docker compose kill -s HUP agentd). Invalid configs, and new protected branches without GitHub rules, are rejected; the previous policy keeps serving. A reload that changes policy supersedes outstanding approvals — reviewing one returns 409 APPROVAL_SUPERSEDED, and the agent retries to create a new request.
API actions
API actions default to deny and are separate from Git push authorization. All also require git.read.
| Action | Scope | GitHub App permission |
|---|---|---|
github.pr.read | Repository; allow/deny | Pull requests: read |
github.pr.create | Repository, head ref, optional headRepository; allow/deny/approval | Pull requests: write |
github.pr.comment | Repository; allow/deny | Pull requests: write |
github.pr.merge | Repository, base ref, headRepository, mergeMethods; approval/deny only | Pull requests: read, Contents: write |
github.actions.read | Repository; allow/deny | Actions: read |