Decide a permission ask
Allows or denies a pending ask, optionally remembering the decision for the session or permanently. A denial is reported to the agent with its reason and the agent continues rather than crashing. Every decision is recorded in the audit. Deciding an already-decided ask is a conflict.
Path Parameters
The permission ask's id.
Body
A decision on a pending permission ask. A denial is never remembered: remember must be none (or absent) whenever decision is deny, and any other combination is refused with 400. The host offers four answers — allow once, allow always in this project, allow always globally, and deny with a message — so a remembered refusal is not one of them, and the prompt states before the answer exists that remembering would grant an allow rule.
allow, deny Scope to remember the decision at — none decides only this ask, session remembers for this session, project appends a rule scoped to this repository, global appends a rule to the user's own configuration. Two "always" scopes rather than one because "fine in THIS repository" and "fine everywhere I work" are different claims, and a single "always" forces everybody to over-grant. Only an allow is remembered; any scope other than none alongside decision=deny is a 400.
none, session, project, global Optional correction shown to the agent, useful on deny. It reaches the model verbatim as something it can act on: a denial saying only "denied" teaches nothing, so the model tries a variant and burns the turn, while "do not push to main, open a PR branch instead" ends the exchange.
4096Response
The recorded decision. This operation answers a PENDING ask and 409s anything else, so decidedBy and decidedAt are always present in this response. They are optional on the shared schema because the audit listing reports expired entries too, which nobody decided — a client reading only this operation may treat both as guaranteed.
One entry of the decision audit. There is exactly one decision per ask, so the decision's id IS the ask's id: id and permissionId carry the same identifier.
WHAT IS RECORDED, stated here because it is narrower than "every decision" and deliberately so: every ASK and its answer, whoever answered it, and every DENY — including the ones taken without asking anybody, which is the shape almost every denial has in unattended work. A rule-derived ALLOW on a free action is NOT a row. Recording every permitted read would write thousands of rows per session and bury the two questions this audit exists to answer — what was denied and why, and what did I approve.
AND A DECISION IS NOT A RECORD OF EXECUTION. It says what was decided, not what ran: a call interrupted in the same instant its decision was released can leave an allow here for something that never happened. Read it as the trail of judgements, and the transcript for what followed.
expired is an ask nobody answered before the call it was blocking ended. It carries no decider and no decidedAt, because "nobody answered" is itself the finding when somebody asks why an action did not happen.
allow, deny, expired When the decision was raised. It is what the audit is ordered and paged by, so a page boundary is stable while new decisions land.
1284096Who decided — a human, the policy deciding without asking (which includes a rule that landed after the ask was raised and covered it), or the configured executable at the permission-ask decision point. Absent on an expired entry.
user, policy, hook Why, in the decider's own words: a person's message on a deny-with-message, the rule a policy refusal names, or the hook that decided — a hook denial that does not say which hook is an audit trail ending in a shrug. Absent when the outcome speaks for itself.
4096none, session, project, global Absent on an expired entry, which nobody decided.

