# Production Guardrails

Building an AI agent is easy.

Building one that safely interacts with production systems is much harder.

Unlike traditional applications, AI agents make decisions dynamically. A single prompt can trigger multiple API calls, execute workflows, or interact with critical business systems. Without proper safeguards, mistakes can quickly become production incidents.

Swytchcode provides multiple layers of protection to help you build reliable AI applications. This guide explains the recommended practices for deploying AI agents in production.

---

## Defense in Depth

No single safeguard is enough.

Instead, combine multiple layers of protection.

```text
User Prompt
      │
      ▼
AI Agent
      │
      ▼
Trusted Tools
(tooling.json)
      │
      ▼
Policy Validation
(policies.json)
      │
      ▼
Execution Controls
(manifest.json)
      │
      ▼
Authentication
      │
      ▼
Provider API
```

If one layer fails, the remaining layers continue protecting your application.

---

## Principle of Least Privilege

Only expose the tools your application actually needs.

For example, if an AI assistant only creates GitHub issues, it should not also have permission to:

- Delete repositories
- Manage organization members
- Create deployments
- Modify repository settings

Every additional capability increases the potential impact of an unexpected or incorrect request.

Keep your trusted tool list as small as possible.

---

## Run agents safely

Policies are written at build time and enforced at run time. A deployed agent must not be able to change them. Swytchcode enforces policies only on calls that go through Swytchcode, so set up the agent's environment so it has no other path:

- **Connect with the `agent` MCP profile only** (`swy mcp serve --profile agent`, the default). It can list policies but has no tools to add or remove them. Keep `--profile full` for your editor.
- **No shell or file-system access to the project.** An agent that can run commands or edit files can change or delete `.swytchcode/integrations/policies.json`, and a missing file means no guards.
- **Deploy `policies.json` read-only**, exactly as it was committed and reviewed.
- **No access to provider API keys** (`.env` files, secrets). With the keys, an agent can call the provider's API directly, for example with `curl`, and skip Swytchcode and every policy.

`REQUIRES_APPROVAL` policies still reach a human at run time through [human approval](/policies/human-approval/). Each approval covers one call, unless the policy sets [`reuse`](/configuration/policy-json/#reuse).

Know what policies can and can't do:

- **Limits are per machine.** `rate`, `sum`, and the other [conditions on earlier calls](/configuration/policy-json/#conditions-on-earlier-calls) count calls made from one project on one machine. Five agents on five machines each get their own daily cap.
- **Response policies can't undo a call.** They hide or cut what the agent sees; the provider has already acted.
- **Detectors are pattern-based.** `contains_pii`, `contains_secret`, and `REDACT`'s `detect` catch common formats, not every one.
- **Only calls through Swytchcode are checked.** That's why the agent must not have the keys or a shell.

---

## Separate Development and Production

Never use production resources during development.

Instead:

```text
Development
        │
        ▼
Sandbox APIs
        │
        ▼
Testing
        │
        ▼
Production
```

Use sandbox endpoints whenever they are available.

Before switching to production, verify that:

- Policies have been validated.
- Authentication is configured correctly.
- Expected requests behave as intended.

---

## Protect Destructive Operations

Operations that modify or delete data deserve additional protection.

Examples include:

- Deleting repositories
- Canceling subscriptions
- Refunding payments
- Revoking user access
- Removing infrastructure
- Deleting databases

Consider blocking these operations entirely in production unless they are explicitly required. In a version-2 file, one policy can cover every tool:

```json
{
  "id": "no-prod-deletes",
  "target": ["*"],
  "when": {
    "operator": "all",
    "conditions": [
      { "field": "$http_method", "operator": "==", "value": "DELETE" },
      { "field": "$env", "operator": "==", "value": "production" }
    ]
  },
  "action": { "type": "POLICY_BLOCKED", "message": "Deletes are disabled in production" }
}
```

Or for a single method:

```json
{
  "id": "block-database-reset",
  "target": ["postgres.database.reset"],
  "when": { "field": "database", "operator": "exists" },
  "action": {
    "type": "POLICY_BLOCKED",
    "message": "Database resets are disabled in production."
  }
}
```

When possible, separate read-only tools from write operations - only enable the write method in `tooling.json` for the environments and agents that genuinely need it.

---

## Keep Sensitive Data from the Agent

What a provider returns goes into the agent's context, and from there possibly into logs, prompts, and other tools. A response policy changes the response before the agent - or the local audit log - sees it:

```json
{
  "id": "hide-sensitive-response-data",
  "target": ["*"],
  "stage": "response",
  "when": { "field": "$status_code", "operator": "<", "value": 300 },
  "action": { "type": "REDACT", "detect": ["card", "ssn", "iban", "secret"] }
}
```

Use `TRUNCATE` to cap how many records one call returns, and a `sum` over `$response_items` to cap records read per day. See [Response Policies](/configuration/policy-json/#response-policies).

---

## Validate Every Request

Do not assume that generated requests are correct.

Always validate important request fields before execution.

Examples include:

- Payment amounts
- Email addresses
- Resource identifiers
- Organization names
- Deployment environments
- Regions

Reject invalid requests before they reach the provider.

---

## Use Idempotency for Mutating Operations

Network failures happen.

Retries happen.

Without idempotency, the same request can execute more than once.

```text
Create Payment
      │
      ▼
Request Times Out
      │
      ▼
Automatic Retry
      │
      ▼
Duplicate Payment
```

With idempotency enabled:

```text
Create Payment
      │
      ▼
Request Times Out
      │
      ▼
Retry
      │
      ▼
Existing Operation Returned
```

For APIs that support idempotency, enable it whenever requests create, modify, or delete resources.

---

## Configure Retries Carefully

Retries improve reliability, but they should be used selectively.

Good retry candidates include:

- Temporary server failures
- Network interruptions
- Rate limiting
- Service unavailable responses

Avoid retrying requests that fail because of invalid input or authorization issues.

A retry should only happen when another attempt has a reasonable chance of succeeding.

---

## Limit Concurrency

AI agents often execute multiple operations simultaneously.

Without limits, this can overwhelm downstream services.

Instead of allowing unlimited parallel requests:

```text
100 Parallel Requests
```

Use reasonable concurrency limits based on the provider's recommendations.

This reduces:

- Rate limiting
- Resource exhaustion
- Unexpected API failures

---

## Secure Authentication

Treat API credentials as production secrets.

Never:

- Hardcode API keys
- Commit credentials to Git repositories
- Embed secrets in prompts
- Store secrets in source code

Instead:

- Use environment variables.
- Use OAuth where supported.
- Rotate credentials regularly.
- Grant only the minimum required permissions.

---

## Restrict Network Access

Whenever possible, limit outbound requests to trusted providers.

Instead of allowing requests to any destination, configure an allowlist of expected hosts.

For example:

- `api.stripe.com`
- `api.github.com`
- `api.slack.com`

Restricting network access helps prevent accidental or unauthorized communication with unexpected endpoints.

---

## Pin Integration Versions

Always use pinned integration versions.

Avoid automatically upgrading integrations in production without testing.

Version pinning provides:

- Reproducible behavior
- Predictable request formats
- Easier debugging
- Safer deployments

Review new integration versions before adopting them.

---

## Test Before Deploying

Every change should follow a predictable deployment process.

```text
Update Configuration
        │
        ▼
Validate Policies
        │
        ▼
Run Sandbox Tests
        │
        ▼
Review Results
        │
        ▼
Deploy to Production
```

Testing before deployment reduces the likelihood of production incidents and makes behavior easier to verify. In command form, that pipeline is:

```bash
swy policy validate                        # catch errors in policies.json and run its tests
swy exec <canonical_id> --dry-run          # run every policy on a real request without executing it
# review results, then deploy
```

Run `swy policy validate` in CI so a broken rule or a failing policy test stops the deploy.

---

## Monitor and Audit

Production systems should be observable. Swytchcode keeps a local audit trail under `~/.swytchcode/audit/` that you can query directly, without needing Cloud Sync or signing in:

```bash
swy audit stats            # total runs, success rate, last run, top provider
swy audit network -n 20    # recent outbound calls: host, method, status, duration
swy audit policy -n 20     # recent policy decisions: blocked, changed, hidden, monitored
swy policy state           # counts kept by rate, sum, and repeat limits
swy doctor                 # tooling, bundles, auth, permissions, secrets
```

Regularly review:

- Enabled tools (`swy list tooling`) and active integrations (`swy list integrations`)
- Policy changes - diff `policies.json` in code review like any other config file
- Failed executions and their exit codes (see [Troubleshooting](/reference/troubleshooting/))
- Policy violations via `swy audit policy` - this is a read-only history of what got blocked or held, distinct from `swy policy list`, which shows the rules themselves
- Authentication failures - `swy whoami` and `swy auth status` show current auth state; failing calls also show up in `swy audit network`
- Workspace [log storage](/guides/workspaces/#logs) in the dashboard, if you turned it on for that workspace
- Pending [approval requests](/policies/human-approval/) in Slack

Treat changes to policies and integrations with the same level of review as application code.

For high-impact production actions, require [human approval](/policies/human-approval/) so a person must confirm the command before it runs.

---

## Production Checklist

Before deploying an AI agent, verify the following:

- [ ] Only required tools are enabled (`swy list tooling`).
- [ ] Policies have been validated and their tests pass (`swy policy validate`, in CI).
- [ ] New rules were tried in monitor mode before enforcing them.
- [ ] Responses with sensitive data are redacted before the agent sees them.
- [ ] The deployed agent uses the `agent` MCP profile, has no shell access, and cannot read provider API keys ([Run agents safely](#run-agents-safely)).
- [ ] Sandbox testing has been completed.
- [ ] Production credentials are configured securely (`swy auth status`, `swy doctor`).
- [ ] Integration versions are pinned.
- [ ] Idempotency is enabled for mutating operations.
- [ ] Retry behavior has been reviewed.
- [ ] Concurrency limits have been configured.
- [ ] Network access is restricted where possible (`swy doctor --network`).
- [ ] Secrets are managed securely.
- [ ] Policy and configuration changes have been reviewed.
- [ ] High-impact commands require [human approval](/policies/human-approval/) where appropriate.
- [ ] Workspace [log storage](/guides/workspaces/#logs) is on if you need a searchable dashboard history.

---

## Key Takeaways

A production-ready AI agent should be:

- **Least-privileged** - Only the required capabilities are available.
- **Policy-driven** - Every request is validated before execution.
- **Reliable** - Retries, timeouts, and idempotency are configured appropriately.
- **Observable** - Behavior can be monitored and audited.
- **Predictable** - Configuration is version-controlled and reproducible.

By combining trusted tools, policy validation, execution controls, and secure authentication, you can confidently deploy AI agents that interact with real-world APIs while minimizing operational risk.

---

## Next steps

- [Policies overview](https://docs.swytchcode.com/policies/overview/) - The policy engine that decides what an agent can do, when, and how.
- [Policy Rules](https://docs.swytchcode.com/policies/policy-rules/) - Write custom policies using conditions, operators, and actions.
- [Policy recipes](https://docs.swytchcode.com/policies/recipes/) - Ready-to-use policies for email, payments, data safety, and more.
- [Human approval](https://docs.swytchcode.com/policies/human-approval/) - Hold high-impact commands until someone approves in Slack.
- [Best Practices](https://docs.swytchcode.com/policies/best-practices/) - Recommendations for maintainable, predictable, secure policy configurations.
- [manifest.json](https://docs.swytchcode.com/configuration/manifest-json/) - Configure endpoints, retries, timeouts, and idempotency for each integration.
