governance block lets you seed all governance resources directly in config.json. On startup, Bifrost loads these into the configuration store. This is the recommended approach for GitOps workflows where governance state is managed as code.
In default split mode, file-backed governance resources seed or update the DB by hash while unrelated DB-only resources are preserved. With
source_of_truth: "config.json", only governance sub-sections that are explicitly present in the file are authoritative. Omit a sub-section to leave DB-managed rows alone; set it to an empty array only when you intend to remove stored rows for that sub-section. See Source of Truth & Reconciliation.Governance enforcement is always active in OSS - you do not need a plugin entry to enable it. To require a virtual key on every inference request, set
client.enforce_auth_on_inference: true. This is the global default, but a more specific inference-auth flag such as governance.auth_config.disable_auth_on_inference overrides it; if no specific override is set, client.enforce_auth_on_inference applies.Admin Authentication
Protect the Bifrost dashboard and management API with username/password auth:Virtual Keys
Virtual keys are issued to clients and act as scoped API tokens. Each key specifies which providers, models, and API keys the bearer is allowed to use.Virtual Key Fields
Provider Config Fields
Budgets
Budgets cap cumulative spend (in USD) for an owning governance entity over a rolling window. The owner is declared on the budget:
Set at most one owner field on a budget. A team can own multiple budgets with different reset durations.
Rate Limits
Rate limits cap requests or tokens over a rolling window:
Attach a rate limit to a virtual key via
virtual_keys[].rate_limit_id, or to a provider config via virtual_keys[].provider_configs[].rate_limit_id.
Model Limits
governance.model_configs applies budgets and rate limits keyed on a model name, an optional provider, and a scope. This is the same data the Budget & Limits → Model Limits UI manages.
Routing Rules
Routing rules dynamically select the provider and model for each request based on a CEL expression. They are evaluated in priority order before the request is dispatched.Rule Fields
Target Fields
Customers & Teams
Define organizational entities and attach rate limits directly. Team budgets reference their owner throughgovernance.budgets[].team_id:
Projects
Declare projects that requests opt into for access and accounting. A project composes with what the caller already holds, spends against its own budgets, the calling principal’s, or both asaccounting_mode directs, and can divide every budget and rate limit it holds equally between its members.
governance.projects is an enterprise capability. Members are added from the dashboard: a project declared here starts with none, and membership cannot be declared in the file. The schema rejects a members key.x-bf-project-name header.
Project Fields
Budgets and rate limits inside a project are declared without ids.
Project Provider Config Fields
How projects are reconciled
- Matched by name. A name not in the database creates the project; a name already stored updates it when the declaration’s hash differs from the one recorded at the last sync, and leaves it alone otherwise, so dashboard edits survive until the file changes.
- Edits keep spend. Budgets are paired with their stored rows by
reset_duration(in declared order when a duration appears twice), provider configs byprovider_name, model budgets bymodel_name, and MCP configs by client. A paired row is updated in place, so raising a cap does not forgive what was already spent against it. A budget, provider, or client the file stops declaring is removed. - Equal splits redivide in the background. Changing a cap or the split policy of a project with
split_policy: equalqueues a recalculation of every member’s share, which runs shortly after startup. - Members are never touched. The file cannot add or remove members; the schema rejects a
memberskey on a project. - With
source_of_truth: "config.json"andgovernance.projectspresent, declarations always overwrite the database and projects the file does not declare are deleted, members included.

