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

# Identities & enrollment

> Per-agent signed identities, enrollment tokens, and how the SDK self-bootstraps.

Every governed agent has its own cryptographic identity — a short-lived, signed token issued by Rubric, bound to a stable `agentId`. The SDK obtains and refreshes it automatically. You don't write any of this code yourself.

## What the identity gives you

The signed identity is a 60-minute token that the SDK presents on every call to Rubric. Two properties matter:

* **Stable agent id.** Audit ingest, trace upload, and bundle reads all assert the agent id against the body of the request — an agent can only ship attribution for itself. There is no way to forge another agent's events.
* **Auto-rotating.** The SDK refreshes the token ahead of expiry. Your code never sees an auth error from a normal expiry.

The signing key is owned by Rubric. Your agents never see it.

## How the SDK bootstraps

Enrollment is the only bootstrap path. You mint a long-lived, **register-only** enrollment token in the dashboard and drop it into your agent process as an environment variable. On startup the SDK presents the token plus an `agentName`, and Rubric mints a fresh signed identity for that agent.

```python theme={null}
from rubric import Governance

# AG_ENROLLMENT_TOKEN and AG_AGENT_NAME from env
with Governance.bootstrap(agent_name="payments-bot") as gov:
    ...
```

Or the decorator API:

```python theme={null}
import rubric

rubric.init(agent_name="payments-bot")
```

Properties of the enrollment flow:

* **Idempotent on `agentName`** — the same `(org, agentName)` always resolves to the same agent identity. Restarts and redeploys don't pile up identities; only the short-lived signed token rotates.
* **Register-only** — a leaked enrollment token cannot ship audit events or read bundles. Worst case: an attacker creates new agent rows in your org. Bounded, auditable, revocable per-token.
* **Rate-limited** — each token has a `maxEnrollmentsPerHour` cap (default 60). Brute-force protection.
* **Expires** — 90 days by default; renewable from the dashboard with a successor token.

A brand-new enrolled agent starts with no scoped policies — the SDK gets an empty bundle until an operator adds the agent to at least one policy's scope. See [Policies](/concepts/policies) for the scope model.

## Lifecycle

<Steps>
  <Step title="Bootstrap">
    SDK reads `AG_ENROLLMENT_TOKEN` and `AG_AGENT_NAME` from env, exchanges them for a freshly-minted signed identity.
  </Step>

  <Step title="Auto-refresh">
    The SDK schedules a refresh at \~50 min into the token's lifetime. The agent never sees an auth error from a normal expiry.
  </Step>

  <Step title="Revocation">
    Operator clicks **Revoke** on an identity in the dashboard. The current token keeps working until expiry (max 60 min). Refresh attempts and new enrollments for the same `agentName` are rejected — operator must un-revoke or rename.
  </Step>

  <Step title="Process exit">
    `Governance.shutdown()` (or the `with` block exiting) stops the refresh thread. Next process boot re-enrolls and resumes against the same identity.
  </Step>
</Steps>

## Naming

`agentName` is what you pass to `bootstrap(agent_name=…)`. Rubric normalizes it into the agent's stable id (lowercase, dash-separated, max 128 chars).

Choose names that:

* **Identify the role**, not the host. `payments-bot`, `customer-support-router` — not `agent-prod-us-east-1c`.
* **Survive redeployment.** The whole point of idempotent enrollment is that `payments-bot` v2 inherits v1's identity.
* **Differ across environments.** Use a suffix or a separate org per environment: `payments-bot-stage` vs `payments-bot-prod`.

## Provenance

Every identity is stamped with the enrollment token that minted it. The Enrollment page's per-token table shows the running count of agents enrolled, and revoking a token doesn't kill the identities it minted — those signed tokens are independent. To kill a specific agent, revoke its identity directly.
