From bpmn-to-code
Migrates generated bpmn-to-code API usage from v1.1.0 to v2.0.0, handling TaskTypes → ServiceTasks, typed wrappers, and flagging manual changes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/bpmn-to-code:migrate-bpmn-to-code-v1-to-v2 [path/to/scan][path/to/scan]This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Update user source code that references the v1.1.0 generated Process API to use the v2.0.0 API shape.
Update user source code that references the v1.1.0 generated Process API to use the v2.0.0 API shape.
// Generated by bpmn-to-code)..bpmn)../gradlew generateBpmnModelApi or mvn io.miragon:bpmn-to-code-maven:generate-bpmn-api).ProcessApi.Variables.VAR → ProcessApi.Variables.ElementName.VAR) cannot be resolved automatically — the element name must be looked up in the regenerated API. Flag these for manual review.additionalVariables → additionalInputVariables / additionalOutputVariables) cannot be resolved automatically — BPMN files must not be edited by the skill. Flag occurrences for manual rewrite.| v1.1.0 | v2.0.0 |
|---|---|
ProcessApi.TaskTypes.FOO | ProcessApi.ServiceTasks.FOO |
ProcessApi.Timers.BpmnTimer (nested type) | import io.miragon.bpmn.runtime.BpmnTimer (standalone) |
ProcessApi.Errors.BpmnError (nested type) | import io.miragon.bpmn.runtime.BpmnError (standalone) |
ProcessApi.Variables.VAR_NAME | ProcessApi.Variables.ElementName.VAR_NAME (manual — look up the element in the regenerated API; direction is now carried by the wrapper type, not the path) |
<camunda:property name="additionalVariables" value="a,b"/> (BPMN) | <camunda:property name="additionalInputVariables" .../> and/or <camunda:property name="additionalOutputVariables" .../> (manual BPMN edit — skill flags occurrences, cannot rewrite) |
useVersioning = true/false (Gradle / Maven plugin config) | removed — delete the line |
const val PROCESS_ID: String + Elements/Messages/Variables/Signals/Compensations/CallActivities.X: String | typed wrappers: ProcessId, ElementId, MessageName, VariableName, SignalName (Kotlin data class, imported from io.miragon.bpmn.runtime.* — shipped by the bpmn-to-code-runtime artifact) |
In v2.0.0 every leaf identifier except ServiceTasks.* and PROCESS_ENGINE is wrapped in a type-safe class:
PROCESS_ID → ProcessIdElements.*, Compensations.* → ElementIdCallActivities.* → ProcessIdMessages.* → MessageNameSignals.* → SignalNameVariables.<Element>.* → VariableName.Input, VariableName.Output, or VariableName.InOut — sealed interface with direction-aware subtypesServiceTasks.* and PROCESS_ENGINE stay as const val String because Kotlin/Java annotation arguments must be compile-time constants.
Every wrapper overrides toString() to return its underlying string. Consumers now have three options at each call site, in preference order:
fun sendMessage(name: MessageName)). No unwrap needed.toString(): for string templates, logging, println, or any Any?-accepting API, the wrapper is implicitly converted to its string form. No unwrap needed..value (Kotlin) or .value() (Java record) only where a strict String parameter is declared and retyping isn't available.Call sites that previously used these constants in annotation arguments (other than ServiceTasks) cannot be trivially migrated — Kotlin value-class instances and Java records are not compile-time constants.
**/*ProcessApi*.kt and **/*ProcessApi*.java.// Generated by bpmn-to-code.de.emaarco.example)NewsletterSubscriptionProcessApi)ServiceTasks object (confirms it is already v2)ServiceTasks and lack nested BpmnTimer/BpmnError types, inform the user that the generated API is already v2 and only source code references may need updating.$ARGUMENTS contains a directory path, use that as the scan root.src/main/ in the project root.**/*.kt and/or **/*.java files depending on what exists.src/test/) unless the user requests test migration.Search for useVersioning in build configuration files:
build.gradle.kts and build.gradle — look for useVersioning inside any bpmnToCode { } or plugin configuration blockpom.xml — look for <useVersioning> inside the bpmn-to-code plugin <configuration> blockThe parameter was removed entirely. The fix is to delete the line — no replacement is needed.
If any occurrences are found, include them in the migration plan (Step 5) and apply the deletion in Step 6.
Search the scoped files for the following patterns and record file path, line number, and full line for each match:
A. TaskTypes references
\.TaskTypes\..ServiceTasks.ProcessApi.TaskTypes.SEND_MAIL → ProcessApi.ServiceTasks.SEND_MAILB. Nested BpmnTimer type usage
\w+ProcessApi\.Timers\.BpmnTimer or \.Timers\.BpmnTimer used as a type reference (in variable declarations, function parameters, return types)BpmnTimer directly and add import import io.miragon.bpmn.runtime.BpmnTimerval t: NewsletterSubscriptionProcessApi.Timers.BpmnTimer → val t: BpmnTimerC. Nested BpmnError type usage
\w+ProcessApi\.Errors\.BpmnError or \.Errors\.BpmnError used as a type referenceBpmnError directly and add import import io.miragon.bpmn.runtime.BpmnErrorD. Variables flat references (flag only — do not auto-fix)
ProcessApi\.Variables\.[A-Z_]+ where [A-Z_]+ is not a sub-object nameVariables.StartEventFoo.VAR_NAME). Direction is carried by the variable's type (VariableName.Input / .Output / .InOut), not by the path. Flag each occurrence for manual review; the user must open the regenerated API to find the element the variable belongs to.E. Legacy Inputs / Outputs paths from earlier v2 iterations (auto-fix when direction is clear)
ProcessApi\.Variables\.[A-Z][a-zA-Z0-9]*\.(Inputs|Outputs)\.[A-Z_]+Variables.Element.Inputs.NAME / Outputs.NAME. The final shape drops the Inputs / Outputs segment; direction now lives in the type.ProcessApi.Variables.<Element>.<NAME> — drop the .Inputs / .Outputs segment.F. Typed leaf constants used where a String is expected (flag only)
In v2.0.0 leaf constants under PROCESS_ID, Elements, CallActivities, Messages, Compensations, Signals, and Variables are wrapper types, not String. Every wrapper overrides toString(), so:
println / Any?-accepting APIs: no change required — toString() handles the conversion implicitly.String parameter types (val s: String = ..., Map<String, String>, third-party APIs with String arg): require either unwrap (.value / .value()) or retyping the consumer API.The skill cannot reliably distinguish these cases without type information. Flag each occurrence for manual review.
ProcessApi class name):
ProcessApi\.PROCESS_IDProcessApi\.Elements\.[A-Z_]+ (excluding sub-object name qualifiers)ProcessApi\.CallActivities\.[A-Z_]+ProcessApi\.Messages\.[A-Z_]+ProcessApi\.Signals\.[A-Z_]+ProcessApi\.Compensations\.[A-Z_]+ProcessApi\.Variables\.[A-Z][a-zA-Z0-9]*\.[A-Z_]+.value (Kotlin) or .value() (Java) already follows the constant — those are already unwrapped. In practice: if the matched span is immediately followed by .value or .value(), the call site is migrated and no action is needed.@JobWorker(type = ...), @MessageCorrelationKey(...)), flag as BLOCKED — annotation arguments cannot reference value-class / record instances, so the consumer needs a different approach (e.g. keep a separate const val String constant).G. Legacy additionalVariables in BPMN files (flag only — do not auto-fix)
**/*.bpmn files (all directories; do not exclude test BPMNs — they model real processes too)name="additionalVariables" (literal, inside <camunda:property> / <operaton:property>)name="additionalInputVariables" (values read by the element) and/or name="additionalOutputVariables" (values produced by the element). The skill must not edit BPMN files per the IMPORTANT section.Group findings by file and present a summary:
## Migration Plan
### src/main/kotlin/com/example/MyWorker.kt
| Line | Pattern | Change |
|------|---------|--------|
| 14 | .TaskTypes.SEND_MAIL | → .ServiceTasks.SEND_MAIL |
| 28 | .Timers.BpmnTimer (type ref) | → BpmnTimer + import |
**Imports to add:**
- `MyWorker.kt` → `import io.miragon.bpmn.runtime.BpmnTimer`
### ⚠️ Manual review required
| File | Line | Pattern | Reason |
|------|------|---------|--------|
| src/main/kotlin/com/example/MyWorker.kt | 42 | .Variables.SUBSCRIPTION_ID | Variables are now nested per-element — check generated API for correct path |
**Total: 2 automatic replacements in 1 file, 1 item requires manual review**
If nothing is found, report that no v1 API patterns were detected.
Ask: "Apply these replacements? (yes / skip [file-or-line] / cancel)"
For each approved change:
useVersioning from build.gradle.kts, build.gradle, or pom.xml..TaskTypes. with .ServiceTasks. on the matched line.import line in the file.
import io.miragon.bpmn.runtime.BpmnTimer / import io.miragon.bpmn.runtime.BpmnErrorimport io.miragon.bpmn.runtime.BpmnTimer; / import io.miragon.bpmn.runtime.BpmnError;Inputs / Outputs paths (Pattern E): drop the .Inputs. / .Outputs. segment while preserving the element and leaf names. Example: Variables.StartEventX.Inputs.FOO → Variables.StartEventX.FOO../gradlew compileKotlin or ./gradlew compileJavamvn compiletoString() makes .value optional in most contexts.additionalVariables and always splitting Variables.<Element>.npx claudepluginhub miragon/bpmn-to-code --plugin bpmn-to-codeCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.