Skip to content

Verdicts

How a tool call becomes allow, block or hold, and every block reason.

Every tool call gets exactly one verdict: allow, block or hold.

  1. Token. The signature must be valid and the token not expired (30 seconds of clock leeway). Otherwise invalid_token or token_expired.
  2. Plan. The call must match a step of the signed plan. Otherwise not_in_plan.
  3. Limits. The step’s maxCalls must not be used up. Otherwise call_limit.
  4. Policy. Rules are evaluated in order; the first match decides. No match is no_matching_rule.

The plan checks run before the policy, so a policy can never allow a call that is outside the plan. Any error anywhere is a block with internal_error.

The same pure check() function from @intentlock/core runs on the server and in the client, so any decision can be recomputed later from its signed token.

A tool runs only on an explicit allow. An error, a timeout, a missing decision, a bad signature, an expired token that cannot be refreshed, or an audit write that fails: each of these is a block.

When a call is blocked, the model receives an error result instead of the tool output, for example:

Output
Blocked by Intentlock (not_in_plan): ...
This action is outside what the user asked for.
Reason Meaning
not_in_plan The tool or its arguments are not in the signed plan. Typical for prompt injection.
call_limit The step’s maxCalls was used up.
no_matching_rule No rule matched, so default: block applied.
a rule id A block rule matched. Its reason is included.
invalid_token The token signature did not verify.
token_expired The guard refreshes it automatically; blocks only if the refresh fails.
invalid_call The call itself was malformed.
internal_error Something threw while deciding.
server_unavailable The server was needed but unreachable (network error, timeout or 5xx).
api_key_rejected The server answered 401: the API key is unknown or revoked, or the agent is disabled.
gate_rejected The server refused with another 4xx; the guard’s error event has its error code.
audit_write_failed The decision could not be written to the local outbox.
audit_backlog The server has fallen too far behind on audit uploads.
hold_requires_server A hold rule matched, but the gate has no server (LocalGate).
unknown_tool, invalid_args The model called a tool you did not register, or with arguments your schema rejects.

A hold verdict pauses the call until a person decides. See Holds.