Circuit: The conversation is the canvas
An MCP server that turns a sentence into a workflow board and then runs it one deterministic step at a time — on the connectors you already gave Claude, holding no credentials of its own.
Solo — server, board UI, protocol work · 2026
The problem
There are two ways to automate something today and both ask for a thing you should not want to give. A visual workflow builder asks you to learn its canvas and hand it OAuth for every service it touches. An agent loop asks you to trust that a model will remember, on the ninth step of a run it started twenty minutes ago, to filter before it sends.
Meanwhile the assistant already holds the connectors. Gmail, Slack, Airtable — they are connected, scoped, and revocable in one place. What is missing is not integration. What is missing is determinism and a picture: a branch that branches the same way every time, and something to look at while it happens.
Circuit is the smallest thing that provides both. It never calls a connector, never stores a credential, and never asks the model to hold the control flow in its head.
Architecture
One hop of a run. Circuit decides what happens next; Claude is the only thing that touches a connector.
- You describe the automation in chat
- Claude — holds your connectors and your credentials
- circuit_design streams; every step object that closes draws a chip on the board
- circuit_bind checks every tool name against the list Claude reported
- circuit_run — a state machine handing out exactly one directive per hop
- Filter, branch, branches, each and flow.call never leave the server
- Claude calls the connector it already has, then reports back with circuit_step
- gate.approve parks the run on the board for your edit and your approval
- The run timeline is recorded, payload-clipped, and replayable
Key decisions
Own no credentials, and check the names instead
A step names a tool from your list as a plain string — `Gmail:search_threads`, `Slack:send_message`. That means anything you can connect to Claude, Circuit can orchestrate on day one, and there is nothing in Circuit worth breaching. The sharp edge is obvious: a wrong string fails halfway through a run. So Claude reports its actual tool list once, Circuit checks every step against it while the board is still being drawn, and a near-miss inside the right connector scores far above a closer spelling in some other service. When nothing scores well enough you get no suggestion, rather than a confident wrong one.
The server drives; the model does exactly one thing
At run time Circuit is a state machine, not an executor. `circuit_run` hands over one directive; Claude does that one thing and reports back with `circuit_step`; the next directive comes out. Five of the fourteen step types — filter, branch, branches, each and flow.call — are resolved inside the server and never become a directive at all. A nine-step workflow with a loop is nine deterministic hops instead of one long improvisation.
A test run that actually does not send
`mode: "test"` used to label the run and nothing else, which is worse than having no test mode — the word promises something the code does not deliver. Now a step declares whether it writes, and where it has not, the verb decides: send, post, create, delete and reply write; search, list, get and read do not. In a test run a writing step comes back as a `preview` directive that says, in the instruction itself, not to call the tool. Everything upstream runs for real, so the draft you are reviewing is the draft that would actually go out, with the templates resolved — which is where most workflow bugs live.
Arming something unattended is a decision, not an oversight
`circuit_arm` refuses a workflow where a step that writes has no approval gate on every path to it, and names the step. You can override it, out loud, with force. And because Circuit has no scheduler of its own, "armed" is a claim it verifies rather than a state it asserts: `circuit_health` flags a workflow that was armed but never wired to a scheduled task, and judges overdue at two windows late measured against the widest gap in the schedule — so a weekdays-at-one job is not called an outage every Sunday.
Editing the board never wakes the model
Dragging a chip, pulling a wire out of a port, cutting one — all of it goes through app-only tools that the board calls directly. Rewiring costs no turn and no tokens. The build animation is the opposite trick: the host forwards partial tool input while Claude is still emitting the design call, and each step object that closes places its chip. The animation is the model's output arriving, not a canned sequence.
A failed step is a designed outcome
Each step carries its own policy — stop, skip, retry, or route out of an error port — and a stopped run keeps its data, its queue and its place, so resuming hands out the same directive again instead of repeating every side effect that already happened. The instruction to the model is blunt, because the mechanism only works if it is honest: report the failure, never substitute a plausible result.
Numbers
- 23 — MCP tools (plus four prompts and two resource templates)
- 14 — step types (five of them resolved server-side, never a directive)
- 0 — credentials stored (no OAuth flow, no API keys, no secrets at rest)
- 240 — moments kept per run (oldest dropped with a marker, so a big loop cannot grow it without limit)
- ~2.5 kB — a clipped 9 kB payload (keeps the shape — forty rows, first five intact)
Circuit is version 0.8 and MIT-licensed. It has no scheduler, no multi-user accounts — one owner key, one workspace — and the capability it advertises is deliberately narrower than what the SDK would turn on by default, because a stateless HTTP session has no channel to push a change notification down and a capability that can never fire leaves a client waiting forever.
github.com/brandononchain/circuit-mcp