Outpost Budget Enforcement
The Outpost enforces per-org budget caps locally before forwarding requests to AI providers. Caps are configured in the policy bundle and evaluated by BudgetCapEnforcer before each request is proxied. When a cap is exceeded the Outpost can block requests, surface a warning header, or silently log the overage — depending on the configured action mode.
Budget enforcement runs entirely on the Outpost. No real-time call to the Platform is required; enforcement decisions use locally-tracked usage from the SQLite UsageTracker. This design keeps enforcement reliable even when the Outpost has degraded Platform connectivity.
How budget enforcement works
Section titled “How budget enforcement works”Every inbound request to /v1/chat/completions passes through BudgetCapEnforcer.check() before being forwarded:
- The enforcer reads
budget_configfrom the current policy bundle. - It calls
UsageTracker.get_current_period_totals()to retrieve the running dollar spend and request count for the current billing period. - It computes
dollar_percentandrequest_percentas a fraction of each configured cap. - If usage is 80–99% of any cap,
warning=Trueis set and the proxy addsX-Budget-Warning: approachingto the response. - If usage reaches 100% of any cap, the action configured in
action_on_exceedtakes effect. - When
action_on_exceed=block, the proxy returns HTTP 429 withX-Budget-Status: exceeded.
Fail-open guarantee
Section titled “Fail-open guarantee”If budget_config is absent from the policy bundle (first-time deployment, bundle not yet synced), the enforcer defaults to log_only and never blocks requests. Any unexpected exception inside the enforcer is caught and the request is allowed — a bug in budget enforcement must never take down the proxy.
Billing periods
Section titled “Billing periods”The budget_config schema supports two period types:
period value | Period key format | Reset behaviour |
|---|---|---|
monthly (default) | YYYY-MM | Resets at the start of each calendar month |
hourly | YYYY-MM-DDTHH | Resets at the top of each clock hour |
The UsageTracker derives the period key from the current UTC time. Counters for previous periods are retained in the SQLite database for audit history; only the current-period totals are compared against caps.
Policy bundle configuration
Section titled “Policy bundle configuration”Budget configuration lives in the budget_config key of the policy bundle. Configure caps in the Admin Portal under Settings → Budget — values propagate to all Outposts on the next policy sync (default 60-second interval).
{ "budget_config": { "monthly_dollar_cap": 500.0, "monthly_request_cap": 10000, "action_on_exceed": "block", "period": "monthly" }}| Field | Type | Default | Description |
|---|---|---|---|
monthly_dollar_cap | float | 0 (disabled) | Maximum estimated spend in USD per billing period. Set to 0 or omit to disable the dollar cap. |
monthly_request_cap | int | 0 (disabled) | Maximum number of requests per billing period. Set to 0 or omit to disable the request cap. |
action_on_exceed | string | "log_only" | Enforcement mode when a cap is exceeded. See Action modes. |
period | string | "monthly" | Billing period type: "monthly" or "hourly". |
Action modes
Section titled “Action modes”| Mode | On cap exceeded | HTTP status | Response header | Log level |
|---|---|---|---|---|
block | Request denied | 429 | X-Budget-Status: exceeded | WARNING |
warn | Request allowed | 200 | X-Budget-Warning: approaching | WARNING |
log_only | Request allowed | 200 | — | INFO |
block is recommended for production when strict spend control is required.
warn allows continued service while surfacing the overage — use when visibility is needed without hard cutoffs.
log_only (default when no budget_config is present) records the overage without affecting end-users.
Warning threshold
Section titled “Warning threshold”Regardless of action_on_exceed, when usage reaches 80% of any cap the Outpost adds X-Budget-Warning: approaching to the proxied response. This signals approaching limits before enforcement triggers.
Environment variables
Section titled “Environment variables”| Variable | Default | Description |
|---|---|---|
USAGE_DB_PATH | usage_data/usage.db | Path to the SQLite database used by UsageTracker. Set to empty string to disable local usage tracking entirely (budget enforcement becomes a no-op). |
Dollar and request caps are not configurable via environment variables — they are always set through the policy bundle.
Admin API: budget status
Section titled “Admin API: budget status”The Outpost exposes a budget status endpoint on the admin API (port 8301, localhost-only):
GET /admin/api/budget/statusAuthorization: Bearer <admin-token>Response fields:
| Field | Type | Description |
|---|---|---|
period | string | Current billing period key (e.g. 2026-03 or 2026-03-12T14) |
period_type | string | monthly or hourly |
dollar_cap | float | Configured dollar cap (0 = unlimited) |
dollar_spent | float | Estimated USD spend in the current period |
dollar_percent | float | dollar_spent / dollar_cap × 100 (0 when cap is 0) |
request_cap | int | Configured request cap (0 = unlimited) |
request_count | int | Requests made in the current period |
request_percent | float | request_count / request_cap × 100 (0 when cap is 0) |
status | string | ok, warning (80–99%), or exceeded (≥100%) |
Example response:
{ "period": "2026-03", "period_type": "monthly", "dollar_cap": 500.0, "dollar_spent": 412.33, "dollar_percent": 82.5, "request_cap": 10000, "request_count": 8621, "request_percent": 86.2, "status": "warning"}BudgetPanel — admin UI
Section titled “BudgetPanel — admin UI”The Outpost admin UI (http://localhost:8301) includes the BudgetPanel under the Monitoring section. It shows:
- Dollar spend vs. cap — progress bar with warning (amber at 80%) and exceeded (red at 100%) colouring
- Request count vs. cap — same visual treatment
- Current
action_on_exceedbadge - Token counts (input + output) for the current period
- Auto-refresh every 60 seconds
The panel fetches both /admin/api/budget/status and /admin/api/usage to combine budget enforcement state with raw usage totals.
Multi-model cost calculation
Section titled “Multi-model cost calculation”Estimated cost is computed by the UsageTracker using token counts from AI provider responses and per-model pricing from the policy bundle’s cost_rates map. If the provider does not return token counts (e.g. non-buffered streaming path), the usage for that request is recorded as 0 tokens.
Cost estimates may differ from actual provider billing due to provider-specific rounding, mid-period pricing changes, or requests that fail before token counts are returned. Monitor both Arbitex-reported usage and direct provider billing dashboards in production.
Troubleshooting
Section titled “Troubleshooting”Requests blocked unexpectedly (HTTP 429)
Section titled “Requests blocked unexpectedly (HTTP 429)”- Confirm the Outpost has synced the latest policy bundle. Check
last_sync_atin the admin health panel — a stale bundle may contain an outdated lower cap. - Confirm the billing period. Caps reset at period rollover. If the period just rolled over, usage should be near zero.
- Review Outpost logs for
Budget BLOCKentries — they log the exact totals and period that triggered enforcement.
Usage counters not resetting at period rollover
Section titled “Usage counters not resetting at period rollover”The UsageTracker resets counters when the period key changes. If the Outpost was stopped at the rollover boundary, stale totals may persist until the next request. Restart the Outpost or wait for the next request — the reset happens on the first check of the new period.
Action mode not taking effect
Section titled “Action mode not taking effect”- Confirm the policy bundle has been synced. Check the policy version in the admin health panel.
- Verify the cap values are non-zero. A
monthly_dollar_cap: 0withaction_on_exceed: blockwill never trigger —0means no cap.
See also
Section titled “See also”- Outpost health monitoring — heartbeat payload, cert expiry, DLP tier status
- Outpost policy simulator — test budget config against live usage totals before deploying