ADR 012: JSON Export as a First-Class Output Format
Status
Accepted
Context
bpmn-to-code's primary output is a Kotlin/Java constants file. That file is useful for compiler-checked references but is a compiled artifact — it requires building the project to inspect and cannot easily be consumed by non-JVM tooling.
Two use cases emerged that the code artifact does not serve well:
AI-assisted development — developers want to give an AI coding assistant context about a process model (element names, flow structure, variables) without requiring the assistant to parse raw BPMN XML. The XML format is verbose, namespace-heavy, and not optimized for LLM context windows.
Human-readable process structure in code reviews — reviewing a BPMN change in a pull request requires opening Camunda Modeler. A structured text format in version control makes the change visible without visual tooling.
Decision
Add a second output task (generateBpmnModelJson / generate-bpmn-json) that produces a .json file per process alongside the Kotlin/Java API.
The JSON format:
- Includes every flow node with
id,displayName,elementType, incoming/outgoing references,parentId, boundary event links, variables, and engine-specific properties - Sorts nodes in DFS order from the start event(s) so the file reads in execution order — easier to understand without tracing flows manually
- Includes separate top-level arrays for
messages,signals,errors,compensations, andsequenceFlows - Is generated by deterministic rules: same BPMN in → same JSON out, byte-identical across runs
The JSON task is separate and optional — teams that only need the code API are not forced to generate JSON.
Consequences
Positive
- AI agents can consume process structure without parsing BPMN XML
- Process changes are visible as text diffs in pull requests
- Deterministic output prevents AI hallucination of element IDs when used as context
- Works with any JSON-aware tooling (jq, scripts, MCP server, custom validators)
Negative
- Additional output file to manage; teams may need to add it to
.gitignoreor commit it deliberately - Two separate tasks mean two separate build configurations for teams that want both outputs