policies.json
policies.json defines runtime guard policies for your Swytchcode project.
Unlike tooling.json, which controls what can execute, policies.json controls when a tool is allowed to execute based on the request being made.
Every policy is evaluated before execution, allowing you to block requests that violate your organization’s rules.
The file lives at:
.swytchcode/integrations/policies.jsonHow it works
Before executing any method, Swytchcode checks whether a matching policy exists. If a policy condition evaluates to
true, the configured action is applied immediately.
Managing Policies
Swytchcode provides CLI commands for managing policies.
Add a policy
swy policy addCreates a new policy interactively.
List policies
swy policy listDisplays every configured policy.
Remove a policy
swy policy remove <policy-id>Deletes a policy by its ID.
Validate policies
swy policy validateValidation checks for:
- Unknown operators
- Missing required fields
- Duplicate IDs
- Invalid action types
- Empty targets
- Invalid value types
- Dotted field paths
- Malformed nested conditions
Validation errors are reported with human-readable messages before execution.
Review past violations
swy policy only manages the rules - it doesn’t show you what’s happened historically. Every time a policy blocks a request, Swytchcode logs the violation to a local, read-only history. To review it:
swy audit policy # recent policy-violation entriesswy audit policy -n 20 # last 20 entriesswy audit policy --info <id> # full detail for one violation (id looks like pol_...)This is useful when a policy blocks something unexpectedly and you need to see exactly which field/value tripped the rule, without touching policies.json itself. See the Command Reference for the full swy audit surface.
Fail-Closed Behavior
policies.json follows a fail-closed validation model.
| Situation | Behavior |
|---|---|
| File does not exist | No policies are applied. Execution continues normally. |
| File exists and is valid | Policies are evaluated before execution. |
| File exists but is malformed | Execution stops with a validation error. |
This ensures invalid policy definitions never silently bypass security checks.
File Structure
A minimal policy file looks like this:
{ "defaults": { "on_violation": "fail", "evaluation": "pre_execution" }, "policies": [ { "id": "star-repo-approval", "target": [ "github.repo.star" ], "when": { "field": "name", "operator": "exists" }, "action": { "type": "POLICY_BLOCKED", "message": "Starring repositories is blocked." } } ]}The file consists of two sections:
defaultspolicies
defaults
The defaults object defines how policy evaluation behaves.
{ "defaults": { "on_violation": "fail", "evaluation": "pre_execution" }}on_violation
Determines what happens when a policy condition matches.
{ "on_violation": "fail"}Currently, only one value is supported.
| Value | Description |
|---|---|
fail | Immediately stops execution. |
Any other value fails validation.
evaluation
Specifies when policies are evaluated.
{ "evaluation": "pre_execution"}Supported value:
| Value | Description |
|---|---|
pre_execution | Evaluate policies before any API request is made. |
Future versions may introduce additional evaluation stages.
Policy Objects
Every rule inside the policies array represents a single guard.
Example:
{ "id": "block-large-payments", "target": [ "stripe.create_payment" ], "when": { "field": "amount", "operator": ">", "value": 100000 }, "action": { "type": "POLICY_BLOCKED", "message": "Payments above the allowed limit are blocked." }}Each policy contains four required fields.
id
A unique identifier for the policy.
{ "id": "block-large-payments"}If another policy uses the same ID, it replaces the existing policy.
target
Defines which methods or workflows the policy protects.
{ "target": [ "stripe.create_payment" ]}A policy only runs when one of these canonical IDs is executed.
Multiple tools can be protected.
{ "target": [ "stripe.create_payment", "stripe.refund_payment" ]}when
Defines the condition that triggers the policy.
{ "when": { "field": "amount", "operator": ">", "value": 100000 }}If this condition evaluates to true, Swytchcode executes the configured action.
Conditions are covered in detail below.
action
Defines what happens when a condition matches.
{ "action": { "type": "POLICY_BLOCKED", "message": "Payments above the limit are blocked." }}Both type and message are required.
Action Types
Supported action types are:
| Action | Description |
|---|---|
AUTH_FAILED | Authentication failed. |
POLICY_BLOCKED | Request blocked by policy. |
Example:
{ "action": { "type": "POLICY_BLOCKED", "message": "Too many requests." }}When a policy blocks execution:
- the request is never sent
- execution stops immediately
- Swytchcode exits with code 4
Conditions
Conditions determine when a policy should apply.
There are two types:
- Leaf conditions
- Group conditions
Leaf Conditions
Leaf conditions compare a single request field.
Example:
{ "field": "amount", "operator": ">", "value": 100000}Swytchcode evaluates the resolved request arguments before execution.
Group Conditions
Group conditions combine multiple rules.
They use one of three logical operators.
| Operator | Description |
|---|---|
all | Every condition must match (AND). |
any | At least one condition must match (OR). |
not | Inverts a condition (NOT). |
Example:
{ "operator": "all", "conditions": [ { "field": "currency", "operator": "==", "value": "usd" }, { "field": "amount", "operator": ">", "value": 5000 } ]}Execution is blocked only if both conditions evaluate to true.
Comparison Operators
Equality & Ordering
| Operator |
|---|
== |
!= |
> |
>= |
< |
<= |
These operators require scalar values.
Example:
{ "field": "amount", "operator": ">", "value": 1000}Membership
| Operator |
|---|
in |
not_in |
The value must be an array.
{ "field": "currency", "operator": "in", "value": [ "usd", "eur" ]}Substring
| Operator |
|---|
contains |
not_contains |
{ "field": "email", "operator": "contains", "value": "@company.com"}String Matching
| Operator |
|---|
starts_with |
ends_with |
matches |
Example:
{ "field": "branch", "operator": "starts_with", "value": "release/"}matches accepts a regular expression up to 512 characters.
Presence
These operators do not require a value.
| Operator |
|---|
exists |
not_exists |
empty |
not_empty |
Example:
{ "field": "api_key", "operator": "exists"}Time Comparison
Supported operators:
| Operator |
|---|
before |
after |
Example:
{ "field": "expires_at", "operator": "before", "value": "2026-12-31T00:00:00Z"}Time Windows
Supported operators:
| Operator |
|---|
between |
outside |
The value must contain exactly two timestamps.
{ "field": "created_at", "operator": "between", "value": [ "2026-01-01T00:00:00Z", "2026-12-31T23:59:59Z" ]}Nested Conditions
Complex policies can combine multiple logical operators.
Example:
{ "when": { "operator": "all", "conditions": [ { "field": "amount", "operator": ">", "value": 100000 }, { "field": "currency", "operator": "in", "value": [ "usd", "eur" ] }, { "operator": "not", "conditions": [ { "field": "test_mode", "operator": "exists" } ] } ] }}This policy only matches when:
- Amount is greater than
100000 - Currency is either
usdoreur test_modeis not present
Best Practices
- Keep policies focused on a single responsibility.
- Use descriptive policy IDs.
- Validate policies after every change.
- Prefer multiple small policies over one complex rule.
- Store policies in version control alongside your project.
- Test policies in sandbox mode before deploying to production.
Now that you understand runtime guard policies, continue with: