Engine Expert

SkillCommunication

Guides your agent to safely write and review Zeebe workflow engine code, enforcing rules for processors, event appliers, and testing.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Engine Expert skill

About this capability

Use when implementing, fixing, or reviewing Zeebe engine code in zeebe/engine/ — BPMN process execution, DMN decision evaluation, job lifecycle, user/identity management, batch operations, variables, deployments, signals, messages, timers, multi-tenancy, or authorization. Also when modifying or revi

What this skill tells your AI

The instructions your AI receives, as published by camunda/camunda in .claude/skills/engine-expert/SKILL.md and read by ahel’s review.

Reference for making changes to the Zeebe workflow engine with confidence. The engine processes thousands of commands per second on a single thread, state is rebuilt from the log on every restart, and partitions communicate over an unreliable network. Mistakes here cause leader/follower divergence, upgrade-path breakage, or production performance regressions. This skill exists to prevent the well-known classes of mistake.

Iron rules

These are summaries. The reference files (linked below) are authoritative — they carry the rationale, exceptions, and worked examples.

  • No state mutation from processors. State changes only through events applied by event appliers.
  • Released event appliers — and any method on a Mutable*State interface or anything transitively called from an applier — must not change in logic. Add a new version/method instead. Cosmetic changes (formatting, imports, comments, behavior-equivalent renames) are fine. No golden file protects state class methods — extra care required.
  • New event applier versions must reach every newer minor before its initial release. A version that ships only in an older minor's patch breaks upgrade replay — dead partitions, unrecoverable without an ad-hoc patch. See event-appliers.md.
  • Processors must end the command's processing by appending an event or a rejection. Exceptions are a last-resort rollback mechanism and are expensive — prefer pre-validation.
  • Generated keys must be used as the record key of at least one appended record. Otherwise the key generator can't be rehydrated on replay and may hand out a duplicate.
  • Inter-partition command receivers must be idempotent. Prefer reject-redundant-command over re-emitting events.
  • Hot paths log at trace level only. INFO/DEBUG on a hot path is a performance regression at engine throughput.
  • Values returned from ColumnFamily.get(...) / state reads are backed by a shared, mutable buffer reused on the next read of the same column family. Never cache them or hold them across another read — copyFrom(...) if you need to keep the value, or use get(key, valueSupplier) to allocate a fresh instance.
  • Non-transactional side effects (metrics, post-commit hooks) run only after all state and follow-up command writes that could throw. Exceptions roll back state, but already-executed side effects don't roll back — counters drift.
  • No unbounded recursion unless documented why it's safe. Especially for process trees, call activities, and other user-provided input. A StackOverflowError would ban the executing instance. Bound recursion or use iteration/trampolining.

Where to read next

If you are…Read
Designing or extending a record value type, intent, or ValueTyperecords.md
Editing or creating a processor, behavior class, validation, or rejectionprocessors.md
Editing or creating an event applier, a Mutable*State interface method, or anything called from an applierevent-appliers.md
Writing or modifying engine teststesting.md
Working with authorization resource types or permission types (which enum to use in which layer)authz-enums.md

Local checks before commit

Run only the tests relevant to your change — running the full engine test suite locally takes a long time and is what CI is for.

# 1. Format (mandatory before commit when touching Java/markdown/pom.xml).
./mvnw license:format spotless:apply -T1C

# 2. Tests scoped to your change (single class or small pattern). Use
#    -Dtest=YourTest, comma-separated classes, or a glob like '*UserTest*'.
./mvnw verify -pl zeebe/engine \
  -Dtest='YourTest' -DskipTests=false -DskipITs -Dquickly

# 3. If you touched an event applier, a Mutable*State method, or anything
#    transitively called from an applier — also run the golden file check.
./mvnw verify -pl zeebe/engine -Dtest=NoChangesTest \
  -DskipTests=false -DskipITs -Dquickly

Re-run any new or modified test at least 3× to catch flakiness. Push and let CI run the comprehensive suite.

Recommended workflow for new processor logic

  1. Write the test first, using EngineRule and RecordingExporter against appended records (see testing.md). Run it — confirm it fails.
  2. Implement the processor (and its event applier + state changes).
  3. Re-run the test 3+ times. Then run the local checks block above.

Canonical docs

Signals

GitHub stars
4k
Forks
818
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
engine-expert
Source
github.com/camunda/camunda