@nanobpm/nano-workforce 0.60.0 → 0.61.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/nano.app.json CHANGED
@@ -6,13 +6,11 @@
6
6
  "codename": "nano-workforce",
7
7
  "models": {
8
8
  "processes": [
9
- "resources/processes/*.bpmn"
9
+ "resources/processes/*.bpmn",
10
+ "prompts/*.md"
10
11
  ],
11
12
  "forms": [
12
13
  "resources/forms/*.form"
13
- ],
14
- "templates": [
15
- "prompts/*.md"
16
14
  ]
17
15
  },
18
16
  "data": {
@@ -134,6 +132,10 @@
134
132
  "taskType": "pr.record-feature",
135
133
  "handler": "workers/record-feature/worker.ts"
136
134
  },
135
+ {
136
+ "taskType": "pr.record-blocked-ack",
137
+ "handler": "workers/record-blocked-ack/worker.ts"
138
+ },
137
139
  {
138
140
  "taskType": "pr.converge-feature",
139
141
  "handler": "workers/converge-feature/worker.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.60.0",
3
+ "version": "0.61.1",
4
4
  "description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
5
5
  "type": "module",
6
6
  "main": "main.ts",
@@ -59,11 +59,11 @@
59
59
  "source": "app",
60
60
  "table": "feature_runs",
61
61
  "orderBy": { "field": "updated_at", "dir": "desc" },
62
- "filter": [{ "field": "status", "in": ["running"] }]
62
+ "filter": [{ "field": "status", "in": ["running", "awaiting_operator"] }]
63
63
  },
64
64
  "tabs": [
65
- { "label": "Active", "filter": [{ "field": "status", "in": ["running"] }] },
66
- { "label": "History", "filter": [{ "field": "status", "in": ["opened", "converging", "blocked", "skipped", "failed", "abandoned"] }] },
65
+ { "label": "Active", "filter": [{ "field": "status", "in": ["running", "awaiting_operator"] }] },
66
+ { "label": "History", "filter": [{ "field": "status", "in": ["opened", "converging", "merged", "converged", "blocked", "skipped", "failed", "abandoned"] }] },
67
67
  { "label": "All", "filter": [] }
68
68
  ],
69
69
  "columns": [
@@ -71,6 +71,7 @@
71
71
  { "field": "status", "header": "Status", "link": { "kind": "processExplorer", "keyField": "process_key" } },
72
72
  { "field": "base_branch", "header": "Base branch" },
73
73
  { "field": "pr_key", "header": "PR", "link": { "kind": "page", "page": "home", "keyField": "pr_key" } },
74
+ { "field": "delivery_label", "header": "Delivery" },
74
75
  { "field": "converge", "header": "Converge" },
75
76
  { "field": "auto_merge", "header": "Auto-merge" },
76
77
  { "field": "outcome", "header": "Outcome" },
@@ -309,9 +309,17 @@ both live in the source repo, not in the job payload.
309
309
  sequence flows) for the element it is parked on (§5).
310
310
  - **Prompts (agent base instructions):** `prompts/*.md` — `review-round.md`,
311
311
  `plan.md`, `feature.md`, `fix-ci.md`, `rebase.md`, `trial-merge.md`, etc. An
312
- agent's base prompt is **not** a job variable: it is delivered as a model
313
- **template header** (`{{review-round}}`, `{{plan}}`, …) substituted from these files
314
- at deploy time. If an agent misbehaves systematically, the prompt is the first thing
312
+ agent's base prompt is **not** a job variable: it is delivered as a
313
+ **linked resource** (likewise `plan.md`, …):
314
+
315
+ ```xml
316
+ <zeebe:linkedResource resourceId="review-round.md" bindingType="latest" linkName="prompt"/>
317
+ ```
318
+
319
+ that the engine
320
+ resolves to the latest deployed prompt at job activation. Because the binding is
321
+ `latest`, redeploying one of these files updates the prompt mid-epic without a process
322
+ redeploy. If an agent misbehaves systematically, the prompt is the first thing
315
323
  to inspect/fix.
316
324
  - **Job contract:** `senior:pr-review` receives `{ prUrl, repo, prNumber, round,
317
325
  answer? }` and must return a flat result `{ status, summary, question? }` with
@@ -0,0 +1,17 @@
1
+ {
2
+ "id": "feature-blocked",
3
+ "schemaVersion": 18,
4
+ "type": "default",
5
+ "components": [
6
+ {
7
+ "type": "text",
8
+ "text": "This single-issue feature run is **blocked** — the implementation agent could not open a PR (it gave up, or the escalation was abandoned / timed out). It landed in your inbox so a blocked run is never a silent dead-end. Review the outcome, then acknowledge to close the run.",
9
+ "label": "Blocked feature run"
10
+ },
11
+ {
12
+ "type": "textarea",
13
+ "key": "note",
14
+ "label": "Disposition note (what you did / why — recorded on the run)"
15
+ }
16
+ ]
17
+ }
@@ -67,9 +67,9 @@
67
67
  <bpmn:serviceTask id="review-round" name="Review round (agent)">
68
68
  <bpmn:extensionElements>
69
69
  <zeebe:taskDefinition type="senior:pr-review" />
70
- <zeebe:taskHeaders>
71
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{review-round}}" />
72
- </zeebe:taskHeaders>
70
+ <zeebe:linkedResources>
71
+ <zeebe:linkedResource resourceId="review-round.md" bindingType="latest" linkName="prompt" />
72
+ </zeebe:linkedResources>
73
73
  <zeebe:properties>
74
74
  <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrReviewRoundIn" />
75
75
  <zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrReviewRoundOut" />
@@ -18,9 +18,9 @@
18
18
  <bpmn:serviceTask id="implement-task" name="Implement (agent)">
19
19
  <bpmn:extensionElements>
20
20
  <zeebe:taskDefinition type="senior:feature" />
21
- <zeebe:taskHeaders>
22
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{feature}}" />
23
- </zeebe:taskHeaders>
21
+ <zeebe:linkedResources>
22
+ <zeebe:linkedResource resourceId="feature.md" bindingType="latest" linkName="prompt" />
23
+ </zeebe:linkedResources>
24
24
  <zeebe:ioMapping>
25
25
  <zeebe:input source="=&#34;&#10;&#10;---&#10;&#10;&#34; + task.prompt + (if (baseBranchBrief = null) then &#34;&#34; else baseBranchBrief)" target="appendPrompt" />
26
26
  <zeebe:output source="=status" target="status" />
@@ -63,10 +63,35 @@
63
63
  <bpmn:incoming>w_done</bpmn:incoming>
64
64
  <bpmn:incoming>w_abandon</bpmn:incoming>
65
65
  <bpmn:incoming>w_sla</bpmn:incoming>
66
- <bpmn:outgoing>f_toConvergeGw</bpmn:outgoing>
66
+ <bpmn:outgoing>f_toBlockedGw</bpmn:outgoing>
67
+ </bpmn:serviceTask>
68
+ <bpmn:exclusiveGateway id="gw-blocked" name="blocked?" default="f_notBlocked">
69
+ <bpmn:incoming>f_toBlockedGw</bpmn:incoming>
70
+ <bpmn:outgoing>f_blocked</bpmn:outgoing>
71
+ <bpmn:outgoing>f_notBlocked</bpmn:outgoing>
72
+ </bpmn:exclusiveGateway>
73
+ <bpmn:userTask id="feature-blocked" name="Blocked run (human)">
74
+ <bpmn:extensionElements>
75
+ <zeebe:formDefinition formId="feature-blocked" />
76
+ <zeebe:userTask />
77
+ <zeebe:assignmentDefinition candidateGroups="operators" />
78
+ </bpmn:extensionElements>
79
+ <bpmn:incoming>f_blocked</bpmn:incoming>
80
+ <bpmn:outgoing>f_toBlockedAck</bpmn:outgoing>
81
+ </bpmn:userTask>
82
+ <bpmn:serviceTask id="record-blocked-ack" name="Record acknowledgement">
83
+ <bpmn:extensionElements>
84
+ <zeebe:taskDefinition type="pr.record-blocked-ack" />
85
+ <zeebe:ioMapping>
86
+ <zeebe:input source="=featureKey" target="featureKey" />
87
+ <zeebe:input source="=if (is defined(note)) then note else null" target="note" />
88
+ </zeebe:ioMapping>
89
+ </bpmn:extensionElements>
90
+ <bpmn:incoming>f_toBlockedAck</bpmn:incoming>
91
+ <bpmn:outgoing>f_blockedEnd</bpmn:outgoing>
67
92
  </bpmn:serviceTask>
68
93
  <bpmn:exclusiveGateway id="gw-converge" name="converge?" default="f_noConverge">
69
- <bpmn:incoming>f_toConvergeGw</bpmn:incoming>
94
+ <bpmn:incoming>f_notBlocked</bpmn:incoming>
70
95
  <bpmn:outgoing>f_converge</bpmn:outgoing>
71
96
  <bpmn:outgoing>f_noConverge</bpmn:outgoing>
72
97
  </bpmn:exclusiveGateway>
@@ -80,6 +105,7 @@
80
105
  <bpmn:endEvent id="End" name="Done">
81
106
  <bpmn:incoming>f_noConverge</bpmn:incoming>
82
107
  <bpmn:incoming>f_toEndConverged</bpmn:incoming>
108
+ <bpmn:incoming>f_blockedEnd</bpmn:incoming>
83
109
  </bpmn:endEvent>
84
110
  <bpmn:sequenceFlow id="f_toEnsureBase" sourceRef="Start" targetRef="ensure-base-branch" />
85
111
  <bpmn:sequenceFlow id="f_toImplement" sourceRef="ensure-base-branch" targetRef="implement-task" />
@@ -94,7 +120,13 @@
94
120
  </bpmn:sequenceFlow>
95
121
  <bpmn:sequenceFlow id="w_abandon" name="abandon" sourceRef="w_gw_answer" targetRef="record-feature" />
96
122
  <bpmn:sequenceFlow id="w_sla" name="SLA auto-abandon" sourceRef="be_feature_sla" targetRef="record-feature" />
97
- <bpmn:sequenceFlow id="f_toConvergeGw" sourceRef="record-feature" targetRef="gw-converge" />
123
+ <bpmn:sequenceFlow id="f_toBlockedGw" sourceRef="record-feature" targetRef="gw-blocked" />
124
+ <bpmn:sequenceFlow id="f_blocked" name="blocked" sourceRef="gw-blocked" targetRef="feature-blocked">
125
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=featureStatus = "blocked"</bpmn:conditionExpression>
126
+ </bpmn:sequenceFlow>
127
+ <bpmn:sequenceFlow id="f_notBlocked" name="not blocked" sourceRef="gw-blocked" targetRef="gw-converge" />
128
+ <bpmn:sequenceFlow id="f_toBlockedAck" sourceRef="feature-blocked" targetRef="record-blocked-ack" />
129
+ <bpmn:sequenceFlow id="f_blockedEnd" sourceRef="record-blocked-ack" targetRef="End" />
98
130
  <bpmn:sequenceFlow id="f_converge" name="converge" sourceRef="gw-converge" targetRef="converge">
99
131
  <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=converge = true and featureStatus = "opened" and prKey != null</bpmn:conditionExpression>
100
132
  </bpmn:sequenceFlow>
@@ -133,19 +165,31 @@
133
165
  <bpmndi:BPMNShape id="BPMNShape_record-feature" bpmnElement="record-feature">
134
166
  <dc:Bounds x="1116" y="80" width="100" height="80" />
135
167
  </bpmndi:BPMNShape>
136
- <bpmndi:BPMNShape id="BPMNShape_gw-converge" bpmnElement="gw-converge" isMarkerVisible="true">
168
+ <bpmndi:BPMNShape id="BPMNShape_gw-blocked" bpmnElement="gw-blocked" isMarkerVisible="true">
137
169
  <dc:Bounds x="1316" y="95" width="50" height="50" />
138
170
  <bpmndi:BPMNLabel>
139
- <dc:Bounds x="1308" y="76" width="67" height="14" />
171
+ <dc:Bounds x="1311" y="76" width="60" height="14" />
172
+ </bpmndi:BPMNLabel>
173
+ </bpmndi:BPMNShape>
174
+ <bpmndi:BPMNShape id="BPMNShape_feature-blocked" bpmnElement="feature-blocked">
175
+ <dc:Bounds x="1466" y="400" width="100" height="80" />
176
+ </bpmndi:BPMNShape>
177
+ <bpmndi:BPMNShape id="BPMNShape_record-blocked-ack" bpmnElement="record-blocked-ack">
178
+ <dc:Bounds x="1666" y="400" width="100" height="80" />
179
+ </bpmndi:BPMNShape>
180
+ <bpmndi:BPMNShape id="BPMNShape_gw-converge" bpmnElement="gw-converge" isMarkerVisible="true">
181
+ <dc:Bounds x="1491" y="95" width="50" height="50" />
182
+ <bpmndi:BPMNLabel>
183
+ <dc:Bounds x="1483" y="76" width="67" height="14" />
140
184
  </bpmndi:BPMNLabel>
141
185
  </bpmndi:BPMNShape>
142
186
  <bpmndi:BPMNShape id="BPMNShape_converge" bpmnElement="converge">
143
- <dc:Bounds x="1466" y="240" width="100" height="80" />
187
+ <dc:Bounds x="1666" y="240" width="100" height="80" />
144
188
  </bpmndi:BPMNShape>
145
189
  <bpmndi:BPMNShape id="BPMNShape_End" bpmnElement="End">
146
- <dc:Bounds x="1666" y="102" width="36" height="36" />
190
+ <dc:Bounds x="1866" y="102" width="36" height="36" />
147
191
  <bpmndi:BPMNLabel>
148
- <dc:Bounds x="1667" y="83" width="34" height="14" />
192
+ <dc:Bounds x="1867" y="83" width="34" height="14" />
149
193
  </bpmndi:BPMNLabel>
150
194
  </bpmndi:BPMNShape>
151
195
  <bpmndi:BPMNShape id="BPMNShape_be_feature_sla" bpmnElement="be_feature_sla">
@@ -173,15 +217,22 @@
173
217
  <dc:Bounds x="875" y="98" width="32" height="14" />
174
218
  </bpmndi:BPMNLabel>
175
219
  </bpmndi:BPMNEdge>
176
- <bpmndi:BPMNEdge id="BPMNEdge_f_toConvergeGw" bpmnElement="f_toConvergeGw">
220
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toBlockedGw" bpmnElement="f_toBlockedGw">
177
221
  <di:waypoint x="1216" y="120" />
178
222
  <di:waypoint x="1316" y="120" />
179
223
  </bpmndi:BPMNEdge>
180
- <bpmndi:BPMNEdge id="BPMNEdge_f_noConverge" bpmnElement="f_noConverge">
224
+ <bpmndi:BPMNEdge id="BPMNEdge_f_notBlocked" bpmnElement="f_notBlocked">
181
225
  <di:waypoint x="1366" y="120" />
182
- <di:waypoint x="1666" y="120" />
226
+ <di:waypoint x="1491" y="120" />
227
+ <bpmndi:BPMNLabel>
228
+ <dc:Bounds x="1390" y="98" width="78" height="14" />
229
+ </bpmndi:BPMNLabel>
230
+ </bpmndi:BPMNEdge>
231
+ <bpmndi:BPMNEdge id="BPMNEdge_f_noConverge" bpmnElement="f_noConverge">
232
+ <di:waypoint x="1541" y="120" />
233
+ <di:waypoint x="1866" y="120" />
183
234
  <bpmndi:BPMNLabel>
184
- <dc:Bounds x="1481" y="98" width="71" height="14" />
235
+ <dc:Bounds x="1668" y="98" width="71" height="14" />
185
236
  </bpmndi:BPMNLabel>
186
237
  </bpmndi:BPMNEdge>
187
238
  <bpmndi:BPMNEdge id="BPMNEdge_w_abandon" bpmnElement="w_abandon">
@@ -200,22 +251,39 @@
200
251
  <dc:Bounds x="646" y="206" width="67" height="14" />
201
252
  </bpmndi:BPMNLabel>
202
253
  </bpmndi:BPMNEdge>
203
- <bpmndi:BPMNEdge id="BPMNEdge_f_converge" bpmnElement="f_converge">
254
+ <bpmndi:BPMNEdge id="BPMNEdge_f_blocked" bpmnElement="f_blocked">
204
255
  <di:waypoint x="1341" y="145" />
205
- <di:waypoint x="1341" y="280" />
206
- <di:waypoint x="1466" y="280" />
256
+ <di:waypoint x="1341" y="440" />
257
+ <di:waypoint x="1466" y="440" />
207
258
  <bpmndi:BPMNLabel>
208
- <dc:Bounds x="1346" y="206" width="60" height="14" />
259
+ <dc:Bounds x="1346" y="286" width="53" height="14" />
260
+ </bpmndi:BPMNLabel>
261
+ </bpmndi:BPMNEdge>
262
+ <bpmndi:BPMNEdge id="BPMNEdge_f_converge" bpmnElement="f_converge">
263
+ <di:waypoint x="1516" y="145" />
264
+ <di:waypoint x="1516" y="280" />
265
+ <di:waypoint x="1666" y="280" />
266
+ <bpmndi:BPMNLabel>
267
+ <dc:Bounds x="1521" y="206" width="60" height="14" />
209
268
  </bpmndi:BPMNLabel>
210
269
  </bpmndi:BPMNEdge>
211
270
  <bpmndi:BPMNEdge id="BPMNEdge_w_toAnswerGw" bpmnElement="w_toAnswerGw">
212
271
  <di:waypoint x="866" y="280" />
213
272
  <di:waypoint x="966" y="280" />
214
273
  </bpmndi:BPMNEdge>
274
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toBlockedAck" bpmnElement="f_toBlockedAck">
275
+ <di:waypoint x="1566" y="440" />
276
+ <di:waypoint x="1666" y="440" />
277
+ </bpmndi:BPMNEdge>
278
+ <bpmndi:BPMNEdge id="BPMNEdge_f_blockedEnd" bpmnElement="f_blockedEnd">
279
+ <di:waypoint x="1766" y="440" />
280
+ <di:waypoint x="1884" y="440" />
281
+ <di:waypoint x="1884" y="138" />
282
+ </bpmndi:BPMNEdge>
215
283
  <bpmndi:BPMNEdge id="BPMNEdge_f_toEndConverged" bpmnElement="f_toEndConverged">
216
- <di:waypoint x="1566" y="280" />
217
- <di:waypoint x="1684" y="280" />
218
- <di:waypoint x="1684" y="138" />
284
+ <di:waypoint x="1766" y="280" />
285
+ <di:waypoint x="1884" y="280" />
286
+ <di:waypoint x="1884" y="138" />
219
287
  </bpmndi:BPMNEdge>
220
288
  <bpmndi:BPMNEdge id="BPMNEdge_w_sla" bpmnElement="w_sla">
221
289
  <di:waypoint x="816" y="338" />
@@ -216,9 +216,9 @@
216
216
  <bpmn:serviceTask id="fix-ci" name="Fix CI (agent)">
217
217
  <bpmn:extensionElements>
218
218
  <zeebe:taskDefinition type="senior:fix-ci" />
219
- <zeebe:taskHeaders>
220
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{fix-ci}}" />
221
- </zeebe:taskHeaders>
219
+ <zeebe:linkedResources>
220
+ <zeebe:linkedResource resourceId="fix-ci.md" bindingType="latest" linkName="prompt" />
221
+ </zeebe:linkedResources>
222
222
  <zeebe:properties>
223
223
  <zeebe:property name="io.nanobpm.dataEnvelope.in" value="FixCiIn" />
224
224
  <zeebe:property name="io.nanobpm.dataEnvelope.out" value="FixCiOut" />
@@ -246,9 +246,9 @@
246
246
  <bpmn:serviceTask id="rebase" name="Rebase (agent)">
247
247
  <bpmn:extensionElements>
248
248
  <zeebe:taskDefinition type="senior:rebase" />
249
- <zeebe:taskHeaders>
250
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{rebase}}" />
251
- </zeebe:taskHeaders>
249
+ <zeebe:linkedResources>
250
+ <zeebe:linkedResource resourceId="rebase.md" bindingType="latest" linkName="prompt" />
251
+ </zeebe:linkedResources>
252
252
  <zeebe:properties>
253
253
  <zeebe:property name="io.nanobpm.dataEnvelope.in" value="RebaseIn" />
254
254
  <zeebe:property name="io.nanobpm.dataEnvelope.out" value="RebaseOut" />
@@ -23,9 +23,9 @@
23
23
  <bpmn:serviceTask id="plan" name="Plan (agent)">
24
24
  <bpmn:extensionElements>
25
25
  <zeebe:taskDefinition type="senior:plan" />
26
- <zeebe:taskHeaders>
27
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{plan}}" />
28
- </zeebe:taskHeaders>
26
+ <zeebe:linkedResources>
27
+ <zeebe:linkedResource resourceId="plan.md" bindingType="latest" linkName="prompt" />
28
+ </zeebe:linkedResources>
29
29
  <zeebe:ioMapping>
30
30
  <zeebe:input source="=(if (planFindings = null or planFindings = &#34;&#34;) then &#34;&#34; else &#34;&#10;&#10;---&#10;&#10;A prior review REJECTED your last plan. Address every point, then re-emit the full plan:&#10;&#10;&#34; + planFindings)" target="appendPrompt" />
31
31
  </zeebe:ioMapping>
@@ -46,9 +46,9 @@
46
46
  <bpmn:serviceTask id="review-plan" name="Review plan (agent)">
47
47
  <bpmn:extensionElements>
48
48
  <zeebe:taskDefinition type="senior:plan-review" />
49
- <zeebe:taskHeaders>
50
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{plan-review}}" />
51
- </zeebe:taskHeaders>
49
+ <zeebe:linkedResources>
50
+ <zeebe:linkedResource resourceId="plan-review.md" bindingType="latest" linkName="prompt" />
51
+ </zeebe:linkedResources>
52
52
  </bpmn:extensionElements>
53
53
  <bpmn:incoming>f_toReviewPlan</bpmn:incoming>
54
54
  <bpmn:outgoing>f_toRecordPlanReview</bpmn:outgoing>
@@ -121,9 +121,9 @@
121
121
  <bpmn:serviceTask id="implement-task" name="Implement (agent)">
122
122
  <bpmn:extensionElements>
123
123
  <zeebe:taskDefinition type="senior:feature" />
124
- <zeebe:taskHeaders>
125
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{feature}}" />
126
- </zeebe:taskHeaders>
124
+ <zeebe:linkedResources>
125
+ <zeebe:linkedResource resourceId="feature.md" bindingType="latest" linkName="prompt" />
126
+ </zeebe:linkedResources>
127
127
  <zeebe:ioMapping>
128
128
  <zeebe:input source="=&#34;&#10;&#10;---&#10;&#10;&#34; + task.prompt + (if (blackboardBrief = null) then &#34;&#34; else blackboardBrief) + (if (baseBranchBrief = null) then &#34;&#34; else baseBranchBrief)" target="appendPrompt" />
129
129
  <zeebe:output source="=status" target="status" />
@@ -192,9 +192,9 @@
192
192
  <bpmn:serviceTask id="trial-merge" name="Trial merge (agent)">
193
193
  <bpmn:extensionElements>
194
194
  <zeebe:taskDefinition type="senior:trial-merge" />
195
- <zeebe:taskHeaders>
196
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{trial-merge}}" />
197
- </zeebe:taskHeaders>
195
+ <zeebe:linkedResources>
196
+ <zeebe:linkedResource resourceId="trial-merge.md" bindingType="latest" linkName="prompt" />
197
+ </zeebe:linkedResources>
198
198
  <zeebe:ioMapping>
199
199
  <zeebe:input source="=null" target="result" />
200
200
  <zeebe:input source="=null" target="conflicts" />
@@ -14,9 +14,9 @@
14
14
  <bpmn:serviceTask id="synthesize" name="Synthesize &#38; promote (agent)">
15
15
  <bpmn:extensionElements>
16
16
  <zeebe:taskDefinition type="senior:retro" />
17
- <zeebe:taskHeaders>
18
- <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{retro}}" />
19
- </zeebe:taskHeaders>
17
+ <zeebe:linkedResources>
18
+ <zeebe:linkedResource resourceId="retro.md" bindingType="latest" linkName="prompt" />
19
+ </zeebe:linkedResources>
20
20
  <zeebe:ioMapping>
21
21
  <zeebe:input source="=retroDigest" target="appendPrompt" />
22
22
  </zeebe:ioMapping>