usertrust
Policy

Policy Rules

Define governance rules in YAML with enforcement levels, severity, scopes, and time windows.

Rule Format

Rules are defined in YAML (or JSON) and loaded from .usertrust/policies/default.yml by default.

# Requires operator scope on the governor/config, e.g. scope: ["production/api"]
- name: block-expensive-models
  effect: deny
  enforcement: hard
  severity: high
  priority: 50
  conditions:
    - field: model
      operator: in
      value:
        - claude-opus-4-6
        - gpt-5.4
  scopePatterns:
    - "production/*"
  timeWindows:
    - daysOfWeek: [1, 2, 3, 4, 5]
      startHour: 9
      endHour: 17

Rule Fields

FieldTypeRequiredDefaultDescription
namestringyesUnique rule identifier
effect"deny" or "warn"yesWhat happens when matched
enforcement"hard" or "soft"yesHard = block, Soft = allow with warnings
severity"critical" | "high" | "medium" | "low" | "info"noSeverity level
prioritynumberno100Lower = higher priority
enabledbooleannotrueToggle rule on/off
conditionsFieldCondition[]yesConditions to match (ALL must match)
scopePatternsstring[]noMinimatch glob patterns
timeWindowsTimeWindow[]noTime-based restrictions

Enforcement

  • Hard — Returns decision: "deny". The LLM call is blocked.
  • Soft — Returns decision: "allow" with hasWarnings: true. The call proceeds but warnings are logged.

Scope Matching

Uses minimatch glob patterns against the operator-declared scope on the governor or usertrust.config.json — not request content, and not params.params.scope.

scopePatterns:
  - "production/**"    # matches production/api, production/chat/v2
  - "staging/*"        # matches staging/test but not staging/a/b

If the operator sets no scope, a rule with scopePatterns never matches. It does not "narrow a live rule". An absent scopePatterns still matches all calls.

Time Windows

Restrict when a rule is active:

timeWindows:
  - daysOfWeek: [1, 2, 3, 4, 5]   # Mon-Fri (0=Sun, 6=Sat)
    startHour: 9                     # 9 AM
    endHour: 17                      # 5 PM

Default Rules

Three rules ship by default:

  1. block-budget-overshoot — Deny when budget_remaining_after lt 0 (hard)
  2. block-budget-exhausted — Deny when budget_remaining lte 0 (hard)
  3. warn-high-cost — Warn when estimated_cost gt 1000 (soft)

PolicyResult

interface PolicyResult {
  decision: "allow" | "deny";
  hasWarnings: boolean;
  matched: RuleMatch[];
  hardViolations: RuleMatch[];
  softViolations: RuleMatch[];
  reasons: string[];
  evaluatedAt: string;
}