# Detail Fold

> 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 · `detail-fold` · [HTML](https://pi-tui.ratstack.sh/patterns/detail-fold/) · [JSON](https://pi-tui.ratstack.sh/patterns/detail-fold.json) · [all patterns](https://pi-tui.ratstack.sh/patterns.md)

Also known as Expandable tool result.

## Intent

Show compact progress and summaries with bounded expanded tool detail.

## Motivation

Web Access emits phase-specific tool progress while Tool Display caps long expanded previews.

## Applicability

- Use this when structured tool results would overwhelm the transcript.

## Structure

```text
renderCall -> progress
renderResult -> summary / detail
```

## Participants

- [`ToolDefinition.renderCall`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering): Renders the call before or during execution.
- [`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.
- [`ToolRenderContext`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering): Shares per-call state, prior components and invalidation.
- `Structured result`: Supplies guarded partial data and bounded expanded detail.

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

## Consequences

- The transcript stays compact while detail remains inspectable.
- Partial results need guards and expanded previews may still need caps.

## Implementation

- Partial results may not contain final detail fields.
- Mark capped previews rather than silently hiding their limit.
- The tool-display snapshot's peer range stops at 0.80.

## 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.

### In flight

`partial`: Show a synthetic phase-specific partial result.

Checks at every width and theme:

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

Frames:

- 40 columns: ![Detail Fold, In flight, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-40-dark.1e6feb6a2750.webp) ![Detail Fold, In flight, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-40-light.7b80971f0b93.webp)
- 60 columns: ![Detail Fold, In flight, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-60-dark.1e73e02a860d.webp) ![Detail Fold, In flight, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-60-light.15eea5346dc1.webp)
- 80 columns: ![Detail Fold, In flight, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-80-dark.42a74622c258.webp) ![Detail Fold, In flight, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-80-light.80726639ca9b.webp)
- 120 columns: ![Detail Fold, In flight, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-120-dark.10574825346b.webp) ![Detail Fold, In flight, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/partial-120-light.50ef9adfa29c.webp)

### Summary

`collapsed`: Show one compact completion row.

Checks at every width and theme:

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

Frames:

- 40 columns: ![Detail Fold, Summary, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-40-dark.86a5d190fc35.webp) ![Detail Fold, Summary, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-40-light.4c4a839cadf3.webp)
- 60 columns: ![Detail Fold, Summary, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-60-dark.9b4e54b755f3.webp) ![Detail Fold, Summary, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-60-light.cb9ce3fa8b4e.webp)
- 80 columns: ![Detail Fold, Summary, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-80-dark.c43d0d7dfa26.webp) ![Detail Fold, Summary, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-80-light.554a80ab9c69.webp)
- 120 columns: ![Detail Fold, Summary, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-120-dark.e91cb355f490.webp) ![Detail Fold, Summary, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/collapsed-120-light.280440e555c6.webp)

### Bounded detail

`expanded`: Expand details with an explicit preview-cap notice.

Checks at every width and theme:

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

Frames:

- 40 columns: ![Detail Fold, Bounded detail, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-40-dark.cf2c5c810fcd.webp) ![Detail Fold, Bounded detail, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-40-light.cfe4c4dbda70.webp)
- 60 columns: ![Detail Fold, Bounded detail, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-60-dark.e8ad2db1efdf.webp) ![Detail Fold, Bounded detail, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-60-light.d1bdda9051f0.webp)
- 80 columns: ![Detail Fold, Bounded detail, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-80-dark.e7b14f2b3421.webp) ![Detail Fold, Bounded detail, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-80-light.296788be4ce5.webp)
- 120 columns: ![Detail Fold, Bounded detail, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-120-dark.f1556a6b8d2f.webp) ![Detail Fold, Bounded detail, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/detail-fold/expanded-120-light.de2c6754eee3.webp)

## Sample code

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

```ts
// Detail Fold: compact tool progress with explicitly capped expanded detail.
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";

export const story: PatternStory = {
  id: "detail-fold", title: "Detail Fold", kind: "component",
  apis: ["ToolExecutionComponent", "ToolDefinition.renderCall", "ToolDefinition.renderResult"], rows: 16,
  states: [
    { id: "partial", label: "In flight" },
    { id: "collapsed", label: "Summary", steps: [{ type: "action", name: "complete" }] },
    { id: "expanded", label: "Bounded detail", steps: [{ type: "action", name: "expand" }] },
  ],
  setup({ theme, tui, action }) {
    const pages = ["Guide: terminal widths", "Guide: keyboard focus", "Guide: theme tokens",
      "Reference: text wrapping", "Reference: overlay lifetime", "Example: compact footer"];
    const renderers: ToolRenderers = {
      renderCall: () => new Text(theme.fg("toolTitle", "docs_search · terminal UI"), 0, 0),
      renderResult(result, options) {
        const details: unknown = result.details;
        // A streaming result may not have the final page list.
        const found = typeof details === "object" && details !== null && "pages" in details &&
          Array.isArray(details.pages) ? details.pages.filter((p): p is string => typeof p === "string") : [];
        const lines = options.isPartial ? ["Searching reference pages…"] :
          options.expanded ? [...found.slice(0, 3), "Preview: 3 of " + found.length + " pages"] :
            [found.length + " pages found · expand for detail"];
        return {
          invalidate() {},
          render(width) {
            return lines.flatMap(line => wrapTextWithAnsi(line, width)
              .map(row => theme.fg(options.isPartial ? "warning" : "toolOutput", row)));
          },
        };
      },
    };
    const tool = new ToolExecutionComponent("docs_search", "example-search-1",
      { query: "terminal UI" }, undefined, renderers, tui, "/workspace/example");
    tool.markExecutionStarted();
    tool.updateResult({ content: [], isError: false }, true);
    action("complete", () => {
      tool.updateResult({ content: [], details: { pages }, isError: false }, false);
      tui.requestRender();
    });
    action("expand", () => { tool.setExpanded(true); tui.requestRender(); });
    return tool;
  },
};
```

## Known uses: seen in Nico's repos

- [**dot314**](https://github.com/nicobailon/dot314): Render partial, compact and expanded tool results
  - [extensions/todos.ts:1-20](https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/todos.ts#L1-L20) @17cce138
- [**pi-interview-tool**](https://github.com/nicobailon/pi-interview-tool): Render partial, compact and expanded tool results
- [**pi-mcp-adapter**](https://github.com/nicobailon/pi-mcp-adapter): Render partial, compact and expanded tool results
  - [index.ts:500-512](https://github.com/nicobailon/pi-mcp-adapter/blob/85db03d87cd0f7461b55eab8d25c10bce473b801/index.ts#L500-L512) @85db03d8
  - [index.ts:790-804](https://github.com/nicobailon/pi-mcp-adapter/blob/85db03d87cd0f7461b55eab8d25c10bce473b801/index.ts#L790-L804) @85db03d8
  - [index.ts:1765-1775](https://github.com/nicobailon/pi-mcp-adapter/blob/85db03d87cd0f7461b55eab8d25c10bce473b801/index.ts#L1765-L1775) @85db03d8
  - [index.ts:2058-2090](https://github.com/nicobailon/pi-mcp-adapter/blob/85db03d87cd0f7461b55eab8d25c10bce473b801/index.ts#L2058-L2090) @85db03d8
  - [proxy-modes.ts:1130-1140](https://github.com/nicobailon/pi-mcp-adapter/blob/85db03d87cd0f7461b55eab8d25c10bce473b801/proxy-modes.ts#L1130-L1140) @85db03d8
- [**pi-subagent-enhanced**](https://github.com/nicobailon/pi-subagent-enhanced): Render partial, compact and expanded tool results
  - [index.ts:860-930](https://github.com/nicobailon/pi-subagent-enhanced/blob/f895b2a8773341e4b8a2ba197d58bdd43d5cb561/index.ts#L860-L930) @f895b2a8
- [**pi-tool-display**](https://github.com/nicobailon/pi-tool-display): Render partial, compact and expanded tool results
  - [src/tool-overrides.ts:1064-1105](https://github.com/nicobailon/pi-tool-display/blob/fca8c858a0989b63eba18ab935f3d8ed78354c3a/src/tool-overrides.ts#L1064-L1105) @fca8c858
- [**pi-web-access**](https://github.com/nicobailon/pi-web-access): Render partial, compact and expanded tool results
  - [index.ts:1633-1655](https://github.com/nicobailon/pi-web-access/blob/9a0779976ba47350be18f8cfacaffbe2a407113e/index.ts#L1633-L1655) @9a077997

## For agents: choose and check

Choose Detail Fold 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.

- [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.
- [Error Digest](https://pi-tui.ratstack.sh/patterns/error-digest.md): Project structured errors into compact and expanded diagnostic output.
- [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.renderCall`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering), [`ToolDefinition.renderResult`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering), [`ToolRenderContext`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#tool-rendering), `ToolExecutionComponent` before you use them.
- Every reference frame gets the verdict its state expects.

Next actions: `related({ id: "detail-fold" })` lists what to read next, and `states({ id: "detail-fold", 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

- [Call Capsule](https://pi-tui.ratstack.sh/patterns/call-capsule.md): retains a shell across result updates

## Linked from

- [Error Digest](https://pi-tui.ratstack.sh/patterns/error-digest.md): supplies the expansion surface
