# Error Digest

> For agents: start with the [agent guide](https://pi-tui.ratstack.sh/llms.txt). Every page here has a Markdown twin, and every pattern has a JSON record.

Presentation / Tool and message output · `error-digest` · [HTML](https://pi-tui.ratstack.sh/patterns/error-digest/) · [JSON](https://pi-tui.ratstack.sh/patterns/error-digest.json) · [all patterns](https://pi-tui.ratstack.sh/patterns.md)

Also known as Diagnostic summary.

## Intent

Project structured errors into compact and expanded diagnostic output.

## Motivation

Web Access combines cancellation, query failures and runtime facts into one diagnostic plan.

## Applicability

- Use this when several failures need a readable summary without hiding detail.

## Structure

```text
failures -> pure diagnostic plan
plan -> summary / expanded lines
```

## Participants

- [`ToolDefinition.renderResult`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering): Renders partial or final tool output.
- [`Text`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#compose-built-in-components): Renders wrapped text content.
- `Diagnostic plan`: Keeps cancellation and query failures separate from rendering.

Pi component APIs: [`ToolDefinition.renderResult`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering), [`Text`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#compose-built-in-components), `ToolExecutionComponent`

## Consequences

- Errors have a concise summary without losing expanded diagnostic lines.
- Planning must stay separate from component rendering.

## Implementation

- Keep the error plan separate from the TUI renderer.
- Distinguish cancellation from per-query failure.

## States

Each state was rendered at 40, 60, 80 and 120 columns in Pi's dark and light themes. Each frame links one WebP. An animated frame links its first image, then the animation.

### Error summary

`collapsed`: Show a short summary of synthetic query failures.

Checks at every width and theme:

- width: ✓ pass
- style-leak: ✓ pass
- hard-coded-colour: ✓ pass
- height: ✓ pass

Frames:

- 40 columns: ![Error Digest, Error summary, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-40-dark.c8e469224d35.webp) ![Error Digest, Error summary, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-40-light.3ecd9253e6fa.webp)
- 60 columns: ![Error Digest, Error summary, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-60-dark.6ab0e6dce379.webp) ![Error Digest, Error summary, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-60-light.bf9797551d71.webp)
- 80 columns: ![Error Digest, Error summary, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-80-dark.dd42f6984ee5.webp) ![Error Digest, Error summary, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-80-light.85993efa97e3.webp)
- 120 columns: ![Error Digest, Error summary, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-120-dark.678e4e8373d5.webp) ![Error Digest, Error summary, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/collapsed-120-light.42c4c54ab5f6.webp)

### Diagnostic plan

`expanded`: Show all planned diagnostic lines.

Checks at every width and theme:

- width: ✓ pass
- style-leak: ✓ pass
- hard-coded-colour: ✓ pass
- height: ✓ pass

Frames:

- 40 columns: ![Error Digest, Diagnostic plan, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-40-dark.bc2f5562c05b.webp) ![Error Digest, Diagnostic plan, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-40-light.02e204e14722.webp)
- 60 columns: ![Error Digest, Diagnostic plan, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-60-dark.4de401c27943.webp) ![Error Digest, Diagnostic plan, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-60-light.0c68ed283a45.webp)
- 80 columns: ![Error Digest, Diagnostic plan, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-80-dark.8481d7e1f205.webp) ![Error Digest, Diagnostic plan, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-80-light.96aab464d23a.webp)
- 120 columns: ![Error Digest, Diagnostic plan, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-120-dark.a39acdcc7bca.webp) ![Error Digest, Diagnostic plan, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/expanded-120-light.97fad046104d.webp)

### Cancellation

`cancelled`: Show a cancelled operation without labeling it a query failure.

Checks at every width and theme:

- width: ✓ pass
- style-leak: ✓ pass
- hard-coded-colour: ✓ pass
- height: ✓ pass

Frames:

- 40 columns: ![Error Digest, Cancellation, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-40-dark.727554fa9c81.webp) ![Error Digest, Cancellation, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-40-light.01874628fb0e.webp)
- 60 columns: ![Error Digest, Cancellation, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-60-dark.083f65c98a5d.webp) ![Error Digest, Cancellation, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-60-light.a4fde8d0c3e6.webp)
- 80 columns: ![Error Digest, Cancellation, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-80-dark.e8eabdee0680.webp) ![Error Digest, Cancellation, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-80-light.df8f59db8737.webp)
- 120 columns: ![Error Digest, Cancellation, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-120-dark.b33f3e2e42de.webp) ![Error Digest, Cancellation, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/error-digest/cancelled-120-light.a96bb324bf40.webp)

## Sample code

`stories/patterns/presentation/error-digest.ts`, the story the frames above were rendered from.

```ts
// Error Digest: keep diagnostic planning separate from summary/detail rendering.
import { Text, wrapTextWithAnsi } from "@earendil-works/pi-tui";
import { ToolExecutionComponent, type ToolRenderers } from "@earendil-works/pi-coding-agent";
import type { PatternStory } from "../../../src/pattern.ts";

type Outcome = { kind: "cancelled" } | {
  kind: "failed"; queries: readonly { query: string; reason: string }[];
};
function diagnosticPlan(outcome: Outcome) {
  if (outcome.kind === "cancelled") return {
    summary: "Search cancelled · no query failure", lines: ["Cancelled before the next query started."],
  };
  return {
    summary: outcome.queries.length + " queries failed · expand for details",
    lines: outcome.queries.map(q => q.query + ": " + q.reason),
  };
}
export const story: PatternStory = {
  id: "error-digest", title: "Error Digest", kind: "component",
  apis: ["ToolExecutionComponent", "ToolDefinition.renderResult", "Text"], rows: 16,
  states: [
    { id: "collapsed", label: "Error summary" },
    { id: "expanded", label: "Diagnostic plan", steps: [{ type: "action", name: "expand" }] },
    { id: "cancelled", label: "Cancellation", steps: [{ type: "action", name: "cancel" }] },
  ],
  setup({ theme, tui, action }) {
    let outcome: Outcome = { kind: "failed", queries: [
      { query: "terminal widths", reason: "request timed out" },
      { query: "overlay focus", reason: "reference index unavailable" },
    ] };
    const renderers: ToolRenderers = {
      renderCall: () => new Text(theme.fg("toolTitle", "reference_search · two queries"), 0, 0),
      renderResult(_result, options) {
        const plan = diagnosticPlan(outcome);
        const lines = [plan.summary, ...(options.expanded ? plan.lines : [])];
        return {
          invalidate() {},
          render(width) {
            return lines.flatMap(line => wrapTextWithAnsi(line, width)
              .map(row => theme.fg(outcome.kind === "cancelled" ? "muted" : "error", row)));
          },
        };
      },
    };
    const tool = new ToolExecutionComponent("reference_search", "example-search-2", {},
      undefined, renderers, tui, "/workspace/example");
    tool.updateResult({ content: [], isError: true }, false);
    action("expand", () => { tool.setExpanded(true); tui.requestRender(); });
    action("cancel", () => {
      outcome = { kind: "cancelled" };
      tool.updateResult({ content: [], isError: false }, false); tui.requestRender();
    });
    return tool;
  },
};
```

## Known uses: seen in Nico's repos

- [**pi-web-access**](https://github.com/nicobailon/pi-web-access): Web access: collapsed and expanded search-error diagnostics
  - [render-search-error.ts:1-115](https://github.com/nicobailon/pi-web-access/blob/9a0779976ba47350be18f8cfacaffbe2a407113e/render-search-error.ts#L1-L115) @9a077997
  - [index.ts:1633-1723](https://github.com/nicobailon/pi-web-access/blob/9a0779976ba47350be18f8cfacaffbe2a407113e/index.ts#L1633-L1723) @9a077997

## For agents: choose and check

Choose Error Digest when your job matches its intent and applicability above. Its neighbours in Tool and message output are listed below. Read the one whose intent fits your job more closely before you commit.

- [Detail Fold](https://pi-tui.ratstack.sh/patterns/detail-fold.md): Show compact progress and summaries with bounded expanded tool detail.
- [Call Capsule](https://pi-tui.ratstack.sh/patterns/call-capsule.md): Retain a display shell through call and result renders of one tool execution.
- [Hinge Diff](https://pi-tui.ratstack.sh/patterns/hinge-diff.md): Choose compact, unified or split diff presentation from available width.
- [Word Spotlight](https://pi-tui.ratstack.sh/patterns/word-spotlight.md): Emphasize changed words inside parsed patch lines.
- [Renderer Chain](https://pi-tui.ratstack.sh/patterns/renderer-chain.md): Add tool rendering while preserving an existing renderer or fallback.
- [Message Fold](https://pi-tui.ratstack.sh/patterns/message-fold.md): Render custom message content as a preview with expanded detail.
- [Image Parachute](https://pi-tui.ratstack.sh/patterns/image-parachute.md): Render terminal images where supported and text placeholders otherwise.

Check your version:

- Render your version at 40, 60, 80 and 120 columns in the dark and light themes.
- Check width: no rendered line is wider than the terminal.
- Check style-leak: no line ends with colour, bold or a link still switched on.
- Check hard-coded-colour: every colour on screen comes from the active theme.
- Check height: the output fits in the rows the terminal has.
- Read the Pi 1.0.3 docs for [`ToolDefinition.renderResult`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering), [`Text`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#compose-built-in-components), `ToolExecutionComponent` before you use them.
- Every reference frame gets the verdict its state expects.

Next actions: `related({ id: "error-digest" })` lists what to read next, and `states({ id: "error-digest", width: 40 })` returns every frame and verdict at one width. The [build-pi-tui-component skill](https://pi-tui.ratstack.sh/skills/build-pi-tui-component.md) walks through the whole loop.

## Related

- [Detail Fold](https://pi-tui.ratstack.sh/patterns/detail-fold.md): supplies the expansion surface

## Linked from

No other pattern links here.
