Capability Grants
What you'll learn
- Why Craik refuses ambient authority and what a capability grant is.
- The three practical outcomes of a grant check.
- The grant shape, with a worked example.
- Which capability hooks the v0.1.0 runtime enforces today.
Capability grant
An explicit, scoped permission to perform a specific capability against a specific target. Grants compose with policy profiles: the profile sets default posture, grants narrow that posture to what's authorized for the current task.
No ambient authority
Craik does not grant agents ambient authority. An agent can't "write to the docs because it's a docs agent." Side effects require a matching grant that names:
- The capability —
repo.write.docs,shell.execute,github.write,memory.write. - The target — a path glob, a remote URI, a memory scope.
- The operations —
write,execute,propose, etc. - The reason — short, human-readable. Reviewers read this first.
- The approver — the operator identity that authorized the grant.
When the check runs, there are three outcomes:
alloweddeniedstatus: denied for audit.requires_approvalThe grant shape
{
"schema": "craik.capability_grant",
"version": "0.1.0",
"id": "grant_docs_write",
"task_id": "task_docs",
"capability": "repo.write.docs",
"target": {
"paths": ["docs/**"],
"exclude": ["docs/adr/**"]
},
"operations": ["write"],
"reason": "Documentation update for task_docs.",
"approved_by": "user:maintainer"
}
Read the fields top-to-bottom. The grant is reviewable on its own — you don't need to chase down a separate "what does this mean?" reference.
Immutable paths: grants alone are not enough
ADR directories and other declared immutable paths are denied by default under every profile. Writing to one requires both:
Override metadata
approved_by— the operator identity that authorized the override.reason— short, human-readable justification.- Attached at the action site, not buried in policy config.
A matching grant
- Capability must be
repo.write.immutable(notrepo.write.docs). - Target must match the immutable path being changed.
- Grant is task-scoped — it expires with the task.
This belt-and-suspenders rule is intentional. Immutable evidence is the backbone of audit; "I forgot the grant" should not be able to overwrite an ADR by accident.
The four capability hooks today
repo.write.docs
Documentation writes to declared doc roots. Most common grant.
repo.write.immutable
Writes to immutable paths. Requires override metadata and the matching grant.
shell.execute
Shell command execution. Sandbox backend enforces additional restrictions.
github.write
GitHub side effects: PRs, issues, comments, reviews.
memory.write
Direct memory writes. Without this grant, runs leave proposals instead.
The v0.1.0 hook layer checks whether a matching grant exists. Runtime provider and tool-call paths call these checks before performing side effects — there is no "try and fail" path that lets the side effect happen under a denied posture.
Denied receipts
When a check fails, Craik can produce a receipt with status: denied. This
is intentional — the audit trail captures attempted-and-refused actions the
same way it captures successful ones. The denied receipt names the missing
capability, the target, and the operator who would have authorized it.
craik receipts list --status denied gives you the queue of denied
attempts. Frequent denials in the same shape are usually a signal that the
policy envelope or grants need to widen narrowly — not that the runtime
should be looser overall.