Skip to main content
Workflow UIs are now declared by the workflow itself with <UI>. The UI still runs in the browser, talks to the Gateway through gateway-react, and can keep the same .smithers/ui/<workflow>.tsx file: only ownership changes. The workflow TSX names the UI entry, so any Gateway that registers the workflow serves the right UI without out-of-band launcher code.

Before

Older launchers mounted UI from the Gateway side:
.smithers/gateway.ts
The old pack convention auto-mounted a matching .smithers/ui/release.tsx file; an explicit workflow declaration replaces it.

After

Add <UI> inside the workflow’s root <Workflow>:
.smithers/workflows/release.tsx
Then register the workflow without a ui option:
.smithers/gateway.ts
entry paths resolve relative to the workflow file when entryFile is provided; existing self-mounting UI files ending in createGatewayReactRoot(<App />) can stay as-is.

Entry vs Source

Use entry for existing Gateway UI files:
Use source for a browser-safe module that exports a React component; the Gateway mounts it with React and passes props plus boot metadata:
Don’t point source at the workflow module itself: it often imports Node/Bun APIs, agents, prompts, and database setup that can’t run in the browser.

Checklist

  1. Add UI to the workflow’s smthrs import.
  2. Add <UI entry="../ui/<workflow>.tsx" title="..." /> as a direct child of the root <Workflow>.
  3. Remove ui: { entry, title } from gateway.register; keep entryFile.
  4. Leave the browser UI file in .smithers/ui/<workflow>.tsx unless converting it to the source component-export shape.
  5. Verify with bunx smthrs gateway and open /workflows/<workflow> or run bunx smthrs ui RUN_ID.
The Gateway discovers <UI> during register(); the component renders nothing into the workflow graph and never executes client code on the backend.