FactoryBudget
A Software Factory budget: a limit on the tokens or calls the factory spends, for the whole factory, one GitHub organisation, one repository. Fields, YAML, HCL and CLI samples, and how apply treats it.
A Software Factory budget: a limit on the tokens or calls the factory spends, for the whole factory, one GitHub organisation, one repository, one workflow or one step, with alerts and an action at the limit. metadata.name is the budget’s name in the console. One budget per scope and provider. The Factory budget (the whole factory, per month, every provider) is set with the budget settings of FactorySettings, not here. Removing the document deletes the budget; its ledger is kept.
apiVersion |
vulnetix.com/v1 |
kind |
FactoryBudget |
| Group | Factory |
| Status | Served. The config engine plans and applies it. |
| Objects per tenant | many, keyed by metadata.name |
| Token and role | An owner or admin session, or a vmt_ config management token with the owner or admin role that lists FactoryBudget in its kinds. See Management tokens. |
| Applied after | FactoryWorkflow (deleted before them) |
| Terraform resource | vulnetix_factory_budget, imported by name (see Terraform and OpenTofu) |
| CLI | vulnetix config apply, CLI v3.168.0 and later. |
| Pinned schema | v1.15.0/FactoryBudget.schema.json |
| Newest schema | latest/FactoryBudget.schema.json |
| First released in | v1.6.0 |
| Print the built-in copy | vulnetix config schema FactoryBudget |
Minimal
Only the fields the kind requires. From examples/FactoryBudget/minimal.yaml.
YAML
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/FactoryBudget.schema.json
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: org-monthly-tokens
spec:
appliesTo: org
limit: 20000000
HCL (resource vulnetix_factory_budget)
# Only the arguments the kind requires. From config-schemas examples/FactoryBudget/minimal.yaml.
resource "vulnetix_factory_budget" "org_monthly_tokens" {
name = "org-monthly-tokens"
applies_to = "org"
limit = 20000000
}
CLI (applies it)
export VULNETIX_CONFIG_TOKEN=vmt_... # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/FactoryBudget.schema.json
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: org-monthly-tokens
spec:
appliesTo: org
limit: 20000000
EOF
Advanced
Every field the kind supports, with a when expression where it takes one. From examples/FactoryBudget/advanced.yaml.
YAML
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/FactoryBudget.schema.json
# A budget for each scope that takes a reference.
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: patch-train-daily
labels:
team: appsec
spec:
appliesTo: workflow
workflow: security-patch-train
window: day
limit: 1500000
unit: tokens
provider: anthropic,openai
alertAt: [50, 80, 100]
actionAtLimit: pause_run
---
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: patch-step
spec:
appliesTo: node
workflow: security-patch-train
node: patch
window: node
limit: 300000
actionAtLimit: downgrade_to_fast
---
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: payments-repo
spec:
appliesTo: repo
repository: acme/payments
window: month
limit: 5000
unit: calls
actionAtLimit: escalate_human
---
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: acme-org
spec:
appliesTo: org
installationId: 41234567
limit: 10000000
actionAtLimit: alert_only
HCL (resource vulnetix_factory_budget)
# Every argument the kind supports. From config-schemas examples/FactoryBudget/advanced.yaml.
resource "vulnetix_factory_budget" "patch_train_daily" {
name = "patch-train-daily"
action_at_limit = "pause_run"
alert_at = [50, 80, 100]
applies_to = "workflow"
limit = 1500000
model_providers = "anthropic,openai"
unit = "tokens"
window = "day"
workflow = "security-patch-train"
labels = {
team = "appsec"
}
}
resource "vulnetix_factory_budget" "patch_step" {
name = "patch-step"
action_at_limit = "downgrade_to_fast"
applies_to = "node"
limit = 300000
node = "patch"
window = "node"
workflow = "security-patch-train"
}
resource "vulnetix_factory_budget" "payments_repo" {
name = "payments-repo"
action_at_limit = "escalate_human"
applies_to = "repo"
limit = 5000
repository = "acme/payments"
unit = "calls"
window = "month"
}
resource "vulnetix_factory_budget" "acme_org" {
name = "acme-org"
action_at_limit = "alert_only"
applies_to = "org"
installation_id = 41234567
limit = 10000000
}
CLI (applies it)
export VULNETIX_CONFIG_TOKEN=vmt_... # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/FactoryBudget.schema.json
# A budget for each scope that takes a reference.
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: patch-train-daily
labels:
team: appsec
spec:
appliesTo: workflow
workflow: security-patch-train
window: day
limit: 1500000
unit: tokens
provider: anthropic,openai
alertAt: [50, 80, 100]
actionAtLimit: pause_run
---
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: patch-step
spec:
appliesTo: node
workflow: security-patch-train
node: patch
window: node
limit: 300000
actionAtLimit: downgrade_to_fast
---
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: payments-repo
spec:
appliesTo: repo
repository: acme/payments
window: month
limit: 5000
unit: calls
actionAtLimit: escalate_human
---
apiVersion: vulnetix.com/v1
kind: FactoryBudget
metadata:
name: acme-org
spec:
appliesTo: org
installationId: 41234567
limit: 10000000
actionAtLimit: alert_only
EOF
Fields
Paths use dots for nesting and [] for the items of a list. Required means required whenever the parent object is present. A default is what the server uses when the field is left out.
| Field | Type | Required | Default | Allowed values | Description |
|---|---|---|---|---|---|
apiVersion |
string | yes | exactly vulnetix.com/v1 |
The document format version. Every kind in this release is vulnetix.com/v1. | |
kind |
string | yes | exactly FactoryBudget |
Always FactoryBudget. | |
metadata |
object | yes | no other keys | ||
metadata.name |
string | yes | pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ |
The object’s name, unique per kind within a tenant. It is the natural key: plan, apply, export and the Terraform provider all address an object by kind and name. | |
metadata.org |
string | no | format uuid |
The tenant (organization UUID) the document belongs to. When set, plan and apply refuse to run against any other tenant. | |
metadata.labels |
object | no | map of string to string (length 0 to 256); keys match ^[a-z0-9]([a-z0-9._/-]{0,61}[a-z0-9])?$ |
Free key/value labels. Stored with the object, never interpreted by the server. | |
metadata.annotations |
object | no | map of string to string (length 0 to 4096) | Free key/value notes for people and tools, such as a ticket link. | |
spec |
object | yes | no other keys | ||
spec.appliesTo |
string | yes | tenant, org, repo, workflow, node |
What the budget limits. tenant: the whole factory. org: the repositories of one GitHub App installation, or every organisation when installationId is left out. repo: one repository. workflow: one workflow. node: one step of one workflow. | |
spec.window |
string | no | run, day, week, month, node |
The period the limit covers: one run, a day, a week (from Monday) or a calendar month, all in UTC, or one step’s run (node). tenant and workflow take run, day, week or month; org and repo take month; node takes node. Defaults to month, and to node for a node budget. | |
spec.workflow |
string | no | pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ |
workflow and node: the metadata.name of a FactoryWorkflow. | |
spec.node |
string | no | pattern ^[A-Za-z0-9._-]{1,64}$ |
node: the id of the step in the workflow’s graph. | |
spec.repository |
string | no | pattern ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ |
repo: the repository, owner/name. | |
spec.installationId |
integer | no | >= 1 | org: the GitHub App installation id of the organisation. | |
spec.limit |
integer | yes | >= 1 | The limit, in unit, for the window. Not above the budget it sits inside: a step’s budget not above its workflow’s monthly budget, and any other not above the Factory budget, in the same unit. | |
spec.unit |
string | no | tokens |
tokens, calls |
What the limit counts: model tokens, or calls. Defaults to tokens. |
spec.provider |
string | no | pattern ^[A-Za-z0-9:_.-]{1,64}(,[A-Za-z0-9:_.-]{1,64})*$ |
The model providers the budget counts, as one provider id or a comma-separated list, such as anthropic or pix,openai. Every provider when left out. | |
spec.alertAt |
array of integer | no | 1 to 10 items; each item: 1 to 100 | The percentages of the limit, ascending, from 1 to 100, at which the factory raises an alert. Defaults to 80 and 100. | |
spec.actionAtLimit |
string | no | alert_only |
alert_only, pause_run, downgrade_to_fast, switch_to_pix_allocation, escalate_human, hard_stop |
What the factory does when the limit is reached: pause the run, downgrade to the fast model, switch to the Pix allocation, ask a person, stop hard, or only alert. Defaults to alert_only. |
Applying this kind
- Command.
vulnetix config apply -f <file>; the CLI line above says from which release. Plan first withvulnetix config plan: it shows each object as create, update, delete or no change, with aplanHashthat apply then holds to. Apply writes in one transaction. - Manager. Each object records the manager that applied it (
terraform,consoleorgitops:<repo>).--prunedeletes only objects its own manager owns. See The manager and the config engine. - Order. Applied after
FactoryWorkflow, so a document that refers to one bymetadata.namecan be in the same apply. Deleted before them. - Status. Applied, Unchanged or Deleted, with no other status fields. The phases the engine reports are explained under status phases.
How apply treats it
Through the budgets API’s validator and writers, so a budget declared as code gets the same row, event and audit entry. The tenant’s Factory budget belongs to FactorySettings (budget.*) and a repository’s token cap to RepositorySettings (monthlyTokenCap). Neither is listed here, and a document for a scope and provider that one already covers is refused. Delete soft-deletes the row.
Terraform and OpenTofu
The resource is vulnetix_factory_budget in the vulnetix/resolve provider. Its arguments are the spec in snake case, beside name, labels and annotations from metadata. The Minimal and Advanced HCL are above. The provider’s own reference is vulnetix_factory_budget.
Import an object that already exists by its name:
# Import an existing FactoryBudget by its name (metadata.name).
terraform import vulnetix_factory_budget.org_monthly_tokens org-monthly-tokens
Install, authentication and how state is read: Terraform and OpenTofu.
Check a file with vulnetix config validate -f <file>. See Validate documents. In an editor, start the file with the schema comment.