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

# Capture Policy

> Decide which buckets of data leave the process

The capture policy is the first line of defense between your process and the ingest endpoint. It governs the three optional data buckets — `inputs`, `outputs`, and `repairs`. Everything else on a `BoundaryLogEvent` is structural and always sent, because Boundary can't show you a run at all without it.

## The three buckets

```typescript theme={null}
createBoundaryLogger({
  capture: {
    inputs:  false,  // raw LLM prompt you sent       (default: off)
    outputs: false,  // raw LLM response you received (default: off)
    repairs: true,   // repair messages on retry      (default: on)
  },
});
```

Defaults are **conservative**. Raw prompts and completions are the most sensitive payload in an LLM pipeline — they stay off until you explicitly opt in.

## Always-on fields

These are sent on every event regardless of capture config. They're the minimum Boundary needs to plot a run:

| Group                                     | Fields                                                | Why always on                                                                  |
| ----------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------ |
| Identity                                  | `contractName`, `environment`, `timestamp`, `runId`   | Required to coalesce per-attempt + terminal events into one run row.           |
| Run metadata                              | `attempt`, `maxAttempts`, `durationMs`, `ok`, `final` | The shape of "what happened in this run."                                      |
| Contract metadata                         | `model`, `rulesCount`, `schema`, `rules`              | Stamped so the dashboard can attribute failures to the right contract version. |
| Failure attribution (only on `ok: false`) | `category`, `issues`, `ruleFailures`                  | Without these, a failure event is just a flag — useless for triage.            |
| SDK attribution                           | `sdk.name`, `sdk.version`, `sdk.runtime`              | Used to debug version-specific behavior.                                       |

## Field-to-bucket mapping

| Field           | Gate              | Default |
| --------------- | ----------------- | ------- |
| `input`         | `capture.inputs`  | **off** |
| `output`        | `capture.outputs` | **off** |
| `repairs`       | `capture.repairs` | on      |
| Everything else | always sent       | on      |

## Why raw input/output defaults to off

* User prompts contain customer data, PII, and internal context.
* Model completions contain proprietary business logic (lead scores, financial calcs, medical reasoning).
* Both can contain credentials echoed back by the model.

Turning them on is a deliberate operational decision. When you do:

1. Enable them in `staging` or `development` first and audit what actually flows through before flipping production.
2. Pair with [redaction](/sdk/redaction) rules that match your data shape.
3. Or use [`beforeSend`](/sdk/before-send) to hash or summarize the input before it leaves the process.

## Opt-in recipe: debug staging traffic

```typescript theme={null}
const logger = createBoundaryLogger({
  apiKey: process.env.BOUNDARY_API_KEY,
  environment: "staging",
  capture: {
    inputs: true,
    outputs: true,
  },
  redact: {
    fields: ["email", "phone", "ssn"],
    patterns: [
      /\b\d{3}-\d{2}-\d{4}\b/,    // SSN
      /[\w.+-]+@[\w-]+\.[\w.-]+/, // email
    ],
  },
});
```

## When you can't capture failure context

Failure attribution (`category`, `issues`, `ruleFailures`) is always sent on a failed event — there is no flag to drop it. If a specific failure message would leak data because a rule interpolates record values into it, fix it at the source: rewrite the rule to return a generic message string, or use [`beforeSend`](/sdk/before-send) to scrub `issues[]` before the event leaves the process.

## Order of operations

```mermaid theme={null}
flowchart LR
    event[BoundaryLogEvent] --> capture[applyCapture]
    capture --> redact[redact]
    redact --> beforeSend[beforeSend hook]
    beforeSend --> batch[Batcher queue]
    batch --> http[HTTP transport]
```

Capture runs first — anything it strips cannot be resurrected downstream.

## See also

<CardGroup cols={2}>
  <Card title="Redaction" icon="eye-slash" href="/sdk/redaction">
    Fields, patterns, custom per-leaf scrubbing
  </Card>

  <Card title="beforeSend" icon="filter" href="/sdk/before-send">
    Per-event transform or drop
  </Card>

  <Card title="BoundaryLogEvent" icon="file-code" href="/sdk/boundary-log-event">
    Full wire format
  </Card>
</CardGroup>
