Docs
Execution grants
The grant carries authority. It does not prove that authority was consumed.
A decision says what may happen. A grant says what authority was issued for one operation, against one target, for a bounded time. It is the permission object, and it is a separate thing from the evidence that something happened.
The eight fields that carry the model
what is authorized
operationtarget_uriagainst which context
executor_idadapter_idtenant_idunder which constraints
expected_state_tokennonce_hashuntil when
expires_atTogether, these say what operation is authorized, against which target and execution context, under which freshness and replay constraints, and until when.
What the grant proves
Everything in this section follows mechanically from the seventeen signed fields. A verifier with the right key and no network can establish all of it.
- That a named issuer signed this exact statement —
kidresolves the key, and the signature covers the whole body. - That the authority is for one operation against one canonical target, not a class of either.
- That it was issued against a specific decision receipt —
receipt_hash. - That it is bound to one executor and one adapter, so a different one does not match.
- That it has a validity window, and that the window is signed.
What makes it usable
Only what ships. Verification against a pinned keyring is offline and needs no CodeRifts call. Expiry and not_before are read from the signed body. Scope binding — executor, adapter, target, operation — is a byte comparison against the presented context.
The implicit default grant version is dated: a caller that omits grant_version is served by that default, and the date it changes is in the code. This page describes the mechanism, not today's answer — whether the default you receive is cr.exec.v1 or cr.exec.v2 is not something this page can tell you.
What makes it single-use
nonce_hash
The grant carries a nonce for single-use enforcement.
not by itself
Single-use is a property of the consuming enforcement path, not of the signed grant.
The signed grant does not make itself single-use. It carries nonce_hash. Single-use requires a consuming enforcement mechanism that rejects reuse.
The shipped guard does not attest nonce consumption. Where its result classifies nonceConsumedOnce, that value is supplied by the host. Reading the guard result therefore means reading the host's assertion about consumption, not a CodeRifts observation of consumption.
Measured 2026-09-17: consumeOnce appears in the adapter layer of the capability demo and in the conformance package. It does not appear in the shipped guard's source. The commit observation the guard emits is reported, and it does not turn any decision into a refusal.
What it does not prove
- That the authority was consumed. See the section above — this is the one that matters most, and it is why it has its own heading.
- That the tool call which followed matched the authority. The grant does not bind the canonical tool-call bytes; that field is reserved and inert, and a verifier that reads its presence as authorization is wrong.
- That the target actually moved. The after-state is observed by a separate read-back, in a different layer; it is not a field of the grant.
- That a merge, a deploy or a push was stopped. A grant is issued authority, not an enforcement event.
Full grant fields
Seventeen fields, plus one that appears only when the caller supplies it. Measured from the shipped issuer on 2026-09-17.
| field | type | required | meaning |
|---|---|---|---|
v | string | required | The grant format. cr.exec.v2 today when the caller asks for it by name. |
kid | string | required | Which signing key produced the signature. A verifier resolves it against a pinned keyring. |
grant_id | string | required | A UUID minted per grant. The attestation binds this id. |
receipt_hash | string | required | sha256 of the decision receipt this grant was issued against. |
tenant_id | string | required | Whose grant it is. |
executor_id | string | required | Which executor may present it. A different executor does not match. |
adapter_id | string | required | Which adapter may spend it. |
operation | string | required | The operation authorized — not a class of operations. |
target_uri | string | required | The canonical target. The scheme set is closed: fs, git, api, db, registry, deploy. |
expected_state_token | string | required | The state the target must be in before the change. Defaults to sha256: of the empty string when the caller supplies none. |
after_payload_hash | string | required | sha256 of the intended after-payload. A different payload does not match. |
nonce_hash | string | required | sha256 of the nonce. The hash, not the nonce. See the single-use section below. |
policy_hash | string | required | Which policy was in force. Normalised to sha256: form. |
audience_hash | string | required | sha256 of the intended audience. |
not_before | integer | required | UTC seconds. Earlier than this, the grant is not yet valid. |
expires_at | integer | required | UTC seconds. After this, the grant is expired. |
max_attempts | integer | required | How many attempts the grant admits. |
environment | string | present only when supplied | Staging and production grants were byte-identical without it. Omitted when absent, never defaulted to a string — writing an empty value would change the signature of every grant that never asked for the field. |
Two names that are easy to get wrong
nonce_hashis notnonce. The signed body carries the hash. A page, a diagram or an SDK that calls itnonceis describing a field that is not there.- The after-state token and the receipt's own binding hash are not grant fields. They belong to the target-state transition layer and to the receipt respectively.