Defining a contract
defineContract returns a DefinedContract<T> — a reusable object you call .accept() on whenever you want to run an LLM call through this contract.
Using a contract
The.accept() method takes your LLM call as a function. You own the LLM call. Boundary owns the validation.
attempt object gives you everything you need:
| Field | Type | Description |
|---|---|---|
attempt | number | Current attempt number (1-indexed) |
maxAttempts | number | Maximum retries allowed |
instructions | string | Auto-generated prompt from your schema |
repairs | Array<{ role, content }> | Repair messages from prior failures — empty on the first attempt, always role: "user" on retries. See the attempt.repairs field. |
The RunFn
Your function must match this signature:
null if the LLM returned nothing.
The
RunFn must return a string, not a parsed object. Extract the text content from your provider’s response object before returning.Your existing Zod schemas work
Boundary uses Zod for schema validation. If you already have Zod schemas in your codebase, pass them directly — no migration, no rewrite, no Boundary-specific DSL.Configuration options
defineContract accepts these options:
| Option | Type | Default | Description |
|---|---|---|---|
name | string | required | Stable identifier for the contract. Appears on every event and joins to per-contract aggregates on the dashboard. |
schema | ZodType<T> | required | Your Zod schema (v3 or v4). |
rules | Rule<T>[] | [] | Named domain rules — see Rules. |
retry | { maxAttempts?, backoff?, baseMs? } | { maxAttempts: 3, backoff: "none", baseMs: 200 } | How aggressively to retry on failures. |
repairs | Partial<Record<FailureCategory, RepairFn | false>> | — | Override or disable the built-in repair message for a specific failure category. |
instructions | { suffix?: string } | — | Append extra text to the schema-derived prompt. |
onAttempt | (event) => void | — | Per-attempt hook for logging or metrics. |
logger | ContractLogger<T> | — | Lifecycle hooks — pair with createBoundaryLogger for the dashboard, or roll your own. |
model | string | — | Default model label, stamped on every event. Override per-call via contract.accept(run, { model }). |
debug | boolean | false | Verbose console logging during execution. |
Next steps
Rules
Write domain correctness rules
The Repair Loop
How Boundary turns failures into fixes