Scores & verdicts

Every check answers nine questions about the proposed action in one forward pass. Each answer is a calibrated probability (or a distribution), so a 0.9 means roughly nine in ten similar actions were judged that way. The server turns them into a default verdict; you can use it as is or apply your own thresholds.

The nine scores

ScoreDescription
safenumber 0–1P(safe to run now). p_unsafe = 1 − safe.
violationdistributionnone / policy_violation / scope_violation / injection / goal_drift / corrigibility: what kind of problem, if any.
severityordinalnone < low < medium < high: how bad the outcome would be.
destructivenumber 0–1Deletes, overwrites or irreversibly changes data.
exfiltrationnumber 0–1Sends private data, secrets or another tenant's data where it should not go.
injectednumber 0–1Driven by instructions from a tool result or document rather than the user (prompt injection).
approval_policydistributionauto_approve / require_human / reject: what a careful operator would do.
blast_radiusordinalread-only < local or reversible write < production-mutating or external side effect.
args_groundednumber 0–1The arguments are supported by what the user asked: no invented ids, amounts or recipients.

Shapes

Single probabilities are numbers. violation and approval_policy are objects with one probability per option. The two ordinal scores, severity and blast_radius, carry expected (Σ i·p(i)), the most probable level and the probabilities per level, lowest first.

scores (example)json
{
  "safe": 0.0403,
  "violation": {
    "none": 0.0234,
    "policy_violation": 0.0768,
    "scope_violation": 0.383,
    "injection": 0.0552,
    "goal_drift": 0.3826,
    "corrigibility": 0.079
  },
  "severity": {
    "expected": 2.61,
    "level": "high",
    "probabilities": [
      0.03,
      0.08,
      0.14,
      0.75
    ]
  },
  "destructive": 0.9987,
  "exfiltration": 0.0214,
  "injected": 0.0311,
  "approval_policy": {
    "auto_approve": 0.0122,
    "require_human": 0.1105,
    "reject": 0.8773
  },
  "blast_radius": {
    "expected": 1.93,
    "level": "production-mutating or external side effect",
    "probabilities": [
      0.01,
      0.05,
      0.94
    ]
  },
  "args_grounded": 0.2135
}

The default verdict rule

The server applies this rule to the scores, in order:

  1. block if p_unsafe ≥ 0.8, or approval_policy says reject (reject is the most likely option, at 0.6 or more);
  2. ask if p_unsafe ≥ 0.3, approval_policy says require_human, or args_grounded < 0.5;
  3. allow otherwise.

reasons lists what stood out: destructive (≥ 0.5), possible data exfiltration (≥ 0.5), driven by tool output (injected ≥ 0.5), arguments not supported by the request (args_grounded < 0.5), and the most likely violation type when it is at least 0.5.

Your own thresholds

The default is a sensible starting point, not your policy. The scores are there so you can be stricter where it matters (production writes, payments, outbound email) and looser where it does not (read-only tools in a sandbox).

custom rulets
// Your own policy on the scores (TypeScript). Stricter on production writes.
function decide(r: GuardResult, env: "production" | "staging"): "allow" | "ask" | "block" {
  const s = r.scores;
  if (s.exfiltration >= 0.5 || s.injected >= 0.7) return "block";
  if (env === "production" && s.blast_radius.level !== "read-only" && r.p_unsafe >= 0.15) return "ask";
  return r.verdict; // otherwise the server's default
}

What the scores are and are not

  • The model is DeBERTa-v3-base (184M parameters) fine-tuned on about 31k labelled agent actions: public agent-safety data plus our own labelled benign and adversarial tool calls.
  • On R-Judge (a public benchmark of agent safety trajectories, held-out test half, 304 trajectories) it scores AUROC 0.855, against 0.824 for saroku-guard (an open 184M guard model): on par with or better than it. The difference is not yet statistically significant.
  • The model reads about 384 tokens per check. Put the decisive part in action and intent; long conversations are cut.
  • It reduces risk; it does not guarantee safety. Keep deterministic rules for known-bad patterns and use the guard as one layer. See integrations for where it sits.