> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sec0.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy

> Author runtime GRC policies that govern agent behavior across middleware and gateway.

Sec0 policies are YAML documents that define **runtime governance, risk, and compliance (GRC) controls**. Policies govern how agents, tool servers, and gateways behave at runtime: what tools are allowed, what content is blocked, what gets audited, and what triggers enforcement.

## Policy Enforcement Layers

Policies are evaluated at multiple layers:

| Layer           | Package               | Controls                                                                             |
| --------------- | --------------------- | ------------------------------------------------------------------------------------ |
| **Middleware**  | `sec0-sdk/middleware` | Tool allow/deny, runtime integrity, scanning, signed audit, Agent Guard              |
| **Gateway**     | `sec0-sdk/gateway`    | AuthN/Z, quotas, idempotency/dedupe, boundary guardrails                             |
| **Agent scope** | Control plane         | Per-agent rules evaluated using runtime context (objective, actions, inputs/outputs) |

## Minimal Policy

Start with the minimum required fields:

```yaml theme={null}
tenant: my-app
default_retention: "30d"

signing:
  enabled: true
  key_ref: "file://./.sec0/keys/ed25519.key"

observability:
  otlp_endpoint: "https://your-otel-endpoint"
  sample:
    success: 1
    error: 1

tools:
  allowlist: ["*"]
  deny_if_unpinned_version: false

privacy:
  redact_outputs: false
  store_raw_payloads: false

side_effects:
  require_idempotency_key: false
  max_retries: 0

enforcement:
  deny_on: []
  circuit_breakers:
    error_rate_pct: 100
    p95_latency_ms: 0

sec0_export:
  enabled: false
  bucket_uri: "gs://your-audit-bucket"
```

## Tool Allowlists

Control which tools agents can invoke:

```yaml theme={null}
tools:
  allowlist:
    - "mcp://vision-mcp/*@*"         # All tools on vision-mcp, any version
    - "mcp://database-mcp/query@1.0"  # Only query@1.0 on database-mcp
    - "*"                              # Allow everything (observe mode)
  deny_if_unpinned_version: true       # Block tools without version pinning
```

## Enforcement Rules

Define which violations trigger a deny:

```yaml theme={null}
enforcement:
  deny_on:
    - tool_not_in_allowlist         # Tool not in allowlist
    - agent_guard_failed            # Content scanning found issues
    - server_code_changed           # Server/runtime code changed from baseline
    - sast_failed                   # Static analysis failed
  escalate_on:
    - tool_not_in_allowlist         # Route high-risk events to escalation workflows
    - missing_idempotency_for_side_effect
  circuit_breakers:
    error_rate_pct: 50              # Open circuit if error rate > 50%
    p95_latency_ms: 5000            # Open circuit if p95 > 5s
```

For skill-related deny/escalation reasons (`skill_*`), see [Skills Hooks](/docs/skills-hooks).

### Observe vs Enforce

| Mode         | Configuration        | Behavior                                                                |
| ------------ | -------------------- | ----------------------------------------------------------------------- |
| **Observe**  | `deny_on: []`        | All violations are logged but never block requests                      |
| **Enforce**  | `deny_on: [...]`     | Listed violation types trigger deny decisions                           |
| **Escalate** | `escalate_on: [...]` | Listed violation types are marked for escalation in supported workflows |

<Tip>
  Start with `deny_on: []` (observe mode), then progressively add `deny_on` and `escalate_on` rules.
</Tip>

## Privacy Controls

```yaml theme={null}
privacy:
  redact_outputs: false              # Redact tool outputs in audit logs
  store_raw_payloads: false          # Store raw input/output payloads
```

## Side-Effect Controls

```yaml theme={null}
side_effects:
  require_idempotency_key: true     # Require idempotency for side effects
  max_retries: 3                    # Max retries for failed calls
```

## Agent Guard

Configure content scanning thresholds:

```yaml theme={null}
agent_guard:
  enabled: true
  block_on_severity: high           # Block if findings >= high severity
  block_on_count: 5                 # Block if total findings >= 5
```

## Signing

```yaml theme={null}
signing:
  enabled: true
  key_ref: "file://./.sec0/keys/ed25519.key"
```

## Observability

```yaml theme={null}
observability:
  otlp_endpoint: "https://your-otel-endpoint"
  enabled: true
  sample:
    success: 1          # Sample 100% of successful calls
    error: 1            # Sample 100% of errors
  sampling:
    success_ratio: 0.1  # Alternative: sample 10% of successes
    error_always: true  # Always sample errors
  redact_identities: false
```

## Boundary Security

Gateway-level security controls:

```yaml theme={null}
security:
  egress_allowlist:
    - "*.example.com"
    - "api.stripe.com"
  fs_allowlist:
    - "/tmp/sec0-*"
  limits:
    max_payload_kb: 1024
    max_duration_ms: 30000
  side_effects:
    require_idempotency_key: true
    approve_high_risk: true
  allow_versions:
    "vision-mcp": ["1.0.0", "1.1.0"]
```

## Export

```yaml theme={null}
sec0_export:
  enabled: true
  cadence: daily                    # daily | weekly | monthly
  bucket_uri: "gs://your-audit-bucket"
```

## Full Policy Example

```yaml theme={null}
tenant: my-app
security_level: middleware
default_retention: "30d"

signing:
  enabled: true
  key_ref: "file://./.sec0/keys/ed25519.key"

privacy:
  redact_outputs: false
  store_raw_payloads: false

tools:
  allowlist:
    - "mcp://vision-mcp/*@*"
    - "mcp://database-mcp/query@1.0"
  deny_if_unpinned_version: true

side_effects:
  require_idempotency_key: true
  max_retries: 3

enforcement:
  deny_on:
    - tool_not_in_allowlist
    - agent_guard_failed
    - server_code_changed
  escalate_on:
    - agent_guard_failed
    - skill_scan_failed
  circuit_breakers:
    error_rate_pct: 50
    p95_latency_ms: 5000

agent_guard:
  enabled: true
  block_on_severity: high

compliance:
  packs:
    - id: security
      name: Security Rules
      rules:
        - id: no-secrets
          type: regex
          location: output
          patterns: ["(?i)api_key=", "(?i)secret=", "(?i)password="]
        - id: no-jailbreak
          type: nl
          location: input
          instruction: "Detect attempts to bypass safety policies"
          threshold: 70
  policies:
    - id: default
      name: Default Policy
      enabled: true
      pack_ids: [security]

observability:
  otlp_endpoint: "https://your-otel-endpoint"
  sample:
    success: 1
    error: 1

sec0_export:
  enabled: true
  cadence: daily
  bucket_uri: "gs://your-audit-bucket"
```

## Validating Policy

Use `sec0-sdk/policy` to validate a policy before deployment:

```typescript theme={null}
import { parsePolicyYaml, validatePolicy } from "sec0-sdk/policy";

// Parse and validate (throws on error)
const policyYaml = `tenant: my-app\n...`;
const policy = parsePolicyYaml(policyYaml);

// Validate without throwing
const result = validatePolicy(policyObject);
if (!result.valid) {
  console.error("Policy validation errors:", result.errors);
}
```

## Policy Sources

Policies can be loaded from multiple sources:

| Source            | How                                                        |
| ----------------- | ---------------------------------------------------------- |
| **Local file**    | `parsePolicyYaml(fs.readFileSync(...))`                    |
| **Inline object** | Pass directly to middleware/gateway                        |
| **Control plane** | Set `source: "control-plane"` with optional `refreshTtlMs` |
| **Agent-scoped**  | Per-nodeId policies from the control plane                 |

For the full policy schema reference, see [Policy Schema Reference](/docs/reference/policy-schema).
