I replaced n8n with one I could actually trust
I had a workflow problem — a 15-step-per-chapter novel pipeline, plus a half-dozen agent loops — and the obvious answer was n8n. I built my own visual orchestrator instead. Not because n8n is bad, but because the one part I cared most about (a human gate an agent can never approve for itself) is exactly the part a general-purpose tool won't enforce for me. A build log of the in-house Workflow Designer.
I had a real workflow problem and the obvious off-the-shelf answer was n8n. A visual node graph, triggers, retries, a canvas you can show someone — exactly the shape of what I needed for a fifteen-step-per-chapter novel pipeline and a growing pile of agent loops. I spent an evening with it and then did the thing you're not supposed to do: I built my own. This is the build log for why, and what the in-house version buys me that the import never would.
The honest reason it's in-house
It is not that n8n is bad. It's excellent. The reason is that the single feature I care most about isn't a feature you can bolt on — it's an invariant, and invariants have to live where the rest of your trust model lives.
The invariant is this: an agent can commission work, advance it, even let the model critique and revise autonomously — but a human, and only a human, can approve the gate that turns output into canon. On this site that's already the rule everywhere: the credential steward can only narrow access, the playtest gate is deterministic, IAM-sensitive mutations reject anything coming from an agent. A workflow engine that didn't enforce the same boundary would be a hole punched straight through the middle of it. I'd rather own the engine than trust a general-purpose tool to hold a line that specific.
What it actually is
The Workflow Designer (WFS, internally) generalizes the existing job model into a versioned, JSON-defined graph without throwing any of it away. A workflow is a DAG of nodes and edges; a run executes that graph; and — this is the load-bearing trick — every operator node reuses the same job lifecycle the rest of the site already runs on. So an operator step queues and drains on the existing GitHub Actions runner with zero new runner code. I didn't build an execution engine. I built a graph layer over the one I had.
Four node types cover everything so far: operator (do a real job), llm (call the model with shared retry + usage tracking), http (hit a site route), and human-gate (stop and wait for me). Triggers are cron, event, manual, and a signed webhook. The orchestrator is tick-based — each advance reconciles in-flight nodes, schedules everything newly ready, and persists state — so a run can block on a gate for a week and resume from the exact checkpoint when I approve it.
The gate an agent can't open
The control API lets you start a run and advance it autonomously — commissioning and ticking work is fine for an agent to do. But the approve endpoint is special-cased: it rejects any agent actor outright. An act-as agent bearer, even one holding admin scope, cannot approve a human-gate — not its own, not anyone's.
That one asymmetry is the whole reason the engine exists. "Full autonomy, gate the risky steps" is a slogan until there's a line of code that makes the gate un-spoofable. Here the gate is a node type, the rejection is a unit-tested branch, and the canvas renders the blocked node so I can see exactly what's waiting on me. It's the same instinct as the house bot's allowlist or the steward's one-way valve — everything the model can't do alone, made structural.
The first real graph on it: a novel
The proof that it's a real engine and not a demo is that I put something I cared about on it. The fifteen-step writing pipeline for my just-finished novel is now a first-class workflow: sixteen model nodes plus one human-gate, the five critics fanning out from the voice pass and back into revision, Sonnet/Opus routing per node, each carrying its real stage prompt, hand-positioned so it loads as a designed graph instead of a fallback grid.
And because the graph terminates in my gate, the last node is a write-back: it slots the approved chapter into the manuscript, heading and POV preserved, the rest untouched. The approval and the integration are the same event. That's the loop a pile of HTML diagrams could never close — and the reason I'll keep reaching for the engine I own over the one I'd have to trust.
When I'd still just use n8n
If you don't need a hard agent/human boundary baked into the substrate, use n8n — seriously. The in-house build is only worth it because the gate is the point, and because I get to reuse a job runner, a secrets store, an IAM layer, and a usage tracker I'd already paid for. Subtract those and the math flips. The lesson isn't build your own orchestrator. It's figure out which invariant you can't afford to outsource, and own exactly that much.
Get the next one
An occasional note when something genuinely new ships here — essays, free tools, projects. No schedule, no filler, easy out.
Need something like this built?
I design and ship AI tools, full-stack apps, and data pipelines — end to end, to production. Tell me the problem in a sentence; I'll give you an honest read on fit within a day.
Work with me →