Skip to content

Policy reference

The policy decides what agents may do on each kind of environment, what the PreToolUse guard counts as a change and what counts as a secret. Behaviour: SPEC §7; design: 0013; a worked example: Full access on a trusted local machine.

Layers

A later layer wins: the built-in preset named by the global layer → [permission_defaults] and guard_mode from config.toml (legacy, only when set) → the global file (policy.json in the data directory, setting policy_file) → the project layer → the environment layer (both stored in the database, edited in Settings → Policy). The environment's own level and per-capability overrides on Stands & access win over every layer.

Objects merge key by key; scalars and lists replace. A list key may also be written key+ (add items; a pattern with an existing id replaces it) or key- (remove items by value or id); key is applied first, then key+, then key-. $schema and description are ignored; preset is read from the global layer only.

The global file is read on start (a broken file stops relaybay serve with the path and the problem) and again whenever it changes; a file that breaks later is logged, shown on the Policy page, and the last valid version stays in effect. A broken project or environment layer is logged and ignored.

Custom regular expressions (guard.patterns[].command / change, secrets.allow): at most 200 characters, no back-references, no quantified group holding a quantifier ((a+)+) or an alternation ((a|aa)*), at most two unbounded quantifiers (*, +, {n,}), and fast on long hostile input when the layer is loaded. They run case-insensitively with a hard time limit on at most 8 KB of text; a call that times out fails closed (a guard pattern counts as matched, an allow pattern does not allow) and is logged at most once a minute per pattern.

JSON Schema: policy.schema.json (the same file as src/relaybay/policy/schema.json).

Keys

Key Type Meaning
$schema string Editor hint; ignored.
description string (at most 500 characters) A note for people; ignored.
preset one of default, strict, trusted Built-in starting point under every other layer. Global layer only.
levels object Agents' permission level per environment kind, used where an environment sets none itself.
levels.local object default: the level of the kind; a capability key: the level for that capability.
levels.local.default one of none, read, ask, full Level of the kind.
levels.local.sign_in one of none, read, ask, full Signing in and remembering the login.
levels.local.ssh one of none, read, ask, full ssh, scp, rsync, sftp.
levels.local.kubectl one of none, read, ask, full kubectl.
levels.local.db one of none, read, ask, full Database clients.
levels.local.deploy one of none, read, ask, full git push, helm, terraform, GitOps.
levels.test object default: the level of the kind; a capability key: the level for that capability.
levels.test.default one of none, read, ask, full Level of the kind.
levels.test.sign_in one of none, read, ask, full Signing in and remembering the login.
levels.test.ssh one of none, read, ask, full ssh, scp, rsync, sftp.
levels.test.kubectl one of none, read, ask, full kubectl.
levels.test.db one of none, read, ask, full Database clients.
levels.test.deploy one of none, read, ask, full git push, helm, terraform, GitOps.
levels.live object default: the level of the kind; a capability key: the level for that capability.
levels.live.default one of none, read, ask, full Level of the kind.
levels.live.sign_in one of none, read, ask, full Signing in and remembering the login.
levels.live.ssh one of none, read, ask, full ssh, scp, rsync, sftp.
levels.live.kubectl one of none, read, ask, full kubectl.
levels.live.db one of none, read, ask, full Database clients.
levels.live.deploy one of none, read, ask, full git push, helm, terraform, GitOps.
guard object The PreToolUse guard.
guard.mode one of off, log, warn, block off: no checks; log: live journal only, no messages; warn: a warning to the agent; block: deny (ask stays ask in every mode but log).
guard.disable list of one of kubectl-change, helm-change, ssh-remote-change, scp-to-host, sftp-session, sql-change, git-push, terraform-change, mcp-tool-name, at most 50 Built-in mutating rules to switch off, by id (replaces the list).
guard.disable+ list of one of kubectl-change, helm-change, ssh-remote-change, scp-to-host, sftp-session, sql-change, git-push, terraform-change, mcp-tool-name, at most 50 Rule ids to add to the inherited list.
guard.disable- list of one of kubectl-change, helm-change, ssh-remote-change, scp-to-host, sftp-session, sql-change, git-push, terraform-change, mcp-tool-name, at most 50 Rule ids to remove from the inherited list.
guard.patterns list of object, at most 50 Custom mutating patterns (replaces the list).
guard.patterns+ list of object, at most 50 Patterns to add; one with an inherited id replaces it.
guard.patterns- list of string, at most 50 Ids of inherited patterns to remove.
secrets object What counts as a secret in environment fields, access entries and proposals.
secrets.disable list of one of private-key, github-token, github-pat, gitlab-token, openai-key, aws-access-key, slack-token, jwt, url-credentials, password-flag, curl-user, auth-header, token-header, sshpass, mysql-password, docker-login-password, redis-password, secret-assignment, secret-field-name, user-password, at most 50 Built-in secret detectors to switch off, by id (replaces the list). The journal still masks them.
secrets.disable+ list of one of private-key, github-token, github-pat, gitlab-token, openai-key, aws-access-key, slack-token, jwt, url-credentials, password-flag, curl-user, auth-header, token-header, sshpass, mysql-password, docker-login-password, redis-password, secret-assignment, secret-field-name, user-password, at most 50 Detector ids to add to the inherited list.
secrets.disable- list of one of private-key, github-token, github-pat, gitlab-token, openai-key, aws-access-key, slack-token, jwt, url-credentials, password-flag, curl-user, auth-header, token-header, sshpass, mysql-password, docker-login-password, redis-password, secret-assignment, secret-field-name, user-password, at most 50 Detector ids to remove from the inherited list.
secrets.allow list of string (at most 200 characters), at most 50 Regular expressions: a value (or a detected secret) that matches one whole is accepted (replaces the list).
secrets.allow+ list of string (at most 200 characters), at most 50 Allow patterns to add.
secrets.allow- list of string (at most 200 characters), at most 50 Allow patterns to remove.
secrets.test_secrets object Whether access fields may hold harmless test values marked {"value": "...", "test": true}. There is no live key: never on live.
secrets.test_secrets.local boolean Allowed on local environments.
secrets.test_secrets.test boolean Allowed on test environments.
secrets.expose_test_secrets_to_agents boolean Show test secret values to agents in environments_get (otherwise only their names).

A custom pattern (guard.patterns, guard.patterns+):

Key Type Meaning
id string Stable id, not one of the built-in rule ids.
capability one of sign_in, ssh, kubectl, db, deploy, null Capability whose level applies; null or absent: any identifier.
command string (at most 200 characters) Optional: the command the change must follow in the same command segment.
change string (at most 200 characters) What makes the call a change (case-insensitive).
description string (at most 200 characters) Shown in the guard's reason, after "this looks like a".

Built-in guard rules

Id Capability Reason says
kubectl-change kubectl kubectl change
helm-change deploy helm change
ssh-remote-change ssh remote change over ssh
scp-to-host ssh file copy to a host
sftp-session ssh file transfer session
sql-change db SQL change
git-push deploy git push
terraform-change deploy terraform change
mcp-tool-name any MCP tool whose name says it changes something

Built-in secret detectors

private-key, github-token, github-pat, gitlab-token, openai-key, aws-access-key, slack-token, jwt, url-credentials, password-flag, curl-user, auth-header, token-header, sshpass, mysql-password, docker-login-password, redis-password, secret-assignment, secret-field-name, user-password.

Switching a detector off affects only the check on write; the live-actions journal still masks every shape it knows.

Presets

default

relaybay's behaviour without a policy file.

{
  "description": "relaybay's behaviour without a policy file.",
  "levels": {
    "local": {
      "default": "full"
    },
    "test": {
      "default": "full"
    },
    "live": {
      "default": "read"
    }
  },
  "guard": {
    "mode": "warn",
    "disable": [],
    "patterns": []
  },
  "secrets": {
    "disable": [],
    "allow": [],
    "test_secrets": {
      "local": false,
      "test": false
    },
    "expose_test_secrets_to_agents": false
  }
}

strict

Agents ask on test and stay off live; the guard blocks.

{
  "description": "Agents ask on test and stay off live; the guard blocks.",
  "levels": {
    "local": {
      "default": "full"
    },
    "test": {
      "default": "ask"
    },
    "live": {
      "default": "none"
    }
  },
  "guard": {
    "mode": "block",
    "disable": [],
    "patterns": []
  },
  "secrets": {
    "disable": [],
    "allow": [],
    "test_secrets": {
      "local": false,
      "test": false
    },
    "expose_test_secrets_to_agents": false
  }
}

trusted

A trusted machine: full access everywhere, the guard only journals, test secrets on local and test.

{
  "description": "A trusted machine: full access everywhere, the guard only journals, test secrets on local and test.",
  "levels": {
    "local": {
      "default": "full"
    },
    "test": {
      "default": "full"
    },
    "live": {
      "default": "full"
    }
  },
  "guard": {
    "mode": "log",
    "disable": [],
    "patterns": []
  },
  "secrets": {
    "disable": [],
    "allow": [],
    "test_secrets": {
      "local": true,
      "test": true
    },
    "expose_test_secrets_to_agents": false
  }
}