Bpmn xml generator
Skill stateway-io/bpmn-xml-generator/.claude/skills/bpmn-xml-generator
Generate well-formed, valid BPMN 2.0 XML files compatible with BPMN 2.0-compliant process engines. Use this skill whenever the user asks to create, write, design, model, or define a business process, workflow, or BPMN diagram — even if they just describe a flow in plain language ("I need a process that does X then Y..."). Also use it when asked to convert YAML/JSON process definitions to BPMN, or to edit/fix an existing BPMN file. The skill guides information gathering when the request is incomplete, produces schema-valid XML, and enforces schema and compatibility constraints.From its SKILL.md
npx -y skills add stateway-io/bpmn-xml-generator --skill bpmn-xml-generatorAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
15.0 KB, ~3.8k tokens by cl100k_base, as published. Nobody here has run it
BPMN Authoring
Produces valid BPMN 2.0 XML parseable by bpmn-moddle and executable by BPMN 2.0-compliant process engines.
0. Orientation: what you are building
This skill targets engines that parse BPMN via bpmn-moddle (the bpmn-io library), such as Camunda and Flowable-compatible engines.
Key facts that govern every file you generate:
| Fact | Detail |
|---|---|
| Root namespace | xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" |
| Root element | <definitions> with mandatory id and targetNamespace (any valid URI; not read by the engine — it is required by the BPMN 2.0 XML schema only) |
| Each process | <process id="..." isExecutable="true"> |
| Conditions on flows | <conditionExpression>{{expression}}</conditionExpression> (engine-specific; verify with your engine — FEEL is the BPMN-standard alternative) |
| Assignees / dynamic values | {{variables.fieldName}} inside string attributes |
| DMN integration | <businessRuleTask camunda:decisionRef="decision-id"> — decisionRef must match the id of a DMN definition already registered in the engine |
| IDs | All elements must have a unique id attribute. Convention: snake_case or PascalCase_N |
isExecutable | Always true for processes intended for execution |
1. Information gathering — ask before writing
Never generate a BPMN file from an incomplete description. If the user's prompt is missing any of the items below, ask them before proceeding. Ask all missing items in a single response (not one at a time).
1.1 Always required
- Process key — the logical identifier (e.g.,
order-approval). Must be URL-safe, lowercase, hyphen-separated. - Process name — human-readable label.
- Happy-path steps — the sequence of activities from start to end (at least one activity).
- Human tasks — which steps require human action? Who is the assignee or candidateGroup?
- Service tasks — which steps call external systems? What is the
implementationtype? (webhookorhttp) - Gateways — are there any conditional branches? What are the conditions?
1.2 Ask when relevant
- Timer events — any steps that wait for a time or duration? (ISO 8601:
PT1H,2026-12-01T09:00:00Z,R3/PT24H) - Message / Signal events — any steps that wait for or emit an external message?
- Error / boundary events — any error handling on tasks?
- Sub-processes — any embedded sub-flows?
- DMN decisions — does any step evaluate a decision table? If so, what is the
idof the DMN definition that must already exist in the engine? (Thatidgoes incamunda:decisionRef.) - Variable names — what process variables are used? (needed for expressions and
dataInputAssociation) - Data visibility — for each
userTask, which variables should the frontend see? (maps todataInput/dataOutputinioSpecification) - Process-level variables — are there default/initial variable values?
- Diagram layout — do you want the output to include a visual layout (
BPMNDiagramsection), required by tools like bpmn.io? If yes,bpmn-auto-layoutwill be run automatically after saving (requires Node.js ≥ 18 and internet access fornpx).
1.3 Clarify ambiguity
If the user describes a flow like "approve or reject", confirm:
- Is this an
exclusiveGateway(XOR — one path only)? - Are both outcomes leading to different end states?
- What is the condition expression for each outgoing flow?
2. Supported BPMN elements
Read references/elements.md for the full attribute list of each element.
Below is the complete list of supported types — do not use any element not on this list.
Events
| XML element | Type | Notes |
|---|---|---|
<startEvent> | startEvent | None, Timer, Message, Signal, Conditional |
<endEvent> | endEvent | None, Terminate, Message, Signal, Error, Escalation |
<intermediateCatchEvent> | intermediateCatchEvent | Timer, Message, Signal, Conditional |
<intermediateThrowEvent> | intermediateThrowEvent | Message, Signal, Escalation |
<boundaryEvent> | boundaryEvent | Timer (interrupting/non), Error, Message, Signal, Escalation |
Activities
| XML element | Type | Notes |
|---|---|---|
<task> | generic task | passes through immediately |
<userTask> | userTask | assignee, candidateGroups, formKey, dueDate |
<serviceTask> | serviceTask | implementation="webhook" or "http" |
<scriptTask> | scriptTask | expression evaluated against variables |
<sendTask> | sendTask | dispatches message/webhook |
<receiveTask> | receiveTask | waits for correlated message |
<businessRuleTask> | businessRuleTask | camunda:decisionRef must contain the id of a previously registered DMN definition |
<callActivity> | callActivity | calls another process definition |
<subProcess> | subProcess | embedded sub-flow |
Gateways
| XML element | Behavior |
|---|---|
<exclusiveGateway> | XOR — exactly one outgoing flow taken |
<parallelGateway> | AND — all flows activated (join requires all tokens) |
<inclusiveGateway> | OR — one or more flows based on conditions |
<eventBasedGateway> | race — first event wins |
Connectors
| XML element | Notes |
|---|---|
<sequenceFlow> | sourceRef, targetRef, optional <conditionExpression> |
Not commonly supported by BPMN process engines
CMMN, Choreography, Conversation, DataStore, Association (rendered only).
3. XML structure template
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL
http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd"
id="Definitions_{process-key}"
targetNamespace="http://bpmn.io/schema/bpmn" <!-- any valid URI; this value is not used by the engine -->
exporter="bpmn-xml-generator"
exporterVersion="1.0">
<process id="{process-key}" name="{Process Name}" isExecutable="true">
<!-- ═══ START ═══ -->
<startEvent id="start" name="Start">
<outgoing>flow_start_to_first</outgoing>
</startEvent>
<!-- ═══ ACTIVITIES ═══ -->
<!-- ... -->
<!-- ═══ GATEWAYS ═══ -->
<!-- ... -->
<!-- ═══ END ═══ -->
<endEvent id="end" name="End"/>
<!-- ═══ SEQUENCE FLOWS ═══ -->
<!-- List ALL flows at the bottom for readability -->
<sequenceFlow id="flow_start_to_first" sourceRef="start" targetRef="..."/>
</process>
</definitions>
4. Element patterns — copy-paste ready
userTask with assignee and data visibility
<userTask id="review_task" name="Review Request"
camunda:assignee="{{variables.manager}}"
camunda:candidateGroups="approvers">
<extensionElements>
<camunda:formData>
<camunda:formField id="approved" label="Approved?" type="boolean"/>
<camunda:formField id="comment" label="Comment" type="string"/>
</camunda:formData>
</extensionElements>
<ioSpecification>
<dataInput id="in_amount" name="amount"/>
<dataInput id="in_reason" name="reason"/>
<dataOutput id="out_approved" name="approved"/>
<dataOutput id="out_comment" name="comment"/>
</ioSpecification>
<incoming>flow_to_review</incoming>
<outgoing>flow_from_review</outgoing>
</userTask>
serviceTask (webhook)
<serviceTask id="notify_erp" name="Notify ERP"
implementation="webService">
<extensionElements>
<camunda:connector>
<camunda:connectorId>webhook</camunda:connectorId>
</camunda:connector>
</extensionElements>
<incoming>flow_to_notify</incoming>
<outgoing>flow_from_notify</outgoing>
</serviceTask>
exclusiveGateway with conditions
<exclusiveGateway id="gw_approval" name="Approved?">
<incoming>flow_to_gw</incoming>
<outgoing>flow_approved</outgoing>
<outgoing>flow_rejected</outgoing>
</exclusiveGateway>
<sequenceFlow id="flow_approved" sourceRef="gw_approval" targetRef="notify_approved">
<conditionExpression xsi:type="tFormalExpression">{{variables.approved == true}}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow_rejected" sourceRef="gw_approval" targetRef="end_rejected">
<conditionExpression xsi:type="tFormalExpression">{{variables.approved == false}}</conditionExpression>
</sequenceFlow>
timerEvent (intermediate catch — wait N hours)
<intermediateCatchEvent id="wait_24h" name="Wait 24h">
<incoming>flow_to_timer</incoming>
<outgoing>flow_from_timer</outgoing>
<timerEventDefinition>
<timeDuration xsi:type="tFormalExpression">PT24H</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
boundaryEvent (timer, interrupting)
<boundaryEvent id="timeout_boundary" name="Timeout"
attachedToRef="review_task"
cancelActivity="true">
<outgoing>flow_timeout</outgoing>
<timerEventDefinition>
<timeDuration xsi:type="tFormalExpression">PT48H</timeDuration>
</timerEventDefinition>
</boundaryEvent>
businessRuleTask (DMN decision)
<!-- 'credit-score-decision' must be the id of a DMN definition already registered in the engine -->
<businessRuleTask id="credit_check" name="Credit Score Check"
camunda:decisionRef="credit-score-decision">
<extensionElements>
<camunda:in variables="all"/>
<camunda:out variables="all"/>
</extensionElements>
<incoming>flow_to_credit</incoming>
<outgoing>flow_from_credit</outgoing>
</businessRuleTask>
messageStartEvent / messageCatchEvent
<!-- Start on external message -->
<startEvent id="start_on_message" name="Payment Received">
<messageEventDefinition messageRef="msg_payment"/>
</startEvent>
<message id="msg_payment" name="payment_received"/>
<!-- Intermediate wait for message -->
<intermediateCatchEvent id="wait_payment" name="Wait for Payment">
<incoming>flow_to_wait</incoming>
<outgoing>flow_after_payment</outgoing>
<messageEventDefinition messageRef="msg_payment"/>
</intermediateCatchEvent>
5. Expression syntax
This skill uses {{expression}} as the default condition syntax — not FEEL (#{}) and not UEL (${}). Expression syntax is engine-dependent; verify with your engine.
{{variables.amount > 1000}} → boolean condition
{{variables.status == 'approved'}} → string equality
{{variables.items.length > 0}} → array check
{{variables.manager || '[email protected]'}} → fallback
{{variables.score >= 700 && variables.debt < 5000}} → compound
Use in:
<conditionExpression>on sequence flowscamunda:assigneeattribute onuserTask- Timer expressions only use ISO 8601 (no
{{}}in timer values)
6. Validation checklist
Before outputting the final XML, verify every item:
- Every element has a unique
id - Every
<sequenceFlow>hassourceRefandtargetRefpointing to existing element IDs - Every element except end events has at least one
<outgoing>child - Every element except start events has at least one
<incoming>child -
<exclusiveGateway>outgoing flows all have<conditionExpression>(except a default flow ifdefaultattribute is set) -
<parallelGateway>used for both split AND join — the join must have multiple<incoming>matching the split's<outgoing> -
<boundaryEvent>hasattachedToRefpointing to a valid activity - Timer expressions are valid ISO 8601: durations start with
P, dates are full UTC timestamps -
isExecutable="true"on<process> -
targetNamespaceis set on<definitions> - No CMMN, Choreography, or DataStore elements (rarely supported by BPMN process engines)
7. Output format
-
Always output the complete XML (never truncate with
<!-- ... rest of process -->) -
Use consistent 2-space indentation
-
Group flows at the end of the process element, after all nodes
-
Add a brief inline comment above each logical section (START, ACTIVITIES, GATEWAYS, END, FLOWS)
-
If the file is longer than ~150 lines, offer to also write a summary table of elements and flows
-
After outputting the XML, remind the user to validate and upload it according to their engine's API.
-
If the user requested a diagram layout, after writing the BPMN file apply layout via the reusable runner at
/tmp/bpmn-layout-runner/layout.mjs:node /tmp/bpmn-layout-runner/layout.mjs <output-file> <output-file>If
/tmp/bpmn-layout-runner/does not exist yet, set it up first:mkdir -p /tmp/bpmn-layout-runner && \ cd /tmp/bpmn-layout-runner && \ npm init -y > /dev/null && \ npm install bpmn-auto-layout && \ node -e " import { readFileSync, writeFileSync } from 'fs'; import { layoutProcess } from 'bpmn-auto-layout'; const [,,i,o] = process.argv; writeFileSync(o||i, await layoutProcess(readFileSync(i,'utf8')), 'utf8'); console.log('Layout applied.'); " > layout.mjsActually: write
layout.mjswith the Write tool (see below), then runnpm install bpmn-auto-layoutinside/tmp/bpmn-layout-runner/.layout.mjs content:
import { readFileSync, writeFileSync } from 'fs'; import { layoutProcess } from 'bpmn-auto-layout'; const [,, input, output] = process.argv; const xml = readFileSync(input, 'utf8'); const layouted = await layoutProcess(xml); writeFileSync(output || input, layouted, 'utf8'); console.log('Layout applied successfully.');This overwrites the file in-place, adding a
<bpmndi:BPMNDiagram>section with auto-computed shapes and edges. Confirm to the user that layout was applied and the file is ready for bpmn.io.
8. Reference files
Read these when you need deeper detail — do not load them all at once:
| File | When to read |
|---|---|
references/elements.md | Full attribute reference for each element type |
references/examples.md | 4 complete end-to-end BPMN examples (approval, onboarding, timer escalation, message correlation) |
references/validation-errors.md | Common bpmn-moddle parse errors and how to fix them |
What ships with it: 3 files
36.6 KB alongside SKILL.md
references/
- elements.md12.7 KB
- examples.md18.3 KB
- validation-errors.md5.7 KB