Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.phrony.com/llms.txt

Use this file to discover all available pages before exploring further.

L1 anomaly control attaches a JSON rule set to an agent version (under Limits & safety). Rules apply only when the model attempts a tool that is already on that version’s operations allowlist. For why Guard exists and dashboard workflows, start with Guard overview.

How rules are evaluated

Phrony uses two complementary paths:
  1. Inline checks — When the model tries to call a tool, the runtime evaluates the effective rule set before the call proceeds. The outcome can allow, block, pause for review, or end the session, depending on what matched.
  2. Follow-up correlation — The platform replays the same rule definitions against recorded events so per-run / per-session counters stay consistent and Guard incidents, alerts, and audits reflect the run. That path does not undo an inline decision after a call has already finished.
Treat block and session termination as immediate at attempt time when they win precedence. Pause creates an anomaly_review user task so someone can approve or reject before the tool runs.

Effective rule list in multi-agent sessions

In multi-agent trees, a tool attempt may be governed by rules from ancestors in the session as well as the current agent version. Phrony concatenates those lists (ancestors first, then this version’s rules) into one set used for evaluation.

Rule shape

Each rule has:
FieldMeaning
idStable identifier for auditing and UI.
whenConditions (below). An empty when matches nothing—a safeguard against accidental “match everything” rules.
thenOne of allow, block, pause, terminate_session.
reason (optional)Short text carried into audits and operator-facing views.

When several rules match

Every matching rule is recorded in the audit trail. The outcome applied to the call uses strict precedence: terminate_sessionblockpauseallow The strictest matching action wins; history still lists all rules that matched.

Conditions (when)

Top-level predicates are combined with AND. Nested all_of, any_of, and not build richer logic.
Predicate ideaRole
Tool identityMatch allowed tool names via a list or a regex.
ArgumentsCompare, bound, list-membership, regex, or presence checks at JSON paths in the tool payload.
call_count_in_run_gtMatches once a tool (optionally scoped to one tool name) has been attempted more than a threshold in the current run.
call_count_in_session_gtSame pattern across the entire session, including root and sub-agent runs, using shared session semantics.
call_count_in_window_gtMatches when attempts exceed a threshold inside a sliding time window (seconds).
call_count_in_window_gt: Enforced in async / Guard-side evaluation. The inline checker at attempt time does not apply this predicate by itself. Use it for follow-up detection (incidents, alerts), not a guarantee at every single attempt.

Example rules (illustrative)

These snippets show patterns you can adapt. tool_name_in must list the exact tool names Phrony exposes for your allowed operations—that is usually each operation’s id (often a UUID), not the label you see in the UI. Copy real values from the agent version, a manifest export, or session tooling so when matches live attempts. Argument paths (amount, to, and so on) must match the JSON shape your integration’s tool schema uses. Rules with then: pause require a HITL or Sub-agent execution mode agent; block and terminate_session work on Request mode too.

Payments — pause transfers above a threshold (HITL)

Pause before the tool runs so someone can approve large movements (adjust the path and currency field to match your connector).
{
  "id": "transfer-over-10k-usd",
  "when": {
    "all_of": [
      { "tool_name_in": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"] },
      { "arg_gt": { "path": "amount", "value": 10000 } }
    ]
  },
  "then": "pause",
  "reason": "Wire or ACH over $10,000 requires human approval"
}
Replace the placeholder id with your payment / transfer operation’s id. If your API sends cents, use amount_cents and a threshold like 1000000 for $10,000.

Email — block sends without a support ticket (Request)

Use arg_missing so the model cannot call send unless it supplies a field your schema defines (here support_ticket_id).
{
  "id": "email-requires-ticket",
  "when": {
    "all_of": [
      { "tool_name_in": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"] },
      { "arg_missing": { "path": "support_ticket_id" } }
    ]
  },
  "then": "block",
  "reason": "Outbound email must reference a support_ticket_id"
}

Email — pause when the recipient looks like personal webmail (HITL)

arg_regex matches a string at a JSON path. Tune the path (to, recipients.0, body.to, and so on) and pattern to your tool’s arguments.
{
  "id": "email-consumer-inbox-pause",
  "when": {
    "all_of": [
      { "tool_name_in": ["bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"] },
      {
        "arg_regex": {
          "path": "to",
          "pattern": "@(gmail|yahoo|hotmail|icloud)\\."
        }
      }
    ]
  },
  "then": "pause",
  "reason": "Sending to a common consumer domain needs review"
}
Phrony validates regex patterns when rules are saved. In JSON, a literal dot in the pattern is written as \\. (backslash + dot inside the string).

Payments or charges — stop the session after too many attempts

call_count_in_run_gt matches when the attempt count for the scope is strictly greater than value (see the call_count_in_run_gt row in the conditions table). Example: with value: 2 and a tool filter, the rule can match on the third attempt of that tool in the same run, so you can end the session before further payment tries.
{
  "id": "payment-retries-cap",
  "when": {
    "all_of": [
      { "tool_name_in": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"] },
      { "call_count_in_run_gt": { "tool": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "value": 2 } }
    ]
  },
  "then": "terminate_session",
  "reason": "Too many payment attempts in one run"
}
Omit the optional tool on call_count_in_run_gt if you want the threshold to apply across all tools in the run (see the conditions table above).

Email or messaging — burst detection (async / Guard)

Flag many sends in a short wall-clock window for incidents or alerts—not a hard inline gate on every single attempt:
{
  "id": "email-burst-window",
  "when": {
    "call_count_in_window_gt": {
      "tool": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
      "value": 30,
      "windowSeconds": 300
    }
  },
  "then": "pause",
  "reason": "More than 30 send attempts in five minutes"
}
Remember: call_count_in_window_gt is evaluated on the async / Guard path. Pair it with how you want operators to respond (incidents, anomaly_alert tasks, and so on). A rule whose when is only a window predicate does not drive inline checks by itself—use call_count_in_run_gt or argument predicates when you need a hard gate on every attempt.

Execution mode and pause rules

Rules with then: pause stop before the tool executes and open anomaly_review. Phrony rejects saving pause rules on agents in Request execution mode. Use HITL on the agent (or configure a Sub-agent appropriately) when you need pause-for-review behavior from L1. block, allow, and terminate_session remain available on Request-mode agents.

Terminate session

terminate_session ends the session when it wins precedence for a matched attempt. Use it when a pattern must stop all further work in that session, not only block a single call.

Manifest and exports

Version-level anomaly settings appear in a manifest as anomalyControl and optional rules on each version. The JSON rule format is shared across runtime and policy evaluation.