# Deferred Crest

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

Lifecycle / Lifecycle and mounting · `deferred-crest` · [HTML](https://pi-tui.ratstack.sh/patterns/deferred-crest/) · [JSON](https://pi-tui.ratstack.sh/patterns/deferred-crest.json) · [all patterns](https://pi-tui.ratstack.sh/patterns.md)

Also known as Deferred header.

## Intent

Mount optional startup content only after deferred discovery remains eligible.

## Motivation

Powerline Footer discovers optional welcome content asynchronously and rechecks request and session eligibility.

## Applicability

- Use this when a welcome header should not block session startup.

## Structure

```text
startup -> deferred discovery
eligible generation -> setHeader
stale generation -> ignore
```

## Participants

- [`ctx.ui.setHeader`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user): Installs or restores the startup header.
- [`pi.on`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#events): Registers ordered extension event handlers.
- `Session generation`: Rejects stale discovery before mounting optional content.

Pi screen APIs: [`ctx.ui.setHeader`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user), [`pi.on`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#events), `setHeader`, `Text`

## Consequences

- Startup can proceed before optional header discovery.
- Late discovery must not mount stale session content.

## Implementation

- Recheck eligibility after asynchronous discovery.
- Reject callbacks from superseded session generations.

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

### Startup proceeds

`starting`: Show the ordinary host before optional discovery settles.

Checks at every width and theme:

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

Frames:

- 40 columns: ![Deferred Crest, Startup proceeds, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-40-dark.59acf3c59d08.webp) ![Deferred Crest, Startup proceeds, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-40-light.3a1b7f8bef66.webp)
- 60 columns: ![Deferred Crest, Startup proceeds, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-60-dark.4206140bcdce.webp) ![Deferred Crest, Startup proceeds, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-60-light.307f3463c3c3.webp)
- 80 columns: ![Deferred Crest, Startup proceeds, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-80-dark.37dc4bba7719.webp) ![Deferred Crest, Startup proceeds, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-80-light.27014d5db5d3.webp)
- 120 columns: ![Deferred Crest, Startup proceeds, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-120-dark.d578f52e28ea.webp) ![Deferred Crest, Startup proceeds, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/starting-120-light.31d0e59644c4.webp)

### Header mounted

`eligible`: Mount a synthetic welcome header after an eligible result.

Checks at every width and theme:

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

Frames:

- 40 columns: ![Deferred Crest, Header mounted, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-40-dark.7378eb453889.webp) ![Deferred Crest, Header mounted, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-40-light.dce17434fb57.webp)
- 60 columns: ![Deferred Crest, Header mounted, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-60-dark.ca94a3a11c8e.webp) ![Deferred Crest, Header mounted, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-60-light.f758fd9cf36d.webp)
- 80 columns: ![Deferred Crest, Header mounted, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-80-dark.f3906d8bf0a5.webp) ![Deferred Crest, Header mounted, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-80-light.2ab6042151f8.webp)
- 120 columns: ![Deferred Crest, Header mounted, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-120-dark.7d770f614010.webp) ![Deferred Crest, Header mounted, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/eligible-120-light.03860a9d7155.webp)

### Stale discovery ignored

`stale`: Show a new session without a late header from the previous generation.

Checks at every width and theme:

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

Frames:

- 40 columns: ![Deferred Crest, Stale discovery ignored, 40 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-40-dark.cf503b3ac865.webp) ![Deferred Crest, Stale discovery ignored, 40 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-40-light.207a8c586a1b.webp)
- 60 columns: ![Deferred Crest, Stale discovery ignored, 60 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-60-dark.e8aa3d0770ad.webp) ![Deferred Crest, Stale discovery ignored, 60 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-60-light.fa496f662dc9.webp)
- 80 columns: ![Deferred Crest, Stale discovery ignored, 80 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-80-dark.d3a16988b506.webp) ![Deferred Crest, Stale discovery ignored, 80 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-80-light.bd4e4a7749fc.webp)
- 120 columns: ![Deferred Crest, Stale discovery ignored, 120 columns, dark theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-120-dark.e32e64066588.webp) ![Deferred Crest, Stale discovery ignored, 120 columns, light theme](https://pi-tui.ratstack.sh/frames/deferred-crest/stale-120-light.4f01864e63d0.webp)

## Sample code

`stories/patterns/lifecycle/deferred-crest.ts`, the story the frames above were rendered from.

```ts
// Deferred Crest: mount optional startup content only for an eligible generation.
import { Text } from "@earendil-works/pi-tui";
import type { PatternStory } from "../../../src/pattern.ts";

export const story: PatternStory = {
  id: "deferred-crest", title: "Deferred Crest", kind: "screen",
  apis: ["setHeader", "Text"],
  states: [
    { id: "starting", label: "Startup proceeds" },
    { id: "eligible", label: "Header mounted", steps: [{ type: "action", name: "discover" }] },
    { id: "stale", label: "Stale discovery ignored", steps: [{ type: "action", name: "switch-session" }] },
  ],
  setup({ ui, theme, action }) {
    let sessionGeneration = 1;
    let eligible = true;
    // A deferred fixture replaces discovery I/O and session events.
    const discover = (generation: number, title: string) => Promise.resolve().then(() => {
      if (generation !== sessionGeneration || !eligible) return false;
      ui.setHeader((_tui, theme) => new Text(theme.fg("accent", title) + "\n" +
        theme.fg("muted", "Workspace ready · optional welcome"), 0, 0));
      return true;
    });
    ui.setEditorText("Review the task list.");
    ui.setWidget("discovery", [theme.fg("muted", "Welcome pending · editor ready")]);
    action("discover", async () => {
      await discover(sessionGeneration, "Welcome · parser workspace");
      ui.setWidget("discovery", [theme.fg("success", "Eligible result mounted after discovery")]);
    });
    action("switch-session", async () => {
      const lateDiscovery = discover(sessionGeneration, "Old workspace welcome");
      sessionGeneration++;
      eligible = false;
      ui.setHeader(undefined);
      ui.setEditorText("Start a fresh task.");
      const mounted = await lateDiscovery;
      if (mounted) throw new Error("Stale header must not mount");
      ui.setWidget("discovery", [theme.fg("success", "Fresh session · old discovery ignored"),
        theme.fg("muted", "Generation checked before mounting")]);
    });
  },
};
```

## Known uses: seen in Nico's repos

- [**pi-powerline-footer**](https://github.com/nicobailon/pi-powerline-footer): Deferred welcome header
  - [index.ts:3555-3577](https://github.com/nicobailon/pi-powerline-footer/blob/859dee671b633fb533b07ceba3e6c1ab1c43360a/index.ts#L3555-L3577) @859dee67

## For agents: choose and check

Choose Deferred Crest when your job matches its intent and applicability above. Its neighbours in Lifecycle and mounting are listed below. Read the one whose intent fits your job more closely before you commit.

- [Elastic Overlay](https://pi-tui.ratstack.sh/patterns/elastic-overlay.md): Resolve overlay size and placement from current terminal dimensions.
- [Event Relay](https://pi-tui.ratstack.sh/patterns/event-relay.md): Update visible UI from named extension event channels.
- [Process Shell](https://pi-tui.ratstack.sh/patterns/process-shell.md): Bind a temporary terminal process view to one custom interaction.
- [Output Vault](https://pi-tui.ratstack.sh/patterns/output-vault.md): Keep completed job output available after its foreground view closes.
- [Session Memento](https://pi-tui.ratstack.sh/patterns/session-memento.md): Reconstruct deliberate view state from typed custom session entries.
- [Mode Fence](https://pi-tui.ratstack.sh/patterns/mode-fence.md): Keep terminal components separate from dialog-capable and no-UI modes.
- [Snapshot Lens](https://pi-tui.ratstack.sh/patterns/snapshot-lens.md): Derive compact status and bounded detail from lifecycle snapshots.

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 [`ctx.ui.setHeader`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user), [`pi.on`](https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#events), `setHeader`, `Text` before you use them.
- Every reference frame gets the verdict its state expects.

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

- [Mode Fence](https://pi-tui.ratstack.sh/patterns/mode-fence.md): guards the available mount surface

## Linked from

No other pattern links here.
