AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Camunda Ai Agents

skill-camunda-skills-camunda-ai-agents · by camunda

|

No reviews yet
0 installs
39 views
0.0% view→install

Install

$ agentstack add skill-camunda-skills-camunda-ai-agents

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-camunda-skills-camunda-ai-agents)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Camunda Ai Agents? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Camunda AI Agent

Build agentic AI processes in Camunda 8.8+: an LLM driver (the AI Agent connector, Sub-process variant) applied to an ad-hoc subprocess with tools modeled as BPMN activities. Covers shape, prompts, tool modeling with fromAi(), sub-flow tools, and multi-turn agent context.

The older Task variant (AI Agent connector on a service task paired with an external multi-instance ad-hoc subprocess and explicit feedback loop) is documented in [references/ai-agent-task.md](references/ai-agent-task.md) for the niche cases where you need to audit or intercept every tool call. The Sub-process variant is the recommended choice for everything else, and is what the rest of this skill teaches.

Prerequisites

  • Camunda 8.8+ cluster (the AI Agent connector ships in 8.8+)
  • c8ctl CLI installed and a profile configured — see camunda-c8ctl
  • An API key for the model provider you'll use (Anthropic, Amazon Bedrock, Azure OpenAI, Google Vertex AI, OpenAI, or any OpenAI-compatible provider). Store it as a Camunda cluster secret, never in the BPMN file. For local c8run, see camunda-c8ctl for the secrets bootstrap flow.

Cross-References

  • camunda-bpmn: BPMN basics, ad-hoc subprocess element, namespaces, the mandatory lint loop.
  • camunda-connectors: The underlying c8ctl element-template workflow used to apply the AI Agent template (and the REST connector commonly used as a tool).
  • camunda-feel: FEEL syntax for prompts, fromAi() calls, result expressions, type coercion.
  • camunda-process-mgmt: Deploying the process, starting an instance, inspecting incidents from agent invocations.

Authoritative References

Applying the AI Agent Connector

Example — apply the template via c8ctl rather than hand-writing the many provider/prompt/memory fields:

# 0. One-time per environment: sync the OOTB catalog. search,
#    get-properties, and OOTB-ID apply need this to have run at
#    least once. Skip on subsequent runs.
c8ctl element-template sync

# 1. Find the current template ID and version — they evolve
c8ctl element-template search "ai agent"

# 2. Inspect the properties you care about
c8ctl element-template get-properties 
c8ctl element-template get-properties  --detailed data.systemPrompt.prompt

# 3. Apply to your ad-hoc subprocess element
c8ctl element-template apply -i  AgentTools process.bpmn \
  --set provider.type=anthropic \
  --set provider.anthropic.authentication.apiKey='{{secrets.ANTHROPIC_API_KEY}}' \
  --set provider.anthropic.model.model=claude-sonnet-4-5 \
  --set data.systemPrompt.prompt='="You are a customer support agent. Use the available tools to look up customers and orders, and escalate to a human only when needed."' \
  --set data.userPrompt.prompt='="Customer " + customerId + " reports: " + issue' \
  --set data.limits.maxModelCalls='=10'

The template handles zeebe:taskDefinition, the zeebe:adHoc collection bindings, default input mappings, and the model-provider-specific fields — they change across template versions, don't hand-code them.

Supported providers: anthropic, bedrock, azure-openai, vertex-ai, openai, plus OpenAI-compatible (custom endpoint).

The BPMN Shape

The host is bpmn:adHocSubProcess — not a service task and not a regular sub-process. Tools live inside it.

bpmn:adHocSubProcess  (template applied here)
└── 
    bpmn:serviceTask   — e.g., REST connector call
    bpmn:scriptTask    — FEEL computation
    bpmn:userTask      — human-in-the-loop
    bpmn:subProcess    — multi-step or async tool

Hard rules that the lint loop does NOT catch — verify by reading the BPMN:

  • The element type must be bpmn:adHocSubProcess. A regular bpmn:subProcess or a service task will not host the connector.
  • A tool's root node is the entry activity that the LLM picks. A root node has no incoming sequence flow and is not a boundary event. An incoming flow turns the node into a regular flow step and the agent never sees it.
  • The ad-hoc subprocess must contain at least one activity — BPMN semantics; an empty agent is rejected.
  • Somewhere in the tool's execution flow, the variable toolCallResult must be set — for a single-activity tool that's the activity itself; for a sub-flow tool, it can be any activity inside the sub-flow.

Defining Tools

Three things determine whether the LLM picks a tool correctly:

  1. Tool name — the activity ID in the ad-hoc subprocess (e.g., LookupCustomer, GetCurrentWeather). The connector uses the BPMN id, not the human-facing name attribute, as the tool name passed to the LLM. Pick descriptive IDs.
  1. Tool description — the value of ` on the activity. If documentation is missing, the connector falls back to the activity's name` attribute, but always set documentation explicitly. Strong descriptions say what the tool does, when to use it, when not to, and what it returns:

> "Look up a customer by ID. Returns the customer's name, tier, and account status. Call this when the user mentions a customer ID or name. Do not call for anonymous queries."

The LLM sees the description verbatim — keep it free of vendor names, internal URLs, or anything you wouldn't want quoted back. c8ctl element-template apply does not write ``; hand-edit it in after applying a tool connector template.

  1. Input schema — derived automatically from fromAi() calls inside the activity's input mappings. No fromAi() calls → empty schema → the LLM can't pass parameters.

A tool can be a single activity (service task, script task, user task) or a sub-flow rooted at a bpmn:subProcess containing further activities. In both cases the LLM only sees the root node — descriptions, inputs, and schema are read from there. The internal sub-flow steps are invisible to the LLM; they execute in sequence per normal BPMN semantics and propagate variables up when the sub-process completes.

Worked XML for each of the four shapes (REST, script, user task, sub-flow) is in [references/tool-modeling.md](references/tool-modeling.md).

fromAi() — Declaring AI-Generated Parameters

fromAi() tags a value as "the LLM will provide this at runtime". The first argument must be a reference to toolCall. — the last segment becomes the LLM-visible parameter name. The function takes an optional description, type ("string" default, plus "number", "boolean", "array", "object"), a JSON-Schema fragment, and an options context for things like {required: false}.

Full signature, all 6 calling variants (positional, named, enum schemas, optional params, multi-call JSON bodies) in [references/fromai.md](references/fromai.md).

toolCallResult — Returning Output to the Agent

When a tool completes, the connector reads the variable named toolCallResult from the tool's scope and forwards it to the LLM as the tool-call response. The rule is about scope, not which activity sets it:

  • Single-activity tool — the activity itself sets toolCallResult (via a result expression / result variable / output mapping / script result variable).
  • Sub-flow tool — any activity inside the sub-flow can set toolCallResult; BPMN variable scoping propagates the value to the sub-process scope when it completes.

Ways to set it depending on the activity type:

  • Connector with result expression: value="={toolCallResult: response.body}".
  • Connector with result variable: name the result variable toolCallResult.
  • Output mapping: ``.
  • Script task: ``.

The value can be primitive (string, number) or a complex FEEL context — it'll be serialized to JSON before being sent to the LLM. If toolCallResult is missing or empty when the tool completes, the connector sends a generic "tool succeeded without returning a result" message to the LLM and the next turn degrades. Always set it meaningfully.

Prompts

Both data.systemPrompt.prompt and data.userPrompt.prompt are FEEL strings — they start with =.

  • Static prompt: ="You are ...". The = is mandatory even for plain text.
  • Variable interpolation: ="Customer " + customerId + " reports: " + issue. + coerces scalars to string.
  • Feedback-loop prompt: =if (is defined(followUpInput)) then followUpInput else initialUserInput. Used when looping back into the agent with user follow-up — see "Response Interaction" below.

For long, structured prompts, build the string in a script task upstream and pass it in via a variable.

Tool-Call Feedback Loop

The tool feedback loop is internal: the agent job worker repeatedly calls the LLM, activates the tools it chose, collects results, and re-prompts until the LLM produces a final response or data.limits.maxModelCalls is reached. You don't model the loop — only the tools.

Reading the Agent Response

The agent writes its output to a single context variable named by the connector's Result Variable field — default agent. With multiple agents in the same process, give each a unique result variable name (e.g. mySecondAgent) and re-align the agent-context input field accordingly (mySecondAgent.context) to avoid interference between agents.

Which fields the result context contains depends on the response settings (examples below use the default agent):

  • agent.responseText — when data.response.format.type=text (the default).
  • agent.responseJson — when format=json, or when format=text with data.response.parseJson=true.
  • agent.context — when data.response.includeAgentContext=true. Needed for the Response Interaction pattern below.

Provider × format=json compat. Only OpenAI and Google Vertex AI support data.response.format.type=json natively. For Anthropic, Amazon Bedrock, Azure OpenAI, and OpenAI-compatible providers, use format=text + parseJson=true and read agent.responseJson.

Schema is a FEEL context literal. When format=json, data.response.format.schema is feel: required — write it as ={ type: "object", properties: { ... } }, not a quoted JSON string.

When JSON parsing fails. Behavior differs between the two paths: parseJson=true on format=text omits responseJson and still populates responseText with the raw (unparseable) text — no incident. Native format=json raises an incident with error code FAILED_TO_PARSE_RESPONSE_CONTENT; handle it with an error boundary event if you need graceful fallback.

Response Interaction (User Feedback Loop)

After the agent produces its final response, you may want a user (or another agent acting as a judge) to review or amend it and bounce it back in. The pattern is to route from the ad-hoc subprocess to a user task that collects followUpInput, then back to the same agent ad-hoc subprocess. The user-prompt FEEL switches between the initial and the follow-up input:

data.userPrompt.prompt = =if (is defined(followUpInput)) then followUpInput else initialUserInput

The agent preserves conversation context across re-entries; see the Sub-process docs for the current context-handling field names, since these have evolved across template versions.

Limits and Memory

  • data.limits.maxModelCalls — caps the number of LLM calls per agent execution. Always set it (5–20 is a typical starting range); without a sensible cap a misbehaving prompt can rack up cost. There is no time-based limit.
  • data.memory.contextWindowSize — caps how many prior messages the agent replays to the LLM (default 20). Smaller saves tokens, larger preserves more context.
  • data.memory.storage.typein-process (default), camunda-document (offload to the Camunda Document store when context grows past variable size limits), or custom. Use the hyphenated form.

Troubleshooting

Non-obvious failure modes the lint loop will not catch.

  • Tool has an incoming sequence flow — it stops being a tool and becomes a regular flow step. The tool's ROOT node must have no incoming flow. Internal activities inside a sub-flow tool can (and do) have incoming flows — that's how the sub-flow works.
  • Tool name confusion — the LLM-visible tool name is the BPMN id, not the name attribute. Use descriptive PascalCase IDs.
  • Bare-string prompts — both system and user prompts are FEEL. Even literals must be ="...".
  • Number-in-string FEEL — concatenating a number into a URL or message requires string(x); + between a string and an un-coerced number fails. Cross-ref camunda-feel § type coercion.
  • Hyphenated memory storage typein-process, camunda-document, custom. Not camelCase.

Closing Step

Run the BPMN lint loop (see camunda-bpmn) before declaring the agent process done:

c8ctl bpmn lint process.bpmn

Lint catches structural BPMN problems but does not validate connector-template inputs. After lint is clean, verify by reading the BPMN:

  • Host element is bpmn:adHocSubProcess with the AI Agent template applied.
  • Every tool's root node has no incoming sequence flow and has a ` element (apply` doesn't write it — set it via a direct edit).
  • Every tool's flow ends with toolCallResult set in scope.
  • Both prompts start with =.
  • data.limits.maxModelCalls is set.
  • API keys are pulled from {{secrets.*}}, not literal values.

References

For detailed reference material, read from references/:

  • [tool-modeling.md](references/tool-modeling.md) — worked XML for the four tool shapes (REST connector, script task, user task, sub-flow), including async-callback sub-flows
  • [fromai.md](references/fromai.md) — full fromAi() signature, all calling variants (positional, named, enum schemas, optional params, multi-call JSON bodies)
  • [ai-agent-task.md](references/ai-agent-task.md) — the older Task variant (audit/intercept every tool call) — niche use only

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.