Policy Rules
A policy defines when a tool is allowed to execute.
Every request made through Swytchcode is evaluated against your configured policies before an API call is made. If a policy condition matches, Swytchcode applies the configured action immediately. Response policies run once more after the call, before the agent sees the result.
Policies allow you to enforce business rules, security requirements, and operational constraints without changing your application code.
How Policy Evaluation Works
Whenever a tool is executed, Swytchcode performs the following checks:
Tool Execution Requested │ ▼MODIFY policies change the call (if any match) │ ▼Evaluate the other policies on the (changed) call │ ▼Any block? ──Yes──▶ Blocked (exit code 6) │No ▼Any approval? ──Yes──▶ Held for a person (exit code 7) │No ▼Call is sent │ ▼Response policies: hide, cut, or withhold the response │ ▼Result returned to the agentA policy only applies to the methods listed in its target. When several policies match, a block wins over an approval, and an approval over an ALLOW. With "on_no_match": "deny", a call no ALLOW policy matches is blocked, which turns the file into an allowlist.
Anatomy of a Policy
Every policy consists of four parts:
Policy│├── Target├── Condition├── Action└── IdentifierEach part serves a specific purpose.
| Component | Purpose | JSON field |
|---|---|---|
| ID | Uniquely identifies the policy. | id |
| Target | Specifies which methods the policy applies to. | target |
| Condition | Determines when the rule should trigger. | when |
| Action | Defines what happens when the condition is met. | action |
Put together, a policy in .swytchcode/integrations/policies.json looks like this:
{ "id": "block-large-payments", "target": ["stripe.payment_intent.create"], "when": { "field": "amount", "operator": ">", "value": 100000 }, "action": { "type": "POLICY_BLOCKED", "message": "Payments above the allowed limit are blocked." }}If amount on the request exceeds 100000, swy exec (and the equivalent swytchcode_exec MCP call) stops before any network request is made, returns exit code 6, and returns an error naming the policy and its message. To hold a command until a person confirms it, use human approval (REQUIRES_APPROVAL) instead of a hard block.
Besides blocking, a policy can:
- Change the call (
MODIFY) - for example, cap a page size instead of failing. - Allow it (
ALLOW) - with"on_no_match": "deny", only allowed calls run. - Hide or cut the response (
REDACT,TRUNCATE) - for example, replace card numbers with[REDACTED]before the agent sees them. - Only watch (
"mode": "monitor") - record matches without acting, to try a rule first.
These need a version-2 file. See Action Types for the full list.
Choosing a Target
Policies only evaluate requests that match one of their targets. target is always an array of canonical IDs.
{ "target": ["github.repo.star"] }only evaluates requests that star GitHub repositories.
Another policy might target:
{ "target": ["stripe.payment.create"] }to validate payment requests.
A single policy can protect multiple methods if they share the same business rule.
{ "target": [ "stripe.payment.create", "stripe.payment.refund", "stripe.payment.capture" ]}In a version-2 file, a target can be a pattern: "stripe.*" guards every Stripe method, and "*" every tool. Combined with built-in fields such as $http_method, one policy can cover a whole class of calls - for example, every DELETE in production.
Writing Conditions
Conditions determine when a policy should apply.
A condition evaluates information from the request being executed, and - in a version-2 file - about the call itself and earlier calls.
Examples include:
- Payment amount
- Currency
- Email address
- Branch name
- Environment
- Region
- Request metadata
A simple condition might read:
Block any payment greater than 10,000.
which is written as:
{ "field": "amount", "operator": ">", "value": 10000 }Another might read:
Block requests that aren’t from a company email address.
{ "field": "email", "operator": "not_contains", "value": "@yourcompany.com" }A version-2 file adds more to compare against:
- Nested fields:
customer.email,items[*].price. - Built-in fields that Swytchcode fills in, which an agent can’t set:
$http_method,$env,$host,$time,$weekday,$caller, and$email_domains(the domain of every address anywhere in the request), among others. - Lists kept in one place:
{"$list": "blocked_domains"}. - Earlier calls:
rate(calls per window),sum(e.g. daily spend),repeat,called_before,returned_by. - Sensitive data:
contains_piiandcontains_secret.
{ "field": "$email_domains", "operator": "in", "value": ["gmail.com", "yahoo.com"], "ignore_case": true }Policies should describe business intent rather than implementation details. The full set of supported operators - equality/ordering (==, !=, >, >=, <, <=), membership (in, not_in), substring (contains, not_contains), string matching (starts_with, ends_with, matches), presence (exists, not_exists, empty, not_empty), and time comparisons (before, after, between, outside) - is documented in the policies.json reference, with the version-2 built-in fields, condition options, and conditions on earlier calls.
Combining Conditions
Many production rules require more than one condition.
Swytchcode lets you combine leaf conditions (field/operator/value) into a group condition using operator: "all" | "any" | "not" plus a conditions array.
all (AND) - every condition must match:
{ "operator": "all", "conditions": [ { "field": "amount", "operator": ">", "value": 10000 }, { "field": "currency", "operator": "==", "value": "usd" } ]}any (OR) - at least one condition must match:
{ "operator": "any", "conditions": [ { "field": "role", "operator": "==", "value": "admin" }, { "field": "role", "operator": "==", "value": "support" } ]}not - inverts the nested condition:
{ "operator": "not", "conditions": [ { "field": "test_mode", "operator": "exists" } ]}Groups can nest inside groups, so you can build rules like “amount over 10,000 AND currency is USD or EUR AND NOT test mode” as a single when block. See Group Conditions in the policies.json reference for a full worked example.
Common Policy Patterns
The most effective policies are usually simple. Policy recipes has a ready-to-use policy for each of the patterns below.
Spending Limits
Prevent expensive operations.
Examples:
- Payments above a threshold
- Refund limits
- Credit issuance limits
Production Protection
Prevent accidental changes to production systems.
Examples:
- Block delete operations
- Prevent destructive workflows
- Disable infrastructure changes
Organization Rules
Restrict operations based on company policies.
Examples:
- Company email domains only
- Approved GitHub organizations
- Approved cloud projects
Environment Restrictions
Different environments often require different rules.
For example:
Development:
- Relaxed limits
- Test data
- Sandbox providers
Production:
- Strict validation
- Protected resources
- Higher security
Time-Based Rules
Restrict execution during specific time windows.
Examples:
- Business hours only
- Maintenance windows
- Scheduled deployments
Designing Good Policies
When writing policies, follow these principles.
Keep policies focused
Instead of one large policy:
❌
Everything PolicyPrefer:
✅
Payment Limit
Repository Protection
Production Restriction
Email ValidationSmaller policies are easier to review and maintain.
Write descriptive IDs
Good:
block-production-deletesBetter than:
policy-4Policy IDs should describe their purpose.
Avoid deeply nested logic
If a policy becomes difficult to understand, consider splitting it into multiple policies.
Simple policies are easier to debug and less likely to introduce unexpected behavior.
Prefer allowlists
Instead of trying to block every unsafe value:
Block:ABCDEPrefer explicitly allowing trusted values.
Allow:ProductionStagingAllowlists are easier to reason about and generally more secure.
Validating Policies
Before deploying policies, always validate them.
swy policy validateValidation checks for:
- Invalid operators
- Missing required fields
- Duplicate IDs
- Empty targets
- Invalid value types
- Unknown action types
- Incorrect condition structures
- Values that can’t match the field’s type in the tool’s input schema
It also runs the tests written in the file. Fix validation errors before running production workloads: while policies.json is invalid, every call is stopped.
Testing Policies
Policies should be tested before deployment.
A typical workflow looks like this:
Write Policy │ ▼Validate Policy │ ▼Test in Sandbox │ ▼Review Behavior │ ▼Deploy to ProductionThree tools help:
Tests in the file. In a version-2 file, each policy can carry example calls and what should happen to them. swy policy validate runs them against the whole file and fails if one doesn’t match, so they can run in CI:
"tests": [ { "args": { "amount": 250000 }, "expect": "block" }, { "args": { "amount": 500 }, "expect": "allow" }]Tests can also give earlier calls (for rate limits), the expected changed arguments of a MODIFY, or a response for response policies. They never send, count, or log anything. See Tests.
Dry runs. --dry-run runs every policy check on a real request without making the API call:
swy policy validateswy exec <canonical_id> --dry-runMonitor mode. "mode": "monitor" lets a new rule watch real traffic without blocking. Matches show up as monitored in swy audit policy; switch to enforcing once the rule catches exactly what you meant.
Once a policy is live, swy audit policy shows you which requests it has actually blocked, changed, or hidden, so you can tell a too-strict rule from a working one.
Best Practices
- Write one policy per business rule.
- Use descriptive policy IDs.
- Prefer allowlists whenever possible.
- Keep conditions simple and readable.
- Validate policies after every change.
- Test policies in sandbox environments before production.
- Review policies alongside application code during code review.
- Add
teststo each policy and runswy policy validatein CI. - Try new rules in monitor mode first.
- Remove unused policies to keep configurations easy to maintain.
Next steps
Policy recipes
Ready-to-use policies for email, payments, data safety, and more.
Human approval
Hold a matching command until a person approves it in Slack.
Production Guardrails
Recommended safeguards for running AI agents against production systems.
Best Practices
Recommendations for maintainable, predictable, secure policy configurations.
Policies overview
The policy engine that decides what an agent can do, when, and how.