> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pnbr.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Approval

> A delete, a publish or a paid run by an API key or a connected agent waits until an owner or admin approves it.

Concept · access

> **Use when**
>
> A command returned `pending` or exit code 4, or you plan a change that deletes, publishes or spends credits.

> **Looking for something else?**
>
> A change that was refused for a missing permission (card [Credential](https://docs.pnbr.io/concepts/credential.md)). A request whose reply was lost (problem [The reply to a change was lost](https://docs.pnbr.io/troubleshooting/reply-lost.md)).

## For

A project keeps an approval policy. The policy names the effects that need a
person's approval before an agent can do them. The default effects are
destructive, publication and paid. You may ask for one of these with an API
key or as a connected agent. Penumbra then holds your request and gives you a
handle and an approval URL. An owner or admin then approves or denies it.

A Kit set to confirm asks for every save, whatever the policy says.

## Use when

* A command exited with code 4 and printed `outcome: pending`.
* An MCP result says `pending_approval`.
* You will delete, publish or run a paid extraction with an API key or as a
  connected agent.

## Not this

* A permission or role is missing: the result is a refusal, not `pending`.
  Ask an owner for the role (card [Credential](https://docs.pnbr.io/concepts/credential.md)).
* You sent a change and got no reply: use problem [reply-lost](https://docs.pnbr.io/troubleshooting/reply-lost.md).

## Rules

1. `approval.1` The policy holds an effect only for an API key or a connected
   agent. A person's own signed-in session never waits. **Enforced:** for a key
   or a connected agent, a held effect returns `pending`. The default effects
   are destructive, publication and paid. An owner or admin can change them
   with `penumbra approvals policy set`.
2. `approval.2` These changes wait under the default policy. Destructive:
   `penumbra files trash`, `penumbra files collections delete`,
   and `penumbra graph delete`. Publication:
   `penumbra graph workspace submit`. Paid: `penumbra graph extract`,
   `penumbra extractions try-again` and `penumbra shapes new` with `--brief`. A workspace submit that deletes
   entities is destructive as well. The server reads the workspace itself, so
   you cannot hide a delete. Shape draft work (`penumbra shapes push`,
   `penumbra shapes publish` and `penumbra shapes drop`) is the effect
   `shape_change`, and the default policy does not hold it. An owner or admin
   can add `shape_change` to the policy with `penumbra approvals policy set`.
   **Your job:** expect the wait. `penumbra status --explain "<command>"`
   reports a wait for destructive and paid commands only. It does not report
   one for a submit or a publish.
3. `approval.3` `pending` means nothing has changed yet. It is not a failure.
   **Enforced:** the CLI exits with code 4 and prints the approval URL, a
   handle, the request id and the next command. An MCP call returns
   `pending_approval` with `operation_handle`, `approval_url` and `expires_at`.
4. `approval.4` Follow the handle and do not send the change again. **Enforced
   when you ask:** the same request id and the same body return the same
   handle. A different body under that request id is refused with
   `idempotency_conflict`. **Your job:** run `penumbra operations wait <handle>`.
   A new request id is a new request.
5. `approval.5` Only a signed-in owner or admin decides, also for requests from
   their own agents. **Enforced:** any other caller is refused with
   `project_admin_required`. An owner or admin decides with
   `penumbra approvals approve` or `penumbra approvals deny`. You cannot
   approve your own request.
6. `approval.6` An approval covers the exact thing you asked for. **Enforced:**
   if the policy changed, or the target changed, before the approved request
   runs, Penumbra refuses it. The reasons are `policy_changed` and
   `target_changed`. A new File version, a change to a collection's members, or
   a new workspace revision changes the target.
7. `approval.7` An approval request expires after 24 hours. **Your job:** if it
   expired, ask the person again before you send the change again.
8. `approval.8` An approved change runs once. **Enforced:** a run that ends with a
   server error, a timeout or a lost reply has the result `unknown`. Penumbra
   does not run it again. **Your job:** read the state before you try
   again (problem [reply-lost](https://docs.pnbr.io/troubleshooting/reply-lost.md)).
9. `approval.9` Following or stopping an extraction never waits. A stop keeps
   what the run found. **Enforced:** `penumbra graph extractions` and
   `penumbra graph extractions stop` do not return `pending`.

## Failure signs

* A change returned `pending` and you ran it again with a new request id: you
  now have two requests waiting (rule [approval.4](https://docs.pnbr.io/concepts/approval.md#rule-approval-4)).
* An approved change was refused with `target_changed`: someone changed the
  workspace, File or collection after you asked (rule [approval.6](https://docs.pnbr.io/concepts/approval.md#rule-approval-6)).
* A command exited with code 4 and printed `outcome: unknown`: problem
  [reply-lost](https://docs.pnbr.io/troubleshooting/reply-lost.md).

## Doors

| Door | Call |
| - | - |
| CLI (agent) | `penumbra operations wait`, `penumbra operations get`, `penumbra requests get`, `penumbra status` |
| CLI (owner or admin) | `penumbra approvals list`, `penumbra approvals show`, `penumbra approvals approve`, `penumbra approvals deny`, `penumbra approvals policy`, `penumbra approvals policy set` |
| MCP (default) | `check_status` with an approval reference, a workspace or an execution reference. `review_work` shows a workspace with its approval state. |
| MCP (full catalog and Kits with a gated tool) | `penumbra_action_status` |
| SDK | `approvals` |

No MCP tool approves or denies a request.

## HTTP reference

* [Get caller](https://docs.pnbr.io/api/http-me-get.md)
* [List accessible projects](https://docs.pnbr.io/api/http-me-project-scopes.md)
* [List projects](https://docs.pnbr.io/api/http-projects-list.md)
* [Get project connections](https://docs.pnbr.io/api/http-projects-connections-list.md)
* [Get caller access](https://docs.pnbr.io/api/http-access-me.md)
* [List approvals](https://docs.pnbr.io/api/http-approvals-list.md)
* [Get approval](https://docs.pnbr.io/api/http-approvals-get.md)

## Keep going

[Credential](https://docs.pnbr.io/concepts/credential.md) · [Workspace](https://docs.pnbr.io/concepts/workspace.md) · [Entity](https://docs.pnbr.io/concepts/entity.md) · [A change returned pending](https://docs.pnbr.io/troubleshooting/change-waits-for-approval.md) · [The reply to a change was lost](https://docs.pnbr.io/troubleshooting/reply-lost.md)

Penumbra Grammar 0.6.26


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.