GitHub Get in touch
← Stuart Labs

Stuart LabsOpen sourceSpring 2026

AgenticNodes

A local graph editor and runtime for agent workflows. You wire model, tool and data nodes on a canvas, run the graph, and inspect every node and edge event in per-agent swimlanes.

Role
Sole developer
Status
Public repo, development paused
Stack
Python, FastAPI, React 19, TypeScript, Vite, React Flow, Server-Sent Events, MCP, Supabase, Cloudflare Tunnel
Links
Source on GitHub ↗

The one-line description I gave the repo is "Scratch but for AI Agents. Developer focused n8n with full end-to-end control." AgenticNodes (the studio inside is called Graph Agent Studio) is a local app where an agent is a graph. Nodes are model calls, tools, data steps and control flow, and edges decide what runs next. You build the graph on a canvas, press run, and watch each step happen live.

I built it alone. It started in March as a prototype inside my agent-spec repo, moved into its own repository on March 29, and took 61 commits there through May 14.

Where it came from

I design every agent against the same six-part spec: model, tool registry, control loop, state, memory and logging. I first wrote that spec as templates in a separate agent-spec repo in February, and AgenticNodes grew out of a graph-agent prototype there. The spec still shapes this repo, since each part has its own design doc in docs/.

In AgenticNodes the graph is the agent. The first graph completed an agentic task end to end on March 30. The example bundled with the runtime since its first commit is a tool-schema repair loop. A model proposes a tool payload, the tool validates it, and if validation fails a conditional edge routes the error back to a repair step, capped by a configurable repair limit. A failed validation becomes a result the graph can branch on, and the run keeps going.

How it is put together

The backend is a Python runtime behind a FastAPI API. The studio is React 19 with Vite and React Flow.

The runtime validates connections by node category (start, api, provider, tool, control flow, data, end) and never by vendor. A model node binds to a provider such as a mock, OpenAI, the Anthropic API, or a local Claude Code install that the runtime calls through the claude CLI. Swapping providers is a binding change, and the canvas doesn't move. A new node type is added only when execution semantics differ.

The Support Triage graph on the canvas. An inbound email feeds a context builder, Claude classifies the ticket, a logic node routes it by urgency to a Claude or GPT-4.1 mini reply, and each branch ends at an output node.
A support triage graph after a run. The two provider nodes bind to the model nodes they serve, and a logic node sends high-urgency tickets to one reply and the rest to another. Demo workspace: the company, the customer and every model reply are invented.

The control loop is plain on purpose. It starts at the declared start node, executes, records output and timing, then picks the next edge: a matching conditional edge first, otherwise a standard one. It stops when an output node finishes, a loop guard trips (visits per node, repair attempts, or an optional step cap), or an unrecoverable error occurs. Guards end the run with a structured terminal event, so a looping graph shows up in the log as a reason, not a stack trace.

Events as the source of truth

Every run emits a versioned event stream, and that one stream drives live streaming over Server-Sent Events, replay of past runs and the UI. Nodes never mutate shared state directly. They return results, and a reducer folds events into run state. That keeps the frontend and backend views of a run in sync, and a stored manifest plus its event log is enough to rebuild a past run.

The swimlane view is built directly on those events. A test_environment document groups several isolated agent graphs under one run, and each agent gets its own lane of event cards with inputs, payloads and errors.

Agent Run Swimlanes for a completed three-agent run, with filter chips for card and node types above the first event cards in the Support Triage lane
The swimlanes for one run of the demo's three agents. Each card is one runtime event with its payload, and the chips filter cards by event type or node type.

From canvas to something that runs on its own

By late April I wanted graphs that fire without me pressing run, so start nodes now declare a trigger mode. Manual runs are immediate. Discord messages, cron schedules, inbound webhooks and Supabase row events are listeners kept alive by background services. Inbound webhooks need a public URL, so the studio manages a cloudflared tunnel that boots with the first active listener and stops with the last. Each fire becomes a child run, and child events are mirrored onto the listener session so they appear as their own lanes.

Around that core sit the pieces a real workflow needed. There is MCP server management (boot, stop, capability discovery, per-tool toggles). Graphs can iterate spreadsheet rows, branch on conditions and split work in parallel. A Python script node runs uploaded scripts in a subprocess with a 30-second default timeout and typed error codes. Run storage defaults to the local filesystem and can mirror to Supabase asynchronously in batches. An agents CLI launches and tails graphs headlessly, and a Mock Run swaps API-backed model providers for mocks so a graph can be tested without live model calls.

The Order Research graph. A parallel splitter fans one order lookup out to three model nodes for order history, inventory and shipping, a context builder merges their results, and a final model node writes an account brief.
Order Research, another agent in the same demo. One lookup splits into three parallel model calls, and their results merge into a single brief.

Building it with coding agents

I built AgenticNodes with Claude Code and Cursor in the loop, and I set the repo up for that. Most design docs have a paired Claude Code skill, and a written rule says a doc and its skill change in the same commit, so the guidance an agent loads stays in step with the spec. The backend has 34 test files covering execution, the event contract, MCP, triggers and storage.

Where it stands

Feature work paused in May. In October I removed personal example data and screenshots before leaving the repository public. Durable memory is still a placeholder interface behind a stable contract. That was a deliberate scoping call while I proved the execution model, and the contract means memory can be added later without changing the control loop.

Next

Build the Environment, Then Optimize the Harness →