> ## 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.

# Set budgets for AI agents

> Give each AI agent its own credit budget under a shared team limit, and handle denied access by the agent or the team.

In this guide two agents, a drafter and a reviewer, share one team budget while each has a cap of its own. You will watch the drafter get stopped by its own cap while the reviewer keeps working, and then watch the team's cap stop the reviewer even though it still has budget of its own.

```mermaid theme={null}
flowchart TB
    C["customer-acme<br/>credit pool"] --> T["team-research<br/>8 credits / month"]
    T --> D["agent-drafter<br/>3 credits / month"]
    T --> R["agent-reviewer<br/>10 credits / month"]
```

**Before you start:**

* A Stigg server API key.
* [Governance](/documentation/governance/overview) enabled on your account.
* A credit currency `credits` and a customer `customer-acme` with a credit grant much larger than the team budget, so the denials come from the budgets and not from an empty wallet. See [Set up credits](/guides/i-want-to/set-up-credits).

<Steps>
  <Step title="Create the entity types">
    Create two [entity types](/documentation/governance/core-concepts#entity-types) in your environment, once:

    | ID | Attribution key |
    | - | - |
    | `team` | `teamId` |
    | `agent` | `agentId` |

    Do this in the Stigg app or through the API. See [Setting up governance](/documentation/governance/setting-up#define-entity-types).
  </Step>

  <Step title="Create the team and its budget">
    Add the `team-research` entity to `customer-acme` with an assignment of 8 `credits` per month (`P1M`). See [Setting up governance](/documentation/governance/setting-up).

    In a real product, your customer's admin usually sets the team budget through an interface you build.
  </Step>

  <Step title="Register the agents">
    Register each agent when it is created in your product. `register()` creates the entity, places it under the team, and writes its budget.

    ```typescript theme={null}
    import { StiggAgentSDK } from '@stigg/agent-sdk-js';

    const stigg = new StiggAgentSDK(process.env.STIGG_SERVER_API_KEY);

    const credits = { currencyId: 'credits' };

    for (const [agentId, limit] of [['agent-drafter', 3], ['agent-reviewer', 10]] as const) {
      await stigg.register({
        customerId: 'customer-acme',
        agentId,
        entityTypeId: 'agent',
        budget: {
          entitlement: credits,
          parentId: 'team-research',
          limit,
          cadence: 'P1M',
        },
      });
    }
    ```

    <Tip>
      If admins will change agent budgets in the Stigg app, add `apply: 'on-create'` to the `budget`, so your code sets the initial budget and never overwrites theirs.
    </Tip>
  </Step>

  <Step title="Wrap the client">
    ```typescript theme={null}
    import Anthropic from '@anthropic-ai/sdk';
    import { unitsPerTokens } from '@stigg/agent-sdk-js';

    // One wrapped client for every agent. Each call names its customer and agent.
    const anthropic = stigg.wrap(new Anthropic(), {
      stiggContext: {
        entitlement: credits,
        // 1 credit per 1,000 tokens, reported straight to the credit balance.
        usageMapper: unitsPerTokens('credits', 1_000),
        ingestMode: 'sync',
      },
    });
    ```

    * The usage mapper reports to `credits`, the same currency the budgets are written against. Reporting raw token names here would not count against a credit budget.
    * `ingestMode: 'sync'` updates the budgets with each call, so the next check sees the spend.
    * Governance counts agent usage in whole units, so the amount of each call made as an agent is rounded up to a whole credit. A call of 400 tokens costs 1 credit.
  </Step>

  <Step title="Run the agents and handle denied access">
    ```typescript theme={null}
    async function turn(agentId: string) {
      try {
        await anthropic.messages.create({
          model: 'claude-opus-5',
          max_tokens: 1024,
          messages,
          stiggContext: { customerId: 'customer-acme', agentId, attributionKey: 'agentId' },
        });
        console.log(agentId, 'ok', anthropic.stigg.lastDecision?.remaining);
      } catch (err) {
        const decision = stigg.denial(err);
        if (!decision) throw err;
        console.log(agentId, 'DENIED by', decision.deniedBy, decision.reason);
        console.log('  ', decision.message);
      }
    }

    for (let i = 0; i < 12; i++) {
      await turn('agent-drafter');
      await turn('agent-reviewer');
    }
    ```

    `agentId` with `attributionKey` attributes each check and report to that agent, so Governance checks the agent, the team and the customer together.

    Expected output, abbreviated:

    ```text theme={null}
    agent-drafter DENIED by agent-drafter BudgetExceeded
       Budget exhausted for agent-drafter. Ask whoever set this budget to raise it, or wait for the next reset.
    agent-reviewer ok 5
    ...
    agent-reviewer DENIED by team-research BudgetExceeded
       Budget exhausted for team-research. Ask whoever set this budget to raise it, or wait for the next reset.
    ```

    The drafter is stopped by its own cap and the reviewer is not affected. Later the reviewer is stopped by the team, with budget of its own still unspent, because the binding constraint is whichever level runs out first.
  </Step>

  <Step title="Respond to the right person">
    Use `deniedBy` and `remedy` to decide how to respond:

    | Decision | Meaning | Response |
    | - | - | - |
    | `deniedBy` is the agent, `remedy: 'raise-budget'` | The agent's own cap | Notify the agent's owner, or pause just this agent |
    | `deniedBy` is the team, `remedy: 'raise-budget'` | The team's cap | Notify the team admin |
    | `reason: 'InsufficientCredits'`, `remedy: 'top-up'` | The customer's wallet is empty | Offer the account owner to buy more credits with a [top-up](/documentation/modeling-your-pricing-in-stigg/credits/self-service-top-up) |

    Raise a budget by calling `register()` again with a new `budget.limit`, or in the Stigg app. Denials are never cached, so the next call goes through.
  </Step>

  <Step title="See it in Stigg">
    Open `customer-acme` in the Stigg app to see current usage and limits for the team and for each agent. To build the same view in your product, use the [governance query API](/documentation/governance/query).
  </Step>
</Steps>

## Going to production

* Checks for an agent are never cached: each one asks Stigg, so a cap is enforced on the first call that exceeds it, even across several servers. See [Caching and accuracy](/documentation/ai-agents/llm-wrappers/gating#caching-and-accuracy).
* Decide what a call should do when a check cannot complete, with `checkErrorAction`. See [Fallback strategy](/documentation/ai-agents/llm-wrappers/gating#fallback-strategy).
* Start with `budget: { entitlement, limit: null }` to observe usage per agent before you enforce. See [Observe-only rollout](/documentation/ai-agents/agent-governance#observe-only-rollout).


## Related topics

- [Meter LLM token usage](/guides/ai-agents/meter-llm-token-usage.md)
- [Agent governance](/documentation/ai-agents/agent-governance.md)
- [Gating calls](/documentation/ai-agents/llm-wrappers/gating.md)
- [Agent orchestration](/documentation/ai-agents/agent-orchestration.md)
- [Agent SDK](/api-and-sdks/references/sdk/backend/rest/agent-sdk.md)


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