Inline Script Editing
The BPMN Modeler extension lets you edit inline scripts on bpmn:ScriptTask, camunda:ExecutionListener, and camunda:TaskListener elements in real VS Code editor tabs — with syntax highlighting, IntelliSense for the Camunda 7 script API, and full access to your favourite editor features (multi-cursor, snippets, AI assistants).
The script body is not written to disk: each script lives in a virtual in-memory document under the bpmn-script:// URI scheme. Edits are streamed back into the BPMN model as you type, and the BPMN file becomes dirty just like any other modeler change.
Supported Languages
scriptFormat (BPMN) | Language in VS Code | File extension on the tab |
|---|---|---|
javascript | JavaScript | .js |
groovy | Groovy | .groovy |
python | Python | .py |
ruby | Ruby | .rb |
If a script element has no scriptFormat set — or uses one this extension does not recognise — VS Code shows a Quick Pick the first time you open the script so you can choose one of the supported languages. The choice is written back into the BPMN model so subsequent opens skip the prompt.
Usage
There are three entry points. They all open the same kind of editor tab beside the diagram.
1. Script Task — Context Pad
- Select a Script Task on the canvas.
- Click the VS Code icon in the context pad next to the trash bin.
- The script opens in a new editor tab beside the diagram.
2. Script Task — Properties Panel
- Select a Script Task on the canvas.
- Open the Script group in the properties panel on the right.
- Click the VS Code icon in the Script group header.
3. Execution & Task Listeners — Properties Panel
- Select any flow node (e.g. a Service Task or User Task).
- Open Execution Listeners or Task Listeners in the properties panel.
- Each listener row shows a VS Code icon button next to its title — click it to edit that listener's script.
The icon is always shown, even when the listener currently uses Java class, expression, delegate expression, or external-resource script implementation. Clicking it converts the listener to an inline <camunda:script> in a single undoable step before opening the editor.
Heads up: converting a listener replaces its previous implementation (e.g. a Java class reference) with an empty inline script. Press Cmd/Ctrl+Z on the diagram to revert if you opened the editor by mistake.
What the Editor Tab Looks Like
The tab opens in a side group beside the diagram so you can see both at once. Tab titles are derived from the element id and the script kind, so two listeners on the same task do not collide:
| Surface | Tab title |
|---|---|
Script task Task_1 | Task_1.js |
Execution listener start on Task_1 | Task_1.execution-start.js |
Second start execution listener on Task_1 | Task_1.execution-start-1.js |
Task listener create on UserTask_1 | UserTask_1.task-create.js |
Live Edits
- Every keystroke in the script editor is pushed back into the BPMN model immediately — there is no save step.
- Pressing Cmd/Ctrl+S on the script tab is a no-op (the virtual file lives in memory). Save the BPMN file to persist your script changes to disk.
- Closing the script tab discards the in-memory virtual document but does not revert the script in the model — the bytes you typed are already part of the diagram.
- Switching the BPMN tab away while you keep typing is safe: the changes are buffered and replayed when you switch back to the diagram.
IntelliSense
Each supported language gets context-aware completions for the Camunda 7 script API. The available beans depend on where the script lives:
| Script kind | Beans available as completions |
|---|---|
| Script task | execution |
| Execution listener | execution, eventName |
| Task listener | execution, task, eventName |
Typing a bean name plus . triggers a list of methods with parameter hints; typing at the start of a line offers the bean names that are in scope.
Process-variable completions
Inside a getVariable("…") / setVariable("…") string argument — and at the start of a line — you also get completions for the process variables the modeler discovered in the diagram. These are inferred heuristically from input/output mappings, form fields, result variables, call-activity mappings, and setVariable(…) / ${…} occurrences.
Declaring variables with a *.bpmn.vars.json manifest
Heuristic discovery cannot see variables injected from outside the model (a REST start payload, a correlated message, a parent process), and it cannot carry author-supplied types or documentation. To declare those explicitly, add a manifest named after the diagram with a .vars.json suffix under the config folder's vars/ subfolder, mirroring the diagram's workspace-relative path (the same convention as element-templates and code-link):
order-process.bpmn
.camunda/vars/order-process.bpmn.vars.jsonA diagram in a subfolder mirrors that path too — src/order-process.bpmn → .camunda/vars/src/order-process.bpmn.vars.json — so two same-named diagrams in different folders don't collide. The config folder defaults to .camunda and is overridable via miragon.bpmnModeler.configFolder.
{
"variables": [
{ "name": "orderId", "type": "String", "description": "Set by the REST start request" },
{ "name": "amount", "type": "Long" },
{ "name": "approved" }
]
}nameis required;typeanddescriptionare optional.- The
descriptionis shown in the completion documentation popup. - Manifest entries merge with the discovered variables and win on a name clash, so a declared
typeoverrides whatever the heuristic guessed. - The manifest is watched: edits, creation, and deletion update completion live while the script editor is open. A malformed manifest is ignored (it never breaks completion for the rest of the diagram).
- A bundled JSON Schema is associated with every
*.bpmn.vars.jsonfile, so editing one gives you completion, hover docs, and validation (e.g. a missingnameor a misspelled key is flagged) in both VS Code and the standalone IntelliJ-based app — no$schemaline needed.
Declare from the script — the 💡 lightbulb
You don't have to create the manifest by hand. When you reference a variable the model doesn't know, put the caret on it and open the quick-fix menu (💡, or Ctrl/Cmd+.): "Declare '<name>' in variable manifest" appends a name-only entry to the diagram's manifest and opens that file so you can fill in the type and description. The new variable then appears in completion as an authored entry immediately, since the manifest is watched. The same action is available in the standalone IntelliJ-based app via Alt+Enter on a Groovy script tab.
Pair with an AI Assistant
Because the script editor is a real VS Code document, AI assistants that operate on the active editor buffer work the same as in any other file. This is one of the biggest practical reasons to edit your scripts here instead of in the properties-panel textarea — you get the full AI-pair-programming experience on a single line of glue code.
Two flavours of AI feature work out of the box:
- Ghost-text completions (e.g. GitHub Copilot, Cursor Tab) — multi-line suggestions appear inline as you type, the same as in any other tab.
- Inline chat / inline edit (e.g. GitHub Copilot Chat — Cmd+I) — opens a chat input directly inside the editor. Describe the change you want in natural language, accept the diff, and your BPMN file is dirty the moment the new bytes land.
Typical Workflow
- Open the script via the context pad or one of the properties-panel buttons.
- Hit your AI extension's inline-chat keybinding (most use Cmd+I / Ctrl+I).
- Describe the change in natural language, e.g. "Set a process variable
customerEmailfrom the user task's assignee." or "Wrap this in try/catch and log errors viaexecution.setVariable." - Accept the suggestion. The script updates in the editor, the BPMN file becomes dirty, and you can save the diagram to persist the change.
What does not work: AI tools that read files from disk — including Claude Code's
@file reference and other terminal-based assistants — cannot see the script body, because the virtual document lives only in memory. Stick to extensions that operate on the active editor buffer.
Tips
- Multiple scripts at once. Open as many script tabs as you like, on the same element or across elements. They all stream back into the BPMN model independently.
- Close tabs you don't need. When you close a script tab, re-opening it loads the latest content from the BPMN model. This is the cleanest way to discard a stale buffer if you ever suspect drift.
For implementation details, see Contributing → Inline Scripting internals.