# Approvals
Source: https://docs.treeship.dev/guides/approvals

> An approval is a cryptographic authorization for an action, bound by a nonce and constrained by a signed scope.

An approval answers "who authorized this, to do what, against which subject" -- signed, scoped, and verifiable.

## How approvals work

```bash
# Approver issues a scoped approval
treeship attest approval \
  --approver human://alice \
  --description "approve stripe charge max $500 to acme-corp" \
  --allowed-actor agent://payments \
  --allowed-action stripe.charge.create \
  --max-uses 1 \
  --expires 2026-03-26T18:00:00Z

# Returns:
# ✓ approval attested
#   id:    art_approval_abc123
#   nonce: nce_7f8e9d0a1b2c3d4e
#   scope: actors=["agent://payments"], actions=["stripe.charge.create"], max_uses=1
```

The nonce is the binding token. Pass it to your agent.

```bash
# Agent acts under the approval
treeship attest action \
  --actor agent://payments \
  --action stripe.charge.create \
  --approval-nonce nce_7f8e9d0a1b2c3d4e \
  --meta '{"amount":450,"vendor":"acme-corp"}'
```

## What gets checked

Treeship's verify pass enforces three independent properties and reports each separately. Conflating them would let a fooled audit reader trust a guarantee that wasn't actually evaluated.

| Property    | What it proves                                                                                               | Stateless?                   |
| ----------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------- |
| **Binding** | The action's `approvalNonce` matches a real signed approval                                                  | Yes                          |
| **Scope**   | Action's `actor`, `action`, and `subject` are inside the approval's signed allow-lists; approval not expired | Yes                          |
| **Replay**  | The nonce has not been consumed before                                                                       | **Verifier-state-dependent** |

```
✓  approval binding nonce matched a signed approval
✓  approval scope   actor / action / subject matched approval scope
⚠  replay check     package-local only -- no global ledger consulted
```

<Callout type="warn" title="Replay posture as of v0.9.6">
  Stateless verifiers cannot detect replay across artifacts they never saw. The current implementation observes replay **only within a single verified package** -- if the same nonce appears on two actions in one package, the second fails. A `--max-uses` value is signed into the grant for future enforcement, but no global ledger is consulted yet.

  **Roadmap:**

  * **v0.10:** local Approval Use Journal (append-only, hash-chained, with signed Merkle checkpoints) for device/workspace replay enforcement.
  * **v0.11+:** Hub/org checkpoints for distributed single-use across machines and teams.
</Callout>

## Approval flags

| Flag                       | Required       | Description                                                                                                                                         |
| -------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--approver <uri>`         | Yes            | Human or identity URI, e.g. `human://alice`                                                                                                         |
| `--description <text>`     | No             | Plain text scope of what is authorized                                                                                                              |
| `--allowed-actor <uri>`    | No, repeatable | Actor URIs permitted to consume this approval                                                                                                       |
| `--allowed-action <label>` | No, repeatable | Action labels permitted under this approval                                                                                                         |
| `--allowed-subject <uri>`  | No, repeatable | Subject URIs permitted as the action's target                                                                                                       |
| `--max-uses <n>`           | No             | Signed into the grant for future ledger enforcement                                                                                                 |
| `--unscoped`               | No             | Required to mint a bearer approval (no scope axes set). Without it the CLI refuses, since unscoped approvals authorize any actor / action / subject |
| `--expires <timestamp>`    | No             | RFC 3339 expiry time                                                                                                                                |
| `--subject <id>`           | No             | Artifact ID being approved (the subject of the approval itself)                                                                                     |

## Verifying an approved action

```bash
treeship verify art_charge --format json | jq '{outcome, approver, approval_description}'
# {
#   "outcome": "pass",
#   "approver": "human://alice",
#   "approval_description": "approve stripe charge max $500 to acme-corp"
# }
```