// runtime guardrails

Rule language

Write Runtime Guardrails rules directly in YAML with CEL expressions, normalized event fields, parsed shell commands, and sequences.

You can write Runtime Guardrails rules directly in the YAML editor. The rule assistant is optional.

  1. Open Agents → Rules.
  2. Select New rule.
  3. Replace the commented example in the editor with your rule.
  4. Choose the client groups that should receive it and set the rule to Monitor, Enforce, or Disabled.
  5. Select Save.

Superagent validates the YAML structure and compiles the CEL expression before saving. Each endpoint validates the rule again before activation.

Start with a complete rule

This rule detects reads of .env files while ignoring .env.example:

id: acme.secrets.env_read
version: "1.0"
enabled: true
title: Environment file read
description: |-
  Detects a requested read of an environment file that may contain credentials.
  It does not treat example environment files as secrets.
severity: high
tags:
  - secrets
  - attack.t1552.001
expr: |-
  event.event_type == "file.read" &&
  event.file_path.matches("(^|/)\\.env(\\.[^/]+)?$") &&
  !event.file_path.endsWith(".env.example")
enforce: false

Use an organization-specific prefix such as acme. for custom rule IDs. Increment version whenever the rule logic changes so findings show which policy produced the match.

Top-level fields

A rule is one YAML object, up to 128 KiB of UTF-8 text. Do not use YAML aliases, wrap it in rules:, place multiple rules in one document, or add unknown top-level fields.

Field Required Description
id Yes Stable, dot-separated identifier, up to 128 characters
version Yes Rule-owned version string copied into findings
title Yes Human-readable finding title
severity Yes info, low, medium, high, or critical
expr One of CEL predicate evaluated against one event
sequence One of Ordered multi-event detection
description No Operator-facing explanation of what a match proves
tags No Categories copied into findings
enabled No Enables the rule; defaults to true
enforce No Makes eligible matches blockable; defaults to false
deny_message No Control-free, single-line message returned for a denied action, up to 512 UTF-8 bytes

Define exactly one of expr or sequence. Superagent recommends including description, tags, and an explicit enabled value even though the rule engine can supply their defaults.

Rule IDs use lowercase letters, digits, underscores, and dashes in dot-separated segments. Each segment must start and end with a letter or digit.

The Mode control in the editor writes enabled and enforce when you save. Use that control when changing a rule's operating mode.

Write CEL expressions

Every expr must return true or false. Start by selecting the event types the rule understands, then add the conditions that identify the behavior.

event.event_type == "file.write" &&
event.file_path.startsWith("/etc/")

Common CEL operations include:

Operation Example
Boolean logic a && b, `a
Equality a == b, a != b
Membership value in ["a", "b"]
String tests contains(), startsWith(), endsWith(), matches()
List predicates exists(), all(), exists_one()
List ranges items.slice(start, end)
Integer indexes lists.range(n).exists(i, ...)
Missing nullable value event.exit_code == null

matches() uses RE2 regular expressions. CEL strings require escaping, so a literal dot is written as "\\.env".

Use direct field access such as event.command. Unknown fields and computed field access are rejected.

Choose the right input

Rules can evaluate two inputs:

  • event is the normalized action and context recorded across supported coding agents.
  • shell_commands is a parsed, rule-only view of commands found in event.command.

Choose the simplest input that preserves the distinction you need:

What you need to match Input
File, URL, MCP, permission, model, or other normalized data event
Literal text in the original command event.command
Executable names, arguments, pipelines, redirects, or wrappers shell_commands
Ordered activity across multiple events sequence

Raw command text can match comments, quoted examples, or here-document content. Prefer shell_commands when a rule depends on what the shell will execute, especially for enforcement rules.

Normalized events

Actions use the most specific available event type. A recognized shell request is command.exec, not both command.exec and tool.call. tool.call is the fallback when the action cannot be classified more specifically.

Common event types and their principal fields are:

Event type Meaning Principal fields
command.exec Requested shell or process action command, tool_name, tool_call_id
command.result Observed command result command, exit_code, duration_ms, tool_call_id
file.read Requested file access file_path, tool_name, tool_call_id
file.write Requested or observed file change file_path, diff_sha256, diff_bytes
file.delete Requested or observed file deletion file_path, diff_sha256, diff_bytes
network.indicator Known web or network target url, mcp_server, mcp_tool
tool.call Other or unknown tool request tool_name, mcp_server, mcp_tool
tool.result Result of a generic tool call tool_name, tool_call_id
permission.requested Permission prompt approval_required, approval_reason
permission.approved Approved permission request approval_decision, approval_reason
permission.denied Denied permission request approval_decision, approval_reason
config.agent Observed agent configuration Context fields
config.mcp Observed MCP configuration mcp_server, mcp_tool
session.start, session.end Session boundary Context fields
prompt.user User prompt content_preview
message.assistant, message.reasoning Agent output content_preview

Context fields are available on every event type:

event.actor
event.cli_version
event.confidence
event.content_preview
event.entrypoint
event.git_branch
event.model
event.model_provider
event.project_path
event.session_id
event.source_agent
event.source_type
event.sub_agent
event.tags
event.timestamp

All event keys are present during evaluation. Missing strings are "", missing diff_bytes is 0, and missing tags are []. The nullable fields approval_required, duration_ms, and exit_code are null when unavailable.

Pre-action events describe requested behavior, not confirmed execution. A later result may be linked by tool_call_id, but some integrations record only one side.

For command activity, hooks and artifacts normally provide command.exec. Some OpenTelemetry sources expose only command.result, so a rule that needs both capture paths can use:

event.event_type == "command.exec" ||
(event.source_type == "otel" && event.event_type == "command.result")

The source_type condition prevents the rule from matching both the request and result on sources that emit both.

Parse executable commands

Use shell_commands to reason about executable behavior instead of matching raw text:

id: acme.network.curl_upload
version: "1.0"
enabled: true
title: Curl file upload requested
description: Detects curl commands that request a local file upload.
severity: high
tags:
  - exfiltration
expr: |-
  event.event_type == "command.exec" &&
  shell_commands.exists(command,
    command.name == "curl" &&
    command.argv.slice(1, command.argv.size()).exists(arg,
      arg in ["--upload-file", "-T"]
    )
  )
enforce: false

Each parsed command provides:

Field Description
name Lowercase executable basename with common Windows suffixes removed
executable Statically parsed executable value
argv Parsed arguments, including the executable at index 0
arguments Arguments with source, quoting, and expansion metadata
assignments Command-scoped shell assignments
redirects Input and output redirections
dialect posix, powershell, or cmd
wrappers Recognized launchers around the command
statement_id Identifier for this command within the event
pipeline_id Shared identifier for commands in one pipeline; 0 means none
parent_statement_id Enclosing command identifier; 0 means none
preview normal, preview, or uncertain
function_call Whether this is a statically resolved shell function call
recursive Whether this is a statically resolved recursive function call

The richer collections expose these nested fields:

Object Fields
argument value, source, quote, expands, subcommands
assignment name, value, append
redirect fd, op, target, target_source, target_quote, target_expands, subcommands
wrapper name, executable, argv

For example, detect a write or append redirect to an SSH authorization file:

shell_commands.exists(command,
  command.redirects.exists(redirect,
    redirect.op in ["write", "append"] &&
    redirect.target.endsWith("/authorized_keys")
  )
)

The parser does not execute commands, expand variables, or read referenced scripts. If no safe static projection is available, rules that depend on shell_commands skip that event.

Correlate events with sequences

Use a sequence when one event is not enough to establish the behavior:

id: acme.secrets.read_then_send
version: "1.0"
enabled: true
title: Secret read followed by external transfer
description: Detects an environment file read followed by a curl command.
severity: critical
tags:
  - secrets
  - exfiltration
sequence:
  within_events: 30
  steps:
    - expr: |-
        event.event_type == "file.read" &&
        event.file_path.matches("(^|/)\\.env$")
    - expr: |-
        event.event_type == "command.exec" &&
        shell_commands.exists(command, command.name == "curl")
enforce: false
Sequence field Description
steps Two to eight ordered CEL predicates
within Optional wall-clock window such as 30m
within_events Optional event-count window, from the step count through 4096
max_matches Findings per rule and correlation partition; defaults to 1, maximum 16

Set within, within_events, or both. When both are present, both limits must hold.

Sequences correlate only within the same agent, source, session, and project. The final step is the only action an enforced sequence can block because earlier steps have already happened.

Monitor or enforce

Rules monitor by default. Set Mode → Enforce in the editor to make a matching pre-action eligible for blocking. The saved YAML contains:

enforce: true
deny_message: Contact your security team before accessing this file.

severity only prioritizes the finding. It does not enable blocking.

Enforcement also depends on the coding agent exposing a supported synchronous pre-action hook. Post-action events, artifact scans, and sources without a blocking hook remain detection-only. For shell-derived matches, commands with dynamic values, substitutions, multiple statements, unsupported control flow, or parser diagnostics can be detected but are not blocked.

Use monitor mode first, review the resulting findings for false positives, and then enable enforcement for high-confidence rules.

Fix validation errors

Selecting Save runs both structural validation and CEL compilation. Common failures include:

  • Defining both expr and sequence, or neither
  • Using an unknown event or command field
  • Returning a non-boolean CEL value
  • Forgetting to escape a backslash inside a CEL string
  • Using fewer than two or more than eight sequence steps
  • Setting within_events below the number of steps or above 4096
  • Using a duplicate rule ID

If a new catalog fails validation on an endpoint, that endpoint keeps its last known-good rules.

Next steps