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

# Policy Examples

> Manifests for a team policy with a pool, a budget and rate limits, a provider tier on an account, per-project budgets and per-person caps

Each example is a `relay.wyolet.dev/v1alpha3` manifest bundle. Apply it with [`relay apply`](https://docs.wyolet.com/concepts/gitops), dry run first:

```bash theme={null}
relay apply -f policies/ --dry-run
relay apply -f policies/
```

The examples build on each other: the later ones use the team, project and provider account the first one declares. The tier presets they bind (`openai-build`, `openai-grow`) ship in catalog releases with the v1alpha3 schema. How the pieces combine is on [Policies](https://docs.wyolet.com/concepts/policies.md), and the account names (`team-ml`, `project-search`, `sa-eval-runner`) on [Accounts](https://docs.wyolet.com/concepts/accounts.md#accounts-relay-makes). An apply that declares a team, project or service account can bind its account in the same bundle.

## A team policy with a pool, a budget and rate limits

An admin provisions the upstream side: one OpenAI organization as a provider account, its two keys, and a pool of them. The team's account gets a policy that draws on the pool, a monthly budget, and request and token limits.

```yaml theme={null}
apiVersion: relay.wyolet.dev/v1alpha3
kind: Team
metadata:
  name: ml
spec: {}
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Project
metadata:
  name: search
spec:
  team: ml
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Account
metadata:
  name: acme-openai
  owner: {kind: system}
spec:
  host: openai
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: HostKey
metadata:
  name: acme-openai-a
  owner: {kind: system}
spec:
  hostId: openai
  account: acme-openai
  valueFrom: {kind: env, env: OPENAI_KEY_A}
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: HostKey
metadata:
  name: acme-openai-b
  owner: {kind: system}
spec:
  hostId: openai
  account: acme-openai
  valueFrom: {kind: env, env: OPENAI_KEY_B}
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Pool
metadata:
  name: openai-main
  owner: {kind: system}
spec:
  host: openai
  credentials: [acme-openai-a, acme-openai-b]
  selection: prioritized
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Budget
metadata:
  name: ml-monthly
  owner: {kind: team, name: ml}
spec:
  amountUsd: "2000"
  period: month
  mode: hard
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: RateLimit
metadata:
  name: ml-limits
  owner: {kind: team, name: ml}
spec:
  rules:
    - {meter: requests, amount: 600, window: 1m, strategy: sliding-window}
    - {meter: tokens, amount: 2000000, window: 1m, strategy: sliding-window}
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Policy
metadata:
  name: ml
  owner: {kind: team, name: ml}
spec:
  models: [openai]
  pools: [openai-main]
  rateLimits:
    - ref: ml-limits
  budgets:
    - ref: ml-monthly
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: PolicyBinding
metadata:
  name: ml
  owner: {kind: team, name: ml}
spec:
  policy: ml
  accounts: [team-ml]
```

What this gives every request on the team's rung, which is every lane in `ml`: the member accounts of the team and its projects, and the accounts of their service accounts:

* Only OpenAI models, and only through `openai-main`. The policy links a pool, so it decides reach: the team's lanes no longer fall back to the host keys their scopes own.
* 600 requests and 2,000,000 tokens a minute, and \$2,000 a month, each one counter shared by the whole team across every model.
* Unpriced OpenAI models are refused while the budget applies.

A team member's personal account climbs no team rung, so a relay key in it is not governed by this policy. A key in the member's account in `ml` is.

The provider account, the host keys and the pool are system-owned, so any team's policy can link the pool. The rate limit, the budget, the policy and the binding belong to the team, so a `team-admin` can change them. A team that brings its own OpenAI keys can own them, and a pool of them, the same way.

Every host key names its account, so the `Account` comes first in the bundle (or exists already); a host key without `account` is refused.

## Binding a tier to an account

The account's keys share the organization's limits only once a tier policy is bound to the account. Bind the catalog preset that matches your OpenAI usage tier:

```yaml theme={null}
apiVersion: relay.wyolet.dev/v1alpha3
kind: PolicyBinding
metadata:
  name: acme-openai-tier
  owner: {kind: system}
spec:
  policy: openai-grow
  accounts: [acme-openai]
```

A project that brings its own OpenAI organization owns its account and binds the tier itself, with a binding owned by the project:

```yaml theme={null}
apiVersion: relay.wyolet.dev/v1alpha3
kind: Account
metadata:
  name: search-openai
  owner: {kind: project, name: search}
spec:
  host: openai
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: PolicyBinding
metadata:
  name: search-openai-tier
  owner: {kind: project, name: search}
spec:
  policy: openai-build
  accounts: [search-openai]
```

A tier negotiated with the provider is a policy of your own. Scope each rate limit to the models it covers, as the presets do, so each model counts on its own:

```yaml theme={null}
apiVersion: relay.wyolet.dev/v1alpha3
kind: Account
metadata:
  name: acme-openai-enterprise
  owner: {kind: system}
spec:
  host: openai
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: RateLimit
metadata:
  name: acme-openai-gpt-5-5
  owner: {kind: system}
spec:
  rules:
    - {meter: requests, amount: 20000, window: 1m, strategy: sliding-window}
    - {meter: tokens, amount: 40000000, window: 1m, strategy: sliding-window}
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Policy
metadata:
  name: acme-openai-enterprise-tier
  owner: {kind: system}
spec:
  rateLimits:
    - ref: acme-openai-gpt-5-5
      models: [openai/gpt-5-5]
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: PolicyBinding
metadata:
  name: acme-openai-enterprise-tier
  owner: {kind: system}
spec:
  policy: acme-openai-enterprise-tier
  accounts: [acme-openai-enterprise]
```

An account has one policy. To move it to another tier, change the binding's `policy`; counters of a rate limit both tiers link carry over, since upstream counters do not depend on the policy.

## Per-project budgets

The `search` project gets a weekly cap and an alert below it, and its evaluation service account a daily cap and a single model:

```yaml theme={null}
apiVersion: relay.wyolet.dev/v1alpha3
kind: Budget
metadata:
  name: search-weekly
  owner: {kind: project, name: search}
spec:
  amountUsd: "250"
  period: week
  mode: hard
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Budget
metadata:
  name: search-weekly-alert
  owner: {kind: project, name: search}
spec:
  amountUsd: "150"
  period: week
  mode: alert
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Policy
metadata:
  name: search
  owner: {kind: project, name: search}
spec:
  budgets:
    - ref: search-weekly
    - ref: search-weekly-alert
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: PolicyBinding
metadata:
  name: search
  owner: {kind: project, name: search}
spec:
  policy: search
  accounts: [project-search]
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: ServiceAccount
metadata:
  name: eval-runner
spec:
  project: search
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Budget
metadata:
  name: eval-runner-daily
  owner: {kind: project, name: search}
spec:
  amountUsd: "20"
  period: day
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Policy
metadata:
  name: eval-runner
  owner: {kind: project, name: search}
spec:
  models: [openai/gpt-4o-mini]
  budgets:
    - ref: eval-runner-daily
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: PolicyBinding
metadata:
  name: eval-runner
  owner: {kind: project, name: search}
spec:
  policy: eval-runner
  accounts: [sa-eval-runner]
```

A request with an `eval-runner` key climbs three caller rungs: `team-ml`, `project-search`, then `sa-eval-runner`. It must fit the team's $2,000 a month, the project's $250 a week and the service account's $20 a day, and it may call only `gpt-4o-mini`, since the team allows all of OpenAI and the service account narrows that to one model. Neither project policy links a pool, so reach still comes from the team's `openai-main`. The alert budget refuses nothing; the charge that reaches $150 counts once in `relay_limits_budget_crossings_total`.

## Per-person caps

To give every person in a project the same cap of their own, link it per lane on the project's account rather than binding a policy to each member:

```yaml theme={null}
apiVersion: relay.wyolet.dev/v1alpha3
kind: RateLimit
metadata:
  name: per-person-rpm
  owner: {kind: project, name: search}
spec:
  rules:
    - {meter: requests, amount: 60, window: 1m, strategy: sliding-window}
---
apiVersion: relay.wyolet.dev/v1alpha3
kind: Policy
metadata:
  name: search
  owner: {kind: project, name: search}
spec:
  rateLimits:
    - ref: per-person-rpm
      shared: false
  budgets:
    - ref: search-weekly
    - ref: search-weekly-alert
```

Each lane under `project-search` (every member account in the project, and `sa-eval-runner`) now counts its own 60 requests a minute, while the weekly budgets stay one count for the project.

To cap one person differently, bind a policy to their member account in the project, `alice-project-search` for the user `alice`. It governs that account only: the requests of alice's inference tokens for `search`, and of her keys in that account. Her personal account and her accounts in other teams and projects are not affected.

## Checking the result

List what a credential can reach; a model a rung refuses does not appear:

```bash theme={null}
curl http://localhost:8080/v1/models -H "Authorization: Bearer <eval-runner key>"
```

Read the rungs a lane climbs and what is left of every limit on them:

```bash theme={null}
curl -H "Authorization: Bearer $RELAY_ADMIN_TOKEN" http://localhost:8081/api/accounts/sa-eval-runner/limits
```

Read what one policy allows and the limits it applies per model, without the rest of the ladder:

```bash theme={null}
curl -H "Authorization: Bearer $RELAY_ADMIN_TOKEN" http://localhost:8081/api/policies/ml/models
curl -H "Authorization: Bearer $RELAY_ADMIN_TOKEN" http://localhost:8081/api/policies/ml/rate-limits
```

A refused request names the rung and the policy that refused it; the codes are in [Policy refusals](https://docs.wyolet.com/reference/inference-api.md#policy-refusals).


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