arcflow GitHub

A flow engine your users can see and your model can write.

Define a step once. arcflow gives you the TypeScript types, the runtime validation, the form on the canvas, and the catalog a model builds against — from that one definition. Everything in between is plain JSON.

npm install @arcsig-labs/core @arcsig-labs/editor

One definition

A step is a kind, a config schema and a run. That is the whole contract, and the four things under it are generated from it — which is why the canvas, the validator, the compiler and the model can never disagree about what a step takes.

import { defineNode, f } from '@arcsig-labs/core';
import { postMessage } from './slack.js';

export const slackPost = defineNode({
	kind: 'slack.post',
	title: 'Post to Slack',
	description: 'Posts a message to a channel and outputs its timestamp.',
	config: {
		channel: f.string({ label: 'Channel', placeholder: '#treasury' }),
		text: f.text({ label: 'Message', placeholder: 'Payroll of {{ input.amount }} USDC is ready' }),
		urgent: f.boolean({ default: false, label: 'Ping the channel' })
	},
	outputs: [{ id: 'out' }, { id: 'error', label: 'Error' }],
	run: async (ctx) => ({ output: { ts: await postMessage(ctx.config) } })
});

The types

Inside run, the config is the definition. A typo is a compile error, not a run-time surprise.

ctx.config.channel; // string
ctx.config.urgent;  // boolean
ctx.config.chanel;
// error TS2551: Property 'chanel' does not exist on type
// '{ channel: string; text: string; urgent: boolean; }'. Did you mean 'channel'?

The validation

Untrusted JSON — from a file, an API or a model — comes back with a stable code and a JSON path.

{
	"level": "error",
	"code": "required",
	"path": "nodes[1].config.channel",
	"message": "Post to Slack: Channel is required.",
	"nodeId": "notify"
}

The form

The canvas builds the inspector from the same fields: labels, placeholders, controls, defaults.

{
	"channel": { "kind": "string", "label": "Channel", "placeholder": "#treasury" },
	"text": { "kind": "string", "multiline": true, "label": "Message",
	          "placeholder": "Payroll of {{ input.amount }} USDC is ready" },
	"urgent": { "kind": "boolean", "default": false, "label": "Ping the channel" }
}

The catalog

And a model reads this, so it writes flows against what exists instead of guessing.

### `slack.post` — Post to Slack
Posts a message to a channel and outputs its timestamp.
- Outputs: `out`, `error`
- Config:
  - `channel`: text — Channel
  - `text`: text (multi-line) — Message
  - `urgent`: true | false, default false — Ping the channel

The canvas is the same flow

This is the editor itself, running in this page — not a screenshot. Drag a step in, connect it, press Test run: steps with a test mode report what they would do, and the HTTP step really sends its GET to the GitHub API, since test runs only hold back other methods. Whatever you build here is the same JSON the engine runs.

Loading the editor…

Step shapes, themes, a compact toolbar, translated labels, read-only and a narrow container, on one editor: open the playground.

Built to be driven by a model

The catalog, the validator and the simulated run are the same three things an agent needs. Add arcflow to a coding agent and it has them over MCP — four tools on its own, nine against a running server.

claude mcp add arcflow -- npx -y @arcsig-labs/mcp

A session recorded from this repository, start to finish:

list_steps            → 39 entries, 7 042 characters
validate_flow         → error required @ nodes[1].config.url
validate_flow (fixed) → 0 issues
test_flow             → failed · GET example.com/status returned 404 Not Found

Every validation issue carries the path that caused it, which is what lets a model repair its own output instead of starting over. AI and agents has the generate, edit and repair loop.

What is in the box

PackageWhat it is
@arcsig-labs/coreThe engine: steps, flows, validation, expressions, branching, loops, waits, sub-flows. No dependencies.
@arcsig-labs/nodesThirteen standard steps: triggers, HTTP, sandboxed JavaScript, set fields, if, switch, merge, loop, wait, run flow.
@arcsig-labs/editorThe canvas. One ES module with styles included, framework-free, 19 colour tokens, 151 replaceable strings.
@arcsig-labs/serverWebhooks, schedules, restart-safe timers, run history, encrypted credentials, live events.
@arcsig-labs/aiBuild and change flows with a model: every attempt is validated, and the issues go back for repair for a set number of tries.
@arcsig-labs/mcpAn MCP server, so agents list steps, write flows, check them and run them.

Start somewhere

  • Quick start — build a flow, run it, open it on a canvas.
  • Flows and steps — the format, the schema, expressions, what the engine handles.
  • Editor — embedding in React, Vue or Svelte, theming, shortcuts, server mode.
  • Server — one command to run flows for real.
  • AI and agents — the prompt bar, the repair loop, MCP.