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.

- 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 request's scope array:

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

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. zero-budget — Block if budget is 0 (hard deny)
  2. high-cost — Warn on estimated cost > 1000 UT (soft warn)
  3. budget-exhausted — Block if remaining budget < estimated cost (hard deny)

PolicyResult

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