Skip to main content
The decision engine evaluates guardrail rules at two boundaries: run start and step creation. Evaluation short-circuits on the first DENY — if the kill switch is active, no other rules are checked.

Evaluation Priority

Rules are evaluated in this exact order:
PriorityRuleDeny ReasonRun StartStep
1Kill switchKILL_SWITCH_ACTIVEYesYes
2User blockedUSER_BLOCKEDYesYes
3Workspace daily budgetWORKSPACE_DAILY_BUDGET_EXCEEDEDYesYes
4User daily budgetUSER_DAILY_BUDGET_EXCEEDEDYesYes
5Monthly run limitMONTHLY_RUN_LIMIT_EXCEEDEDYesNo
6Max concurrent runsMAX_CONCURRENT_RUNS_EXCEEDEDYesNo
Rules 5 and 6 only apply at run start — they don’t make sense for individual steps within an already-running run.

Run Start vs Step Checks

Run Start (all 6 rules)

When guard.run() is entered, the SDK calls POST /v1/runs/. The engine evaluates all 6 rules:
  1. Is the kill switch active?
  2. Is this user blocked?
  3. Has the workspace exceeded its daily budget?
  4. Has this user exceeded their daily budget?
  5. Has the workspace hit its monthly run limit?
  6. Are there too many concurrent runs?
If allowed: a new run is created with status RUNNING, the concurrent run counter is incremented, and the monthly run counter is incremented.

Step Checks (rules 1-4)

When run.model_call() or run.tool_call() is called, the SDK calls POST /v1/runs/{id}/steps. The engine evaluates rules 1-4:
  1. Is the kill switch active?
  2. Is this user blocked?
  3. Has the workspace exceeded its daily budget?
  4. Has this user exceeded their daily budget?
This catches cases where budgets are exceeded mid-run, or where the kill switch is activated while a run is in progress.

Two-Tier Evaluation

Pikarc uses a two-tier evaluation strategy for performance:
Request → Try Redis cache → cache hit? → evaluate from cache → return
                          → cache miss? → warm from Postgres → retry
                          → still miss? → fall back to full DB query

Fast Path (Redis)

All guardrail data is cached in Redis:
  • Kill switch state
  • Workspace config (budgets, concurrent limit, plan, monthly run limit)
  • User blocked status
  • Daily spend counters (workspace and per-user)
  • Concurrent run count
  • Monthly run count
Spend counters use microdollars (1 USD = 1,000,000 microdollars) for atomic INCRBY without floating-point drift.

Fallback Path (Postgres)

If any Redis value is missing, the engine attempts to warm the cache from Postgres and retry. If the cache is still incomplete, it falls back to a full database evaluation. In practice, the Redis fast path handles the vast majority of requests. The Postgres fallback is a safety net for cold starts and Redis failures.

Decision Record

Every evaluation produces a Decision record stored alongside the step:
{
  "outcome": "DENY",
  "reason": "WORKSPACE_DAILY_BUDGET_EXCEEDED",
  "evaluated_rules": {
    "kill_switch": "PASS",
    "user_blocked": "PASS",
    "workspace_daily_budget": "DENY"
  }
}
The evaluated_rules field shows exactly which rules were checked and their results, which is useful for debugging why a request was denied.

Kill Switch

The kill switch is the highest-priority guardrail. When active, every run start and step creation is immediately denied with KILL_SWITCH_ACTIVE. No other rules are evaluated. Toggle it via the API:
# Enable
curl -X POST http://localhost:8000/v1/workspace/kill-switch \
  -H "Authorization: Bearer lg_..." \
  -H "Content-Type: application/json" \
  -d '{"active": true}'

# Disable
curl -X POST http://localhost:8000/v1/workspace/kill-switch \
  -H "Authorization: Bearer lg_..." \
  -H "Content-Type: application/json" \
  -d '{"active": false}'
Or use the toggle in the Configuration page of the dashboard.
The kill switch requires the Scale plan or higher.