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

# Schema gate: validate agent output with Zod

> Enforce a strict structural contract on agent output or input using any Zod schema, with per-issue failure details returned for debugging.

The schema gate runs a Zod `safeParse` against `ctx.output` (or `ctx.input` when you set `target: "input"`) and fails the evaluation if validation does not succeed. It is the right tool when your agent is expected to return structured data — a JSON object, a typed array, a specific string format — and you need a hard guarantee that every field is present and correctly typed before the output reaches downstream code.

On failure, the gate returns up to five Zod validation issues in `details` so you can diagnose exactly which fields are wrong without needing to re-run the agent.

## Usage

```typescript theme={null}
import { createEngine, gates } from "@pecta/core";
import { z } from "zod";

const BidResponseSchema = z.object({
  id: z.string(),
  seatbid: z.array(
    z.object({
      bid: z.array(
        z.object({
          id: z.string(),
          impid: z.string(),
          price: z.number().positive(),
          adm: z.string().optional(),
        })
      ),
    })
  ),
});

const engine = createEngine({
  gates: [
    gates.schema(BidResponseSchema),
  ],
});

const result = await engine.evaluate({
  agent_id: "dsp-bidder",
  output: {
    id: "abc123",
    seatbid: [{ bid: [{ id: "b1", impid: "imp1", price: -0.5 }] }],
  },
});
```

## What a failure looks like

When validation fails, `reason` contains a human-readable summary and `details` contains the raw Zod issues (capped at five):

```json theme={null}
{
  "name": "schema",
  "passed": false,
  "reason": "schema validation failed (1 issue): seatbid.0.bid.0.price: Number must be greater than 0",
  "latency_ms": 0.31,
  "details": {
    "issues": [
      {
        "path": ["seatbid", 0, "bid", 0, "price"],
        "code": "too_small",
        "message": "Number must be greater than 0"
      }
    ],
    "total": 1
  }
}
```

`details.total` reflects the true number of Zod issues even when more than five exist.

## Configuration

<ParamField path="zodSchema" type="ZodTypeAny" required>
  Any Zod schema — `z.object`, `z.array`, `z.string`, `z.union`, or any composition thereof. Pass it as the first argument to `gates.schema(...)`.
</ParamField>

<ParamField path="target" type="&#x22;output&#x22; | &#x22;input&#x22;">
  Which field of the evaluation context to validate. Defaults to `"output"`. Set to `"input"` to validate what the agent received rather than what it produced.
</ParamField>

<ParamField path="name" type="string">
  Override the gate name recorded in results. Defaults to `"schema"`.
</ParamField>

## Validating a flat string response

The schema gate works on any Zod type, not just objects:

```typescript theme={null}
import { createEngine, gates } from "@pecta/core";
import { z } from "zod";

const engine = createEngine({
  gates: [
    gates.schema(z.string().url(), { name: "schema.url" }),
  ],
});

const result = await engine.evaluate({
  agent_id: "link-bot",
  output: "not-a-valid-url",
});
// result.passed === false
// reason: "schema validation failed (1 issue): <root>: Invalid url"
```

<Tip>
  Combine the schema gate with `gates.content()` to reject empty output before Zod runs. Because the engine runs gates in parallel by default, both gates evaluate simultaneously — but with `failFast: true` (the default), a content failure aborts the schema gate before it finishes if content fails first.
</Tip>
