Open Source · MIT · AI-Native · TypeScript

BPMN diagrams
from code, not clicks

A fluent TypeScript API that generates deployable BPMN 2.0 diagrams with auto-layout. Built for AI agents, automation platforms, and workflow builders.

BPMN is the industry standard for business-process diagrams. BPMN Kit lets your developers — and AI assistants — create, test, and deploy them as fast as they write code. Analysts still review and edit everything visually in the built-in editor.

order-flow.bpmn
Why BPMN Kit

Everything you need,
nothing you don't

AI-Native Design

LLMs call a fluent API instead of wrestling with raw XML. A compact intermediate format makes the entire diagram fit in a single prompt — AI generates it, the SDK validates and renders it.

const compact = compactify(defs)
const xml = Bpmn.export(expand(compact))

No Third-Party
Dependencies

Pure ESM, tree-shakeable. Runs in browsers, Node, Deno, Bun, and edge runtimes.

0
third-party deps

Auto-Layout

Sugiyama layout engine produces clean, readable diagrams with orthogonal edge routing. No coordinate math.

Sugiyama algorithm SVG export

Type-Safe

Strict TypeScript throughout. 29 type guard predicates narrow the BpmnFlowElement union. Typed errors are instanceof-catchable.

29 type guards ParseError / ValidationError findElement / getZeebeExtensions

Roundtrip Fidelity

Parse → modify → export without data loss. All Zeebe extensions, custom namespaces, and diagram info preserved — verified by the roundtrip test suite.

Parse Modify Export

Camunda 8 Ready

Native Zeebe task definitions, IO mappings, connectors, forms, and modeler templates. Deploy directly to Camunda Cloud.

100 API Connectors, Out of the Box

Generate typed Zeebe connector templates from 100 built-in OpenAPI specs — GitHub, Stripe, Slack, DigitalOcean, Kubernetes, and more. Over 18,145 API endpoints covered with zero boilerplate. Browse the catalog →

100 services 18,145+ endpoints
For process teams

Your analysts model it.
Your developers ship it. AI drafts it.

Faster process changes

Process updates ship through code review — versioned, tested, and audit-traceable — not a modeling-tool ritual.

AI-drafted workflows

Describe a process in plain language; get a valid, deployable BPMN diagram your analysts review visually.

No lock-in, no license fees

Open source (MIT). Standard BPMN 2.0 files that open in any BPMN tool, including Camunda Modeler.

BPMN Kit doesn't replace visual modeling — the built-in editor and any BPMN 2.0 tool still open every diagram. It replaces the copy-paste-redeploy gap between the diagram and production. Explore use cases →

SDK Quality

TypeScript-first,
from top to bottom

29 Type Guard Predicates

Narrow BpmnFlowElement to a specific type without casting. One predicate per BPMN element type — isBpmnServiceTask, isBpmnParallelGateway, isBpmnBoundaryEvent, and group guards like isBpmnGateway, isBpmnActivity, isBpmnEvent.

Typed Error Classes

ParseError (malformed XML) and ValidationError (builder rule violations) both extend BpmnSdkError. Every error carries a machine-readable code string — no string matching on err.message.

Element Lookup Utilities

findElement, findProcess, findSequenceFlow, getAllElements, and getZeebeExtensions give you a clean query layer over the parsed model — no manual array traversal.

Full JSDoc Coverage

Every public API has @param, @returns, @throws, and @example documentation. Hover any function in your IDE and get complete usage guidance inline.

type-guards.ts
import {
  Bpmn, findElement, getZeebeExtensions,
  isBpmnServiceTask, isBpmnGateway,
  ParseError,
} from "@bpmnkit/core";

try {
  const defs = Bpmn.parse(xml); // throws ParseError if invalid

  const el = findElement(defs, "task1");
  if (isBpmnServiceTask(el)) {
    // el is BpmnServiceTask ✓ — no cast needed
    const ext = getZeebeExtensions(el.extensionElements);
    console.log(ext.taskDefinition?.type); // "my-worker"
  }

  if (isBpmnGateway(el)) {
    console.log("gateway:", el.type); // narrowed to gateway types
  }
} catch (err) {
  if (err instanceof ParseError) {
    // Typed, instanceof-catchable ✓
    console.error(err.code, err.message);
  }
}
Developer Experience

Stop writing XML.
Start building workflows.

Drag the divider to compare

Without SDK
<bpmn:definitions
  xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
  xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
  xmlns:zeebe="http://camunda.org/schema/zeebe/1.0">
  <bpmn:process id="p" isExecutable="true">
    <bpmn:startEvent id="s">
      <bpmn:outgoing>Flow_1</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:serviceTask id="t">
      <bpmn:extensionElements>
        <zeebe:taskDefinition
          type="worker"/>
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_1</bpmn:incoming>
      <bpmn:outgoing>Flow_2</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="e">
      <bpmn:incoming>Flow_2</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_1"
      sourceRef="s" targetRef="t"/>
    <bpmn:sequenceFlow id="Flow_2"
      sourceRef="t" targetRef="e"/>
  </bpmn:process>
  <bpmndi:BPMNDiagram>
    <bpmndi:BPMNPlane>
      <bpmndi:BPMNShape
        bpmnElement="s">
        <dc:Bounds x="152" y="82"
          width="36" height="36"/>
      </bpmndi:BPMNShape>
      <!-- ...more shapes + edges... -->
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>
With BPMN Kit
import { Bpmn } from "@bpmnkit/core";

const xml = Bpmn.export(
  Bpmn.createProcess("my-flow") // fluent API
    .startEvent("start")        // trigger
    .serviceTask("task", {
      name: "Do Something",
      taskType: "my-worker",    // Zeebe type
    })
    .endEvent("end")
    .withAutoLayout()           // Sugiyama
    .build()
);

// ✓ Valid BPMN 2.0 XML
// ✓ Auto-layout applied
// ✓ Zeebe extensions set
Interactive Examples

See it in action

Watch a process get built — each line of code (or AI instruction) instantly becomes a diagram your team can read.

This section continuously animates through five example scripts, each typing out a BPMN Kit builder call and rendering the resulting diagram live. The code and diagrams shown are also available in the Examples and Playground sections below as static, interactive code.

REST API Client

Camunda 8 API,
fully typed

client.ts
import { CamundaClient } from "@bpmnkit/api";

const client = new CamundaClient({
  baseUrl: "https://api.cloud.camunda.io",
  auth: {
    type: "oauth2",
    clientId:     process.env.CAMUNDA_CLIENT_ID!,
    clientSecret: process.env.CAMUNDA_CLIENT_SECRET!,
    tokenUrl:     "https://login.cloud.camunda.io/oauth/token",
    audience:     process.env.CAMUNDA_AUDIENCE!,
  },
});

// Start a new instance of an already-deployed process
const instance = await client.processInstance.createProcessInstance({
  processDefinitionId: "my-flow",
  variables: { orderId: "ord-123" },
});

// React to lifecycle events
client.on("request", (e) => console.log(e.method, e.url));
client.on("error",   (e) => metrics.inc("api.error"));
180
typed methods
30+
resource classes
3
auth modes
auto-retry w/ backoff

A complete TypeScript client for the Camunda 8 REST API. Every endpoint is typed end-to-end — from request body to response shape. Drop it into any Node.js or edge runtime.

OAuth2 / Bearer / Basic LRU + TTL cache Exponential backoff TypedEventEmitter ESM tree-shakeable Processes Jobs & Workers Decisions Messages Incidents Variables Signals
Command-Line Interface

Manage Camunda 8
from your terminal

casen — the BPMN Kit command line.

Interactive TUI

Arrow-key navigation through menus, commands, and input forms. No flags to memorize.

Connection Profiles

Store multiple Camunda clusters. Switch between dev, staging, and prod in one keystroke.

Full API Coverage

Processes, jobs, incidents, decisions, variables, messages — all accessible from the terminal.

Tabular Results

Query results rendered as scrollable tables with detail view on enter. Copy-friendly output.

This terminal continuously animates a demo session of casen, the BPMN Kit CLI: navigating the main menu, opening the "process" command group, listing process definitions, and viewing a tabular result.

Quickstart

Up and running
in 4 steps

01

Install

pnpm add @bpmnkit/core
bun add @bpmnkit/core
npm install @bpmnkit/core
yarn add @bpmnkit/core
02

Create a process

import { Bpmn, exportSvg } from "@bpmnkit/core";

const defs = Bpmn.createProcess("hello")
  .startEvent("start")
  .serviceTask("task", {
    name: "Hello World",
    taskType: "greet",
  })
  .endEvent("end")
  .withAutoLayout()
  .build();

const xml = Bpmn.export(defs); // ✓ BPMN 2.0 XML
const svg = exportSvg(defs);   // ✓ SVG image, zero deps
03

Simulate it locally

import { Engine } from "@bpmnkit/engine";

// Simulate the process in-process — for tests and local development.
// Deploying to a real Camunda 8 cluster? See the API client below.
const engine = new Engine();
engine.deploy({ bpmn: defs });

engine.registerJobWorker(
  "greet",
  async (job) => {
    console.log("Hello!");
    job.complete();
  }
);
engine.start("hello");

The engine is an in-process simulator for tests and demos — for production execution, deploy to Camunda 8/Zeebe (next step).

04

Deploy to Camunda 8

import { CamundaClient } from "@bpmnkit/api";

const client = new CamundaClient({
  baseUrl: "https://api.cloud.camunda.io",
  auth: {
    type: "oauth2",
    clientId:     process.env.CAMUNDA_CLIENT_ID!,
    clientSecret: process.env.CAMUNDA_CLIENT_SECRET!,
    tokenUrl:     "https://login.cloud.camunda.io/oauth/token",
    audience:     process.env.CAMUNDA_AUDIENCE!,
  },
});

// Start a new instance of an already-deployed process
const instance = await client.processInstance.createProcessInstance({
  processDefinitionId: "my-flow",
  variables: { orderId: "ord-123" },
});

// React to lifecycle events
client.on("request", (e) => console.log(e.method, e.url));
client.on("error",   (e) => metrics.inc("api.error"));
DMN & Forms

Beyond BPMN — decisions
and forms, too

The same fluent builder pattern works for DMN decision tables and Camunda Forms. Reference them directly from your BPMN process.

eligibility.ts
import { Dmn } from "@bpmnkit/core";

// Build a DMN decision table
const dmnDefs = Dmn.createDecisionTable("Eligibility")
  .name("Loan Eligibility")
  .input({ label: "Credit Score", expression: "creditScore", typeRef: "integer" })
  .input({ label: "Income", expression: "income", typeRef: "number" })
  .output({ label: "Eligible", name: "eligible", typeRef: "boolean" })
  .output({ label: "Max Amount", name: "maxAmount", typeRef: "number" })
  .rule({ inputs: [">= 700", ">= 50000"], outputs: ["true", "500000"] })
  .rule({ inputs: [">= 600", ">= 30000"], outputs: ["true", "200000"] })
  .rule({ inputs: ["-",       "-"],       outputs: ["false", "0"] })
  .build();

const xml = Dmn.export(dmnDefs); // ✓ valid DMN 1.3 XML

DMN Decision Tables

Build DMN decision tables with a fluent API. Define inputs, outputs, and rules — the SDK generates valid DMN 1.3 XML with auto-computed DMNDI layout.

Fluent builder DMN 1.3 XML export Auto-layout DMNDI Hit policies FEEL type refs Compact AI format

Use Dmn.createDecisionTable(id) to build decision tables, Dmn.export(defs) to serialize to XML, and Dmn.layout(defs) to assign diagram positions automatically.

application-form.ts
import { Form } from "@bpmnkit/core";

// Build a Camunda form from code
const form = Form.makeEmpty("ApplicationForm");
// Forms are JSON-based; extend with fields:
// { type: "textfield", key: "applicantName", label: "Applicant Name" }
// { type: "number",    key: "requestAmount", label: "Requested Amount" }
// { type: "select",    key: "loanType",      label: "Loan Type",
//     values: [{ label: "Personal", value: "personal" },
//              { label: "Business", value: "business" }] }
// { type: "submit",    label: "Submit Application" }

const json = Form.export(form); // ✓ valid Camunda form JSON

Camunda Forms

Scaffold Camunda form JSON from code. Use Form.makeEmpty(id) to get a baseline form structure, then extend it with typed fields for text inputs, numbers, dropdowns, and more.

Form JSON export textfield / number / select Schema version 16 Compact AI format Round-trip fidelity

After applying a BPMN from the AI chat, the editor automatically detects referenced forms and DMN tables and offers to scaffold them as companion files.

loan-application.ts
import { Bpmn } from "@bpmnkit/core";

// BPMN process referencing a DMN decision and a Camunda Form
const defs = Bpmn.createProcess("loan-application")
  .name("Loan Application")
  .startEvent("start", { name: "Application Received" })

  // User task linked to a Camunda Form by ID
  .userTask("collect-data", {
    name: "Collect Applicant Data",
    formId: "ApplicationForm",
  })

  // Business rule task evaluated by a DMN table
  .businessRuleTask("check-eligibility", {
    name: "Check Eligibility",
    decisionId: "Eligibility",
    resultVariable: "eligibilityResult",
  })

  .exclusiveGateway("gw", { name: "Eligible?" })
  .branch("approved", (b) =>
    b.condition("= eligibilityResult.eligible")
      .serviceTask("disburse", {
        name: "Disburse Loan",
        taskType: "disburse-loan",
      })
      .endEvent("end-ok", { name: "Loan Approved" }),
  )
  .branch("rejected", (b) =>
    b.defaultFlow()
      .serviceTask("notify", {
        name: "Notify Applicant",
        taskType: "send-rejection-email",
      })
      .endEvent("end-rejected", { name: "Rejected" }),
  )
  .withAutoLayout()
  .build();

BPMN with DMN & Form references

Link your BPMN process to a DMN decision table via businessRuleTask and to a Camunda Form via userTask. Both use Zeebe extension attributes so the process is immediately deployable to Camunda 8.

userTask → formId businessRuleTask → decisionId resultVariable Camunda 8 / Zeebe Auto-layout
Playground

Try the builder API
live in your browser

Write Bpmn, Dmn, and Form builder expressions. Press Ctrl+Enter (or ⌘ Enter) to render.

playground.ts Ctrl+Enter to run
Live Preview
Examples