Skip to content

Declarative Workflows ​

Flowcraft allows defining workflows using JSON blueprints, decoupling structure from implementation. The primary difference from programmatic workflows is separating the WorkflowBlueprint (the JSON structure) from the NodeRegistry (the code implementations), which allows for dynamic workflow generation or storage in a database.

Node Registry ​

First, create a registry of reusable node functions.

typescript
const nodeRegistry = {
	takeOrderFn: async ({ context }) => {
		const order = { item: 'Coffee', size: 'Medium' }
		await context.set('order', order)
		return { output: order }
	},
	makeDrinkFn: async ({ input, context }) => {
		const order = input as { item: string; size: string }
		return { output: `Made ${order.size} ${order.item}` }
	},
	serveCustomerFn: async ({ input }) => {
		return { output: `Served: ${input}` }
	},
}

Workflow Blueprint ​

Define the workflow as a JSON object.

json
{
	"id": "coffee-shop-order",
	"nodes": [
		{
			"id": "take-order",
			"uses": "takeOrderFn"
		},
		{
			"id": "make-drink",
			"uses": "makeDrinkFn",
			"inputs": "take-order"
		},
		{
			"id": "serve-customer",
			"uses": "serveCustomerFn",
			"inputs": "make-drink"
		}
	],
	"edges": [
		{
			"source": "take-order",
			"target": "make-drink"
		},
		{
			"source": "make-drink",
			"target": "serve-customer"
		}
	]
}

Execution ​

Load and run the blueprint with the registry.

typescript
import { FlowRuntime } from 'flowcraft'

const runtime = new FlowRuntime({ registry: nodeRegistry })
const result = await runtime.run(
	blueprint,
	{
		/* Initial context */
	},
	{ functionRegistry: nodeRegistry },
)

This approach separates workflow structure from code, enabling dynamic configurations.

Demo ​

This workflow can be visualized and run in the demo below:

Released under the MIT License