<!-- Generated by scripts/ax-docs.mts from the JSDoc in registry/ouro/ax/. Do not edit; run `pnpm run docs`. -->

# ax-surfaces

What a repository hands the checker: its agent-facing words as one JSON file a repository can produce cheaply. The checker reads this, not the source, so a CLI, an MCP server, a hook or a script take the same path in.

- `errors`: the error and refusal texts an agent can hit, with the stable `code` of a text that has one.
- `tools`: the tools or commands, with the description an agent loads.
- `replies`: the actions' replies, with the field names they carry.
- `texts`: other words that speak to an agent, such as a hook's text or a reply's message.

An `id` is stable across edits to the wording (a code, a tool name, or `file#first-words`), because the ratchet records findings by it.

```sh
npx shadcn@latest add ourostack/ouro-ui/ax-surfaces#v1.3.68
```

It installs `lib/ouro/ax/surfaces.ts`, with `ax-dev-commands`, `ax-exit-codes`, `ax-problem`. Its tests are `ax-surfaces-tests`. Every item runs on Node 22.18 or later as it is copied: the files import each other as `./<file>.ts`. The [Ouro AX guide](ax.md) shows how they fit together.

## Exports

### `BaselineResult`

```ts
interface BaselineResult {
  added: SurfaceFinding[];
  fixed: string[];
  known: number;
  ok: boolean;
}
```

### `checkSurfaces`

Runs the checks over a manifest. Throws, with the fix, on a manifest that is not one. A finding names its check, the surface, what is wrong and what to change; the order is the manifest's.

```ts
function checkSurfaces(manifest: Surfaces): SurfacesReport
```

Example:

```ts
checkSurfaces({ ax: "surfaces/1", tool: "notes", errors: [{ id: "send-empty", text: "The draft is empty. Pass --text.", code: "send_empty" }] }).findings;
// [{ check: "error.leads-with-fix", surface: "send-empty", ... }]
```

### `countFindings`

The findings per group, which is what the baseline file records.

```ts
function countFindings(report: SurfacesReport): Record<string, number>
```

### `ErrorSurface`

```ts
interface ErrorSurface {
  id: string;
  text: string;
  code?: string;
  where?: string;
}
```

### `extractSurfaces`

The error texts in JavaScript and TypeScript source: the first string (or strings joined with `+`) after a throw, an `Error` constructor, `console.error`, a stderr write, `die`, `fail`, `refuse`, or an `error:` or `message:` property, outside tests, when it has several words. An id is `<path>#<first words>`, with `~2` for a repeat, so rewording an error's end keeps its id. A `code:` on the same line, or on the line before or after, gives the error its code. It reads the source as text, so it can miss a text built elsewhere and read a string that is not an error: its manifest is a start to edit, and the ratchet works from the manifest you keep.

```ts
function extractSurfaces(options: { root: string; paths: readonly string[]; tool: string; }): Surfaces
```

Example:

```ts
extractSurfaces({ root: ".", paths: ["src"], tool: "notes" }).errors;
```

### `FIX_VERBS`

The first words of a sentence that tell the reader what to do. A fix that opens an error starts with one of these (after an optional "Please" or "Then"), or with a label such as "Fix:" or "To continue,".

```ts
const FIX_VERBS: ReadonlySet<string>
```

### `leadsWithFix`

Whether an error's words open with the fix: after a leading `tool:` or `thing:` label, the first sentence is a command (starts with an imperative verb such as "Run", "Pass" or "Call") or a label such as "Fix:" or "To continue,". `later` says the fix does come, in a sentence after the problem.

```ts
function leadsWithFix(text: string): { leads: boolean; later: boolean; }
```

Example:

```ts
leadsWithFix("Pass --why. The send reaches other people."); // { leads: true, later: false }
leadsWithFix("send: the draft is empty. Fix: pass --text."); // { leads: false, later: true }
```

### `main`

The checker's command line. `check` reads a manifest and exits with the Ouro AX codes: ok, findings (with a baseline: a finding it does not list, or a listed one that is fixed), usage and error. `check --init` writes the first baseline and refuses to overwrite one; `--update` rewrites it with the findings that remain and refuses to add one. `extract` writes a manifest from source.

```ts
function main(args: readonly string[], io?: Io): Promise<number>
```

### `ratchet`

Compares a run to the recorded baseline, which counts findings per check and file (the group `error.has-code:src/send.js`), so rewording an error or moving it in its file leaves the baseline as it was. A group with more findings than recorded fails, and so does one with fewer: the pull request that fixes a finding lowers its count, so the count only goes down.

```ts
function ratchet(report: SurfacesReport, baseline: Readonly<Record<string, number>>): BaselineResult
```

Example:

```ts
ratchet(report, { "error.has-code:src/send.js": 2 }); // { added: [], fixed: ["error.has-code:src/send.js: was 2, now 1"], known: 1, ok: false }
```

### `ReplySurface`

```ts
interface ReplySurface {
  id: string;
  action: boolean;
  fields: string[];
  where?: string;
}
```

### `SURFACE_CHECKS`

The checks, in report order, and the rule they hold a surface to.

```ts
const SURFACE_CHECKS: readonly { id: string; rule: string }[]
```

### `SurfaceFinding`

```ts
interface SurfaceFinding {
  check: string;
  surface: string;
  where: string | null;
  problem: string;
  fix: string;
  key: string;
  group: string;
}
```

### `Surfaces`

What a repository hands the checker: its agent-facing words as one JSON file a repository can produce cheaply. The checker reads this, not the source, so a CLI, an MCP server, a hook or a script take the same path in.

- `errors`: the error and refusal texts an agent can hit, with the stable `code` of a text that has one.
- `tools`: the tools or commands, with the description an agent loads.
- `replies`: the actions' replies, with the field names they carry.
- `texts`: other words that speak to an agent, such as a hook's text or a reply's message.

An `id` is stable across edits to the wording (a code, a tool name, or `file#first-words`), because the ratchet records findings by it.

```ts
interface Surfaces {
  ax: typeof SURFACES_VERSION;
  tool: string;
  errors?: ErrorSurface[];
  tools?: ToolSurface[];
  replies?: ReplySurface[];
  texts?: TextSurface[];
  outcomeFields?: string[];
  limits?: Partial<SurfacesLimits>;
}
```

### `SURFACES_BASELINE_VERSION`

The baseline file's version.

```ts
const SURFACES_BASELINE_VERSION: "surfaces-baseline/2"
```

### `SURFACES_DEFAULT_LIMITS`

```ts
const SURFACES_DEFAULT_LIMITS: SurfacesLimits
```

### `SURFACES_VERSION`

The manifest's version, written as its `ax` field.

```ts
const SURFACES_VERSION: "surfaces/1"
```

### `SurfacesLimits`

```ts
interface SurfacesLimits {
  toolDescription: number;
  outcomeFields: string[];
}
```

### `SurfacesReport`

```ts
interface SurfacesReport {
  tool: string;
  surfaces: number;
  findings: SurfaceFinding[];
}
```

### `surfacesText`

The report for an agent or a person: the verdict on the first line, then the findings as `<check> <surface> (<where>): <problem>. Fix: <fix>.`, then what the ratchet wants.

```ts
function surfacesText(report: SurfacesReport, result: BaselineResult | null, options?: { baselinePath?: string | undefined; }): string
```

### `TextSurface`

```ts
interface TextSurface {
  id: string;
  text: string;
  where?: string;
}
```

### `ToolSurface`

```ts
interface ToolSurface {
  name: string;
  description: string;
  where?: string;
}
```
