Configuration Reference

Everything in RADIUS is controlled by a single YAML file. This page covers every section, every option, and the three built-in profiles.


Config file discovery

RADIUS looks for config files in this order:

  1. radius.yaml
  2. radius.yml
  3. .radius.yaml

The first match wins. All paths are relative to the current working directory.


Full annotated example

# ── Global Settings ──────────────────────────────
global:
  profile: standard                      # local | standard | unbounded
  workspace: "${CWD}"                    # Agent workspace root
  defaultAction: deny                    # deny | allow
  requireSignedPolicy: false             # Require signed policy file
  onUndefinedTemplateVar: error          # error | empty

# ── Module Pipeline ──────────────────────────────
# Order matters. First deny wins. Audit should be last.
modules:
  - kill_switch
  - skill_scanner
  - tool_policy
  - fs_guard
  - command_guard
  - exec_sandbox
  - egress_guard
  - output_dlp
  - rate_budget
  - approval_gate
  - audit

# ── Module Configuration ─────────────────────────
moduleConfig:
  kill_switch:
    enabled: true
    envVar: RADIUS_KILL_SWITCH           # Set this env var to activate
    filePath: ./.radius/KILL_SWITCH      # Or create this file
    denyPhases:
      - pre_request
      - pre_tool
    reason: "emergency kill switch active: human safety override"

  skill_scanner:
    scanOnStartup: true
    scanOnReload: true
    actionOnCritical: challenge           # deny | challenge | alert
    requireSignature: false
    requireSbom: false
    requirePinnedSource: false
    onProvenanceFailure: challenge

  tool_policy:
    default: deny                         # deny | allow
    # rules:                              # Per-tool guidance: /docs/modules/

  fs_guard:
    allowedPaths:
      - "${workspace}"
      - "/tmp"
    blockedPaths:
      - "~/.ssh"
      - "~/.aws"
      - "/etc"
    blockedBasenames:
      - ".env"
      - ".env.local"
      - ".envrc"

  command_guard:
    denyPatterns:
      - "(^|\\s)sudo\\s"
      - "rm\\s+-rf\\s+/"
      - "(^|\\s)(cat|less|more|head|tail|grep|awk|sed)\\s+[^\\n]*\\.env(?:\\.|\\s|$)"

  exec_sandbox:
    engine: bwrap                         # bwrap | none
    required: false                       # true = deny if bwrap unavailable

  egress_guard:
    # allowedDomains: []                  # Allowlist mode
    # blockedDomains: []                  # Blocklist mode

  output_dlp:
    action: redact                        # deny | redact | alert
    # customPatterns: []                  # Additional regex patterns

  rate_budget:
    windowSec: 60
    maxCallsPerWindow: 60

  approval_gate:
    # enabled: false                      # Enable for human-in-the-loop

  audit:
    sink: file                            # file | stdout | webhook | otlp
    path: .radius/audit.jsonl

# ── Audit Settings ───────────────────────────────
audit:
  sink: file
  path: .radius/audit.jsonl
  includeArguments: true
  includeResults: true
  # webhookUrl: https://...
  # otlpEndpoint: https://...
  # headers: {}
  # timeoutMs: 5000

# ── Approval Settings ────────────────────────────
approval:
  enabled: false
  mode: sync_wait                         # sync_wait | async_token
  waitTimeoutSec: 300
  onTimeout: deny                         # deny | alert
  onConnectorError: deny                  # deny | alert
  store:
    engine: sqlite                        # sqlite | memory
    path: .radius/approvals.db
  channels:
    telegram:
      enabled: false
      transport: polling                  # polling | webhook
      botToken: "${TELEGRAM_BOT_TOKEN}"
      allowedChatIds: []
      approverUserIds: []
      pollIntervalMs: 2000

global section

KeyTypeDefaultDescription
profilelocal | standard | unboundedstandardBase security profile
workspacestring${CWD}Agent workspace root directory
defaultActiondeny | allowdenyAction for tools not covered by rules
requireSignedPolicybooleanfalseRequire policy file signature verification
onUndefinedTemplateVarerror | emptyerrorBehavior when a template variable is undefined

Template variables

Use template variables anywhere in the YAML. They’re resolved at config load time.

VariableResolves to
${workspace}The global.workspace value (after its own resolution)
${CWD}Current working directory
${HOME}User home directory
${ENV_VAR_NAME}Any environment variable

Example:

fs_guard:
  allowedPaths:
    - "${workspace}"        # /home/user/project
    - "${HOME}/.config"     # /home/user/.config
    - "${CUSTOM_PATH}"      # whatever CUSTOM_PATH is set to

modules array

The pipeline runs each module in array order. Order matters:

  1. kill_switch — check first, halt everything if triggered
  2. skill_scanner — scan artifacts before processing
  3. tool_policy — explicit allow/deny by tool name
  4. fs_guard — filesystem path constraints
  5. command_guard — shell command pattern blocking
  6. exec_sandbox — namespace isolation for commands
  7. egress_guard — outbound network filtering
  8. output_dlp — secret detection in outputs
  9. rate_budget — rate limiting
  10. approval_gate — human approval for remaining actions
  11. audit — log the final decision (always last)

You can remove modules you don’t need. You can reorder them (but the above order is recommended). You can add the same module twice with different configs if needed.


moduleConfig overview

Each key in moduleConfig maps to a module name. The config object is passed to that module’s configure() method.

Runtime note for agentradius@0.4.0: keep effective module settings inside moduleConfig.<moduleName>. For audit, set sink/path in moduleConfig.audit for hook adapters (OpenClaw/Nanobot), even if you also keep a top-level audit block for readability.

Detailed per-module guidance is now documented in Modules. The full annotated example above still provides the fastest complete reference.


audit section

For runtime compatibility in v0.4.0, prefer moduleConfig.audit as the source of truth.

KeyTypeDefaultDescription
sinkfile | stdout | webhook | otlpfileWhere to write audit events
pathstring.radius/audit.jsonlFile path (for file sink)
webhookUrlstringWebhook endpoint (for webhook sink)
otlpEndpointstringOTLP endpoint (for otlp sink)
headersRecord<string, string>Custom headers for webhook/OTLP
timeoutMsnumber5000Request timeout for webhook/OTLP
includeArgumentsbooleantrueInclude tool arguments in audit log
includeResultsbooleantrueInclude tool results in audit log

approval section

KeyTypeDefaultDescription
enabledbooleanfalseEnable human-in-the-loop approval
modesync_wait | async_tokensync_waitWait for approval or return a token
waitTimeoutSecnumber300How long to wait for human response
onTimeoutdeny | alertdenyAction when approval times out
onConnectorErrordeny | alertdenyAction on channel error
store.enginesqlite | memorysqliteApproval state storage
store.pathstring.radius/approvals.dbSQLite database path
channels.telegram.enabledbooleanfalseEnable Telegram channel
channels.telegram.transportpolling | webhookpollingHow to receive Telegram updates
channels.telegram.botTokenstringTelegram bot token (use env var)
channels.telegram.allowedChatIdsstring[][]Allowed Telegram chat IDs
channels.telegram.approverUserIdsstring[][]Users who can approve
channels.telegram.pollIntervalMsnumber2000Polling interval

Profiles comparison

Three profiles ship with RADIUS. Use them as starting points — every setting can be overridden in your radius.yaml.

SettingLocalStandardUnbounded
Default actiondenydenyallow
Module modeenforceenforceobserve
exec_sandboxrequiredoptionalnot included
output_dlp actiondenyredactalert
rate_budget30 calls/min60 calls/min120 calls/min
skill_scanner on criticaldenychallengealert
Provenance checkssignature + SBOM + pinned source requiredchallenge on failurealert only
egress_guardincludednot includednot included
kill_switchenforceenforceobserve
Recommended forproduction, billing, credentialsdevelopment, staging, daily workresearch, migration, rollout

Profile aliases

AliasResolves to
strictlocal
balancedstandard
monitorunbounded
unleashedunbounded

Use either name in --profile or in the YAML global.profile field.


Local profile

Zero trust. Every tool is denied unless explicitly allowed. Sandbox is required for shell commands. Secrets in output cause an immediate deny. Supply chain provenance is enforced.

global:
  profile: local
  defaultAction: deny
modules:
  - kill_switch
  - skill_scanner
  - tool_policy
  - fs_guard
  - command_guard
  - exec_sandbox      # required: true
  - egress_guard      # included in local only
  - output_dlp        # action: deny
  - rate_budget       # 30 calls/min
  - audit

Use this for production environments, systems handling billing or credentials, and anywhere a compromised agent could cause real damage.


Standard profile

Trust but verify. Default deny, but the sandbox is optional, secrets are redacted (not blocked), and the rate limit is generous enough for normal development.

global:
  profile: standard
  defaultAction: deny
modules:
  - kill_switch
  - skill_scanner
  - tool_policy
  - fs_guard
  - command_guard
  - exec_sandbox      # required: false
  - output_dlp        # action: redact
  - rate_budget       # 60 calls/min
  - audit

This is the default for npx agentradius init. Good for development, staging, and daily work.


Unbounded profile

Safety off, logging only. All modules run in observe mode — they log what they would have blocked, but don’t actually block anything. The rate limit is high.

global:
  profile: unbounded
  defaultAction: allow
modules:
  - kill_switch       # observe mode
  - skill_scanner     # observe mode
  - tool_policy       # observe mode
  - fs_guard          # observe mode
  - command_guard     # observe mode
  - output_dlp        # action: alert, observe mode
  - rate_budget       # 120 calls/min, observe mode
  - audit

Use this for initial migration: install RADIUS in unbounded mode, review the audit log to understand what would be blocked, then switch to standard or local.