Skip to main content
Governance lets you control who can call which providers, how much they can spend, how fast they can go, and how traffic is routed. Everything is declared under bifrost.governance in your values file and seeded into the database at startup.
The governance plugin must also be enabled for enforcement to take effect:
See the Plugins page for plugin configuration details.

Admin Authentication

Protect the Bifrost dashboard and management API with username/password auth.

Budgets

Spending caps that reset on a configurable period. Team-owned budgets declare team_id on the budget itself; teams do not declare budget_id.

Rate Limits

Token and request-count caps per time window. Referenced by ID from virtual keys, teams, customers, or providers.

Customers & Teams

Optional organizational hierarchy. Virtual keys can be assigned to customers or teams, inheriting their budgets and rate limits.

Virtual Keys

Virtual keys are the primary access tokens issued to callers. They scope which providers, models, and underlying API keys are accessible.
provider_configs[].key_ids and provider_configs[].keys are both supported in Helm values. Prefer key_ids for parity with config.json (key_ids should contain provider key names). To delete expired keys globally, set bifrost.client.deleteExpiredVirtualKeys: true (renders into client.delete_expired_virtual_keys). A daily job then removes every expired key except those with delete_after_expire: false. To let a virtual key call an A2A agent, grant it from the agent side with bifrost.agents[].virtual_key_ids. Use a virtual key in API calls:

Model Limits

Apply budgets and rate limits at the model level. Each entry is keyed on model_name (use "*" for all models), an optional provider, and a scope that determines who the limit applies to.

Provider Governance

Apply budgets and rate limits at the provider level:

Routing Rules

CEL-expression-based routing rules redirect requests to different providers or models based on request attributes.

Complexity Router Configuration

If you use complexity_tier in routing rules, choose a decision model or Semantic as the primary classifier in Helm. The chart renders this block to governance.complexity_analyzer_config in config.json. The decision model is Typesafe Jev by default, or any decision model reachable through /v1/decisions (for example gpt-6-luna on openai, Clef on cloudflare, or Laya or Nimble served by a custom provider with base_provider_type: typesafe); it uses that provider’s enabled key. Semantic needs an embedding provider and reference phrases. Omit this block, or leave complexityAnalyzerConfig: null, to leave complexity classification disabled. To enable it, supply all three keywords lists. They are required by the current config shape even when the decision model is primary, though it does not use the phrases. In the default split mode, supplied phrases merge with stored built-in defaults; with sourceOfTruth: config.json, the supplied lists are the complete phrase set. For a decision model as the primary classifier:
decision.provider and decision.model are set together; omit both to use typesafe/jev-latest. decision.previous_message_count accepts 0 to 5 earlier user messages in addition to the current request. Decision-model usage counts toward request cost and budgets. decision.criteria optionally overrides the tier guidance the decision model classifies against. Its keys are SIMPLE, MEDIUM, and COMPLEX, each with an optional definition (max 500 characters), signals, and examples (each max 12 items of 300 characters). A supplied list replaces the whole default list, and anything omitted uses the shipped default. See Tier guidance for the defaults and how to write your own. To use the decision model after an inconclusive semantic result, keep the semantic configuration below, set semantic.fallback: decision, and optionally include the decision settings above. For Semantic as the primary classifier:
session.enabled is optional and defaults to false for both classifiers. When enabled, an identified session retains its highest observed tier for 24 hours of inactivity; normally sequential turns can escalate while lower proposals keep the stored tier. Overlapping requests for the same session are best-effort and resolve by last writer wins. The lifetime is built in and is separate from provider prompt-cache TTLs.
In the default split mode, runtime UI and API edits are preserved while the matching Helm-rendered section is unchanged. When Helm changes a section, keyword lists are merged additively with stored runtime phrases (union with duplicates removed), and the semantic block is replaced as one unit. Use bifrost.sourceOfTruth: config.json only when Helm should replace stored config state. See Source of Truth & Reconciliation for the full startup rules.
Existing releases that still use code_keywords, technical_keywords, and reasoning_keywords remain valid during upgrade. Bifrost maps them into the three reference-phrase lists; new configurations should use the three-list shape shown above. Legacy tier_boundaries also remain accepted when present, but are optional and ignored by semantic routing.

Full Example


Access Profiles (Enterprise)

You can seed enterprise access_profiles directly from Helm values. The chart renders bifrost.accessProfiles into top-level access_profiles in config.json.