> Call POST /v1/check before a tool that writes. DENY means do not invoke the tool. For clean Markdown of any page, append .md to the page URL. For the complete index, fetch https://docs.withwrit.com/llms.txt.

# Concepts

> Principals, decisions, receipts, policies, grants, and the kill switch.

Everything in Writ is built from three objects. Understand these and the
rest of the product is just operations on them.

## What to protect first

Start with the five categories where one bad agent action is expensive:

1. **Money movement** — `payments.refund`, `billing.charge`, `payouts.create`
2. **Identity and permissions** — `iam.grant_admin`, `users.promote`, `tokens.issue`
3. **Customer data changes** — `users.delete`, `records.update`, `crm.modify`
4. **External communications** — `email.send`, `sms.send`, `webhooks.fire`
5. **Infrastructure changes** — `aws.terminate`, `dns.update`, `deploy.promote`

One bad call in any of these categories is expensive and hard to undo.
Start here, expand by verb.

Writ sits on top of your existing infrastructure — Okta, AWS IAM, Stripe,
your API gateway. It does not replace them. It governs the actions your
agents take through them.

## Principal

A principal is **who is acting, and on whose behalf**: a human sponsor, an
agent, a task, and a purpose — bound together. It is not a shared service
account. `svc-support-admin` can do anything; a principal can only do the
thing its sponsor approved, for the purpose stated.

Two credentials represent the two halves:

| Credential    | Looks like    | Held by            | Unlocks                        |
| ------------- | ------------- | ------------------ | ------------------------------ |
| API key       | `writ_...`    | the agent / tenant | checks, receipts, policy reads |
| Sponsor token | `writ_sp_...` | the human          | grants, revokes, reinstate     |

The API key says *which tenant is asking*. The sponsor token says *a human
approved this*. The sponsor token is shown once at tenant creation and never
recoverable — if it leaks, the tenant's human side is compromised. It can
also come from the `WRIT_SPONSOR_TOKEN` environment variable.

## Decision

A decision is Writ's answer at the moment of the write: `ALLOW`, `DENY`, or
`STEP_UP`. It is made by `POST /v1/check`, which matches the request against
the tenant's policy and any live grants on five fields — **sponsor, agent,
verb, target, purpose**. All five must match. Anything else is `DENY`.

* **ALLOW** mints a 90-second auth token bound to the exact write: this
  verb, this target, this purpose, this policy version. The agent performs
  the write, then verifies the token against what it actually did with
  `POST /v1/tokens/verify`. The grant is single-use semantics: it cannot be
  reused for a different write.
* **DENY** means the write must not run. A receipt is still written — the
  refusal itself is auditable.
* **STEP_UP** means a human sponsor must approve. The agent stops and tells
  the user. The sponsor mints a one-time **grant** (dashboard or
  `POST /v1/grants` with the sponsor token), and the agent calls
  `POST /v1/check` again. STEP_UP also pages the tenant's account email
  with the receipt id and a deep link to the portal grants page — at most
  one notification per write per hour. Opt out of email with
  `notify_step_up_email = false` on the tenant row, or route STEP_UPs to a
  generic JSON or Slack webhook with `step_up_webhook_url` and
  `step_up_webhook_type`.

## Receipt

A receipt is the audit record of a decision — ALLOW, DENY, STEP_UP, REVOKE,
all of them. Receipts are **hash-chained** (`prevHash` / `chainHash`,
HMAC-SHA256 keyed by the deploy secret), so altering a stored receipt breaks
the chain detectably. They are **tenant-isolated**: one tenant's receipts
are never visible to another.

The receipt is the product's answer to the auditor. Instead of "send us the
CloudTrail," the compliance owner opens the receipt: who, what, which
purpose, which policy version, when. See [Audit log](/audit-log) for
streaming, SIEM ingestion, and chain verification.

## Policy modes

Each verb in a tenant has a mode, set with `./writ policy --set <verb> <mode>` or the dashboard policy editor:

| Mode            | Meaning                                                      |
| --------------- | ------------------------------------------------------------ |
| `allow`         | Checks on this verb return ALLOW when the principal is valid |
| `deny`          | Checks always return DENY (with a receipt)                   |
| `require_grant` | ALLOW only with a live sponsor grant                         |
| `step_up`       | Returns STEP_UP until a sponsor approves                     |

Start strict (`deny` or `step_up`) on consequential verbs, relax as the
agent earns trust. Policy changes take effect immediately. The policy is
layered — a principal's override beats the environment override, which
beats the tenant default. See [Policies](/policies).

## Grants

A grant is a sponsor's one-time approval for a specific write: sponsor,
agent, verb, target, purpose, 90-second lifetime. Minted in the dashboard or
with `./writ grant --sponsor-token ...`. The agent's next `POST /v1/check`
with matching fields returns ALLOW. Grants are how STEP_UP resolves — the
human stays in the loop without becoming the bottleneck for every write.

## Kill switch

A sponsor can revoke a principal at any time (`POST /v1/revoke` with the
sponsor token, or the dashboard). Every later check for that sponsor and
agent is DENY — even under an allow policy, even with a live grant. The
revocation itself writes a receipt. `POST /v1/reinstate` undoes it.

Use it when an agent misbehaves, a credential leaks, or a purpose drifts.
Revocation is per-tenant: one tenant's sponsor can never touch another
tenant's principals.

## Tenants and teams

One tenant = one isolation boundary: its own keys, policy, receipts, and
chain. A tenant starts with one member (whoever created it). Members are
added with invite codes (`./writ invite`), each getting their own API key;
the sponsor token stays with the tenant creator. Members share the tenant's
policy and receipts.