ADR-076: An unattended run gets its git and gh permissions per session from a checked run allowlist, never from a settings file
Status: Accepted (2026-11-03) Amends: ADR-037 — cplat commands that bundle steps never widen the session’s permissions (cplat bundles also honour the run allowlist); spec 131
Context
Section titled “Context”A non-interactive claude -p session cannot ask for approval. When it tries an action that no allowlist grants, the
action is refused, and the run escalates after it has already spent its budget. Between 3 and 4 escalations a week were
git or gh actions refused this way (retro #207). The platform repo has no committed allowlist at all. Editing a user’s
or a repo’s settings to fix this would change files the user owns and would grant the actions to every later session too.
Decision
Section titled “Decision”-
The run allowlist is fixed per command. It covers only what an unattended run needs beyond file edits:
- create and switch to the spec’s feature branch;
- stage and commit with sign-off;
- push that branch without force;
gh pr create;- merge only through
cplat component ship land(andcplat system ship entry land), which merge on green checks.
/system:shipusesfeature/*, because its repo branches are not known in advance. -
It is granted per session. Every session of the run is started with
--allowedTools <run allowlist>and--disallowedTools <refused rules>(force push, push to the default branch,gh pr merge,gh api …merge…,cplat pr wait --merge). This is in addition to the repo’s committed allowlist. No settings file is created or changed. -
A preflight runs before anything is spent. Before the first session it checks:
- the repo’s committed allowlist;
- the deny and ask rules of every settings layer (managed, user, project, local) against a representative command of each action;
- the git author identity, the
ghlogin for the remote’s host, and push access.
A failure starts no session and prints
preflight failed: <category>: <detail>. The run is recorded as escalated with the causeenvironment. -
cplat’s bundles read the same grant. Sessions get
CPLAT_RUN_ALLOWLIST, andcplat pr openaccepts its rules the way it accepts the settings files’ allow rules (ADR-037). A deny or ask rule in a file still wins.
Consequences
Section titled “Consequences”- An unattended run no longer stops on an approval nobody can give, and what it cannot be granted fails at second 0 with $0 spent.
- A user who wants an action refused keeps that power: a deny or ask rule anywhere makes the preflight fail with the rule and its file named, and it never overrides the rule.
- The refused rules are glob patterns, and a wrong pattern could refuse a legitimate push. The matcher and the patterns are tested together.
Not included
Section titled “Not included”- Writing or proposing changes to any settings file (making a repo’s committed allowlist fit stays a template change).
- A preflight for fleet commands.