@smithers-orchestrator/gateway-ui is a set of drop-in React components for
building a custom workflow UI. They are built on the
gateway-react hooks, so each one connects to the
Gateway by itself: give it a runId or a filter and it renders live data and
wires the actions. Reach for these instead of hand-wiring hooks when you want a
run dashboard fast.
Import them from the smithers-orchestrator/gateway-ui subpath, alongside
createGatewayReactRoot from gateway-react. Every component is styled with
inline styles (no CSS import), so it bundles cleanly through the Gateway’s
bundler, and every component accepts className and style to override.
The inline styles are theme-following: every color is a
var(--token, #lightFallback) expression over the
workflow UI style-guide tokens, which the
Gateway’s HTML shell injects into every /workflows/<key> page. Components
therefore render light or dark with the rest of the page, following the OS
prefers-color-scheme or an explicit data-theme="dark|light" on <html>
(which the shell sets from a ?theme= query param). Outside a themed page the
fallbacks reproduce the light look. Tints derive via color-mix over the same
tokens, never hex-plus-alpha.
Components
StatusPill, statusColor, statusColors, and the theme style tokens are
also exported for building your own rows that match the components, plus the
node-status helpers nodeStatusIndex(nodes) (logical-id → merged status map
over useGatewayRunTree rows) and rollupNodeStatus(index, nodeIds) (one
pipeline’s aggregate status) so UIs never hand-roll status rank maps, and the
pure buildNodeChatTranscript(frames, nodeId) fold behind NodeChatStream.
Live-feedback rule: every agent node a UI surfaces should get a
NodeChatStream so humans can watch the agent work in real time; the
create-ui workflow’s deterministic compliance gate
(gradeWorkflowUiSource from smithers-orchestrator/scorers) rejects
generated UIs that hand-roll pills/tables/colors or omit live agent chat.
The gate also requires the author’s verified result and independently checks
that both /workflows/<key> and /workflows/<key>/__smithers_ui/client.js
return HTTP 200. It retries authoring for at most three rounds and fails with
RALPH_MAX_REACHED when violations persist.
For a workflow whose UI just needs launch-watch-approve, render
<SimpleWorkflowDashboard workflow="my-workflow" /> inside
createGatewayReactRoot and you are done. For everything you compose around
these run widgets (buttons, cards, inputs, dialogs, tabs, empty states, chat
surfaces), reach for the shared
smithers-orchestrator/ui component library instead of
hand-writing markup and CSS.
A complete UI
This is a full.smithers/ui/<workflow>.tsx bundle: a run picker, the node tree,
a live event log, a node-output pane, and the approval queue, wired together with
local state. Save it next to a workflow, declare it from that workflow with
<UI entry="../ui/<workflow>.tsx" />, and open it with
bunx smithers-orchestrator ui RUN_ID (or bunx smithers-orchestrator ui --workflow <workflow>).
To open the full local control surface instead of a single workflow UI, see
bunx smithers-orchestrator ui --app below.
RunList polls for new runs, RunTree and RunEventLog
stream live as the run advances, ApprovalPanel lets you clear human gates, and
LaunchButton starts a fresh run. Mix these with raw
gateway-react hooks whenever you need something the
components do not cover.
The full local Smithers UI
bunx smithers-orchestrator ui --app serves the full local control surface (apps/smithers)
instead of a single workflow’s UI. It builds the app bundle on first use, serves
it same-origin with a local Gateway (reverse-proxying the Gateway’s RPC,
WebSocket, and health paths), and opens it in your browser as a dashboard for
your runs, approvals, workspace files, and VCS state.
Prerequisites
The app ships a local “concierge” chat that answers questions and backgrounds workflows for you, so--app fails fast unless both of these hold:
- A chat credential. Set exactly one of
CEREBRAS_API_KEY(recommended, fastest),OPENAI_API_KEY,CODEX_ACCESS_TOKEN, orCODEX_REFRESH_TOKEN. With none set, the command exits before it binds a port and prints which variable to set. bunon yourPATH. The concierge runs on Bun, so the command checks for it up front and exits with an install hint if it is missing.
The concierge
The concierge is a small local chat backend the app talks to at/api/chat. Its
system prompt is seeded with the live catalog of workflows registered on your
Gateway, so it can background any of them for you, including create-workflow,
the meta-workflow that authors a brand-new workflow. It streams answers back
token by token, binds to loopback only, and needs no cloud account.
Local workspace endpoints
Alongside the Gateway proxy, the--app server exposes a few loopback-only
endpoints the app uses to read and edit your working tree:
GET /api/files/tree,GET /api/files/read, andPOST /api/files/writefor the file browser and editor./__smithers/vcsfor the local VCS (jj/git) status the app renders./__smithers/local-workspaceand/__smithers/local-workspace/readinessfor workspace detection and readiness against the proxied Gateway.
127.0.0.1 only and are scoped to the directory you launch from.
Flags
Without
--app, bunx smithers-orchestrator ui [runId] opens a single workflow run’s custom UI
(the component gallery above) against the Gateway rather than the full surface.
When to drop to hooks
The components own the common shapes. When you need a bespoke layout, an embedded editor, or a custom card, read the same hooks the components use (useGatewayRuns, useGatewayRunTree, useGatewayRunEvents,
useGatewayApprovals, useGatewayActions) directly. See
Custom Workflow UIs for the full hook walkthrough
and Workflow UI (React) for a hand-wired example.