BPMN 2.0: bpmn-beta - PR series tracker
Tracking the PR series for native BPMN 2.0 support. Companion to #2623 (demand and scoping) and #7699 (design proposal, Status: Approved).
Note on prior art and the
bpmn-betakeyword. @OKHP3 published@okhp3/mermaid-diagram-bpmnon 2026-08-05 - an external diagram using thebpmn-betakeyword with syntax very close to this one - and asked whether the core or plugin path was wanted. @derari has had https://derari.github.io/mermaid-bpmn/editor.html up since 2026-07-25 and asked four questions on #7699. @andreas-emrich proposed and scoped the work on #7699 in May. None of them has had a maintainer reply. I am not claiming the keyword or the design, and I would rather the syntax question were decided between the candidates than settled by whoever opens a PR first.
What this looks like
This source:
bpmn-beta LR
pool "Order handling"
lane "Sales"
start message s1 "Order received"
user task t1 "Approve order"
boundary timer b1 "2 days"
xor gw "Approved?"
lane "Warehouse"
service task t2 "Pick items"
end e1 "Shipped"
s1 --> t1 --> gw
gw -- yes --> t2 --> e1
b1 --> t2
renders this:
The two images that carry the most notation detail are the event tables. BPMN 2.0.2 Table 10.93 draws a trigger unfilled when the event catches and filled when it throws, which is why the same keyword produces a different marker on an intermediate than on an end:
A collaboration: two pools joined by a message flow, drawn dashed with an open arrowhead and a hollow ring at its source.
The five gateways and the activity types:
The artifacts - data object, data store, text annotation - and a group:
A group on its own:
What these images are and are not. They are the fixtures committed in #8166, rendered at its current head in Chromium with the default theme, and they exist so this discussion has something concrete to argue about. They are not test baselines - the visual baselines are the Argos snapshots, which need maintainer approval - and they are not evidence that the layout is stable across themes or directions. They are hosted on a branch of my fork rather than committed, so they add nothing to any diff.
Status
PR1 to PR5 are ready for review. PR6, PR7 and PR8 are drafts.
Last checked 2026-09-10. No unresolved review threads; every PR mergeable. Heads: #8161 5c9d30d47, #8162 a2078550b, #8163 2ba838535, #8164 92dff689b, #8165 78f237c9e, #8166 ef2adc58b, #8167 10d9423f1, #8171 8995b8783. #8161, #8164 and #8165 are green on every check including argos and need no baseline decision. Correction: #8171 is not a trailing follow-up - its commits are ancestors of #8166, so #8166 cannot land without it. 12.0.0 published 2026-09-10; develop is 77 commits behind master with no merge-back open yet, so the whole series is waiting on that.
The five that are ready contain no bpmn-beta diagram between them. They are a bug fix, a behaviour-neutral refactor, and three additions to the swimlane engine and the shape layer - each with its own tests, each justified without reference to BPMN, and each useful to whoever touches those files next. They are ready because their merit does not depend on the grooming answer.
The three that hold the diagram stay drafts, because they do. #7699 carries Required Grooming - "Need discussion before start implementation" - and the core-vs-external question has never been answered. They exist to give that discussion something tangible to argue about, and I would rather rework them against an answer than defend them.
(#8171 also contains no BPMN and could be reviewed on the same footing as PR1 to PR5; it is left as a draft only because its argos changes are worth reading alongside its description first.)
Open questions I would like answered
- Which syntax? Four candidates now exist (@andreas-emrich's two tiers on #7699, @OKHP3's published plugin, and mine). @OKHP3's and mine converged independently on the same keyword, the same keyword-position element type and the same quoted-label form. I have no stake in which wins - porting mine to another is a parser change and nothing else.
- Core or external plugin? @sidharthv96 (#6305), @ashishjain0512 (#6305, #6317) and @pbrolin47 (#7624) have all said this is an architectural decision maintainers make per diagram. If the answer is "external plugin", that is a reasonable outcome and @OKHP3 already has one published.
- Scope. @knsv named Level 1 Descriptive as the realistic target on #2623 and every community reply agreed. What is here goes beyond that, and I would rather say so than have it discovered in review - see Coverage below. If Level 1 is what is wanted, say so and the extra elements move to a follow-up.
The PR sequence
Recommended merge order. Maintainers choose the pace; anything can be dropped per-phase or per-PR.
Independent of BPMN
- PR1 #8161
fix(clusters): scope a swimlane's DOM id like every other cluster- the swimlane cluster shape wrote the author-suppliednode.idinto theidattribute, so two diagrams on one page collided. Every other cluster shape inclusters.jsusesdomId. The uniqueness sweep could not catch it becauseswimlanewas excluded from it; the exclusion is removed and a fixture added. Fails before, passes after. Ready for review. - PR2 #8162
refactor(swimlanes): resolve a node's lane through one shared model- several call sites each decided independently that a lane is a group with no parent. Behaviour-neutral; the proof is the existing swimlane specs green with zero churn. - PR3 #8163
feat(swimlanes): pin a node to another node's border- anchored nodes, needed because boundary events must straddle their host activity's border. Ships with a synthetic swimlane fixture and no BPMN code. - PR4 #8164
feat(rendering-util): the open-arrow and hollow-circle edge markers- covered by the existing non-BPMN marker specs. - PR5 #8165
feat(shapes): the BPMN element shapes- one shape per file over a shared core, matching the usecase actor pattern. - PR8 #8171
fix(swimlanes): dock an edge on the shape it points at- two fixes to where a swimlanes edge meets what it points at. An event reserves room for a caption above and below its circle, so a flow clipped to that box stopped short of anything drawn; and a straight edge asked each shape for a boundary point using that shape's own endpoint as the reference, which describes no direction, so it could leave from the wrong face. Contains no BPMN code; the swimlane engine is the only consumer today. What it moves in the swimlanes snapshots is tabulated per argos sheet in its description - one edge per affected diagram.
The diagram
- PR6 #8166
feat(bpmn): the bpmn-beta diagram- grammar, db, styles, registration, config namespace, theme variables, opt-in pool support in the swimlane engine, and the e2e fixtures and rendering spec. - PR7 #8167 docs page, demo page, changeset.
The e2e fixtures started out as a PR of their own. They cannot be: scripts/e2e-diagram-scope.spec.ts requires every folder under src/diagrams/ to have a matching folder under e2e/rendering/ or e2e/diagrams/, so a diagram PR without its coverage fails that test. They ship inside PR6.
Coverage
Pools and lanes, with separate participants drawn apart and message flows running between their borders; the thirteen trigger types of BPMN 2.0.2 at the five positions the notation draws each of them at, unfilled when they catch and filled when they throw; boundary events pinned to their host's border; the five gateways; tasks with the seven task types, sub-processes and call activities; sequence, labelled and message flows; and the data object, data store, text annotation and group artifacts.
A position and trigger pair the notation does not draw is refused while the line is read, naming the line and where that trigger does belong. The table of which pairs those are is on the docs page, and the parser and the tests read it from the same place, so they cannot drift apart.
Known gaps, also stated in the docs page rather than left to be found:
- An event sub-process and a transaction have no syntax, so the two rules that depend on one are wider here than in the notation:
error,escalationandcompensationare accepted on anystart, andcancelon anyboundaryorend. Every other position and trigger pair is checked. - Activity markers (loop, parallel and sequential multi-instance, ad-hoc, compensation) have no syntax yet.
- A group is contained by one lane, so it cannot yet stretch across pools the way Figure 8.14 shows.
Following the agentflow precedent for an unannounced beta, bpmn is deliberately absent from the examples registry and from the docs sidebar until the syntax is declared stable; the docs page still builds and is reachable by URL.
Review conveniences
- Atomic commits, reviewable one at a time. Tests live in the same commit as the code they cover.
- Stacked PRs are noted in each body as "Stacked on #N - review only commits X..Y", since a cross-fork PR cannot target another branch.
- Branches are updated by merging
develop, never rebasing, so no force-push cascade. - A red
argoson these PRs is new baselines needing approval, not a regression. - Three suites guard the diagram, and none of them needs a screenshot:
bpmn-elements.spec.tsasserts one case per element of the Analytic set, driven by the grammar's own trigger and task lists;bpmn-invariants.spec.tssweeps every fixture for things that are wrong whatever one's taste (a line stopping short, a line crossing a shape, two shapes sharing space); andbpmn-characterization.spec.tspins the behaviour a change would quietly alter. - The
.ddltlayout specs are load-sensitive: a different subset fails each parallel run at the default 5s timeout and they pass at--testTimeout=30000. A red one is not a regression until it has been re-run alone.
Source: mermaid-js/mermaid