toolsJune 21, 20264 min read
By

I replaced n8n with one I could actually trust

I had a fifteen-step-per-chapter novel pipeline and a pile of agent loops, and the obvious answer was n8n. I built my own visual orchestrator instead. Not because n8n is weak, but because the part I cared about most, a human gate an agent can never approve for itself, is exactly what a general-purpose tool will not enforce. 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. It is the right shape for a fifteen-step-per-chapter novel pipeline and a growing pile of agent loops. I spent an evening with it, then built my own. The reason fits in one sentence: I needed a graph layer, not an execution engine, and I already owned the engine. This is the build log for what that bought me.

The honest reason it's in-house

This is not a story about n8n being bad. It is excellent. The orchestrator is in-house because the one capability I cared about is not a feature you can bolt on; it is an invariant, and an invariant has to live where the rest of your trust model lives.

The invariant: an agent can commission work, advance it, and let the model critique and revise on its own, but only a human can approve the gate that turns output into canon. That rule already runs everywhere on this site. The credential steward (a secrets layer that can only narrow access) holds it. The playtest gate (a deterministic pre-merge check on the games) holds it. IAM-sensitive changes reject anything an agent initiates. A workflow engine that quietly skipped that boundary would undo it everywhere else, so I would rather own the engine than trust a general tool to hold a line this specific.

What it actually is

The Workflow Designer (WFS, internally) turns the existing job model into a versioned, JSON-defined graph without discarding any of it. A workflow is a DAG of nodes and edges; a run executes that graph. The load-bearing trick is that 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.

Four node types cover everything so far: operator (do a real job), llm (call the model with shared retry and 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. A run can block on a gate for a week and resume from the exact checkpoint when I approve it.

triggermanualoperatorjobllmcriticllmcriticllmcritichuman-gateblockedwrite-backwaiting
system stephuman-gaterun blocked, write-back waiting
A run advancing left to right, blocked on the human-gate. Operator, model, and route nodes drain on infrastructure the site already trusts; only the gate waits on a person.

The gate an agent can't open

The control API can start a run and advance it autonomously; commissioning and ticking work is fine for an agent. The approve endpoint is the exception. It rejects an agent actor outright, so an act-as agent bearer, even one holding admin scope, cannot approve a human-gate, not its own and not anyone else's.

That single asymmetry is why the engine exists. "Full autonomy, gate the risky steps" stays a slogan until a line of code 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 what is waiting on me. It is the same instinct behind the house bot's allowlist, where the bot can only run pre-approved commands: give the model room to work, and put the irreversible step behind a person.

The first real graph on it: a novel

The test of whether this is 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 and one human-gate, with five critics fanning out from the voice pass and back into revision, Sonnet and Opus routed per node, each carrying its real stage prompt, hand-positioned so it loads as a designed graph instead of a fallback grid.

Because the graph terminates in my gate, its 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 is the loop a folder of static diagrams could never close, and the reason I keep reaching for the engine I own.

The same pipeline as a vertical cut: a run advances to the gate, then waits.

When I'd still just use n8n

If you do not need a hard agent-and-human boundary baked into the substrate, use n8n. I mean that. The in-house build is only worth it because the gate is the whole point, and because I got to reuse a job runner, a secrets store, an IAM layer, and a usage tracker I had already paid for. Subtract those and the math flips. The lesson is not "build your own orchestrator." It is narrower: find the one invariant you cannot afford to outsource, and own exactly that much.

Experience it yourselfRead how the novel's pipeline closed its own loop
ShareXLinkedInHacker NewsEmail

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 →