# Policy

A request that passed the [binding](https://docs.mehen.dev/concepts/credentials.md#bindings) meets the item's policy, which says `allow`, `approve` (wait for a human, see [Approvals](https://docs.mehen.dev/concepts/approvals.md)) or `deny`.

## The shape

```ts
type Policy = {
  default: "allow" | "approve" | "deny"
  rules: {
    action: "allow" | "approve" | "deny"
    methods?: string[]
    paths?: string[]
    body?: BodyMatcher
    note?: string
  }[]
}
```

Rules combine as **deny over approve over allow**, never first match wins, so adding a rule cannot silently open something. If no rule matches, `default` applies. A rule may name a **body matcher** for requests whose meaning is in the body rather than the path, such as GraphQL. Matchers fail closed: a body they cannot read in full (empty, not UTF-8, invalid JSON, a repeated JSON key, a batch) is treated as the risky case, so it is held or refused, never let through.

Policy, not intent, decides. Some reads and narrowly allowed writes run without asking, and a human may change a credential's policy from its page with a passkey. Requests in protected environments also need an approval ([Projects, environments and runs](https://docs.mehen.dev/concepts/projects.md#protected-environments)).

## What templates allow, hold and refuse

Provider templates fail closed. For an item made from a template:

- **Reads are allowed** (`GET`, `HEAD`), except a read that hands back another secret: a database password or connection string, a decrypted environment variable, a stored secret, a mail server's details. Those need an approval.
- **Every other method needs a human's approval by default**, except a few narrow everyday writes the template allows explicitly: model calls for an AI provider, searches and scrapes for a search API, read-only queries.
- **Sends and money movements are pinned to an approval**, so no later allow rule can open them: email and messages, payouts and refunds, anything billed, and root access to a server.
- **The worst routes are denied outright**: anything that sends mail or data elsewhere for good (forwarding, filters, mailbox rules, delegates, webhooks, destinations, log drains), gives someone else access (SSH and deploy keys, collaborators, members, invitations, roles, app registrations), mints or revokes tokens, or cannot be shown honestly on an approval card; and deleting a whole project, team or organisation.

`mehen templates <id>` prints a template's rules as three lines (without a human, needs approval, refused), and `mehen show <item>` shows an item's policy. [Providers and templates](https://docs.mehen.dev/reference/providers.md) lists every template's three lines. Do not look for a way round a denied route; use the alternative:

| You try to | The vault | Do this instead |
| --- | --- | --- |
| Send a saved Gmail draft by id (`drafts/send`) | Denies it (`policy_denied`) | A draft can change after the send is approved, so the approval could not show what is sent. Send the whole message with `POST .../messages/send` and a `raw` body; the approval shows it. |
| Send a stored Microsoft Graph message by id, or forward or reply to a stored message | Denies it | The same reason. Send the whole message with `sendMail`. |
| Use Microsoft Graph `$batch` | Denies it | A batch carries requests the vault cannot check one by one. Send each request on its own. |
| Change mail forwarding, delegates, filters, mailbox rules or settings; add SSH or deploy keys, webhooks, collaborators or app registrations | Denies it | These give lasting access to someone else. Ask the human to do it themselves, outside the vault. |
| Mint or revoke an API token, invite a member, add a webhook, log drain or event destination, or delete a whole project or organisation | Denies it | The same reason, and a deleted project does not come back. Ask the human to do it in the provider's own console. |
| Read a Fathom recording's summary or transcript | Holds it for approval | That route can post the text to any URL named in its query, which no rule can see. List meetings with `GET /meetings?include_transcript=true` instead. |
| Call Notion | Needs a `Notion-Version` header | The vault adds only the secret; send `Notion-Version` yourself on every request. |
| Reach a scoped npm package (`@scope/name`) | Refuses it as an ambiguous path | Its name travels as `@scope%2fname`, an encoded slash. Unscoped packages work; ask the human to publish a scoped one. |
| Run a GitHub GraphQL request | Allows a read-only query that a strict matcher can read in full; holds anything else for approval | Prefer a plain query, or the REST endpoint. |

## Credentials without a template

A credential stored without a template (an agent proposed its binding) fails closed as well: its policy is `approve` by default with no rules, so every request waits for a human. The intake page offers one tick, unticked, to let reads (`GET`, `HEAD`, `OPTIONS`) through without asking; the passkey signs that choice with the rest of the form. A rotation keeps the item's policy, and a template's intake takes the template's. Only a human can widen a policy afterwards, from the item's page with a passkey.

## How the summaries are written

The three policy lines (`without a human`, `needs approval`, `refused`) for a built-in template use the template's reviewed notes ("reads; creates a draft; changes labels"). For an item, they describe each rule from what it matches (method and paths), never from its note, because nothing proves an item's policy is a template's. "anything else" always lands on the line of the policy's default. `mehen check` runs the same matcher locally to say what a request would get; it is advisory ([Find a credential and call an API](https://docs.mehen.dev/guides/call-an-api.md#check-before-you-send)).

## Policy proposals

`mehen policy preview` and `propose` exist in the command line, but the vault refuses them in this release with `forbidden` ("Policy widening is not available yet"). Do not retry them; a policy window never stands in for a protected context. `mehen policy show`, `cancel` and `stop` work.
