Rule recipes
Ready-to-paste rules for the things teams ask for most - secrets, main, production clusters, databases, the web, MCP tools and models.
Each recipe is a complete rule file you can paste into Policies → Custom rules → Source, or merge into your own. Every example on this page is compiled and checked against the policy engine before the docs are published.
Keep secrets out of the agent's context#
default: allow
rules:
- deny: { touches: dotenv }
reason: "Secrets stay out of agent context: use the secret broker"
- deny: { touches: private_key }
reason: "Private keys never reach the agent"
- deny: { touches: cloud_creds }
reason: "Cloud credentials never reach the agent"To let the agent use a secret without seeing it, see the secret broker.
Protect main#
default: allow
rules:
- deny: "git push --force"
reason: "Never force-push"
- ask: "git push"
when: { branch: [main, master] }
reason: "Pushing to main needs a person"
- deny: "git commit --no-verify"
reason: "Hooks run on every commit"git push --force covers every forcing form: -f, --force-with-lease and +branch refspecs.
Read-only production clusters#
default: allow
rules:
- deny: kubectl
when: { flag.context: "prod-*" }
unless: { subcommand: [get, describe, logs] }
reason: "Production clusters are read-only for agents"
- deny: aws
when: { flag.profile: prod }
reason: "No AWS calls with the prod profile"
- deny: "terraform destroy"
reason: "Nobody destroys infrastructure from a chat"No writes to production databases#
default: allow
rules:
- deny: { tool: "*" }
when: { env: prod, stmt: [update, delete, drop, truncate, alter, insert] }
reason: "Production data is read-only for agents"Warden works out env from host names, connection strings, profiles and MCP arguments, and reads the SQL statement and tables from psql, mysql and database MCP tools.
Keep production data on approved models#
default: allow
rules:
- deny: { tool: "*" }
when: { env: prod }
unless: { model_route: ["aws_bedrock/*", "anthropic/claude-opus-*"] }
reason: "Production data only reaches models on our approved accounts"The model is checked when the data is read, and again on every later request in that chat. If Warden can't tell which model is in use, the rule fires: missing facts fail closed.
Web access only to sites you trust#
default: allow
rules:
- deny: { tool: WebFetch }
unless: { domain: [github.com, "*.github.com", docs.python.org, developer.mozilla.org] }
reason: "Web fetches only to approved documentation"
- deny: { domain: [pastebin.com, "*.pastebin.com", transfer.sh] }
reason: "No uploads to paste or file-drop sites"Ask before destructive MCP tools#
default: allow
rules:
- ask: { mcp.tool: ["*delete*", "*drop*", "*remove*"] }
reason: "Destructive tool calls need a person"
- deny: { mcp.server: stripe }
when: { mcp.tool: "*refund*" }
reason: "Refunds go through the finance team"Keep deletes inside the project#
default: allow
rules:
- deny: "rm -rf"
unless: { path: "./*" }
reason: "Recursive deletes stay inside the project"
- deny: { touches: outside_project }
when: { access: write }
reason: "The agent only writes inside this project"rm -rf also matches rm -fr, rm -r -f and rm --recursive --force.
Ask before new dependencies#
default: allow
rules:
- ask: { touches: package_install }
reason: "New dependencies need a person: check the licence and the maintainer"Restoring what a lockfile or manifest already pins (npm ci, a bare npm install, pip install -r requirements.txt, bundle install, uv sync) isn't counted as adding a dependency.
Stricter when nobody is watching#
default: allow
rules:
- ask: "git push"
when: { trigger_mode: automated }
reason: "Unattended runs don't push"
- deny: git push
when: { trigger_mode: automated, assurance_meets_l2: "false" }
reason: "Unattended pushes need L2 assurance"See Automated runs.
A strict allow-list#
default: deny makes the file an allow-list: only what a rule allows can run.
default: deny
rules:
- allow: { tool: [Read, Glob, Grep] }
- allow: { tool: [Write, Edit] }
unless: { touches: outside_project }
- allow: npm
when: { subcommand: [test, run] }
- allow: git
when: { subcommand: [status, diff, log, add, commit] }