Skip to content

Latest commit

 

History

498 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Workflow Graph

npm license Open in GitHub Codespaces

A self-hosted workflow engine you embed in your application. Your code declares the vocabulary — Events, actions, and integrations — and your team builds workflows in a visual editor.

Role Who What they do
Event Author The developer who embeds Defines Events, actions, and which integrations to turn on
Workflow Builder Their less technical team Builds the graph and declares Lifecycle Rules in the editor

Workflow Graph runs on your infrastructure (Node, PostgreSQL or SQLite, and Inngest).

Run locally

Prerequisites: Node 24 and pnpm (see packageManager in package.json).

# Install
pnpm install

# Root .env.local (gitignored)
cat > .env.local <<EOF
INTEGRATION_ENCRYPTION_KEY=$(openssl rand -hex 32)
# Optional: enables the build agent in the editor.
OPENAI_API_KEY=your-openai-api-key
# Optional: enables Slack OAuth. See .env.example for the redirect URL to
# register on the Slack app.
SLACK_CLIENT_ID=your-slack-client-id
SLACK_CLIENT_SECRET=your-slack-client-secret
EOF

# App :4017, editor :5173. The Inngest CLI takes free ports and prints its own.
# INNGEST_DEV_PORT pins that one.
pnpm run dev

Open the editor at http://localhost:5173. The example host app lives in examples/app.ts. Sign in at /login as admin, editor, or readonly. Each local demo account uses the password password.

The example app stores its data in SQLite, at examples/wfgraph.sqlite, which is gitignored and created on first boot. There is no migration step and no separate service. Point SQLITE_PATH somewhere else to move the file, and delete it to start over.

The build agent is optional. Set OPENAI_API_KEY in .env.local to enable the Agent panel. The key stays on the server; the browser sends chat requests to the host app, which calls the configured model. Leave the variable empty to run the editor without the agent.

Production-style single process (built client handed to the app):

pnpm run build
pnpm run start

Run in GitHub Codespaces

  1. Select the Open in GitHub Codespaces badge.
  2. Create the codespace.
  3. Wait for the setup command to finish.

The setup command installs the workspace and creates the required encryption key. The codespace starts the development stack and keeps its own SQLite database. After the app starts, Codespaces opens the forwarded Workflow Graph port. Sign in with any demo account listed in Run locally. Codespaces also forwards the Inngest port for its development UI. If startup fails, read /tmp/wfgraph-dev.log in the codespace.

Embed in your app

pnpm add @wfgraph/core @wfgraph/client inngest hono

inngest and hono are peer dependencies, so your application owns the version of each that runs in its process. Add @wfgraph/plugins for the built-in integrations.

The published packages include Agent Skills (TanStack Intent). After install, run pnpm dlx @tanstack/intent@latest install, then pnpm dlx @tanstack/intent@latest list and pnpm dlx @tanstack/intent@latest load @wfgraph/core#wfgraph-core when embedding or writing an integration.

createWfGraphApp returns a fetch handler. Pass Events, actions, and integrations in one extensions object:

import { createServer } from "node:http";
import { z } from "zod";
import { clientBundle } from "@wfgraph/client";
import {
  createRequestListener,
  createWfGraphApp,
  defineWfGraphAuth,
  defineAction,
  defineEvent,
  WfGraphRoles,
} from "@wfgraph/core";
import { wfPostgres } from "@wfgraph/core/postgres";
import { builtInIntegrations } from "@wfgraph/plugins";

const appointmentCreated = defineEvent({
  name: "app/appointment.created",
  label: "Appointment created",
  schema: z.object({
    appointment: z.object({
      id: z.string().describe("Appointment ID"),
      startsAt: z.iso.datetime(),
    }),
  }),
  correlationPath: "appointment.id",
});

const cancelAppointment = defineAction({
  id: "appointments/cancel",
  label: "Cancel Appointment",
  category: "Appointments",
  input: z.object({
    appointmentId: z.string().describe("Appointment ID"),
    reason: z.string().min(1),
  }),
  output: z.object({
    appointmentId: z.string(),
    status: z.string(),
  }),
  handler({ input }) {
    return { appointmentId: input.appointmentId, status: "cancelled" };
  },
});

const auth = defineWfGraphAuth(async (request) => {
  const session = await readSession(request);
  return session ? WfGraphRoles[session.role] : null;
});

const wfgraph = await createWfGraphApp({
  persistence: wfPostgres({
    url: process.env.DATABASE_URL!,
    migrations: { runOnStartup: true },
  }),
  encryption: { key: process.env.INTEGRATION_ENCRYPTION_KEY },
  agent: { apiKey: process.env.OPENAI_API_KEY },
  auth,
  client: clientBundle,
  inngest: { id: "my-wfgraph-app", connect: true },
  extensions: {
    events: [appointmentCreated],
    actions: [cancelAppointment],
    integrations: builtInIntegrations(),
  },
});

createServer(createRequestListener(wfgraph)).listen(3000);

See Authentication and authorization for role semantics, custom grants, and trusted upstream authentication.

examples/app.ts is the canonical host. If this README disagrees with it, the example wins.

For embedded SQLite, use wfSqlite() for an ephemeral in-memory database or pass a file to keep data across restarts:

import { wfSqlite } from "@wfgraph/core/sqlite";

persistence: wfSqlite(); // in memory
persistence: wfSqlite({ filename: "./wfgraph.db" }); // persistent

See Embedding: Persistence for PostgreSQL, SQLite, and Cloudflare Hyperdrive setup.

Docs

Doc What it covers
docs/embedding.md Mounting, editor, database, migrations, package exports, options
docs/events.md defineEvent, umbrella sources, intake, Lifecycle model
docs/integrations.md defineIntegration, OAuth adapters, handlers, schemas, testing
CONTEXT.md Domain vocabulary
docs/adr/ Design decisions

Packages

The three published packages release together and always carry the same version, so the editor can never be installed against a backend whose API contract it no longer matches.

Package What it is
@wfgraph/core Run engine, authoring vocabulary, createWfGraphApp
@wfgraph/client The editor, as a built bundle
@wfgraph/plugins The six built-in integrations

@wfgraph/shared holds types the three have in common. It stays private and is inlined at build time, so it never appears as a dependency of anything you install.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages