{
  "$schema": "https://pi-tui.ratstack.sh/schema/pattern.schema.json",
  "aka": [
    "Event-driven view"
  ],
  "animated": false,
  "apis": [
    {
      "name": "pi.events",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#choose-an-integration-point"
    },
    {
      "name": "EventBus",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#choose-an-integration-point"
    },
    {
      "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": "TUI.requestRender",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#understand-the-component-model"
    },
    {
      "name": "createEventBus",
      "url": null
    },
    {
      "name": "EventBus.on",
      "url": null
    },
    {
      "name": "EventBus.emit",
      "url": null
    },
    {
      "name": "setStatus",
      "url": null
    },
    {
      "name": "setWidget",
      "url": null
    }
  ],
  "applicability": [
    "Use this when tools and hooks coordinate without direct module imports."
  ],
  "category": "lifecycle",
  "categoryLabel": "Lifecycle and mounting",
  "consequences": [
    "A visible view can react without directly importing the publisher.",
    "Unknown payloads need validation and listeners need cleanup."
  ],
  "family": "behavioral",
  "familyLabel": "Behavioral",
  "id": "event-relay",
  "implementation": [
    "Validate unknown event payloads.",
    "Unsubscribe when the owning view ends."
  ],
  "intent": "Update visible UI from named extension event channels.",
  "jsonUrl": "https://pi-tui.ratstack.sh/patterns/event-relay.json",
  "kind": "screen",
  "knownUses": [
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [
        {
          "file": "packages/coding-agent/src/core/event-bus.ts",
          "lines": "1-33",
          "sha": "9c9e6822",
          "url": "https://github.com/earendil-works/pi/blob/9c9e6822e3af7e0c17cd4116b8eab01d79eb69a8/packages/coding-agent/src/core/event-bus.ts#L1-L33"
        }
      ],
      "repo": "earendil-works/pi",
      "repoUrl": "https://github.com/earendil-works/pi",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "terminal-progress-interception",
      "moreRefs": 0,
      "refs": [
        {
          "file": "extensions/handover/index.ts",
          "lines": "700-747",
          "sha": "17cce138",
          "url": "https://github.com/nicobailon/dot314/blob/17cce138f3f687211d0485d204408a9650953c61/extensions/handover/index.ts#L700-L747"
        }
      ],
      "repo": "dot314",
      "repoUrl": "https://github.com/nicobailon/dot314",
      "title": "Bound input interception to foreground progress"
    },
    {
      "example": "terminal-progress-interception",
      "moreRefs": 0,
      "refs": [
        {
          "file": "subagent-step.ts",
          "lines": "443-462",
          "sha": "6da20591",
          "url": "https://github.com/nicobailon/pi-prompt-template-model/blob/6da205917e549cbe8e855c1d241c616ae1fb1627/subagent-step.ts#L443-L462"
        },
        {
          "file": "subagent-step.ts",
          "lines": "533-558",
          "sha": "6da20591",
          "url": "https://github.com/nicobailon/pi-prompt-template-model/blob/6da205917e549cbe8e855c1d241c616ae1fb1627/subagent-step.ts#L533-L558"
        },
        {
          "file": "subagent-step.ts",
          "lines": "748-762",
          "sha": "6da20591",
          "url": "https://github.com/nicobailon/pi-prompt-template-model/blob/6da205917e549cbe8e855c1d241c616ae1fb1627/subagent-step.ts#L748-L762"
        }
      ],
      "repo": "pi-prompt-template-model",
      "repoUrl": "https://github.com/nicobailon/pi-prompt-template-model",
      "title": "Bound input interception to foreground progress"
    },
    {
      "example": "terminal-progress-interception",
      "moreRefs": 0,
      "refs": [
        {
          "file": "index.ts",
          "lines": "63-75",
          "sha": "0194b7a3",
          "url": "https://github.com/nicobailon/pi-prune/blob/0194b7a3eb87db71648fef672effbfb65411a82a/index.ts#L63-L75"
        },
        {
          "file": "index.ts",
          "lines": "131-132",
          "sha": "0194b7a3",
          "url": "https://github.com/nicobailon/pi-prune/blob/0194b7a3eb87db71648fef672effbfb65411a82a/index.ts#L131-L132"
        }
      ],
      "repo": "pi-prune",
      "repoUrl": "https://github.com/nicobailon/pi-prune",
      "title": "Bound input interception to foreground progress"
    },
    {
      "example": "terminal-progress-interception",
      "moreRefs": 0,
      "refs": [
        {
          "file": "src/slash/slash-commands.ts",
          "lines": "350-440",
          "sha": "6826b054",
          "url": "https://github.com/nicobailon/pi-subagents/blob/6826b0545216077195ae8ffe468a6434715814b7/src/slash/slash-commands.ts#L350-L440"
        },
        {
          "file": "src/slash/slash-commands.ts",
          "lines": "770-835",
          "sha": "6826b054",
          "url": "https://github.com/nicobailon/pi-subagents/blob/6826b0545216077195ae8ffe468a6434715814b7/src/slash/slash-commands.ts#L770-L835"
        }
      ],
      "repo": "pi-subagents",
      "repoUrl": "https://github.com/nicobailon/pi-subagents",
      "title": "Bound input interception to foreground progress"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "dot314",
      "repoUrl": "https://github.com/nicobailon/dot314",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-coordination",
      "repoUrl": "https://github.com/nicobailon/pi-coordination",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-interactive-shell",
      "repoUrl": "https://github.com/nicobailon/pi-interactive-shell",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-intercom",
      "repoUrl": "https://github.com/nicobailon/pi-intercom",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-mcp-adapter",
      "repoUrl": "https://github.com/nicobailon/pi-mcp-adapter",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-prompt-template-model",
      "repoUrl": "https://github.com/nicobailon/pi-prompt-template-model",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-rewind-hook",
      "repoUrl": "https://github.com/nicobailon/pi-rewind-hook",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-subagent-enhanced",
      "repoUrl": "https://github.com/nicobailon/pi-subagent-enhanced",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "pi-subagents",
      "repoUrl": "https://github.com/nicobailon/pi-subagents",
      "title": "Add an event bus for tools and hooks"
    },
    {
      "example": "nico-extension-event-bus",
      "moreRefs": 0,
      "refs": [],
      "repo": "surf-cli",
      "repoUrl": "https://github.com/nicobailon/surf-cli",
      "title": "Add an event bus for tools and hooks"
    }
  ],
  "linkedFrom": [],
  "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/event-relay.md",
  "motivation": "Nico's extension bus coordinates tools and hooks through named channels used by progress UI.",
  "name": "Event Relay",
  "participants": [
    {
      "name": "pi.events",
      "role": "Exposes the shared extension event bus.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#choose-an-integration-point"
    },
    {
      "name": "EventBus",
      "role": "Publishes unknown payloads on named channels.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/extensions.md#choose-an-integration-point"
    },
    {
      "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": "TUI.requestRender",
      "role": "Requests a coalesced redraw after state changes.",
      "url": "https://github.com/earendil-works/pi/blob/v1.0.3/packages/coding-agent/docs/tui.md#understand-the-component-model"
    },
    {
      "name": "Payload validator",
      "role": "Checks unknown channel data before changing visible state.",
      "url": null
    }
  ],
  "pi": "1.0.3",
  "related": [
    {
      "how": "owns subscriptions and redraws",
      "id": "refresh-lease",
      "jsonUrl": "https://pi-tui.ratstack.sh/patterns/refresh-lease.json",
      "mdUrl": "https://pi-tui.ratstack.sh/patterns/refresh-lease.md",
      "name": "Refresh Lease",
      "url": "https://pi-tui.ratstack.sh/patterns/refresh-lease/"
    }
  ],
  "sampleCode": {
    "code": "// Event Relay: validate named-channel payloads before updating a keyed view.\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { createEventBus } from \"@earendil-works/pi-coding-agent\";\nimport type { PatternStory } from \"../../../src/pattern.ts\";\n\ntype Progress = { task: string; completed: number; total: number };\nfunction isProgress(value: unknown): value is Progress {\n  return typeof value === \"object\" && value !== null &&\n    \"task\" in value && typeof value.task === \"string\" &&\n    \"completed\" in value && typeof value.completed === \"number\" && Number.isInteger(value.completed) &&\n    \"total\" in value && typeof value.total === \"number\" && Number.isInteger(value.total) &&\n    value.total > 0 && value.completed >= 0 && value.completed <= value.total;\n}\n\nexport const story: PatternStory = {\n  id: \"event-relay\",\n  title: \"Event Relay\",\n  kind: \"screen\",\n  apis: [\"createEventBus\", \"EventBus.on\", \"EventBus.emit\", \"setStatus\", \"setWidget\", \"TUI.requestRender\"],\n  states: [\n    { id: \"subscribed\", label: \"Waiting view\" },\n    { id: \"event\", label: \"Event applied\", steps: [\n      { type: \"action\", name: \"invalid-event\" }, { type: \"action\", name: \"progress-event\" },\n    ] },\n    { id: \"unsubscribed\", label: \"Owner gone\", steps: [\n      { type: \"action\", name: \"unsubscribe\" }, { type: \"action\", name: \"late-event\" },\n    ] },\n  ],\n  setup({ ui, theme, tui, action }) {\n    const events = createEventBus(); // Same exported bus used by pi.events; isolated fixture.\n    const channel = \"task:progress\";\n    let applied = 0;\n    let rejected = 0;\n    ui.setHeader(() => new Text(theme.fg(\"accent\", \"Pi · Event Relay\"), 0, 0));\n    ui.setEditorText(\"Review the token boundary tests\");\n    ui.setStatus(\"progress\", theme.fg(\"muted\", \"waiting\"));\n    ui.setWidget(\"relay\", [\n      theme.fg(\"accent\", \"Subscribed → \" + channel),\n      theme.fg(\"muted\", \"Waiting for parser test progress\"),\n    ]);\n    const unsubscribe = events.on(channel, payload => {\n      if (!isProgress(payload)) { rejected++; return; }\n      applied++;\n      ui.setStatus(\"progress\", theme.fg(\"success\", payload.completed + \"/\" + payload.total));\n      ui.setWidget(\"relay\", [\n        theme.fg(\"accent\", channel + \" → validated view\"),\n        theme.fg(\"text\", payload.task + \": \" + payload.completed + \"/\" + payload.total),\n        theme.fg(\"muted\", \"Applied \" + applied + \" · rejected \" + rejected),\n      ]);\n      tui.requestRender();\n    });\n    action(\"invalid-event\", () => events.emit(channel, { completed: \"not a count\" }));\n    action(\"progress-event\", () => events.emit(channel, { task: \"Parser tests\", completed: 3, total: 8 }));\n    action(\"unsubscribe\", () => {\n      unsubscribe();\n      ui.setStatus(\"progress\", undefined);\n      ui.setWidget(\"relay\", [\n        theme.fg(\"muted\", \"Progress view removed · unsubscribed\"),\n        theme.fg(\"dim\", \"Later events cannot recreate its slot\"),\n      ]);\n    });\n    action(\"late-event\", () => {\n      events.emit(channel, { task: \"Parser tests\", completed: 8, total: 8 });\n      ui.setWidget(\"publisher\", [\n        theme.fg(\"text\", \"Publisher sent another progress event\"),\n        theme.fg(\"dim\", \"Applied remains \" + applied + \" · footer slot absent\"),\n      ], { placement: \"belowEditor\" });\n    });\n    return () => { unsubscribe(); events.clear(); ui.setStatus(\"progress\", undefined); };\n  },\n};\n",
    "lang": "ts",
    "path": "stories/patterns/behavioral/event-relay.ts"
  },
  "states": [
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Event Relay, Waiting view state, 40 columns, dark theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-40-dark.da9223178d29.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Event Relay, Waiting view state, 40 columns, light theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-40-light.ba04dae87aba.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Event Relay, Waiting view state, 60 columns, dark theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-60-dark.7933cb047207.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Event Relay, Waiting view state, 60 columns, light theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-60-light.5bbdbb792942.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Event Relay, Waiting view state, 80 columns, dark theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-80-dark.6ffdb5b21f37.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Event Relay, Waiting view state, 80 columns, light theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-80-light.baf2d4f2b3d2.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Event Relay, Waiting view state, 120 columns, dark theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-120-dark.9d130f692f48.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Event Relay, Waiting view state, 120 columns, light theme, 11 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": 484,
          "rows": 11,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/subscribed-120-light.c6fbeb9a9222.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Show a synthetic status awaiting a named event.",
      "id": "subscribed",
      "label": "Waiting view",
      "problems": []
    },
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Event Relay, Event applied state, 40 columns, dark theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-40-dark.2f938ea134c3.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Event Relay, Event applied state, 40 columns, light theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-40-light.adba8644cbed.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Event Relay, Event applied state, 60 columns, dark theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-60-dark.def66719943a.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Event Relay, Event applied state, 60 columns, light theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-60-light.c12584e36edd.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Event Relay, Event applied state, 80 columns, dark theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-80-dark.8511c4512090.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Event Relay, Event applied state, 80 columns, light theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-80-light.1403fe943004.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Event Relay, Event applied state, 120 columns, dark theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-120-dark.bc95ceab6ee3.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Event Relay, Event applied state, 120 columns, light theme, 12 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": 528,
          "rows": 12,
          "still": "https://pi-tui.ratstack.sh/frames/event-relay/event-120-light.64774c03bb88.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Publish a validated payload and update the status.",
      "id": "event",
      "label": "Event applied",
      "problems": []
    },
    {
      "dont": false,
      "expectFail": [],
      "frames": [
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-40-dark.a6d15e9bb6c5.webp",
          "theme": "dark",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-40-light.75fe18457a67.webp",
          "theme": "light",
          "w": 800,
          "width": 40
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-60-dark.7ef957d634f2.webp",
          "theme": "dark",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-60-light.0dd749dee0d7.webp",
          "theme": "light",
          "w": 1200,
          "width": 60
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-80-dark.504acca08cfc.webp",
          "theme": "dark",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-80-light.d3f5943071d1.webp",
          "theme": "light",
          "w": 1600,
          "width": 80
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-120-dark.131622c0b830.webp",
          "theme": "dark",
          "w": 2400,
          "width": 120
        },
        {
          "alt": "Event Relay, Owner gone 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/event-relay/unsubscribed-120-light.46a6caf39057.webp",
          "theme": "light",
          "w": 2400,
          "width": 120
        }
      ],
      "how": "Show that a later event no longer updates the cleared slot.",
      "id": "unsubscribed",
      "label": "Owner gone",
      "problems": []
    }
  ],
  "structure": "publisher -> named channel\nchannel -> validate -> visible state",
  "thumbnails": {
    "dark": {
      "animation": null,
      "src": "https://pi-tui.ratstack.sh/thumbs/event-relay/dark.6eac2ae07a5b.webp"
    },
    "light": {
      "animation": null,
      "src": "https://pi-tui.ratstack.sh/thumbs/event-relay/light.7f8e61c7e769.webp"
    }
  },
  "url": "https://pi-tui.ratstack.sh/patterns/event-relay/",
  "widths": [
    40,
    60,
    80,
    120
  ]
}
