Guardrails API
Guardrails are the trust policy the deterministic executor evaluates before any side effect runs. Rules can live in two places: embedded on an operator (the guardrails array in the Operators API) or as tenant-level policies managed here, which apply across every operator. This page documents policy CRUD, the rule schema, versioning, and the dry-run evaluator that answers "what would this policy do to this action?" without running anything.
Shared conventions are defined in the API overview. The conceptual model, fail-closed evaluation and the ALLOW/ALERT/BLOCK verdicts, is covered in Governance & trust and Trust tiers.
Evaluation composes tenant policies with the proposing operator's embedded guardrails: a side-effecting action must be allowed by at least one matching rule from either set, and any matching rule whose constraint fails blocks it. No matching rule at all means BLOCK. Deleting every policy does not open anything; it closes everything.
The guardrail policy object
Unique identifier, prefixed grd_.
Always guardrail_policy.
Slug-style name, unique within the tenant, for example refund-ceiling. Immutable; the name is how receipts cite the policy.
Free-text intent, for auditors and future maintainers.
active or disabled. A disabled policy is skipped in evaluation. Because the model is default-closed, disabling an ALLOW policy narrows what can run; it never widens it.
Monotonic version number, starting at 1. Every change to rules increments it; prior versions remain readable. Receipts record the exact version that produced each verdict.
The rule documents, evaluated as a set. Schema below.
RFC 3339 timestamp of creation.
RFC 3339 timestamp of the last version bump.
The rule document schema
Each rule matches a slice of proposed actions and contributes a decision. The fields mirror the kernel's TrustPolicy:
Match only actions on this connector. Omitted means any connector.
Match only actions calling this tool, for example order.hold. Omitted means any tool.
Ceiling compared against the action's value (a refund amount, an order total). A matching action whose value exceeds the ceiling is blocked, whatever the rule's decision says.
ALLOW or ALERT. ALERT means the action needs a human approval before it runs. BLOCK is not writable: blocking is what happens when nothing allows, or when a constraint fails.
Evaluation semantics, identical to the kernel's evaluate(): collect every rule whose connector and tool matchers fit the action, across active tenant policies and the operator's embedded guardrails. No matches: BLOCK. Any match whose max_value constraint fails: BLOCK. Otherwise, if any matching rule says ALERT: ALERT; else ALLOW. The most cautious matching rule always wins.
{
"id": "grd_3c90e1",
"object": "guardrail_policy",
"name": "refund-ceiling",
"description": "Refunds auto-run to $250; larger refunds page a human.",
"status": "active",
"version": 3,
"rules": [
{ "tool": "order.refund", "decision": "ALLOW", "max_value": 250 },
{ "tool": "order.refund", "decision": "ALERT" }
],
"created_at": "2026-05-14T10:00:00Z",
"updated_at": "2026-06-30T16:42:12Z"
}
Read the example carefully: a $180 refund matches both rules, the first allows it under its ceiling, the second says ALERT, and ALERT wins, so a human approves every refund. To auto-run small refunds, the second rule would need a min_value-style split, which v0.9 expresses by giving the ALERT rule to a different tool or by relying on the ceiling alone: one ALLOW rule with max_value: 250 blocks larger refunds outright rather than alerting. Test the composition you intend with the dry-run endpoint before activating it.
List policies
guardrails:readReturns the tenant's guardrail policies, newest first, cursor-paginated with the standard limit and cursor parameters.
Filter by active or disabled.
Only policies with at least one rule matching this tool, including rules with no tool matcher.
curl "https://api.fibric.io/v1/guardrails?status=active" \
-H "Authorization: Bearer $FIBRIC_KEY"
Create a policy
guardrails:writeCreates a policy at version: 1. New policies take effect for the next evaluated plan; plans already disposed are never re-evaluated.
Slug-style name, unique within the tenant. Lowercase letters, digits, and hyphens; 3–40 characters.
One or more rule documents per the schema.
Free-text intent. Defaults to null.
active or disabled. Defaults to active.
curl -X POST https://api.fibric.io/v1/guardrails \
-H "Authorization: Bearer $FIBRIC_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: grd-create-refund-ceiling" \
-d '{
"name": "refund-ceiling",
"description": "Refunds auto-run to $250; larger refunds are blocked by the ceiling.",
"rules": [
{ "tool": "order.refund", "decision": "ALLOW", "max_value": 250 }
]
}'
Error cases:
| Status | Code | When |
|---|---|---|
400 | missing_parameter | name or rules is absent, or rules is empty. |
400 | invalid_parameter | A rule's decision is not ALLOW or ALERT, or max_value is not a positive number. |
409 | state_conflict | A policy with this name already exists in the tenant. |
Retrieve a policy
guardrails:readReturns the current version of the policy. Pass version as a query parameter to read a historical version verbatim, which is how an auditor reconstructs the exact rules behind a verdict cited in a receipt.
The policy id, for example grd_3c90e1.
A historical version number. Defaults to the current version.
curl "https://api.fibric.io/v1/guardrails/grd_3c90e1?version=2" \
-H "Authorization: Bearer $FIBRIC_KEY"
Update a policy
guardrails:writeUpdates rules, description, or status. A change to rules replaces the whole array and increments version; there is no per-rule patching. Versions are immutable once written: the history of what governed and when is part of the audit surface.
curl -X PATCH https://api.fibric.io/v1/guardrails/grd_3c90e1 \
-H "Authorization: Bearer $FIBRIC_KEY" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{ "tool": "order.refund", "decision": "ALLOW", "max_value": 400 }
]
}'
Error cases:
| Status | Code | When |
|---|---|---|
400 | invalid_parameter | A rule fails schema validation, or the body attempts to set version or name. |
404 | not_found | No policy with this id exists for the authenticated tenant. |
Delete a policy
guardrails:writeRemoves the policy from evaluation. Historical versions remain readable for audit; receipts citing the policy keep resolving. Because evaluation is default-closed, deletion can only narrow what runs. Prefer status: "disabled" when the removal may be temporary.
curl -X DELETE https://api.fibric.io/v1/guardrails/grd_3c90e1 \
-H "Authorization: Bearer $FIBRIC_KEY"
Evaluate (dry run)
guardrails:readRuns the real evaluator against a hypothetical action and returns the verdict and the matched rules. Nothing executes, nothing is receipted; the endpoint is a read in POST clothing, which is why it needs only the read scope. Use it in CI to pin policy behavior before a change ships.
A hypothetical action: connector, tool, optional value, optional args. The same fields a PlannedAction carries.
Include this operator's embedded guardrails in the evaluation, exactly as a real plan from it would. Omit to evaluate tenant policies alone.
Hypothetical policy documents to evaluate instead of the tenant's stored policies. For testing an edit before saving it.
curl -X POST https://api.fibric.io/v1/guardrails/evaluate \
-H "Authorization: Bearer $FIBRIC_KEY" \
-H "Content-Type: application/json" \
-d '{
"operator_id": "op_8f2a1c",
"action": { "connector": "cn_7d2f4a", "tool": "order.refund", "value": 300 }
}'
{
"object": "guardrail_evaluation",
"decision": "BLOCK",
"matched": [
{
"policy_id": "grd_3c90e1",
"policy_version": 3,
"rule": { "tool": "order.refund", "decision": "ALLOW", "max_value": 250 },
"constraint_failed": "max_value"
}
],
"explanation": "value 300 exceeds max_value 250 on refund-ceiling v3; no other rule allows order.refund."
}
Error cases:
| Status | Code | When |
|---|---|---|
400 | missing_parameter | action is absent or lacks connector or tool. |
400 | invalid_parameter | A hypothetical policy in policies fails schema validation. |
404 | not_found | operator_id names no operator in the tenant. |