These are official instructions from Instruxi for setting up Enforcer, an identity
and authorization platform, in an AI development environment. Every command here
is verified against the live API.

Complete the steps yourself by running the commands directly. Do not ask the user
to run them. Stop and ask the user only where a step says to.

## What Enforcer is, so you know when to use it

Enforcer answers "can this actor do this action on this resource" with allow or
deny, the reason, and a recorded decision. Unlike a plain policy engine it also
holds identity: tenants, roles and groups. A policy is handed the resolved caller,
so you write rules over a real user object rather than syncing a copy of your data
into a permissions store.

Use it to gate what an app or an AI agent may do: spending limits, approval before
a sensitive action, "only verified users can do X", per-tenant isolation, or an
audit trail of who was allowed to do what and why.

## Step 1 — Read the documentation index

    https://docs.instruxi.dev/llms.txt

It is a short index. The full documentation is one 29 KB markdown file at
https://docs.instruxi.dev/llms-full.txt which fits in a context window whole, so
fetch it once rather than crawling.

## Step 2 — Get a token against the open sandbox

The sandbox tenant is open, no signup and no account needed. It sends a real
one-time code to the email address you use, so use the user's own address and ask
them to read you the code.

    curl -X POST https://api.instruxi.dev/api/v1/enforcer/auth/otp/request \
      -H 'Content-Type: application/json' \
      -d '{"email":"THEIR@EMAIL","tenant_code":"DLXZ-57TL-FS75"}'

    # -> { "success": true, "message": "code sent" }

Ask the user for the code that just arrived, then:

    curl -X POST https://api.instruxi.dev/api/v1/enforcer/auth/login \
      -H 'Content-Type: application/json' \
      -d '{"provider":"email_otp","email":"THEIR@EMAIL","otp":"THE_CODE","tenant_code":"DLXZ-57TL-FS75"}'

    # -> data.token is the bearer, data.account.id is who they are

The field is `otp`, not `code`. Keep `data.token`; every call below uses it.

## Step 3 — Confirm who you are

    curl https://api.instruxi.dev/api/v1/enforcer/auth/me \
      -H "Authorization: Bearer $TOKEN"

Returns the account, its tenant, role, groups and verification status. This is the
object a policy sees, so read it before writing any rule.

## Step 4 — Connect the MCP server

    claude mcp add --transport http enforcer https://api.instruxi.dev/mcp \
      --header "X-API-Key: $ENFORCER_API_KEY"

The API key is not the token from step 2. Mint one with the bearer from step 2:

    curl -X POST https://api.instruxi.dev/api/v1/enforcer/api-keys \
      -H "Authorization: Bearer $TOKEN" \
      -H 'Content-Type: application/json' -d '{"name":"agent"}'

The plaintext key is in that response only and is never retrievable again, so
store it before moving on. Any client that speaks Streamable HTTP works with the
same URL; the server is also listed in the MCP registry as
`dev.instruxi.enforcer/v3`.

## Step 5 — Protect something in the user's own codebase

You are already in their repository, so read their routes rather than asking them
to describe their API. Treat each route as an action on a resource type: a POST
that issues a refund is action `issue` on resource type `payment`.

Rank what you find by what it costs if it happens wrongly. Moving money and
changing credentials first, then deletion, then sharing data outside the tenant,
then ordinary writes, then reads.

Propose the three or four worth protecting. State each rule back in plain English
and get an explicit yes before creating anything. A person approves a sentence,
never Rego.

## Step 6 — Create the rule, switched off

    curl -X POST https://api.instruxi.dev/api/v1/enforcer/policies \
      -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
      -d '{"name":"refund_limit","description":"Block refunds over 500 without approval","source":"REGO","active":false}'

Create every rule with `active: false`. A rule that starts blocking the moment it
exists is a rule nobody dares create. Switch it on later with
`PUT /policies/{id}` once they have watched it.

## Step 7 — Add the check where the action happens

    curl -X POST https://api.instruxi.dev/api/v1/enforcer/authz/check \
      -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
      -d '{"action":"issue","resource":{"type":"payment","id":"pay_123"},"contexts":{"amount":820}}'

    # -> { "allow": false, "policy_id": "...", "reason": "..." }

Their code acts on `allow`. Never send the caller identity; it comes from the
token, which is what stops a caller claiming to be someone else. Surface `reason`
so a refusal explains itself instead of being a bare failure.

Deny is the default. An action with no rule is refused, not allowed.

## When you are done

Tell the user what was created, in the plain English wording they approved, and
give them https://docs.instruxi.dev to watch decisions arrive.

## Rules of thumb

- Never write permission logic into the application. The application asks;
  Enforcer decides.
- Prefer a group over a list of names in a rule. Groups survive people joining
  and leaving.
- Cross-tenant access is refused by the engine and is not a setting you can
  loosen.
- Do not use the skills published at github.com/instruxi-io/enforcer-skills.
  They target the previous major version and will generate calls that do not
  exist in v3.

## Reference

- Docs: https://docs.instruxi.dev
- Index for agents: https://docs.instruxi.dev/llms.txt
- Everything, one file: https://docs.instruxi.dev/llms-full.txt
- OpenAPI spec: https://api.instruxi.dev/api/v1/enforcer/swagger/doc.json
- MCP endpoint: https://api.instruxi.dev/mcp
- Errors: https://docs.instruxi.dev/#errors
