Why Guardrails Are Critical

An agent that can browse the web, run code, and send emails touches real systems with real consequences. Without guardrails:

  • A misunderstood instruction could delete files or send unintended emails
  • A stuck loop could exhaust API budgets in minutes
  • User input could be used to manipulate the agent (prompt injection)
  • Sensitive data could leak through tool outputs or logs

Input Validation

Validate user input before it reaches the LLM. Block obvious prompt injection patterns, deny-list dangerous instructions, and sanitise content.

guardrails:
  input:
    max_length: 4000
    deny_patterns:
      - "ignore previous instructions"
      - "you are now"
      - "pretend you are"
    pii_detection: true       # Detect and redact PII before processing
    content_filter: "strict"  # off | moderate | strict

Output Validation

Scan agent responses before returning them to users. Block harmful content, prevent data leakage, and enforce response format rules.

guardrails:
  output:
    content_filter: "strict"
    pii_redaction: true
    max_length: 10000
    required_format: null    # json | markdown | text | null

Action Restrictions

Explicitly allow or deny specific tools and operations. Use a allowlist approach for production agents.

guardrails:
  tools:
    allowed: ["web_search", "wiki", "calculator"]  # Allowlist
    denied: []
    file_system:
      read_dirs: ["/data/reports"]
      write_dirs: ["/data/outputs"]
      deny_extensions: [".env", ".key", ".pem"]
    network:
      allowed_domains: ["api.openweather.org", "en.wikipedia.org"]
      deny_localhost: true

Step and Cost Budgets

guardrails:
  budgets:
    max_steps: 15
    max_tokens_total: 80000
    max_cost_usd: 0.25
    max_wall_time_seconds: 90
    on_budget_exceeded: "return_partial"  # return_partial | abort | alert

Human-in-the-Loop

Require human approval before executing certain high-risk actions:

from openclaw import Agent

def approval_callback(action: str, args: dict) -> bool:
    """Called before high-risk actions. Return True to approve."""
    print(f"\nAgent wants to: {action}({args})")
    return input("Approve? [y/n] ").strip().lower() == "y"

agent = Agent(
    model="gpt-4o",
    tools=["file_writer", "email_sender", "code_exec"],
    human_in_the_loop={
        "tools": ["email_sender", "file_writer"],  # Require approval for these tools
        "callback": approval_callback,
    },
)

Dry-Run Mode

Preview what the agent would do without actually executing any tools:

result = agent.run("Send a project update email to the team", dry_run=True)
for step in result.planned_steps:
    print(f"Would call: {step.tool_name}({step.args})")

Audit Logging

guardrails:
  audit:
    enabled: true
    backend: "file"               # file | postgres | s3
    path: ".openclaw/audit.jsonl"
    include_inputs: true
    include_outputs: true
    include_tool_results: false   # false = only log tool name, not result data
    retention_days: 90
Key takeaways:
  • Always set max_steps and max_cost_usd — never run an agent without budgets in production.
  • Use a tool allowlist (not denylist) for production agents with external access.
  • Enable pii_detection on inputs for any agent handling user data.
  • Human-in-the-loop approval is the right pattern for irreversible actions.
  • Dry-run mode is invaluable for testing agent behaviour before going live.

Building Custom Guardrails

Beyond built-in safety filters, you can implement domain-specific guardrails using the guardrail hook API:

from openclaw import Agent
from openclaw.guardrails import GuardrailResult

def budget_guardrail(action: dict, context: dict) -> GuardrailResult:
    """Block any financial operations above the user's approval limit."""
    if action.get("tool") == "execute_payment":
        amount = action.get("args", {}).get("amount_usd", 0)
        limit  = context.get("user_approval_limit", 100)
        if amount > limit:
            return GuardrailResult.block(
                reason=f"Payment ${amount} exceeds approval limit ${limit}. Human review required."
            )
    return GuardrailResult.allow()

agent = Agent(model="gpt-4o", guardrails=[budget_guardrail])

Layered Guardrail Architecture

Production systems typically layer multiple guardrails at different points in the pipeline:

  1. Input guardrails — validate and sanitise user input before it reaches the agent (prompt injection detection, PII detection)
  2. Action guardrails — validate each tool call before execution (allowlist checks, parameter validation, spend limits)
  3. Output guardrails — review agent responses before delivery (toxicity filters, confidentiality checks, format validation)

Layer these three tiers so each one is independent. An input guardrail failure should not require the action or output guardrails to run — reject early and cheaply. Action guardrails are the most critical layer for production safety because they govern what the agent actually does, not just what it says. Output guardrails serve as a final safety net and are especially important for customer-facing agents where a harmful response has direct reputational consequences.