Roscoe ships with a React + Vite web app that covers the graph editor, live run animation, run history, and settings. Reach for it when you want to draft a workflow, eyeball a run as it executes, or skim recent history without dropping into the terminal.
In dev mode (bun run dev) the UI runs on http://localhost:3000 and talks to
the API on :8080. The compiled roscoe serve binary serves both on a single
port (default http://localhost:7777). See
Environment variables for port overrides.
The sidebar switches projects. The active project decides which project store the library reads, and run history filters to it by default, so switching changes what those pages show. See Global vs Project.
Workflows (/workflows)#
The library. Lists every workflow visible to Roscoe, split into Project
(<repo>/.roscoe/workflows/) and Global (~/.roscoe/workflows/) sections.
Search by name or filter by source. The New Workflow action scaffolds a new
YAML file.
Roscoe dims and badges any global workflow row a same-id project copy shadows, so you know which file actually runs. Delete lives in the workflow detail page's kebab menu. There is no rename in the web UI.
If the install is empty the page shows an onboarding card with a Create starter workflows button, which seeds the example workflows.
Workflow editor (/workflows/$id/edit)#
The authoring surface. The graph canvas is a React Flow view with one node per state: click a node to open its config panel, and add nodes from the canvas add menu. You author edges as transitions in that panel. The canvas auto-lays out as you edit.
Edits validate against the workflow schema and surface errors inline. Save writes the file on the server, and the watcher pushes the change to other open tabs.
The editor enforces the same schema and integrity rules as roscoe validate,
so a workflow that saves cleanly is one that will start cleanly.
Edit with a prompt hands the workflow to Claude instead of the canvas. Describe the change you want ("add a step", "handle a failure") and it edits the file. Unsaved canvas edits are not included, and the editor says so before it starts.
Undo (⌘Z) and Redo (⌘⇧Z) sit in the toolbar. If the file changes on disk while you have unsaved edits, a notice offers you the new version rather than overwriting either copy silently.
A subworkflow node opens its child read-only in
the same editor, tracked in the URL as ?drill=. The ?from= trail is how
the back link finds its way out again.
Workflow detail (/workflows/$id)#
A read-mostly preview. Renders the graph, surfaces validation errors when the
config fails to parse, and offers the primary Run action. A History
button jumps to the run history list pre-filtered to this workflow. The kebab
menu has Move to Project / Move to Global for promoting a workflow
between sources, plus Delete workflow; the moves round-trip through
POST /api/workflows/:id/move.
Run viewer (/runs/$id)#
The live run page. The header links its workflow title back to the workflow detail page (dimmed and un-clickable only when the source workflow no longer exists) and renders the run id and run metadata as click-to-copy chips. The graph animates as nodes execute: running nodes pulse, completed nodes fill in, and failed nodes go red. During a live run a Follow active node toggle (top-right of the canvas) keeps the camera spotlighted on the currently executing node, auto-panning as the run advances; click it to stop following and pan freely.
The right rail shows a per-node trace with input, output, duration, error (if
any), and child sub-runs (e.g. one row per
consensus agent with its individual verdict and
reasoning). With no node selected, the rail follows the live front
of the run. It opens on the node currently executing, falling back to the
most-recently-finished node once nothing is active, so an in-progress run shows
what's running, not the last completed step. Click any node to pin the rail to
it.
Script (script) output streams live: a running node's
stdout/stderr appear in the rail as they are produced (coalesced
server-side so the poll stays cheap), rather than only landing once the node
finishes. Terminal streams
(stdout, stderr, error) render in a monospace block with ANSI colors
preserved: the SGR (Select Graphic Rendition) escapes that test runners and
build CLIs emit (vitest's green checks, red failures, dim notes) show as themed
color instead of dropping to plain text or leaking as literal [0m noise. Long
lines and box-drawing rules wrap rather than overflow.
When the run pauses at a human node, an
Awaiting input panel above the canvas surfaces transition buttons; click one to
call POST /api/runs/:id/resume. Consensus nodes get a dedicated panel showing
each agent's vote, the quorum threshold, and the final outcome.
While a run is running or paused, a Cancel run button (with a
confirmation modal) stops it. Cancelling marks the node the run was sitting on
as cancelled, and Roscoe kills the running script worker or claude CLI/SDK
call rather than leaving it to finish in the background. A cancelled node is
rendered neutral gray, distinct from the red of a failed node, since a
deliberate stop is not an error. You can cancel any run, including runs driven
over MCP (Model Context Protocol).
Runs started via MCP show an MCP badge; Claude Code controls those
transitions and no approval panel renders. When such a run is paused on an AI
handback node (ai_agent /
ai_judge / consensus /
round_robin, i.e. the
calling agent is actively generating a response), the status reads
Processing in blue with a pulsing dot, rather than the amber Paused
used for a human wait. A genuine human node still shows amber Paused,
because that one really is blocked on a person. The run page, the run history
list, and the Workflows "last run" column all read the same run field
(pauseKind: 'agent' vs 'human'), so the same run reads consistently
everywhere.
On a finished run the header also has a Record button (or Edit
recording once you have directed it). It opens the recording editor at
/runs/$id/record, where the run plays back fast on the real canvas and you
choose which steps the camera stops on before exporting a 1080p MP4. See
Record a run.
A run carries its own cost and token totals, split between metered API spend
and the subscription-equivalent of work that ran on your Claude plan. A run
you capped that hit the cap stops as cancelled with a banner naming the cap
it hit. A run can carry both a dollar and a token cap and stops at whichever
comes first.
Run history (/runs)#
Every run, with branch and workflow filters and a Clear all runs action. Use this to clear test debris or audit recent activity.
The page is workspace-scoped. A scope selector toggles between this workspace (the default), which shows only runs for the workspace the nav project switcher currently has active, and all workspaces, which shows every run across Global and all projects with a per-row tag (a globe for Global, a folder + project name otherwise) so mixed rows stay distinguishable. The active workspace can be a project or Global, where cwd-less runs from the Claude desktop app land (see Global vs Project).
When the active project has no runs, the empty state points you to where your
runs actually live: a View Global runs shortcut for desktop-app runs that
landed in Global rather than the project you're sitting in. Opening a run
(/runs/$id) carries the run's scope in the URL, and the ?project=… links
the MCP returns auto-select the matching workspace.
Those MCP links point at /open/runs/$id, which hands the run to the desktop
app when it is installed and falls back to this browser UI when it is not —
see Run links open in the app.
Settings (/settings)#
Edit roscoe.yaml (the active merged config, global plus project overrides)
directly in the browser. Adjust the model list and default model, pick the AI
backend, set the CLI path, override ports, and tweak retry/timeout, analytics,
and preference defaults. Changes hit disk immediately and the file watcher
fires server-sent events (SSE) so other open tabs reload without a refresh. See
roscoe.yaml for the schema and worked
example.
The Updates card at the bottom shows the running version next to the latest
release on the channel: a blue "Update available" badge appears
when a newer build exists, flipping to a filled "Update ready" once the
background pre-download finishes. Click Download & install to swap the
binary, then stop the server (Ctrl-C or q) and run roscoe serve again. The
sidebar chip mirrors this state machine in a single icon so you can tell at a
glance from any page.
Sidebar version chip#
The icon at the bottom of the left sidebar reflects the update state for the running binary:
- Neutral check → the current version matches the latest manifest.
- Blue up-arrow with a static dot → a newer release exists and Roscoe is pre-downloading it in the background.
- Blue up-arrow with a pulsing dot → the new binary is on disk; one click takes you to Settings to apply.
- Teal reload icon with a teal dot → the new binary is installed; restart to run it.
Docs (/docs)#
These docs, served in-app. Useful when you're already in the UI and don't want to context-switch to a browser tab.
When the app cannot start normally#
A fresh install opens an onboarding flow instead of the library: it checks the prerequisites, offers to seed the example workflows, and hands you to the Workflows page when it is done.
If the database cannot be opened, the app drops into a recovery screen rather than failing page by page. The server reports the problem honestly instead of serving errors from a server still claiming to be healthy. See Database recovery.
Default URLs#
Dev (bun run dev) serves the UI at http://localhost:3000; roscoe serve
serves it at http://localhost:7777. Override either with ROSCOE_WEB_PORT
(dev) or --port / ROSCOE_PORT (serve).
See also#
- Command-line interface — drive the same operations from the terminal.
- Claude integration — drive them from Claude Code.
- roscoe.yaml — what the Settings page is editing.
- REST API reference — the HTTP API the web UI is built on.