From camunda-skills
Authors and runs Camunda Process Test suites for 100% BPMN element coverage with minimum test segments. Parses coverage reports, deduplicates scenarios.
How this skill is triggered — by the user, by Claude, or both
Slash command
/camunda-skills:camunda-process-testThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Author and run Camunda Process Test suites for Camunda 8.8+ that reach **100% BPMN element coverage** with the minimum number of test segments. Test assertions are limited to reachability and routing — CPT exercises that the engine traverses the right elements, not the data values produced by service tasks or external systems.
Author and run Camunda Process Test suites for Camunda 8.8+ that reach 100% BPMN element coverage with the minimum number of test segments. Test assertions are limited to reachability and routing — CPT exercises that the engine traverses the right elements, not the data values produced by service tasks or external systems.
./mvnw), Docker runtime (OrbStack, Docker Desktop, or Rancher Desktop) — see references/setup.mdcamunda-process-test-spring 8.9+ on the test classpath (instruction-based JSON format requires 8.9)c8ctl bpmn lint on the process under test before authoring scenarios — failing lints surface as deploy-time @TestDeployment failures.npx dmnlint for structural checks.COMPLETE_JOB_AD_HOC_SUB_PROCESS and context.when().then() orchestrate.c8ctl call deploys a process under test.ASSERT_VARIABLE instructions on service-task output unless the variable is the FEEL input to a downstream gateway you also test.Find the BPMN under test in priority order:
src/main/resources/processes/src/main/resources/bpmn/../resources/ (Node.js layouts where the test harness lives in test/)Skip target/, node_modules/, .git/, build/. If multiple files match, list them and ask which to target.
Check pom.xml (or test/pom.xml) for camunda-process-test-spring. If missing, go to step 2.
Follow references/setup.md: verify Java 21+, Maven, Docker; add the CPT dependency; scaffold src/test/java/io/camunda/tests/ProcessTest.java and src/test/resources/scenarios/. Confirm with mvn test-compile.
Plan the minimum number of segments before authoring anything. Apply references/coverage-strategy.md:
processId, element IDs and types, gateway outgoing flows + conditions, error / timer / escalation boundaries, end events, called DMN decisions (<zeebe:calledDecision decisionId="…">) and the DMN rules inside them.segment name | root | predicted ids covered | end condition. Authoring then implements exactly this list — no speculative scenarios that may be deduped later.For each segment, write one entry inside src/test/resources/scenarios/<processId>.test.json using references/authoring.md. Naming: "<who/what> — <outcome>". Assertions: ASSERT_ELEMENT_INSTANCES on the elements the segment must visit, ASSERT_PROCESS_INSTANCE only when the segment runs to an end event.
Use the Java fallback only when the segment needs Spring bean mocking, parameterized data tables, non-deterministic runtime races (context.when().then() (8.9+)), or assertions richer than the JSON instruction set offers — see references/test-context.md. Accept that Java tests are invisible to Web Modeler.
mvn test
On failure, diagnose with references/troubleshooting.md. Distinguish test problems (variable typo, wrong element id, missing instruction) from process problems (wrong FEEL condition, wrong DMN rule, wrong error code). Fix the right side. Re-run. Stop after 3 repair cycles with no progress.
When the run exits — pass or fail — proceed straight to step 6 and open the coverage report.
CPT emits a coverage report at target/coverage-report/report.html (per-process HTML; the page embeds the full coverage dataset in a window.COVERAGE_DATA JSON literal). Parse it:
python3 - <<'PY'
import re, json
html = open("target/coverage-report/report.html").read()
# Balanced-brace extraction. Walk character by character, but track string
# state so braces inside JSON strings (e.g. inside a description) don't
# unbalance the counter.
m = re.search(r"window\.COVERAGE_DATA\s*=\s*", html)
start = html.index("{", m.end())
depth = 0; in_str = False; esc = False; end = start
for k, ch in enumerate(html[start:], start):
if in_str:
if esc: esc = False
elif ch == "\\": esc = True
elif ch == '"': in_str = False
else:
if ch == '"': in_str = True
elif ch == "{": depth += 1
elif ch == "}":
depth -= 1
if depth == 0:
end = k + 1
break
data = json.loads(html[start:end])
el = set(); flows = set(); total = None
for s in data["suites"]:
for r in s["runs"]:
for c in r["coverages"]:
el.update(c.get("completedElements", []))
flows.update(c.get("takenSequenceFlows", []))
total = c.get("totalElementCount", total)
covered = len(el) + len(flows)
print(f"coverage={covered}/{total}={100*covered/total:.2f}%")
print("covered_elements:", sorted(el))
print("covered_flows:", sorted(flows))
PY
Diff against the BPMN element + sequenceFlow id list (grep -oE 'id="[A-Za-z0-9_]+"' <bpmn>, exclude _di, BPMNDiagram, BPMNPlane, Definitions_, ErrorDef_, TimerDef_, Signal_, Message_).
Surface the HTML report path to the user as soon as mvn test exits — pass or fail. The agent already verifies coverage from the JSON data above; the HTML report is for the user to inspect. Print the absolute path (target/coverage-report/report.html) in the final reply so they can open it themselves. In an interactive local session you may additionally offer to open it on their behalf (open on macOS, xdg-open on Linux, start on Windows) — do not run that unprompted in a sandboxed / remote environment where it has no effect.
Patch-loop on prediction misses — default behavior. Set-cover planning in step 3 should reach 100% on the first authoring pass. When it does not, the gap is a prediction miss: the static walk for some candidate did not match runtime behavior. For each uncovered id:
INCREASE_TIME with an ISO 8601 duration greater than the timer cycle (e.g. "PT25H" for R/PT24H). The boundary fires; the outgoing path's job is created; complete it with COMPLETE_JOB.PUBLISH_MESSAGE instruction with matching name + correlationKey.mvn test) → step 6. Each iteration should strictly reduce the uncovered set; if it does not, the planner's path prediction is wrong — fix the prediction logic in references/coverage-strategy.md, do not paper over with more scenarios.Hard blockers that terminate the loop:
Do not declare the suite done while ids remain uncovered and no hard blocker applies.
Note: in early 8.9 SNAPSHOT releases the report generator may throw
IllegalStateException: Report resources not foundand skip the HTML output. Tests still pass. Walk the BPMN against scenarios from source to confirm coverage in that case.
Set-cover planning in step 3 should produce a non-redundant suite by construction. Verify with a leave-one-out check against the runtime coverage data: for each scenario, compute the union of all other scenarios' covered ids; if removing the scenario loses zero ids, it is redundant and the planner has a bug — fix the planner, then drop the scenario.
Also flag (cheap, do unconditionally):
<who/what> — <outcome> (e.g. "test1", "happy").ASSERT_VARIABLE instructions on variables that no gateway or DMN downstream consumes — data assertions are out of scope.Print the Surefire result line, the coverage percentage, the segment count, and any flagged duplicates.
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
Coverage: 100% (24/24 elements)
Segments: 1 happy path + 5 secondary
Duplicates flagged: 0
.test.json schema, full 8.9 instruction reference, Java fallbackCamundaProcessTestContext Java API surface (job/decision/child-process mocking, time control, conditional behavior)Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub camunda/skills --plugin camunda-skills