Guides
Guardrails & Policies
Policies are rules the Niitaka SDK evaluates in real time as your agent runs — cost limits, step caps, retries, and fallbacks — without touching your agent code.
Where to configure policies
Dashboard
Create and edit policies in the Policies page. Changes take effect on the next session — no redeploy needed.
YAML file
Define policies in a local file and pass policy_file= to configure(). File policies take priority over DB policies for matching agents.
Policy types
cost_limitEmit a warning or abort when accumulated session cost crosses a threshold. Each entry is one threshold — use two entries (warn + abort) for a soft and hard limit.
| Field | Description |
|---|---|
condition.cost_exceeded | Dollar amount (USD). Triggers when total session cost exceeds this value. |
action.type | "warn" emits a signal and lets the session continue. "abort" raises AgentExecutionStopped before the next LLM call. |
step_limitAbort or warn when the number of completed LLM + tool calls in a session reaches a cap. Catches runaway loops before they drain budget.
| Field | Description |
|---|---|
condition.steps_exceeded | Integer. Triggers when step count reaches or exceeds this value. |
action.type | "warn" emits a signal and continues. "abort" halts before the next call. |
retryAutomatically retry failed LLM calls with configurable backoff. Scope to specific error types so unrecoverable errors (auth, bad request) propagate immediately.
| Field | Description |
|---|---|
condition.on_error | Always true — condition is met whenever any LLM/tool call raises an error. |
action.max_retries | Maximum number of retry attempts before giving up. |
action.backoff_seconds | Base delay in seconds between retries. |
action.backoff | "exponential" (default) doubles delay each attempt. "linear" waits backoff_seconds each time. |
action.on_errors | Optional list of error class names to retry on. Omit to retry on any error. |
fallbackSwitch to an alternate model after all retry attempts are exhausted. Pairs with retry to form the full resilience stack.
| Field | Description |
|---|---|
condition.on_error | Always true — condition is met on any error after retries are exhausted. |
action.fallback_model | Model ID to switch to (e.g. "gpt-4o-mini"). |
action.on_errors | Optional list of error class names that trigger the fallback. Omit to fall back on any error. |
Full YAML example
A complete policy file with all four policy types configured for one agent. Each cost_limit or step_limit threshold is its own entry — create two entries (warn + abort) to get both a signal and a hard stop:
# policies.yaml — load with niitaka.configure(policy_file="policies.yaml")
version: "1"
policies:
# Warn at $0.30
- agent_id: my-agent
type: cost_limit
priority: 5
condition:
cost_exceeded: 0.30
action:
type: warn
# Hard abort at $0.50
- agent_id: my-agent
type: cost_limit
priority: 10
condition:
cost_exceeded: 0.50
action:
type: abort
# Cap the number of LLM + tool call steps
- agent_id: my-agent
type: step_limit
priority: 10
condition:
steps_exceeded: 20
action:
type: abort
# Retry transient errors with exponential backoff
- agent_id: my-agent
type: retry
priority: 8
condition:
on_error: true
action:
max_retries: 3
backoff_seconds: 2
backoff: exponential
on_errors:
- RateLimitError
- APITimeoutError
- InternalServerError
# Fall back to a cheaper model after retries are exhausted
- agent_id: my-agent
type: fallback
priority: 7
condition:
on_error: true
action:
fallback_model: gpt-4o-mini
on_errors:
- RateLimitError
- APITimeoutErrorimport os
import niitaka
niitaka.configure(
api_key=os.getenv("NIITAKA_API_KEY"),
policy_file="policies.yaml", # file policies take priority over DB policies
)Accessing guardrail values in code
The SDK enforces guardrails automatically — you don't need to check thresholds manually. If you need to read the active policy values from your agent (e.g. for logging or adaptive behaviour), use get_runtime_config():
import niitaka
# The SDK enforces guardrails automatically — no manual checks needed.
# To inspect active policy values from your agent code:
with niitaka.start_session(agent_id="my-agent"):
result = niitaka.get_runtime_config()
cfg = result.get("config", {})
# Guardrail thresholds from the active shipped version / experiment variant:
guardrails = cfg.get("guardrails", {})
cost_limit = guardrails.get("cost_limit_usd") # e.g. 0.50 (None if not set)
max_steps = guardrails.get("max_steps") # e.g. 20 (None if not set)
# Use for observability / logging — enforcement is handled by the SDK.
print(f"Active cost limit: {cost_limit}, step limit: {max_steps}")How guardrails fire
Cost and step guardrails are pre-call gates. Before each LLM call the SDK checks accumulated totals from previous calls against the configured limits. If a threshold is crossed:
- warn — emits a guardrail signal in the session timeline and lets the call proceed.
- abort — raises
AgentExecutionStoppedbefore the next call starts. The current call always completes and is logged — limits prevent the next call from running, not the one that just finished.
Policy evaluation order
Higher priority numbers are evaluated first. When multiple policies of the same type match, the highest-priority action wins. A common pattern: abort at priority 10, warn at priority 5 — if both thresholds are crossed, the abort fires first, as intended. All policy changes are versioned and logged in the Policy Audit Log in the dashboard.