Skip to main content
Each example is a relay.wyolet.dev/v1alpha3 manifest bundle. Apply it with relay apply, dry run first:
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, and the account names (team-ml, project-search, sa-eval-runner) on Accounts. 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.
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:
A project that brings its own OpenAI organization owns its account and binds the tier itself, with a binding owned by the project:
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:
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:
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:
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:
Read the rungs a lane climbs and what is left of every limit on them:
Read what one policy allows and the limits it applies per model, without the rest of the ladder:
A refused request names the rung and the policy that refused it; the codes are in Policy refusals.