Risk Center
Read the distribution, tune from evidence rather than intuition, and understand why raising a threshold is a security change.
/risk in the console, backed by GET /v1/risk/overview.
#What the overview shows
| Counts by level | How much LOW / MEDIUM / HIGH / CRITICAL traffic you have |
| Signal breakdown | Which of the thirteen signals are firing, and how often |
| High-risk tools | Which tools produce the most elevated scores |
| Destinations | What your agents are actually contacting |
| Policy violations | Recent refusals, by agent |
| Credential anomalies | Unusual credential use |
Every score decomposes into named signals with human-readable explanations. There is no opaque model, because a refusal an operator cannot explain to the person it affected is a refusal that gets overridden, and then switched off.
#Read it in this order
The distribution
A healthy distribution has most traffic low and a thin tail. Two bad shapes:
Everything is HIGH. Your weights are too aggressive or your thresholds too
low. Any rule testing risk.score is now firing on everything, which means it
is not discriminating.
Everything is LOW. Either your traffic is genuinely uniform, or your
weights are too low to register anything. Check the signal breakdown — if
nothing is firing at all, the engine is not contributing.
The signal breakdown
For each of the thirteen signals, how often it fires.
| Pattern | Means | Do |
|---|---|---|
| Fires on nearly every action | Not discriminating | Lower its weight, or fix the baseline |
| Never fires | Irrelevant to your traffic, or weighted too low | Investigate before dismissing |
| Fires on a thin, consistent slice | Working as intended | Leave it |
New agents trip every "new" signal
NEW_TOOL, NEW_RESOURCE, NEW_RECIPIENT and UNUSUAL_DESTINATION are
baseline signals — they compare against what this agent has done before. A
brand-new agent has no baseline, so they fire on almost everything it does.
That is correct and it settles. Run new agents in OBSERVE or SIMULATE long
enough to establish a baseline before promoting, or you will spend the first week
reading noise.
High-risk tools
Tools that consistently produce elevated scores. Two questions for each:
- Is
dangerousset? If a tool is reliably scoring high, it probably deserves the flag and the approval requirement that comes with it. - Is the risk coming from the tool, or from how one agent uses it? The tool breakdown and the agent breakdown answer different things.
Destinations
What your agents actually contact, which is frequently not what anyone expected.
Compare against your tools' destination_allowlist entries. A destination
appearing here that nobody intended is worth a conversation, and probably a
narrower allowlist.
#Tune from evidence
httpPUT /v1/risk/configuration
Requires risk:configure. The change is audited.
The method:
- Run in
OBSERVEorSIMULATEand let real traffic accumulate — at least a week, covering a normal day and a quiet one. - Read the distribution and the breakdown.
- Adjust weights so each signal contributes in proportion to how much it actually tells you.
- Set thresholds where the distribution has a natural gap, not at round numbers.
- Re-check after a week.
Raising a threshold is a security change, not a tuning tweak
Moving the HIGH threshold from 70 to 85 silently removes the approval
requirement from every rule that tests it. Nothing errors. Nothing warns. Fewer
things get escalated and everything looks calmer.
It is audited for exactly that reason. Simulate before and after, and look at what stops being escalated — not at whether the dashboard looks tidier.
#Prefer signals over scores in rules
json{
"kind": "condition",
"id": "c-signal",
"field": "risk.signals",
"operator": "contains",
"value": "UNUSUAL_DESTINATION"
}
reads better than
json{ "kind": "condition", "id": "c-score", "field": "risk.score", "operator": "gte", "value": 70 }
A named signal is a sentence an operator can read back to you. A score is a number whose meaning changes every time you retune weights — which means a rule written against a score silently changes behaviour when you tune, and a rule written against a signal does not.
Use the score as a general safety net, and signals for the specific things you care about.
The raw observations behind the signals are available too, so you can write a
rule on the observation rather than the derived signal when that is clearer:
velocity.actions_last_minute, velocity.amount_last_day,
history.tool_used_before, history.destination_used_before,
history.resource_used_before, time.hour_utc, time.day_of_week.
#Risk events
httpGET /v1/risk/events
Every assessment that crossed a threshold, with its signal evidence attached.
Acknowledge with risk:acknowledge, so "we have looked at this" is recorded
rather than remembered. An unacknowledged backlog is a queue nobody is working,
same as approvals.
#Weekly review
- Distribution shape — any drift from last week?
- Any signal newly firing on everything, or newly silent?
- New destinations?
- New high-risk tools, or an existing one that got worse?
- Unacknowledged events accumulating?
Fifteen minutes. The value is in the deltas, not the absolute numbers.