Bpmn xml generator
Skill stateway-io/bpmn-xml-generator/.claude/skills/bpmn-xml-generator
AI agent code skill to generate valid BPMN XML files.
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.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
15.0 KB, 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 |