{
  "$schema": "https://pi-tui.ratstack.sh/schema/pattern.schema.json",
  "aka": [
    "Status-widget pair"
  ],
  "animated": false,
  "apis": [
    {
      "name": "ctx.ui.setStatus",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user"
    },
    {
      "name": "ctx.ui.setWidget",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user"
    },
    {
      "name": "Text",
      "url": null
    }
  ],
  "applicability": [
    "Use this when progress needs both a short signal and a task display."
  ],
  "category": "status",
  "categoryLabel": "Status and widgets",
  "consequences": [
    "A compact signal can coexist with structured detail.",
    "Two owned keys require paired cleanup."
  ],
  "family": "structural",
  "familyLabel": "Structural",
  "id": "signal-pair",
  "implementation": [
    "Clear both owned keys when the operation ends.",
    "Guard terminal widget factories with TUI mode."
  ],
  "intent": "Pair a compact footer signal with a structured near-editor widget.",
  "jsonUrl": "https://pi-tui.ratstack.sh/patterns/signal-pair.json",
  "kind": "screen",
  "knownUses": [
    {
      "example": "status-widget-pair",
      "moreRefs": 0,
      "refs": [
        {
          "file": "extensions/plan-mode.ts",
          "lines": "575-590",
          "sha": "17cce138",
          "url": "https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/plan-mode.ts#L575-L590"
        },
        {
          "file": "extensions/pi-codex-goal/src/goal-runtime-status.ts",
          "lines": "42-63",
          "sha": "17cce138",
          "url": "https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/pi-codex-goal/src/goal-runtime-status.ts#L42-L63"
        },
        {
          "file": "extensions/plan-mode.ts",
          "lines": "1-18",
          "sha": "17cce138",
          "url": "https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/plan-mode.ts#L1-L18"
        }
      ],
      "repo": "dot314",
      "repoUrl": "https://github.com/nicobailon/dot314",
      "title": "Separate compact status from structured detail"
    },
    {
      "example": "status-widget-pair",
      "moreRefs": 0,
      "refs": [
        {
          "file": "runtime/session-state.ts",
          "lines": "49-78",
          "sha": "a0e4700b",
          "url": "https://github.com/nicobailon/pi-custom-compaction/blob/a0e4700badb1c5c1c2dd12eeb250ff067fa67b7e/runtime/session-state.ts#L49-L78"
        },
        {
          "file": "runtime/session-state.ts",
          "lines": "105-183",
          "sha": "a0e4700b",
          "url": "https://github.com/nicobailon/pi-custom-compaction/blob/a0e4700badb1c5c1c2dd12eeb250ff067fa67b7e/runtime/session-state.ts#L105-L183"
        }
      ],
      "repo": "pi-custom-compaction",
      "repoUrl": "https://github.com/nicobailon/pi-custom-compaction",
      "title": "Separate compact status from structured detail"
    },
    {
      "example": "status-widget-pair",
      "moreRefs": 0,
      "refs": [
        {
          "file": "ralph-wiggum/index.ts",
          "lines": "190-215",
          "sha": "bca5070b",
          "url": "https://github.com/nicobailon/pi-extensions/blob/bca5070b541ffa7d273e74036dcd7d5f8b63eed3/ralph-wiggum/index.ts#L190-L215"
        }
      ],
      "repo": "pi-extensions",
      "repoUrl": "https://github.com/nicobailon/pi-extensions",
      "title": "Separate compact status from structured detail"
    },
    {
      "example": "status-widget-pair",
      "moreRefs": 0,
      "refs": [
        {
          "file": "index.ts",
          "lines": "72-82",
          "sha": "92b4c9c3",
          "url": "https://github.com/nicobailon/pi-memory-workbench/blob/92b4c9c3ad07841418d77118bf8bd02ad204f7c4/index.ts#L72-L82"
        }
      ],
      "repo": "pi-memory-workbench",
      "repoUrl": "https://github.com/nicobailon/pi-memory-workbench",
      "title": "Separate compact status from structured detail"
    },
    {
      "example": "status-widget-pair",
      "moreRefs": 0,
      "refs": [
        {
          "file": "index.ts",
          "lines": "295-305",
          "sha": "09937ed6",
          "url": "https://github.com/nicobailon/pi-messenger/blob/09937ed647a1b07a3b595bf75943feacb80ff123/index.ts#L295-L305"
        }
      ],
      "repo": "pi-messenger",
      "repoUrl": "https://github.com/nicobailon/pi-messenger",
      "title": "Separate compact status from structured detail"
    }
  ],
  "linkedFrom": [
    {
      "how": "pairs compact and detailed signals",
      "id": "result-relay",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/result-relay.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/result-relay.md",
      "name": "Result Relay",
      "url": "https://pi-tui.ratstack.sh/patterns/result-relay/"
    },
    {
      "how": "provides the two display surfaces",
      "id": "snapshot-lens",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/snapshot-lens.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/snapshot-lens.md",
      "name": "Snapshot Lens",
      "url": "https://pi-tui.ratstack.sh/patterns/snapshot-lens/"
    }
  ],
  "links": {
    "agentGuide": "https://pi-tui.ratstack.sh/llms.txt",
    "index": "https://pi-tui.ratstack.sh/patterns.md",
    "skill": "https://pi-tui.ratstack.sh/skills/build-pi-tui-component.md"
  },
  "mdUrl": "https://pi-tui.ratstack.sh/patterns/signal-pair.md",
  "motivation": "Memory Workbench and other extensions need a short status plus a larger task display.",
  "name": "Signal Pair",
  "participants": [
    {
      "name": "ctx.ui.setStatus",
      "role": "Writes or clears one named footer slot.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user"
    },
    {
      "name": "ctx.ui.setWidget",
      "role": "Mounts, replaces or clears one near-editor widget.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#interact-with-the-user"
    },
    {
      "name": "Paired keys",
      "role": "Identify the compact signal and its structured detail.",
      "url": null
    }
  ],
  "pi": "1.0.3",
  "related": [
    {
      "how": "provides the detail surface",
      "id": "widget-dock",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/widget-dock.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/widget-dock.md",
      "name": "Widget Dock",
      "url": "https://pi-tui.ratstack.sh/patterns/widget-dock/"
    }
  ],
  "sampleCode": {
    "code": "// Signal Pair: publish compact progress and structured detail, then clear both owned keys.\nimport { Text } from \"@earendil-works/pi-tui\";\nimport type { PatternStory } from \"../../../src/pattern.ts\";\n\nexport const story: PatternStory = {\n  id: \"signal-pair\", title: \"Signal Pair\", kind: \"screen\",\n  apis: [\"ctx.ui.setStatus\", \"ctx.ui.setWidget\", \"Text\"],\n  states: [\n    { id: \"active\", label: \"Signal and detail\" },\n    { id: \"finished\", label: \"Paired cleanup\", steps: [{ type: \"action\", name: \"finish\" }] },\n  ],\n  setup({ ui, theme, action }) {\n    const statusKey = \"preview\";\n    const widgetKey = \"preview-tasks\";\n    const showProgress = () => {\n      ui.setStatus(statusKey, theme.fg(\"warning\", \"2/3\"));\n      ui.setWidget(widgetKey, (_tui, widgetTheme) => new Text([\n        widgetTheme.fg(\"accent\", \"Task preview · 2/3\"),\n        widgetTheme.fg(\"success\", \"✓ Measure display columns\"),\n        widgetTheme.fg(\"success\", \"✓ Render dark frame\"),\n        widgetTheme.fg(\"warning\", \"> Render light frame\"),\n      ].join(\"\\n\"), 0, 0));\n    };\n    const clearProgress = () => {\n      ui.setStatus(statusKey, undefined);\n      ui.setWidget(widgetKey, undefined);\n    };\n\n    ui.setEditorText(\"Review the completed preview\");\n    showProgress();\n    action(\"finish\", () => {\n      clearProgress();\n      ui.notify(\"Preview ready · all 3 tasks complete\");\n    });\n    return clearProgress;\n  },\n};\n",
    "lang": "ts",
    "path": "stories/patterns/structural/signal-pair.ts"
  },
  "states": [
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Signal Pair, Signal and detail state, 40 columns, dark theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-40-dark.9e4b62c2f9fc.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Signal Pair, Signal and detail state, 40 columns, light theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-40-light.35ab3ebcdc36.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Signal Pair, Signal and detail state, 60 columns, dark theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-60-dark.235d6eb2290f.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Signal Pair, Signal and detail state, 60 columns, light theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-60-light.0aa55c3466f3.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Signal Pair, Signal and detail state, 80 columns, dark theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-80-dark.0bd9f41f291a.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Signal Pair, Signal and detail state, 80 columns, light theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-80-light.7e1d64bcd73c.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Signal Pair, Signal and detail state, 120 columns, dark theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-120-dark.e616c1b4f409.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Signal Pair, Signal and detail state, 120 columns, light theme, 13 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 572,
          "rows": 13,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/active-120-light.d43b72eebe40.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Show a short running status and a small task widget.",
      "id": "active",
      "label": "Signal and detail",
      "problems": []
    },
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Signal Pair, Paired cleanup state, 40 columns, dark theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-40-dark.3e2c10b04190.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 40 columns, light theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-40-light.cf5a7d62e15b.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 60 columns, dark theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-60-dark.c08c0b2366da.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 60 columns, light theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-60-light.769ece0eea99.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 80 columns, dark theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-80-dark.9ab1e2bbc7c6.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 80 columns, light theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-80-light.94c46febc1e4.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 120 columns, dark theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-120-dark.c3d80129b1b7.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Signal Pair, Paired cleanup state, 120 columns, light theme, 10 rows",
          "animated": false,
          "animation": null,
          "checks": [
            {
              "evidence": [],
              "name": "width",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "style-leak",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "hard-coded-colour",
              "status": "pass",
              "verdict": "pass"
            },
            {
              "evidence": [],
              "name": "height",
              "status": "pass",
              "verdict": "pass"
            }
          ],
          "h": 440,
          "rows": 10,
          "still": "https://pi-tui.ratstack.sh/frames/signal-pair/finished-120-light.0a0661633e58.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Clear both surfaces when the synthetic task ends.",
      "id": "finished",
      "label": "Paired cleanup",
      "problems": []
    }
  ],
  "structure": "operation -> status key\noperation -> widget key\nend -> clear both",
  "thumbnails": {
    "dark": {
      "animation": null,
      "src": "https://pi-tui.ratstack.sh/thumbs/signal-pair/dark.7e127b2f9265.webp"
    },
    "light": {
      "animation": null,
      "src": "https://pi-tui.ratstack.sh/thumbs/signal-pair/light.38f19aebbb1a.webp"
    }
  },
  "url": "https://pi-tui.ratstack.sh/patterns/signal-pair/",
  "widths": [
    40,
    60,
    80,
    120
  ]
}
