RunFn, and options in one shot. Returns a ContractResult<T>. Implemented on top of defineContract; behavior is identical.
Signature
| Param | Type | Description |
|---|---|---|
schema | ZodType<T> | Zod schema for the expected output |
run | RunFn | (attempt) => Promise<string | null> — your LLM call |
options | ContractOptions<T> & { name: string } | Rules, retry, logger, etc. name is required. |
options
Same shape as ContractConfig<T> minus schema.
| Field | Type | Default | Description |
|---|---|---|---|
name | string | required | Human-readable identifier for the run — appears in logs, traces, dashboard |
rules | Rule<T>[] | [] | Domain correctness rules |
retry | RetryOptions | { maxAttempts: 3 } | Retry behavior |
repairs | RepairOverrides | — | Custom repair per category |
instructions | { suffix?: string } | — | Append text to the auto-generated prompt |
onAttempt | AttemptHook | — | Called after each attempt |
logger | ContractLogger<T> | — | Lifecycle hooks (pass createBoundaryLogger(...) to ship events) |
debug | boolean | false | Shorthand for createConsoleLogger() |
model | string | — | Stamped onto BoundaryLogEvent.model for this run |
Example
When to use enforce vs defineContract
enforce— one-off, ad-hoc, experimental. Inline definition and execution.defineContract— reusable, shared across endpoints, passed as a value.
See also
defineContract
Reusable contracts
Types
Full type reference