| name | migrate-to-bpmn-to-code-apis |
| argument-hint | [path/to/scan] | [ProcessApiClassName] |
| description | Replace hardcoded BPMN strings with references to the generated Process API. Use when the user asks to 'migrate to the process API', 'replace hardcoded strings with API references', 'use the generated BPMN API', or 'refactor to type-safe BPMN constants'. |
| allowed-tools | Read, Glob, Grep, Edit |
Skill: migrate-to-bpmn-to-code-apis
Replace hardcoded BPMN string literals in user code with references to the generated Process API.
IMPORTANT
- Read-only until confirmation: Do not edit any files until the user explicitly approves the proposed changes.
- Never modify generated Process API files (files starting with
// Generated by bpmn-to-code).
- Never modify BPMN model files (
.bpmn) — these are source-of-truth inputs, not generated code.
- If no generated Process API files are found, abort and tell the user to run the code generation task first (
./gradlew generateBpmnModelApi or mvn io.miragon:bpmn-to-code-maven:generate-bpmn-api).
- When a string value matches multiple API classes and the surrounding code context is not enough to determine the correct process, ask the user to disambiguate.
- Only replace exact string literal matches — do not replace substrings or partial matches within larger strings.
- Preserve existing code formatting and style when making replacements.
Instructions
Step 1 – Locate generated Process API files
- Use Glob to find candidate files:
**/*ProcessApi*.kt and **/*ProcessApi*.java.
- Read each candidate and confirm it is a generated API file (contains
// Generated by bpmn-to-code on the first line).
- If
$ARGUMENTS specifies a class name, filter to only that API. Otherwise, collect all generated API files.
- If no API files are found, abort with the message described in the IMPORTANT section.
Step 2 – Parse the API constants
For each generated API file, extract a lookup table of string values mapped to their fully qualified API references:
- Kotlin
object: Parse const val NAME: String = "value" lines within the top-level object and each nested object (Elements, Messages, ServiceTasks, Timers, Errors, Signals, Variables, CallActivities).
- Java
final class: Parse public static final String NAME = "value"; lines within the top-level class and each nested static final class.
- Record the fully qualified reference path. For example, a constant
PROCESS_ID with value "newsletterSubscription" in NewsletterSubscriptionProcessApiV1 becomes:
NewsletterSubscriptionProcessApiV1.PROCESS_ID
- For nested sections:
NewsletterSubscriptionProcessApiV1.Variables.SUBSCRIPTION_ID
- Also record the package of each API file for import management.
Skip non-string constants (e.g. BpmnTimer and BpmnError object references) — these are composite types and not direct string replacements.
Step 3 – Determine scan scope
- If
$ARGUMENTS contains a directory path, use that as the scan root.
- Otherwise, default to
src/main/ in the project root.
- Determine the project language:
- If
.kt source files exist, scan **/*.kt files.
- If
.java source files exist, scan **/*.java files.
- If both exist, scan both.
- Exclude the generated API files themselves from the scan.
- Exclude test directories (
src/test/) unless the user explicitly requests test migration.
Step 4 – Scan for matching string literals
For each string value in the lookup table from Step 2, use Grep to search for exact occurrences in the scoped files:
- Search for the literal string in quotes:
"<value>" (escaped appropriately for regex).
- Skip values that are too short (fewer than 3 characters) or too generic (common words like
"id", "name", "type") to avoid false positives.
- For each match, record:
- File path and line number
- The full line of code (for context)
- The current hardcoded value
- The proposed API reference replacement
Step 5 – Present the migration plan
Group the proposed replacements by file and present a summary table:
## Migration Plan
### src/main/kotlin/com/example/MyService.kt
| Line | Current | Replacement |
|------|---------|-------------|
| 24 | "newsletterSubscription" | NewsletterSubscriptionProcessApiV1.PROCESS_ID |
| 31 | "subscriptionId" | NewsletterSubscriptionProcessApiV1.Variables.SUBSCRIPTION_ID |
### src/main/kotlin/com/example/AnotherService.kt
| Line | Current | Replacement |
|------|---------|-------------|
| 12 | "Message_FormSubmitted" | NewsletterSubscriptionProcessApiV1.Messages.MESSAGE_FORM_SUBMITTED |
**Imports to add:**
- `MyService.kt` → `import com.example.api.NewsletterSubscriptionProcessApiV1`
- `AnotherService.kt` → `import com.example.api.NewsletterSubscriptionProcessApiV1`
**Total: 3 replacements across 2 files**
If a string value matches constants from multiple API classes and the context does not make it clear which process is intended, flag it and ask the user which reference to use.
If no matches are found, report that no hardcoded strings were found that match the generated API.
Ask: "Apply these replacements? (yes / skip [file-or-line] / cancel)"
- yes — proceed to Step 6
- skip — remove the specified file(s) or line(s) from the plan, show updated plan, ask again
- cancel — stop without changes
Step 6 – Apply replacements
For each file in the approved plan:
- Add the import statement if not already present:
- Kotlin: Add
import <package>.<ApiClassName> after the last existing import line.
- Java: Add
import <package>.<ApiClassName>; after the last existing import line.
- If the file already imports the API class, skip this step for that file.
- Replace each string literal with the API reference using the Edit tool. Replace only the quoted string (including quotes) with the constant reference.
- Process files one at a time, top-to-bottom by line number within each file.
Step 7 – Verify and report
- Show a summary of all changes made (number of replacements per file).
- Suggest the user verify the changes compile:
- Gradle:
./gradlew compileKotlin or ./gradlew compileJava
- Maven:
mvn compile
- Note any string values from the API that had zero matches in the codebase (these may indicate unused API constants, or strings used in configuration files outside the scan scope).