What this skill does
Helps you understand existing .bpmn files in plain language and produce new or
edited ones that are valid and visually clean when opened in any modeler
(Camunda Modeler, bpmn.io, Cawemo, etc.).
The job splits cleanly:
- You do the semantic reasoning: what the process means, what to add or change.
- The bundled script does the deterministic mechanics: parsing, regenerating layout, and validating. Lean on it instead of hand-rolling these each time.
The one idea that makes BPMN tractable: two layers
A .bpmn file holds two layers in one XML document:
- Semantics - the actual process:
bpmn:processwith tasks, gateways, events, andsequenceFlows connecting them. This is the meaning. - Diagram interchange (DI) -
bpmndi:BPMNDiagramwith x/y coordinates for every shape and waypoints for every edge. This is only the picture.
Editing DI by hand is where BPMN work goes wrong: coordinates drift, shapes
overlap, edges cross. So we never hand-write DI. You edit semantics; the
layout command owns the DI. That is exactly what makes the diagram "clear" - a
tidy left-to-right layout, generated deterministically.
layout is non-destructive by default, which is the rule that keeps you out
of trouble: on a file that already has a diagram it preserves the existing
layout and only syncs it to your edit (prune shapes for deleted elements, place
shapes for new ones). On a file with no DI it generates a fresh layout. It only
throws the whole diagram away and rebuilds from scratch when you pass
--rebuild. So the habit is simple: after editing semantics, always run
layout; it never destroys a good diagram.
Setup (once per machine)
The script needs two npm packages. From the skill's own directory:
npm install --prefix "<SKILL_DIR>"
<SKILL_DIR> is the folder containing this SKILL.md. After that, the four
commands below are available. If a run fails with "Cannot find package", the
install step was skipped - run it and retry.
Reading / explaining a diagram
-
Get a structured outline (don't try to read raw DI coordinates):
node "<SKILL_DIR>/scripts/bpmn-tool.mjs" summarize path/to/file.bpmnThis prints pools/lanes, start/end events, activities (with their type), gateways (with direction), boundary events (host + interrupting?), and every sequence flow as
source -> target [condition]. Add--jsonif you want to process it programmatically. -
Explain it the way a person would understand the process: the happy path first, then decision points (what each gateway branches on), parallel work, and exception/boundary handling. Name real business steps, not element IDs. Match the user's language.
The summarize output is your source of truth for "what does this diagram do" - read from it rather than eyeballing the XML, especially for anything non-trivial.
To locate a specific element before an edit, use find <file> <term> (matches
name or type). To compare two diagrams - As-Is vs To-Be, or to show exactly
what an edit changed - use diff <a> <b>; it reports elements added, removed,
renamed, or retyped and any sequence flows that were rewired.
When the user wants a review ("is this correct?", "find the bug", "why does
it hang?"), also run lint. It catches control-flow bugs that are valid XML and
pass validate but are wrong behavior - the kind that are easy to miss by eye:
node "<SKILL_DIR>/scripts/bpmn-tool.mjs" lint path/to/file.bpmn
It flags: a parallel (AND) join fed by an exclusive (XOR) split (deadlock); a parallel split merged by an exclusive join (runs twice); an exclusive gateway whose conditions can all be false with no default (stuck token); unreachable nodes; dead ends (non-end node, no outgoing); a missing start/end; an implicit split (non-gateway node with several outgoing flows); misdirected events (start with an incoming flow, end with an outgoing one); a boundary event on a non-activity; a node in no lane when the process uses lanes; and a message flow that stays inside one pool. Read its finding, confirm it against the model, then explain it in plain terms.
Creating or editing a diagram
Before writing XML for a new process, think like a business analyst and pin down the structure - it's what separates a clear model from a box-and-arrow mess. If any of these is unclear from the request, ask:
- Trigger - what starts the process (and is it a plain start, a message, a timer?).
- Participants - who does what. Multiple actors usually means lanes (one pool) or pools + message flows (separate processes).
- Happy path - the main sequence of activities when nothing goes wrong.
- Decision points - where the path forks, on what condition, and which gateway fits (exclusive = either/or, parallel = all, inclusive = one-or-more).
- Exceptions / alternatives - timeouts, rejections, errors; often boundary events or extra branches.
- End states - the distinct ways the process can finish.
If the user is documenting current vs future state, treat As-Is and To-Be as separate diagrams/files and label them as such.
The reliable loop is then edit semantics -> regenerate layout -> validate -> lint:
-
Write or change the semantics. For a new diagram, hand-author a semantics-only document (no
bpmndi:block) - it's compact and easy to get right. For an edit, runsummarizefirst to understand the current model, then change thebpmn:processbody. Seereferences/bpmn-reference.mdfor the skeleton, every element's XML shape, and copy-paste recipes (exclusive / parallel / inclusive gateways, boundary events, pools, lanes, message flows). -
Lay out. Sync the diagram to your edit:
node "<SKILL_DIR>/scripts/bpmn-tool.mjs" layout in.bpmn out.bpmnOmit
out.bpmnto rewrite the file in place. On a file that already has DI this preserves the existing layout (hand-tuned positions, Camunda multi-diagram sub-process pages) and only prunes/places shapes to match your change. On a brand-new semantics-only file it generates a clean layout. Add--rebuildonly when the user explicitly wants the entire diagram re-laid-out from scratch (this discards any manual positioning - say so). -
Validate. Confirm it parses, every flow element got a shape, and no shapes overlap:
node "<SKILL_DIR>/scripts/bpmn-tool.mjs" validate out.bpmnFix anything it flags (dangling refs surface as parse warnings; missing shapes usually mean you skipped
layout; overlaps are checked per diagram plane, so a real overlap means a crowded layout - re-runlayout --rebuild). -
Lint the control flow - especially when you added or rewired gateways and branches:
node "<SKILL_DIR>/scripts/bpmn-tool.mjs" lint out.bpmnvalidateproves the file is well-formed;lintproves the logic is sound. It catches the silent bugs: gateway split/join mismatches (deadlock, double execution), stuck tokens, unreachable nodes, dead ends, missing start/end, implicit splits, misdirected start/end events, boundary events on a non-activity, unassigned lane nodes, and message flows that stay inside a pool.
Don't claim a diagram is done until validate and lint both pass - they're
quick and catch the mistakes (typo'd refs, missing layout, gateway deadlocks)
that make a file look broken or hang in a real engine.
Modeling for clarity, not just validity
Auto-layout handles placement; clarity also comes from how you model. A few habits that make diagrams readable:
- Name things in business terms. Tasks as verb phrases ("Approve invoice"), gateways as the question they answer ("Amount > 1000?"), and label the outgoing flows with the answers ("yes" / "no").
- Keep one start and clear ends. Distinct end events for distinct outcomes read better than one catch-all end.
- Pair your gateways. A diverging gateway usually needs a converging one; give exclusive gateways a default/else so a token can't get stuck.
- Don't overload one diagram. If it sprawls, push detail into a sub-process.
Auto-layout: what it covers
layout handles the full range of everyday BPMN, not just single-pool flows:
- Collaborations: every pool is laid out, stacked vertically, with message flows routed between them (not just the first participant).
- Lanes (swimlanes): nodes are placed in their lane's horizontal band and the lane shapes are drawn.
- Sub-processes get their own drill-down diagram page (a separate
BPMNDiagramplane), exactly like a Camunda export: the sub-process shows as a box on the main canvas, and you "open" it to see its inner steps laid out on their own page. They are not flattened onto the main canvas and not emptied.summarizeshows the inner steps; a modeler reveals them on open. - Data objects/stores, text annotations, associations get shapes/edges placed next to the element they relate to.
Remaining limits, worth stating honestly when a request leans on them:
- Groups are not auto-placed (a group is a purely visual rectangle with no membership in the model, so there's nothing to size it from). Add one in a modeler if needed.
- Auto-placement of pools, lanes, data objects, and annotations is approximate
- clean and valid, but a user may want to nudge spacing in a modeler.
Details and workarounds are in references/bpmn-reference.md.
Bundled tools
| Command | Purpose |
|---|---|
summarize <file> [--json] |
Structured outline of the process(es), for explaining or for understanding before an edit |
layout <in> [out] [--rebuild] |
Sync the diagram to the semantics: preserve & update existing DI, or generate it if absent. --rebuild re-lays-out from scratch |
validate <file> |
Parse, report warnings, flag any flow element missing a shape or any per-plane overlapping shapes |
lint <file> |
Find control-flow / structural bugs: gateway split/join mismatches, stuck-token gateways, unreachable nodes, dead ends, missing start/end, implicit splits, misdirected events, bad boundary hosts, unassigned lane nodes, intra-pool message flows |
diff <a> <b> |
Semantic + structural diff: elements added/removed/renamed/retyped and sequence flows rewired (e.g. As-Is vs To-Be, or reviewing an edit) |
find <file> <term> |
List flow elements whose name or type contains term (case-insensitive) - quick lookup before an edit |
All four live in scripts/bpmn-tool.mjs. The deeper element reference,
recipes, and edge cases are in references/bpmn-reference.md - read it whenever
you need the exact XML for an element or pattern.