Skip to main content
@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.
That is the whole UI. 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, or CODEX_REFRESH_TOKEN. With none set, the command exits before it binds a port and prints which variable to set.
  • bun on your PATH. 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, and POST /api/files/write for the file browser and editor.
  • /__smithers/vcs for the local VCS (jj/git) status the app renders.
  • /__smithers/local-workspace and /__smithers/local-workspace/readiness for workspace detection and readiness against the proxied Gateway.
These bind to 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.