// security workers

Write and enforce rules

[ view markdown ]

Create, validate, assign, monitor, and enforce Runtime Guardrails rules.

Create a rule

Rules detect behavior in normalized coding-agent activity. They are evaluated locally on each client and distributed through client groups.

Default rules

The Rules table includes the full built-in catalog alongside custom rules. Default rows are labeled Default and apply to all clients.

Deleting a default rule creates a disabled organization override; it does not modify the client binary. The row remains visible with a Disabled status so administrators can restore it later. Select the restore action to remove the override and reactivate the embedded default.

Custom rules are labeled Custom and can be assigned to selected groups. Deleting a custom rule permanently removes it.

Generate a rule with the assistant

  1. Open Agents → Rules.
  2. Select New rule.
  3. Describe the behavior you want to detect in the rule generator terminal.
  4. Select Generate YAML.
  5. Review the generated YAML in the editor.
  6. Ask follow-up questions to refine it, or edit the YAML directly.
  7. Assign one or more client groups and select Validate and save.

For example:

Alert when an agent reads a .env file and then sends data to an external URL.
Make this high severity, but do not block it.

After the first response, the YAML editor appears above the terminal. Follow-up terminal instructions use the current YAML as context:

Limit this to events in production projects and change the window to 30 events.

The assistant is available only to organization owners. Generation is rate-limited and requires AI Gateway configuration on self-hosted deployments.

Write YAML manually

Open New rule and replace the commented example in the YAML editor. You do not need to send a prompt to the rule assistant.

Field Required Description
id Yes Stable, dot-separated identifier using lowercase letters, numbers, dashes, or underscores
version Yes Quoted version copied into alerts
enabled No Whether the rule is active; defaults to true
title Yes Human-readable alert title
description No Precise explanation of what matches and what the finding proves
severity Yes info, low, medium, high, or critical
tags No Categories copied into findings, including relevant MITRE ATT&CK tags
expr One of CEL predicate evaluated against one event
sequence One of Ordered multi-event detection
enforce No Blocks matching actions when true; defaults to false (monitor only)
deny_message No Message returned when an enforceable action is denied

Define exactly one of expr or sequence.

See the rule language reference for every normalized event field, CEL operator, parsed shell command, sequence window, and validation rule.

Single-event rules

Use expr when one event is enough to identify the behavior:

id: acme.secrets.env_read
version: "1.0"
enabled: true
title: Environment file read
description: Detects reads of environment files that commonly contain credentials.
severity: high
tags:
  - secrets
  - attack.t1552.001
expr: |-
  event.event_type == "file.read" &&
  event.file_path.matches("(^|/)\\.env$")

Useful fields include:

  • event.event_type
  • event.file_path
  • event.command
  • event.tool_name
  • event.url
  • event.content_preview
  • event.project_path
  • event.source_agent
  • event.tags

Expressions support normal CEL operators and helpers such as ==, !=, &&, ||, contains(), startsWith(), endsWith(), and matches().

Sequence rules

Use sequence when events must occur in order:

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 an outbound network indicator.
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 == "network.indicator" &&
        event.url != ""

A sequence requires two to eight steps and at least one window:

  • within — wall-clock duration such as 30m
  • within_events — event-count window, up to 4096

Monitoring and enforcement

Rules are monitor-only unless the YAML contains enforce: true (or Mode is set to Enforce in the UI). Installed hooks can deny matching actions for enforce rules; monitor rules only record findings.

Four high-confidence catastrophic-action defaults start in Enforce mode: recursive deletion of root or home, destructive disk operations, fork bombs, and forced termination of all accessible processes. Organization owners can change any of them to Monitor or Disabled. Other default rules start in Monitor mode to avoid blocking legitimate developer and administrator workflows.

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

Severity does not enable blocking. It only prioritizes the resulting alert.

Assign rules to groups

Use terminal commands to manage group assignments while editing:

/groups
/group add Production
/group remove Production
/group create New group

A client receives the union of rules assigned to all of its groups. Rule IDs are unique within an organization, so assigning one rule through multiple groups does not duplicate it.

Use /save to validate and save, /clear to reset the YAML, /close to close the panel, and /help to list commands.

Validation

Superagent validates the YAML structure and compiles every generated or edited rule with the same Numbat monitoring engine before accepting it. Compiler diagnostics are shown in the rule editor so unsupported fields, functions, and expressions can be fixed before saving.

Each endpoint validates downloaded rules again before activation. If a new catalog fails validation, the endpoint keeps its last known-good rules.

On self-hosted Node deployments, you can set AGENT_RULE_VALIDATOR_PATH to an executable Numbat v0.1.2 binary. When it is unset, the server downloads the pinned archive for macOS or Linux on arm64 or x64 during the first validation in each process, verifies the archive SHA-256 checksum, and keeps the validator only in that process's private temporary directory. Rule saves fail safely if the validator is unavailable.

Rule language reference

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