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

# Agent governance

> Give every AI agent its own identity and budget, organize agents under teams, and know exactly which level denied a call.

<Note>
  Agent governance builds on [Stigg Governance](/documentation/governance/overview), which is in public beta.
</Note>

## What it is

Agents act on their own. One misconfigured loop can burn through a customer's entire credit pool overnight, and a single shared budget gives nobody a way to tell which agent did it. Agent governance makes each agent a first-class, budgeted entity in Stigg:

* **Each agent has an identity.** An agent is a Governance [entity](/documentation/governance/core-concepts#entities) of an `agent` entity type, owned by your customer.
* **Each agent can have its own budget.** A monthly cap in credits or in a metered feature, set by you or by your customer's admin.
* **Agents live in a tree.** Place agents under teams, departments or orgs. A call is allowed only if every level above the agent still has budget.
* **Every call is attributed.** Usage lands on the agent and rolls up through the tree automatically, from a single report.
* **You know why access was denied.** When a call is denied, the decision says which limit was reached: the agent's own budget, its team's budget, or the customer's credit balance. You can then respond the right way, for example by asking an admin to raise a budget or offering the customer more credits.

## Why use it

<CardGroup cols={2}>
  <Card title="Contain runaway agents" icon="fire-extinguisher">
    A per-agent cap stops one agent without stopping the others. Siblings keep working when one exhausts its own budget.
  </Card>

  <Card title="Let your customers govern their AI" icon="users-gear">
    Enterprise buyers want to allocate AI spend by team and by agent. Governance gives their admins the controls, and gives you the data to show them.
  </Card>

  <Card title="Answer 'which agent spent this?'" icon="magnifying-glass-chart">
    Usage is attributed to the agent that made the call and to every level above it, so cost reporting per agent, team and org comes for free.
  </Card>

  <Card title="Turn denials into revenue" icon="arrow-trend-up">
    An agent out of budget is an upgrade or top-up moment. The decision tells you which one.
  </Card>
</CardGroup>

## Example use cases

<AccordionGroup>
  <Accordion title="Per-agent caps in a multi-agent product" icon="robot">
    **The problem:** a customer runs a support agent, a research agent and a coding agent from one credit balance. When the research agent loops on a bad prompt, it drains the shared balance and the other two stop working too.

    **With Stigg:** each agent gets its own monthly budget. The research agent is stopped when it reaches its own budget, and the other two keep serving users.
  </Accordion>

  <Accordion title="Department budgets set by the customer's admin" icon="sitemap">
    **The problem:** an enterprise customer wants to split its AI credits between departments, 60% to engineering and 40% to support, and let its own admin manage that split.

    **With Stigg:** agents are placed under their department, and each department has a budget. When a department reaches it, its agents stop, and the admin raises the budget from an interface you build on the [governance query API](/documentation/governance/query).
  </Accordion>

  <Accordion title="Cost reporting per agent" icon="chart-pie">
    **The problem:** the customer's finance team wants to know which agents drive their AI spend, before deciding on any limits.

    **With Stigg:** agents are registered without a limit, so nothing is blocked, and every call is attributed to its agent and team. The customer sees usage per agent and per team without any extra reporting code.
  </Accordion>

  <Accordion title="Budgets for paid tools, not just model calls" icon="screwdriver-wrench">
    **The problem:** agents also call paid tools, such as a web-search API, a data provider or a code sandbox. Each call costs you money, and an agent stuck in a loop can run thousands of them.

    **With Stigg:** tool calls are metered as their own feature, for example web searches, and checked before each call against the same agent and team budgets as its model calls. You can cap them, and charge the customer for them.
  </Accordion>
</AccordionGroup>

## How it works

```mermaid theme={null}
flowchart TB
    C["Customer: acme<br/>credit pool"]
    T["Team: research<br/>limit 30 credits / month"]
    A1["Agent: drafter<br/>limit 3 / month"]
    A2["Agent: reviewer<br/>limit 10 / month"]
    C --> T --> A1
    T --> A2
```

A call made as `reviewer` is checked against the reviewer's own limit, the research team's limit and the customer's credit pool. It is allowed only if all three allow it, and its usage counts against all three. If the drafter spends its 3 credits, its access is denied with `deniedBy: 'drafter'`, and the reviewer keeps working. If the team's 30 credits run out first, both are denied with `deniedBy: 'team-research'`, even though the reviewer has budget of its own left.

The SDK maps this onto three steps:

```mermaid theme={null}
sequenceDiagram
    participant App as Your backend
    participant SDK as Stigg Agent SDK
    participant S as Stigg Governance

    Note over App,S: Once per agent, when it is created in your product
    App->>SDK: register({ customerId, agentId, entityTypeId, budget })
    SDK->>S: upsert entity, upsert assignment

    Note over App,S: On every model call
    App->>SDK: call through a wrapped client, as agentId
    SDK->>S: Check with dimensions { agentId }
    S-->>SDK: decision with the full chain up to the customer
    SDK->>S: Ingest usage with dimensions { agentId }

    Note over App,S: When the agent is no longer needed (optional)
    App->>SDK: deregister({ customerId, agentId })
    SDK->>S: archive entity
```

### 1. Register the agent

`stigg.register()` creates the agent in Stigg: its entity, its budget, and its place in the tree. This registers the drafter from the example above, with its limit of 3 credits a month under the research team:

```typescript theme={null}
await stigg.register({
  // 1. The agent itself (its entity)
  customerId: 'customer-acme',
  agentId: 'drafter',
  entityTypeId: 'agent',
  displayName: 'Drafter',

  // 2. Its budget and place in the tree (its assignment), optional
  budget: {
    entitlement: { currencyId: 'credits' },
    parentId: 'team-research',   // the research team from the diagram above
    limit: 3,                    // 3 credits...
    cadence: 'P1M',              // ...per month (an ISO 8601 duration: P1M = 1 month)
  },
});
```

* **Call it once, when the agent is created in your product.** It saves the agent to Stigg in two parts, matching the two groups in the example: (1) it creates the agent's entity, or updates it if it already exists, and (2) if you pass a `budget`, it sets the agent's budget and place in the tree for that entitlement (a Governance [assignment](/documentation/governance/core-concepts#assignments)). Do not call it on every model call. Wrapped clients only need the agent's ID.
* **It is safe to call again.** Each process remembers which agents it has registered. A call with only part 1 (no `budget`) is skipped the second time, so you can call it on every startup. A call that includes a `budget` is always saved, because a budget or parent change is deliberate.
* **The parent is set per budget.** An agent's place in the tree belongs to each budget, not to the agent, so it can roll up to a different parent for each credit currency or feature. For example, the drafter's credits count against the research team's budget, while its web searches count against a company-wide search budget managed by IT. Register it once per entitlement, each time with the matching `budget.parentId`.
* **Let admins own the limit, if they change it in the Stigg app.** By default, `budget.limit` is saved on every call, so a limit changed in the Stigg app is overwritten the next time your code registers the agent. Pass `apply: 'on-create'` to set the limit only when the agent has no budget yet.
* **Registering is optional.** If you do not register an agent, calls made with its agent ID still work, but Stigg has no entity for that agent. Its usage does not count toward any agent or team budget, and its calls are checked against the customer's limits only.

For every field of `register()`, see the [SDK reference](/api-and-sdks/references/sdk/backend/rest/agent-sdk#register).

### 2. Make calls as the agent

Each model call the agent makes goes through a wrapped client, which checks access before the call and reports usage after it. You do not report usage separately. Wrap the client once, and name the customer and the agent on each call, together with the attribution key of the agent's entity type:

```typescript theme={null}
const anthropic = stigg.wrap(new Anthropic());

await anthropic.messages.create({
  model,
  max_tokens: 1024,
  messages,
  stiggContext: {
    customerId: 'customer-acme',
    entitlement: { currencyId: 'credits' },
    agentId: 'drafter',
    attributionKey: 'agentId',
  },
});
```

One wrapped client can serve every agent and every customer this way. In a real server, the customer and agent IDs come from the request being handled.

`attributionKey` must be the [attribution key](/documentation/governance/core-concepts#entity-types) declared on the agent's entity type. The agent ID travels on every check and report under that key, which is how Governance finds the entity and its chain. The SDK rejects an `agentId` without an `attributionKey`, because a guessed key would silently attribute the spend to the customer instead.

Naming an agent in a context attributes calls to it. It does not create it: that is what `register()` is for.

<Note>
  Governance counts agent and team usage in whole units. When a call is attributed to an agent and its usage draws a credit currency, the SDK rounds the amount up to the next whole credit and logs that it did. Define the credit currency in small enough units, such as thousandths of a dollar, that rounding a single call up costs little. Calls with no agent are reported with their exact fractional amount.
</Note>

#### One client per agent

You can also wrap a separate client for each agent, with the agent as that client's default:

```typescript theme={null}
const drafter = stigg.wrap(new Anthropic(), {
  stiggContext: { entitlement: { currencyId: 'credits' }, agentId: 'drafter', attributionKey: 'agentId' },
});
```

Each call still passes its `customerId`. Do this when you want separate usage totals per agent in your own code: each wrapped client's `stigg.summary()`, for example `drafter.stigg.summary()`, returns what that client has done so far, including how many checks and reports it made and the usage totals per metric. See the [SDK reference](/api-and-sdks/references/sdk/backend/rest/agent-sdk#summary).

#### Fine-grained attribution with dimensions

An agent usually works on behalf of someone, and may use more than one model. To track or limit usage by those as well, attribute each call to them too. For example, in the research team:

* **Per person:** Alice can spend at most 5 credits a month through any of the team's agents.
* **Per model:** calls to an expensive model have a tighter budget than the team's overall one.

Pass them in `stiggContext.dimensions`, next to the agent:

```typescript theme={null}
stiggContext: {
  customerId: 'customer-acme',
  agentId: 'reviewer',
  attributionKey: 'agentId',
  dimensions: { userId: 'user-alice', modelId: 'claude-opus-5' },
}
```

The call is then checked against Alice's budget and the model's budget as well, and its usage counts toward both.

For this to work, users and models must be set up in Governance as entity types, and each key in `dimensions` must be that type's [attribution key](/documentation/governance/core-concepts#entity-types), here `userId` and `modelId`. A key that matches no entity type is ignored. A per-model budget is a [scoped budget](/documentation/governance/core-concepts#scope-dimension-scoped-sub-budgets). Dimensions set on a call are added to the ones set on the client.

#### When access is denied

If the agent, its team or the customer has no budget left, access is denied and the call is not sent to the provider. The wrapped call throws an `AccessDeniedError`, and `stigg.denial(err)` returns the decision, with `hasAccess: false`, just like an [entitlement check](/guides/quick-start-guides/gating-access-to-features#1-check). To find out before a call instead, use [`stigg.check()`](/documentation/ai-agents/llm-wrappers/gating#handling-denied-access), which returns the decision without throwing.

Use the decision to respond the right way:

```typescript theme={null}
try {
  await anthropic.messages.create({
    ...params,
    stiggContext: {
      customerId: 'customer-acme',
      entitlement: { currencyId: 'credits' },
      agentId: 'drafter',
      attributionKey: 'agentId',
    },
  });
} catch (err) {
  const decision = stigg.denial(err);
  if (!decision) throw err; // a different error, not denied access

  if (decision.remedy === 'raise-budget') {
    // An agent or team budget was reached. deniedBy says whose: 'drafter' or 'team-research'.
    notifyBudgetOwner(decision.deniedBy, decision.message);
  } else if (decision.remedy === 'top-up') {
    // The customer's credit balance is empty.
    offerCreditPurchase('customer-acme', decision.message);
  }
  return pauseAgent(decision.message);
}
```

| Field | What it tells you | What to do with it |
| - | - | - |
| `deniedBy` | Whose budget was reached: `drafter`, `team-research` or `customer-acme` | Decide who to notify, and show which budget ran out |
| `reason` | Why access was denied: `BudgetExceeded` for an agent or team budget, `InsufficientCredits` for the customer's credit balance. The equivalent of `accessDeniedReason` | Log it, or branch on it |
| `remedy` | What would let the call through: `raise-budget` or `top-up` | Choose your response: ask the budget's owner to raise it, or offer the customer more credits with a [top-up](/documentation/modeling-your-pricing-in-stigg/credits/self-service-top-up) |
| `remaining` | The smallest budget left anywhere in the chain | Show how much is left, or decide whether a smaller task still fits |
| `message` | A sentence that matches the remedy | Show it to the user as is |

For every field, see [The decision object](/documentation/ai-agents/llm-wrappers/gating#the-decision-object).

### 3. Deregister the agent (optional)

When an agent is no longer needed, archive its entity:

```typescript theme={null}
await stigg.deregister({ customerId: 'customer-acme', agentId: 'drafter' });
```

For long-lived agents this is optional. For **ephemeral agents**, created for a single task or session, deregister each one when it finishes, so finished agents do not pile up in the customer's tree.

## Observe-only rollout

Governance is opt-in: an agent with no budget is never denied access by Governance. To introduce agent budgets safely:

1. Register agents with `budget: { entitlement, limit: null }`. Usage per agent and per team is tracked and visible in the Stigg app, and nothing is blocked.
2. Review the numbers with your customers.
3. Set real limits, per agent or per team, from your code or in the Stigg app.

## Without Governance

Agent-level governance requires [Governance](/documentation/governance/overview) to be enabled in your account. See [Setting up governance](/documentation/governance/setting-up).

If it is not enabled, the SDK keeps working, but without agents or teams:

* **Calls are checked against the customer only.** There are no agent or team budgets, so each call is checked against the customer's own credits or usage limit, as with any wrapped client. When access is denied, `deniedBy` is the customer.
* **Usage is still metered** for the customer, but not attributed to an agent.
* **`register()` with only the agent part** logs a warning and does nothing.
* **`register()` with a `budget`** throws `GovernanceNotEnabledError`, because there are no agent budgets to save them to.

## Tool calls and workflow steps

To put an agent's tool calls or workflow steps under the same budgets as its model calls, check and report them directly. See [Gating actions that are not model calls](/documentation/ai-agents/llm-wrappers/gating#gating-actions-that-are-not-model-calls).


## Related topics

- [Agent SDK](/api-and-sdks/references/sdk/backend/rest/agent-sdk.md)
- [Agent orchestration](/documentation/ai-agents/agent-orchestration.md)
- [Metering usage](/documentation/ai-agents/llm-wrappers/metering.md)
- [Gating calls](/documentation/ai-agents/llm-wrappers/gating.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.