> ## 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.

# Guard API

> Use sec0-sdk/guard for standalone, dashboard, or hybrid allow-redact-block-escalate checks.

`sec0-sdk/guard` is the smallest Sec0 integration surface. Use it when you want policy decisions in application code without wrapping a tool server.

Typical uses:

* outbound message checks before sending to Slack, Discord, email, or SMS
* preflight checks around external API calls
* tool or MCP decisions in apps that do not use `sec0-sdk/middleware`
* approval workflows that need a simple create, wait, and resolve loop

## Core API

`createSec0Guard(...)` returns three methods:

| Method                                         | Use it for                                                                          |
| ---------------------------------------------- | ----------------------------------------------------------------------------------- |
| `guard.check(input)`                           | get a decision without executing anything                                           |
| `guard.execute(input, actionFn, handlers?)`    | run the action only when the decision allows it, redacts it, or resolves escalation |
| `guard.waitForResolution(escalationId, opts?)` | wait on an existing escalation                                                      |

Decision outcomes are:

| Outcome    | Meaning                                                |
| ---------- | ------------------------------------------------------ |
| `allow`    | proceed as-is                                          |
| `redact`   | execute with redacted content                          |
| `block`    | stop immediately                                       |
| `escalate` | create an escalation and either wait or return pending |

## Choose a Mode

| Mode         | Policy source                                                      |
| ------------ | ------------------------------------------------------------------ |
| `standalone` | local `GuardPolicy`, local `policy.yaml`, or local `PolicyObject`  |
| `dashboard`  | remote control-plane policy only                                   |
| `hybrid`     | local plus remote, with `remote-first` or `local-first` precedence |

## Standalone Example

Use standalone mode when the application must work without network access:

```typescript theme={null}
import { createSec0Guard } from "sec0-sdk/guard";

const guard = createSec0Guard({
  mode: "standalone",
  provider: {
    local: {
      policy: {
        defaultOutcome: "allow",
        rules: [
          {
            kind: "message_outbound",
            target: "discord:supplier",
            outcome: "block",
            reason: "supplier_messages_require_review",
          },
        ],
      },
    },
  },
});

await guard.execute(
  {
    kind: "message_outbound",
    target: "discord:supplier",
    content: outboundMessage,
  },
  async () => sendToSupplier(outboundMessage),
);
```

## Dashboard Example

Use dashboard mode when policy should come from the control plane:

```typescript theme={null}
import { createSec0Guard } from "sec0-sdk/guard";

const guard = createSec0Guard({
  mode: "dashboard",
  provider: {
    remote: {
      auth: { apiKey: process.env.SEC0_API_KEY! },
      source: {
        source: "control-plane",
        level: "middleware",
        scope: "base",
        refreshTtlMs: 60_000,
      },
    },
  },
});

const decision = await guard.check({
  kind: "tool_call",
  target: "payments:refund@1.0",
  content: { chargeId: "ch_123" },
});
```

## Hybrid Example

Use hybrid mode when the remote policy should be primary but local fallback must still work:

```typescript theme={null}
import { createSec0Guard } from "sec0-sdk/guard";

const guard = createSec0Guard({
  mode: "hybrid",
  provider: {
    precedence: "remote-first",
    remote: {
      auth: { apiKey: process.env.SEC0_API_KEY! },
      source: { source: "control-plane", level: "middleware", scope: "base" },
    },
    local: {
      policyPath: "./policy.fallback.yaml",
      cacheTtlMs: 5 * 60_000,
    },
  },
});
```

If the remote policy fails after a prior successful fetch, the guard can continue from its remote cache. If no cache exists, hybrid mode falls back to the local provider.

## Execute with Redaction or Block Handlers

`guard.execute(...)` lets you customize what happens on redact and block outcomes:

```typescript theme={null}
const result = await guard.execute(
  {
    kind: "api_call",
    target: "https://billing.example.com/refunds",
    content: payload,
  },
  async (input) => billingClient.refund(input.content),
  {
    onRedactInput(input, decision) {
      return { ...input, content: decision.redactedContent };
    },
    onBlock(decision) {
      return { blocked: true, reason: decision.reason };
    },
  },
);
```

## Escalations and Approvals Transport

The guard can create and wait on escalations, and it can forward those escalation events to the open-source approvals bridge.

```typescript theme={null}
import {
  createApprovalsBridgeTransport,
  createSec0Guard,
} from "sec0-sdk/guard";

const guard = createSec0Guard({
  mode: "dashboard",
  provider: {
    remote: {
      auth: { apiKey: process.env.SEC0_API_KEY! },
      source: { source: "control-plane", level: "middleware", scope: "base" },
    },
  },
  escalation: {
    waitForResolutionByDefault: true,
    timeoutMs: 5 * 60_000,
    pollIntervalMs: 2000,
  },
  transport: createApprovalsBridgeTransport({
    bridgeUrl: process.env.SEC0_APPROVALS_BRIDGE_URL!,
    tenantId: process.env.SEC0_TENANT_ID!,
    bearerToken: process.env.SEC0_APPROVALS_BRIDGE_TOKEN,
    sharedSecret: process.env.SEC0_APPROVALS_BRIDGE_SHARED_SECRET,
  }),
});
```

The transport emits `escalation.created` and `escalation.finalized` events to the bridge. Deploy the reference worker in `apps/sec0-approvals-bridge` when you want Discord or Telegram approval flows.

If your application already knows when to escalate and does not need policy evaluation, use `createEscalationManager(...)` from `sec0-sdk/escalation` instead of `sec0-sdk/guard`. Guard now builds on that same shared escalation lifecycle.

## Waiting on an Existing Escalation

If your application stores the escalation id and resolves it later:

```typescript theme={null}
const resolution = await guard.waitForResolution("esc_123", {
  timeoutMs: 120_000,
  pollIntervalMs: 2000,
});
```

The final status is one of `approved`, `rejected`, `expired`, or `timeout`.

The equivalent standalone API is:

```typescript theme={null}
import { createEscalationManager } from "sec0-sdk/escalation";

const escalation = createEscalationManager({
  apiKey: process.env.SEC0_API_KEY!,
  controlPlaneUrl: process.env.SEC0_CONTROL_PLANE_URL,
});

const resolution = await escalation.waitForResolution("esc_123", {
  timeoutMs: 120_000,
  pollIntervalMs: 2000,
});
```

## When to Use Guard vs Middleware

Use `sec0-sdk/guard` when the action lives in application code. Use `sec0-sdk/middleware` when the action is a tool-server invocation and you want registry freeze, source hashing, signed envelopes, and server-side policy enforcement on every call.
