Skip to main content
Rampart policies are YAML files that define what AI agents can and cannot do. Glob matching, hot-reload on file change.

Quick Start

# Create a custom policy
rampart init

# Edit the generated policy
vim ~/.rampart/policies/custom.yaml
The custom.yaml file is never overwritten by rampart upgrade — your rules persist across updates.

Policy Structure

version: "1"
default_action: allow  # allow or deny

policies:
  - name: block-destructive
    priority: 1  # Lower = evaluated first
    match:
      tool: ["exec"]
    rules:
      - action: deny
        when:
          command_matches: ["rm -rf /"]
        message: "Destructive command blocked"

Schema Reference

Top-Level Fields

version
string
required
Policy schema version. Always "1".
default_action
string
required
Fallback action when no rules match. Either allow or deny.
policies
array
required
List of policy objects. Each policy contains match criteria and rules.

Policy Object

name
string
required
Policy identifier. Used in audit logs and deny messages.
description
string
Human-readable explanation of what this policy does.
priority
integer
Evaluation priority. Lower numbers are evaluated first. Default: 100.
match
object
required
Scope this policy to specific tools or agents.Fields:
  • tool: Array of tool names (e.g., ["exec", "read"]). Use ["*"] to match all tools.
  • agent: Array of agent names (e.g., ["claude-code"]). Default: ["*"].
rules
array
required
List of rule objects. First matching rule wins.

Rule Object

action
string
required
What to do when this rule matches:
  • deny: Block the operation
  • allow: Permit the operation
  • watch: Log but allow (alias: log)
  • ask: Request human approval (alias: require_approval)
when
object
required
Conditions that must match for this rule to apply.
message
string
required
Message shown when this rule triggers.

Match Conditions

The when block supports these matchers:

Command Matching (tool: exec)

command_matches
array
Glob patterns. Matches full command string.
command_matches:
  - "rm -rf /"
  - "sudo **"
  - "curl ** | bash"
Use ** to match paths with slashes (max 2 per pattern).
command_not_matches
array
Inverse of command_matches. Rule only applies if command does NOT match.
command_matches:
  - "rm -rf /var/**"
command_not_matches:
  - "rm -rf /var/tmp/**"  # Allow /var/tmp cleanup
command_contains
array
Substring matching (case-insensitive). Catches shell wrapper bypasses.
command_contains:
  - "DROP TABLE"  # Matches "DROP TABLE users" and "drop table sessions"
  - "rm -rf"
This is more robust than command_matches for detecting dangerous substrings in complex shell invocations.

Path Matching (tool: read, write, edit)

path_matches
array
Glob patterns for file paths.
path_matches:
  - "**/.ssh/id_*"
  - "**/.aws/credentials"
  - "**/etc/shadow"
path_not_matches
array
Inverse of path_matches. Excludes paths from a broader match.
path_matches:
  - "**/.ssh/id_*"
path_not_matches:
  - "**/*.pub"  # Allow public keys

Domain Matching (tool: fetch)

domain_matches
array
Glob patterns for domains.
domain_matches:
  - "*.ngrok.io"
  - "*.requestbin.com"
  - "webhook.site"

Session Matching

session_matches
array
Apply rule only to specific sessions (auto-detected as repo/branch).
session_matches:
  - "myapp/main"
  - "myapp/production"
Override with RAMPART_SESSION=my-label.
session_not_matches
array
Inverse of session_matches. Apply rule to all sessions except listed ones.
session_not_matches:
  - "myapp/dev"
  - "myapp/test"

Response Matching

response_matches
array
Regex patterns to scan tool output. Used for credential leak detection.
response_matches:
  - "AKIA[0-9A-Z]{16}"  # AWS access key
  - "-----BEGIN (RSA |EC )?PRIVATE KEY-----"
  - "ghp_[a-zA-Z0-9]{36}"  # GitHub PAT

Rate Limiting

call_count
object
Trigger rule after N calls in a time window.
call_count:
  gte: 100
  window: 1h
Available time units: s, m, h.

Action Types

deny

Block the operation immediately. Agent never sees it.
rules:
  - action: deny
    when:
      command_matches: ["rm -rf /"]
    message: "Destructive command blocked"

allow

Permit the operation. Use in combination with a deny-by-default policy.
default_action: deny

policies:
  - name: dev-tools-allowlist
    rules:
      - action: allow
        when:
          command_matches:
            - "git *"
            - "npm *"
            - "python3 *"
        message: "Allowed dev tool"

watch

Log the operation but allow it. Alias: log.
rules:
  - action: watch
    when:
      command_matches: ["sudo **"]
    message: "Privileged command logged"

ask

Request human approval. How it works depends on the environment:
  • Claude Code: Native approval prompt in the UI
  • MCP clients: Blocks until approved via API or dashboard
  • OpenClaw: Chat message with inline approve/deny
  • Webhooks: Signed URL sent to your notification endpoint
rules:
  - action: ask
    when:
      command_matches:
        - "kubectl apply **"
        - "terraform apply **"
    message: "Production deployment requires approval"
Add audit: true to log user decisions:
rules:
  - action: ask
    ask:
      audit: true  # Log whether user approved or denied
    when:
      command_matches: ["kubectl apply **"]
    message: "Production deployment requires approval"
Add headless_only: true to block in CI/headless mode:
rules:
  - action: ask
    ask:
      headless_only: true  # In CI, this becomes a deny
    when:
      command_matches: ["kubectl apply **"]
    message: "Production deployment requires approval"

Common Patterns

Block Dangerous Commands

policies:
  - name: block-destructive
    match:
      tool: ["exec"]
    rules:
      - action: deny
        when:
          command_matches:
            - "rm -rf /"
            - "mkfs*"
            - "dd **of=/dev/sd**"
          command_contains:
            - "/dev/tcp/"  # Reverse shell redirect
            - "| bash"     # Piped execution
        message: "Destructive command blocked"

Protect Credentials

policies:
  - name: block-credential-access
    priority: 1  # Evaluate first
    match:
      tool: ["read"]
    rules:
      - action: deny
        when:
          path_matches:
            - "**/.ssh/id_*"
            - "**/.aws/credentials"
            - "**/.env"
          path_not_matches:
            - "**/*.pub"
            - "**/.env.example"
        message: "Credential file access blocked"

Require Approval for Privileged Operations

policies:
  - name: require-sudo-approval
    match:
      tool: ["exec"]
    rules:
      - action: ask
        when:
          command_matches: ["sudo **"]
        message: "sudo requires approval"

Rate Limit Fetch Calls

policies:
  - name: rate-limit-fetch
    match:
      tool: ["fetch", "web_search"]
    rules:
      - action: ask
        when:
          call_count:
            gte: 100
            window: 1h
        message: "High fetch volume — require approval to continue"

Testing Policies

# Test a single command
rampart test "rm -rf /"
# Output: deny  block-destructive  Destructive command blocked

# Explain decision
rampart policy explain "sudo apt install nginx"

# Validate syntax
rampart policy lint ~/.rampart/policies/custom.yaml

Hot Reload

Policy files are watched for changes. Edit and save — no restart required.
# Edit your policy
vim ~/.rampart/policies/custom.yaml

# Changes apply immediately
rampart test "your-command-here"

Evaluation Order

  1. Priority — policies are sorted by priority (lower = first)
  2. First match wins — within a policy, the first matching rule’s action is used
  3. Deny always wins — if any policy denies, the action is denied
policies:
  - name: credential-protection
    priority: 1  # Evaluated first
    rules:
      - action: deny
        when:
          path_matches: ["**/.ssh/id_*"]

  - name: allow-dev-files
    priority: 10  # Evaluated second
    rules:
      - action: allow
        when:
          path_matches: ["**/*.go", "**/*.py"]
Even if allow-dev-files matches, if credential-protection denies, the action is denied.

See Also

Build docs developers (and LLMs) love