A local, no-code builder and observability dashboard for Claude Code's Workflow tool — exposed to the agent over MCP.
Website: szymonpaluch.com/workflow-studio · Install: uvx workflow-studio (PyPI)
Claude Code's Workflow tool is a deterministic multi-agent orchestration primitive — fan-out subagents, pipelines, adversarial review, loops. Workflow Studio gives you two things it doesn't have on its own: a way to watch what a run actually did (phases, agents, tokens, timing, which branch was taken), and a way to author new workflows visually instead of hand-writing the JS. It then exposes both halves to the Claude Code agent over MCP, so you and the agent work through one live surface instead of a script file dropped on disk that the agent can't see.
Everything runs locally. The dashboard binds 127.0.0.1, reads your local Claude Code data on disk, and makes no network calls — no telemetry.
A real deep-research run — Scope → Search → Fetch → Verify → Synthesize — that fanned out to 111 agents across 5 phases (513 tool calls, 3.7M tokens, ~22 min):
Each node is a phase; the ring shows how many of its agents finished, and each edge shows how one stage's output feeds the next (75 ag → [object ×75]). Every number here is read from the run's own overlay — measured, not guessed.
Flip to the timeline lens for the wall-clock view. Here a shorter landing-interactive-review run (9m 49s): the Review fan-out (blue) runs first, then Verify (pink) staggers in as each agent lands.
The no-code block builder. Add typed blocks from + Agents / + Data / + Control, wire them up, and hit Run — it compiles to a runnable Workflow script (this one: START → agent → fan-out ×10 → fan-out ×10 → agent):
A React dashboard that reads Claude Code's own on-disk run artifacts (~/.claude/projects/**/subagents/workflows/wf_*) and renders each run as a graph/timeline: phases, per-agent nodes, tokens, timing, and which branch was taken. Live runs are included and the view auto-refreshes as a run progresses.
A no-code block builder (canvas) that compiles to a runnable Workflow script. It emits real Workflow primitives — agent(), phase(), parallel(), pipeline(), log() — plus a @wf-builder sidecar comment so designs round-trip losslessly between the canvas and the generated script.
There are 12 block kinds:
| Block | What it is |
|---|---|
agent |
A single agent with a prompt |
fanout |
N agents in parallel |
loop |
One agent improves the result over N rounds (in place) |
subwf |
A nested workflow |
gate |
Agent only when a predecessor field meets a condition (0..1) |
filter |
Filter a list by an element field — no agent |
switch |
Branch on a predecessor enum field value (k-way) — no agent |
pipeline |
Each list element flows through the stages independently (no barrier) |
rank |
Sort a list by a field and keep the top N — no agent |
input |
A fixed list of elements (a source for fan-out/pipeline/ranking) — no agent |
param |
A named value (text/path/number) for @{…} in prompts — no agent |
start |
The entry anchor — no agent. Blocks wired from it are the start; 2+ run in parallel |
The package ships a hand-rolled, dependency-free JSON-RPC 2.0 stdio MCP server (no SDK, so the package stays zero-dependency and uvx-startable with no resolution step). It runs via the workflow-studio mcp subcommand and exposes 9 tools:
| Tool | Kind | What it does |
|---|---|---|
get_context |
read | The scope this server operates under (launch project, path, current session) plus a doctor view (dataDir/tasksRoot/dist). Call first. |
list_projects |
read | Every Claude Code project on the machine with workflow history. |
list_runs |
read | OBSERVED runs in the current project (live first, then newest): name, agent count, status, age. |
get_run |
read | Full OBSERVED graph of one run: phases, agents, logs, tokens, timing. |
list_workflows |
read | Reusable workflows visible in the project (builder designs + workflows observed from runs), with honest source. |
get_workflow |
read | One workflow by name: its runnable script, a decoded contract (when hasSidecar), and the runs sharing its name. |
get_run_design |
read | The DECLARED design a specific run executed: script + source + decoded contract. |
save_workflow |
write | Draft a Workflow script INTO the human's block builder (appears in list_workflows). Returns the path + editable flag; refuses to overwrite an existing name unless overwrite=true. |
promote_run |
write | Promote an existing run into a named, reusable workflow (copies the run's own script). Refuses if the name already exists. |
The project's ethos is not conflating what was observed with what was declared, so the flags live in the tool payloads, not in prose:
- Observed run data (
get_run,list_runs) carries:taskMatched—falsemeans the overlay was garbage-collected and the metrics are heuristic/unknown, not measured.status—liveorincompletemeans the elapsed span is a lower bound, not a final measurement.
- Declared designs (
get_workflow,get_run_design) carry:source—'snapshot'= exactly what ran,'template'= a mutable fallback that may differ from what ran,null= none recorded.hasSidecar+ a decodedcontract(declared inputs + per-agent output schema + block/edge skeleton).hasSidecar=falsemeans the structure is best-effort recovery, not a faithful design.
It hands the agent a design's script; the agent runs that script with its own Workflow tool. There is no path by which this server injects a run into your session.
Without this, the only human↔agent channel is a script file dropped on disk that the agent is blind to. The MCP server turns it into a live two-way surface: the agent discovers what you built in the builder, reads a design's declared contract, runs it with its own Workflow tool, inspects the resulting observations, and drafts designs back into your builder for you to review and refine. One surface, both directions.
Requires uv/uvx on your PATH. The package is published on PyPI as
workflow-studio — nothing to build.
You're probably already in a coding agent. Paste this and let it do the whole install:
Read https://github.com/hculap/workflow-studio/blob/main/AGENT_INSTALL.md and set up Workflow Studio for me — run the steps, verify it, and tell me whether to restart Claude Code.
It points the agent at AGENT_INSTALL.md — a short guide that has it register the marketplace, install the plugin, verify the MCP server is connected, and tell you when to restart. The manual commands below do the same thing by hand.
/plugin marketplace add hculap/workflow-studio
/plugin install workflow-studio@workflow-studio
Then /mcp lists workflow-studio (9 tools) and /workflow-studio:dashboard opens the UI. The plugin
launches the MCP server with uvx workflow-studio==0.2.0 mcp, pulling that exact version from PyPI.
/plugin marketplace add /absolute/path/to/plugin-marketplace
/plugin install workflow-studio@workflow-studio
claude mcp add workflow-studio -s user -- uvx workflow-studio mcp
uvx workflow-studio
By default the dashboard is served at the root (http://127.0.0.1:8787/). To mount it under a
subpath — e.g. when location / on your domain is already taken — set a base path. It's a runtime
setting (the PyPI build stays mount-agnostic), so nothing is hard-coded:
WORKFLOW_STUDIO_BASE_PATH=/workflow-studio workflow-studio --no-open
# or: workflow-studio --no-open --base-path /workflow-studio
The server then stamps a <base href> into index.html and prefixes every asset/API/router path, so
assets, the data API, and deep-linked runs all resolve under the prefix. Example nginx (the dashboard
polls over plain HTTP — no WebSocket/SSE, so no Upgrade handling is needed):
location = /workflow-studio { return 301 /workflow-studio/; }
location /workflow-studio/ {
proxy_pass http://127.0.0.1:8787; # no trailing slash: forwards the full path incl. the prefix
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}Stripping proxies work too — the server strips the prefix itself if present, so it doesn't matter
whether the proxy forwards /workflow-studio/runs or the bare /runs.
To keep it up behind the proxy, run the dashboard as a service. A hardened unit (adapt User and the
/home/<user> paths):
# /etc/systemd/system/workflow-studio.service
[Unit]
Description=Workflow Studio
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=<user>
Environment=HOME=/home/<user>
Environment=PATH=/home/<user>/.local/bin:/usr/bin:/bin
Environment=WORKFLOW_STUDIO_BASE_PATH=/workflow-studio
Environment=WORKFLOW_STUDIO_NO_OPEN=1
ExecStart=/home/<user>/.local/bin/uvx workflow-studio --host 127.0.0.1 --port 8787 --no-open --all-projects
Restart=on-failure
# ── hardening ──
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
# uvx materializes its tool environment here — REQUIRED under ProtectSystem=strict or the service
# won't start (add ~/.cache/uv too for a cold first run). The data dir is where "Save as template" writes.
ReadWritePaths=/home/<user>/.local/share/uv /home/<user>/.cache/uv /home/<user>/.local/share/workflow-studio
# ProtectSystem=strict also mounts /tmp read-only — give the service its own writable /tmp.
# Safe: Workflow Studio reads run artifacts from under $HOME, never /tmp.
PrivateTmp=true
[Install]
WantedBy=multi-user.targetThen sudo systemctl daemon-reload && sudo systemctl enable --now workflow-studio.
Two hardening gotchas that block startup under ProtectSystem=strict, both handled above:
ReadWritePathsmust include uv's tool dir (~/.local/share/uv, plus~/.cache/uvon a cold machine) —uvxwrites the resolved package there; with the rest of the FS read-only it can't launch.PrivateTmp=true—strictmakes/tmpread-only; a private tmp restores a writable one. It's safe because run data lives under$HOME, not/tmp.
Scope. A service has no "current project", so --all-projects shows runs from the whole machine.
To pin it to one project instead, drop that flag and add --project /home/<user>/path/to/project
(then systemctl daemon-reload && systemctl restart workflow-studio).
The package is live on PyPI — uvx workflow-studio and uvx workflow-studio mcp work today, and
/plugin marketplace add hculap/workflow-studio installs the plugin from this repo. Plugin 0.2.1, package 0.2.0 on PyPI, MIT.
- Shared data directory.
save_workflow/promote_runwrite toWORKFLOW_STUDIO_DATA(default~/.local/share/workflow-studio). The human's dashboard must read the same directory or the agent's drafts won't appear in the builder. Both default to it when run viauvx; running the dashboard from a source checkout writes to the repo root instead.get_contextreports the resolveddataDirso you can diagnose a mismatch. uvxmust be onPATH. A GUI-launched Claude Code may not inherit it, in which case the MCP server showsfailedin/mcp.
.claude-plugin/marketplace.json
workflow-studio/
.claude-plugin/plugin.json
skills/workflow-studio/SKILL.md
commands/dashboard.md
README.md LICENSE # shipped with the plugin (an install gets only this folder)
README.md LICENSE CHANGELOG.md .gitignore
/plugin uninstall workflow-studio@workflow-studio
/plugin marketplace remove workflow-studio
If you added the MCP server directly (without the plugin):
claude mcp remove workflow-studio -s user
To remove drafted workflows and cached data, delete WORKFLOW_STUDIO_DATA (default ~/.local/share/workflow-studio).
MIT © 2026 Szymon Paluch <hculap@gmail.com>
Website: https://szymonpaluch.com/workflow-studio/ · Source & issues: https://github.com/hculap/workflow-studio


