muse-crew 0.14.8 → 0.14.9

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.
@@ -52,17 +52,24 @@ Applies to: standard, bugfix, chore.
52
52
  <a id="closeout-envelope"></a>
53
53
  ## Closeout transport envelope
54
54
 
55
- Invariant: the work agent returns the runtime's native transport envelope with no schema; the verdict is extracted mechanically by extractVerdict — never by an agent.
55
+ Invariant: the schema-less work-agent courier returns prose; the workflow
56
+ consumes the return as a plain string. Nothing parses a JSON envelope —
57
+ the prompt names none (blocker 43, 2026-09-22: the old "Return your work as
58
+ JSON in exactly this shape: {...}" invitation drew brace-shaped prose into
59
+ a channel where the runtime's JSON-candidate scan threw, and three
60
+ consecutive Integrate failures parked room #28's J1 at the retry cap; the
61
+ second REVIEW pass then reworded the retry trailer's "discarded" why off
62
+ "machine-read as JSON" to the true event — {...}-shaped fragments the scan
63
+ could not parse — since the old framing was an implicit JSON invitation).
64
+ The verdict is extracted mechanically by extractVerdict — never by an agent.
56
65
 
57
66
  Applies to: standard, bugfix, chore.
58
67
 
59
68
  ```
60
- // Work agent returns the runtime's native envelope {"status": "ok",
61
- // "result": "<prose>"} with no schema. The runtime requires JSON output;
62
- // the envelope is its own documented shape, so there is nothing for the
63
- // agent to improvise. The workflow receives the prose report as a plain
64
- // string. The verdict is still extracted deterministically from the report
65
- // text by extractVerdict below — never by an agent.
69
+ // Work agent returns prose on the schema-less courier; the workflow
70
+ // consumes the return as a plain string. The verdict is still extracted
71
+ // deterministically from the report text by extractVerdict — never by
72
+ // an agent.
66
73
  ```
67
74
 
68
75
  <a id="extract-verdict-contract"></a>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muse-crew",
3
- "version": "0.14.8",
3
+ "version": "0.14.9",
4
4
  "description": "Opinionated orchestration for Muse — workflows, identities, and tooling for autonomous software development.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -131,7 +131,7 @@ if (!taskId) {
131
131
  throw new Error("task_id is required in args");
132
132
  }
133
133
 
134
- // See docs/decisions/workflow-core.md#closeout-envelope: the work agent returns the runtime's native envelope; verdict extracted mechanically.
134
+ // See docs/decisions/workflow-core.md#closeout-envelope: the schema-less work courier returns prose, consumed as a plain string; verdict extracted mechanically.
135
135
  const VERDICT_STEPS = ["Build", "Review", "QA", "Reproduce", "Integrate", "Publish"];
136
136
  function extractVerdict(workerText) {
137
137
  // The verdict is the LAST VERDICT: PASS/FAIL in the report (contract: end
@@ -221,7 +221,6 @@ function buildVerdictReaskPrompt(stepName, workerText) {
221
221
  "Decide from the report's own content whether the " + stepName + " step clearly describes successful completion: " +
222
222
  "if it does, the verdict is PASS; otherwise — failure, error, unfinished work, or unclear — the verdict is FAIL. " +
223
223
  "Do NOT copy any VERDICT line from the report — decide from the content.\n\n" +
224
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your verdict line here\"}. " +
225
224
  "The result must be exactly one line and nothing else: VERDICT: PASS or VERDICT: FAIL.";
226
225
  }
227
226
  async function reaskVerdict(stepName, reworkSuffix, workerText) {
@@ -294,8 +293,8 @@ var TOOL_CHECK_PREAMBLE =
294
293
  "3. Run the shell command: echo tool-probe-ok - then write exactly one line: shell_transport: ok - or shell_transport: unavailable if you cannot run shell commands.\n" +
295
294
  "Then do the assignment below.\n\n";
296
295
  function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason) {
297
- // reason: "discarded" (the runtime threw the output away - it could not be
298
- // machine-read), "empty" (agent() returned without throwing but produced
296
+ // reason: "discarded" (the runtime threw the output away — the JSON-candidate
297
+ // scan found {...}-shaped fragments it could not parse), "empty" (agent() returned without throwing but produced
299
298
  // nothing usable), "no-tools" (the worker's TOOL CHECK reported
300
299
  // artifact_tools: missing), or "no-transport" (the worker's TOOL CHECK
301
300
  // reported shell_transport: unavailable).
@@ -306,11 +305,11 @@ function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason)
306
305
  ? "your previous attempt's TOOL CHECK reported artifact_tools: missing (this is a fresh launch, so run the TOOL CHECK's load step again before the work)"
307
306
  : reason === "no-transport"
308
307
  ? "your previous attempt's TOOL CHECK reported shell_transport: unavailable (this is a fresh launch, so run the TOOL CHECK's shell probe again before the work)"
309
- : "your previous attempt's output could not be machine-read as JSON and was discarded";
308
+ : "your previous attempt's output was discarded by the transport because it contained {...}-shaped fragments the transport could not parse; write plain prose with no JSON-shaped fragments";
310
309
  return "\n\nTRANSPORT RETRY (attempt " + attempt + " of 2): " + why + ". " +
311
310
  "First check existing state (worktree/branch at " + repoPath + "/.worktrees/" + taskId + ", the task branch, dashboard sessions for this task) - " +
312
311
  "if the " + stepName + " work is already complete, report on what was done rather than duplicating side effects. " +
313
- "Then return your report as JSON in exactly the shape specified above.";
312
+ "Then return your report in exactly the shape specified above.";
314
313
  }
315
314
  // parseClassifyFerry — room #26 blocker 42 (2026-09-21). Shape-constrained
316
315
  // ferry parser for the classify-branch agent() call. The schema buys SHAPE,
@@ -2172,12 +2171,12 @@ while (i < STEPS.length) {
2172
2171
  "The returned events are filtered to this task. They contain notes and decisions from prior phases.\n\n";
2173
2172
  }
2174
2173
 
2175
- // Work agent returns the runtime's native envelope {"status": "ok",
2176
- // "result": "<prose>"} with no schema. The runtime requires JSON output;
2177
- // the envelope is its own documented shape, so there is nothing for the
2178
- // agent to improvise. The workflow receives the prose report as a plain
2179
- // string. The verdict is still extracted deterministically from the report
2180
- // text by extractVerdict below — never by an agent.
2174
+ // Work agent returns prose on the schema-less courier; the workflow
2175
+ // consumes the return as a plain string (blocker 43, 2026-09-22: the
2176
+ // prompt names no JSON envelope — nothing parses one, and the runtime's
2177
+ // JSON-candidate scan discards brace-shaped prose, which is what the
2178
+ // transport retry guards). The verdict is still extracted deterministically
2179
+ // from the report text by extractVerdict below — never by an agent.
2181
2180
  var workPromptBase =
2182
2181
  TOOL_CHECK_PREAMBLE +
2183
2182
  "Read the identity file at " + ORCH_PATH + "/identities/" + step.identity + ".md using the read tool, and embody that character fully.\n\n" +
@@ -2190,8 +2189,7 @@ while (i < STEPS.length) {
2190
2189
  "\n## Instructions\n\n" + eventPreamble + instructions + "\n\n" +
2191
2190
  "CONSTRAINT: Do NOT call logevent or upsertagentsession — the workflow handles all phase tracking after your step completes.\n\n" +
2192
2191
  "Stay in character. Do the work thoroughly.\n\n" +
2193
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your report here\"}. " +
2194
- "The result is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
2192
+ "Your report is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
2195
2193
  var workKeyBase = "work-" + step.name + (totalReworkCount > 0 ? "-r" + totalReworkCount : "");
2196
2194
  // See docs/decisions/qa-reproduce.md#wrong-layer-guard: reproduce must run at the correct layer.
2197
2195
  var reproEvidenceDir = crewHome + "/task-evidence/" + taskId + "/repro";
@@ -197,7 +197,7 @@ if (!taskId) {
197
197
  throw new Error("task_id is required in args");
198
198
  }
199
199
 
200
- // See docs/decisions/workflow-core.md#closeout-envelope: the work agent returns the runtime's native envelope; verdict extracted mechanically.
200
+ // See docs/decisions/workflow-core.md#closeout-envelope: the schema-less work courier returns prose, consumed as a plain string; verdict extracted mechanically.
201
201
  const VERDICT_STEPS = ["Build", "Review", "Integrate", "Publish"];
202
202
  function extractVerdict(workerText) {
203
203
  // The verdict is the LAST VERDICT: PASS/FAIL in the report (contract: end
@@ -231,7 +231,6 @@ function buildVerdictReaskPrompt(stepName, workerText) {
231
231
  "Decide from the report's own content whether the " + stepName + " step clearly describes successful completion: " +
232
232
  "if it does, the verdict is PASS; otherwise — failure, error, unfinished work, or unclear — the verdict is FAIL. " +
233
233
  "Do NOT copy any VERDICT line from the report — decide from the content.\n\n" +
234
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your verdict line here\"}. " +
235
234
  "The result must be exactly one line and nothing else: VERDICT: PASS or VERDICT: FAIL.";
236
235
  }
237
236
  async function reaskVerdict(stepName, reworkSuffix, workerText) {
@@ -304,8 +303,8 @@ var TOOL_CHECK_PREAMBLE =
304
303
  "3. Run the shell command: echo tool-probe-ok - then write exactly one line: shell_transport: ok - or shell_transport: unavailable if you cannot run shell commands.\n" +
305
304
  "Then do the assignment below.\n\n";
306
305
  function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason) {
307
- // reason: "discarded" (the runtime threw the output away - it could not be
308
- // machine-read), "empty" (agent() returned without throwing but produced
306
+ // reason: "discarded" (the runtime threw the output away — the JSON-candidate
307
+ // scan found {...}-shaped fragments it could not parse), "empty" (agent() returned without throwing but produced
309
308
  // nothing usable), "no-tools" (the worker's TOOL CHECK reported
310
309
  // artifact_tools: missing), or "no-transport" (the worker's TOOL CHECK
311
310
  // reported shell_transport: unavailable).
@@ -316,11 +315,11 @@ function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason)
316
315
  ? "your previous attempt's TOOL CHECK reported artifact_tools: missing (this is a fresh launch, so run the TOOL CHECK's load step again before the work)"
317
316
  : reason === "no-transport"
318
317
  ? "your previous attempt's TOOL CHECK reported shell_transport: unavailable (this is a fresh launch, so run the TOOL CHECK's shell probe again before the work)"
319
- : "your previous attempt's output could not be machine-read as JSON and was discarded";
318
+ : "your previous attempt's output was discarded by the transport because it contained {...}-shaped fragments the transport could not parse; write plain prose with no JSON-shaped fragments";
320
319
  return "\n\nTRANSPORT RETRY (attempt " + attempt + " of 2): " + why + ". " +
321
320
  "First check existing state (worktree/branch at " + repoPath + "/.worktrees/" + taskId + ", the task branch, dashboard sessions for this task) - " +
322
321
  "if the " + stepName + " work is already complete, report on what was done rather than duplicating side effects. " +
323
- "Then return your report as JSON in exactly the shape specified above.";
322
+ "Then return your report in exactly the shape specified above.";
324
323
  }
325
324
  // parseClassifyFerry — room #26 blocker 42 (2026-09-21). Shape-constrained
326
325
  // ferry parser for the classify-branch agent() call. The schema buys SHAPE,
@@ -1900,12 +1899,12 @@ while (i < STEPS.length) {
1900
1899
  "The returned events are filtered to this task. They contain notes and decisions from prior phases.\n\n";
1901
1900
  }
1902
1901
 
1903
- // Work agent returns the runtime's native envelope {"status": "ok",
1904
- // "result": "<prose>"} with no schema. The runtime requires JSON output;
1905
- // the envelope is its own documented shape, so there is nothing for the
1906
- // agent to improvise. The workflow receives the prose report as a plain
1907
- // string. The verdict is still extracted deterministically from the report
1908
- // text by extractVerdict below — never by an agent.
1902
+ // Work agent returns prose on the schema-less courier; the workflow
1903
+ // consumes the return as a plain string (blocker 43, 2026-09-22: the
1904
+ // prompt names no JSON envelope — nothing parses one, and the runtime's
1905
+ // JSON-candidate scan discards brace-shaped prose, which is what the
1906
+ // transport retry guards). The verdict is still extracted deterministically
1907
+ // from the report text by extractVerdict below — never by an agent.
1909
1908
  var workPromptBase =
1910
1909
  TOOL_CHECK_PREAMBLE +
1911
1910
  "Read the identity file at " + ORCH_PATH + "/identities/" + step.identity + ".md using the read tool, and embody that character fully.\n\n" +
@@ -1913,8 +1912,7 @@ while (i < STEPS.length) {
1913
1912
  "Task: " + taskTitle + "\nTask ID: " + taskId + "\nDescription: " + taskDescription + "\nStep: " + step.name + "\n" +
1914
1913
  (step.name !== "Review" ? "Crew API: " + CREW_API + "\n" : "") +
1915
1914
  "\n## Instructions\n\n" + eventPreamble + instructions + "\n\nCONSTRAINT: Do NOT call logevent or upsertagentsession — the workflow handles all phase tracking after your step completes.\n\nStay in character. Do the work thoroughly.\n\n" +
1916
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your report here\"}. " +
1917
- "The result is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
1915
+ "Your report is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
1918
1916
  var workKeyBase = "work-" + step.name + (reworkCount > 0 ? "-r" + reworkCount : "");
1919
1917
  var workerResult = null;
1920
1918
  var workAttempts = [];
package/workflows/docs.js CHANGED
@@ -269,7 +269,6 @@ while (i < STEPS.length) {
269
269
  "Decide from the report's own content whether the " + stepName + " step clearly describes successful completion: " +
270
270
  "if it does, the verdict is PASS; otherwise — failure, error, unfinished work, or unclear — the verdict is FAIL. " +
271
271
  "Do NOT copy any VERDICT line from the report — decide from the content.\n\n" +
272
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your verdict line here\"}. " +
273
272
  "The result must be exactly one line and nothing else: VERDICT: PASS or VERDICT: FAIL.";
274
273
  }
275
274
  async function reaskVerdict(stepName, reworkSuffix, workerText) {
@@ -329,8 +328,8 @@ while (i < STEPS.length) {
329
328
  "3. Run the shell command: echo tool-probe-ok - then write exactly one line: shell_transport: ok - or shell_transport: unavailable if you cannot run shell commands.\n" +
330
329
  "Then do the assignment below.\n\n";
331
330
  function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason) {
332
- // reason: "discarded" (the runtime threw the output away - it could not be
333
- // machine-read), "empty" (agent() returned without throwing but produced
331
+ // reason: "discarded" (the runtime threw the output away — the JSON-candidate
332
+ // scan found {...}-shaped fragments it could not parse), "empty" (agent() returned without throwing but produced
334
333
  // nothing usable), "no-tools" (the worker's TOOL CHECK reported
335
334
  // artifact_tools: missing), or "no-transport" (the worker's TOOL CHECK
336
335
  // reported shell_transport: unavailable).
@@ -341,11 +340,11 @@ while (i < STEPS.length) {
341
340
  ? "your previous attempt's TOOL CHECK reported artifact_tools: missing (this is a fresh launch, so run the TOOL CHECK's load step again before the work)"
342
341
  : reason === "no-transport"
343
342
  ? "your previous attempt's TOOL CHECK reported shell_transport: unavailable (this is a fresh launch, so run the TOOL CHECK's shell probe again before the work)"
344
- : "your previous attempt's output could not be machine-read as JSON and was discarded";
343
+ : "your previous attempt's output was discarded by the transport because it contained {...}-shaped fragments the transport could not parse; write plain prose with no JSON-shaped fragments";
345
344
  return "\n\nTRANSPORT RETRY (attempt " + attempt + " of 2): " + why + ". " +
346
345
  "First check existing state (worktree/branch at " + repoPath + "/.worktrees/" + taskId + ", the task branch, dashboard sessions for this task) - " +
347
346
  "if the " + stepName + " work is already complete, report on what was done rather than duplicating side effects. " +
348
- "Then return your report as JSON in exactly the shape specified above.";
347
+ "Then return your report in exactly the shape specified above.";
349
348
  }
350
349
  // parseToolSignals - bug 3472bf36. The work agent's TOOL CHECK emits two
351
350
  // exact signal lines: artifact_tools: ok|missing and
@@ -432,20 +431,19 @@ function describeWorkAgentFailure(stepName, identity, attempts) {
432
431
  "\nWrite your review as plain prose — findings, then decision. End your report with exactly one line: VERDICT: PASS if it passes, VERDICT: FAIL if it fails.";
433
432
  }
434
433
 
435
- // Work agent returns the runtime's native envelope {"status": "ok",
436
- // "result": "<prose>"} with no schema. The runtime requires JSON output;
437
- // the envelope is its own documented shape, so there is nothing for the
438
- // agent to improvise. The workflow receives the prose report as a plain
439
- // string. The verdict is still extracted deterministically from the report
440
- // text by extractVerdict below — never by an agent.
434
+ // Work agent returns prose on the schema-less courier; the workflow
435
+ // consumes the return as a plain string (blocker 43, 2026-09-22: the
436
+ // prompt names no JSON envelope — nothing parses one, and the runtime's
437
+ // JSON-candidate scan discards brace-shaped prose, which is what the
438
+ // transport retry guards). The verdict is still extracted deterministically
439
+ // from the report text by extractVerdict below — never by an agent.
441
440
  var workPromptBase =
442
441
  TOOL_CHECK_PREAMBLE +
443
442
  "Read the identity file at " + ORCH_PATH + "/identities/" + step.identity + ".md using the read tool, and embody that character fully.\n\n" +
444
443
  "## Your Assignment\n\n" +
445
444
  "Task: " + taskTitle + "\nTask ID: " + taskId + "\nDescription: " + taskDescription + "\nStep: " + step.name + "\n\n" +
446
445
  "## Instructions\n\n" + instructions + "\n\nCONSTRAINT: Do NOT call the crew API directly — the workflow handles all phase tracking after your step completes.\n\nStay in character. All file work under " + REPO_PATH + "/.\n\n" +
447
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your report here\"}. " +
448
- "The result is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
446
+ "Your report is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
449
447
  var workKeyBase = "work-" + step.name + (reworkCount > 0 ? "-r" + reworkCount : "");
450
448
  var workerResult = null;
451
449
  var workAttempts = [];
@@ -139,7 +139,7 @@ if (!taskId) {
139
139
  throw new Error("task_id is required in args");
140
140
  }
141
141
 
142
- // See docs/decisions/workflow-core.md#closeout-envelope: the work agent returns the runtime's native envelope; verdict extracted mechanically.
142
+ // See docs/decisions/workflow-core.md#closeout-envelope: the schema-less work courier returns prose, consumed as a plain string; verdict extracted mechanically.
143
143
  const VERDICT_STEPS = ["Build", "Review", "QA", "Reproduce", "Integrate", "Publish"];
144
144
  function extractVerdict(workerText) {
145
145
  // The verdict is the LAST VERDICT: PASS/FAIL in the report (contract: end
@@ -229,7 +229,6 @@ function buildVerdictReaskPrompt(stepName, workerText) {
229
229
  "Decide from the report's own content whether the " + stepName + " step clearly describes successful completion: " +
230
230
  "if it does, the verdict is PASS; otherwise — failure, error, unfinished work, or unclear — the verdict is FAIL. " +
231
231
  "Do NOT copy any VERDICT line from the report — decide from the content.\n\n" +
232
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your verdict line here\"}. " +
233
232
  "The result must be exactly one line and nothing else: VERDICT: PASS or VERDICT: FAIL.";
234
233
  }
235
234
  async function reaskVerdict(stepName, reworkSuffix, workerText) {
@@ -302,8 +301,8 @@ var TOOL_CHECK_PREAMBLE =
302
301
  "3. Run the shell command: echo tool-probe-ok - then write exactly one line: shell_transport: ok - or shell_transport: unavailable if you cannot run shell commands.\n" +
303
302
  "Then do the assignment below.\n\n";
304
303
  function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason) {
305
- // reason: "discarded" (the runtime threw the output away - it could not be
306
- // machine-read), "empty" (agent() returned without throwing but produced
304
+ // reason: "discarded" (the runtime threw the output away — the JSON-candidate
305
+ // scan found {...}-shaped fragments it could not parse), "empty" (agent() returned without throwing but produced
307
306
  // nothing usable), "no-tools" (the worker's TOOL CHECK reported
308
307
  // artifact_tools: missing), or "no-transport" (the worker's TOOL CHECK
309
308
  // reported shell_transport: unavailable).
@@ -314,11 +313,11 @@ function buildTransportRetryTrailer(stepName, repoPath, taskId, attempt, reason)
314
313
  ? "your previous attempt's TOOL CHECK reported artifact_tools: missing (this is a fresh launch, so run the TOOL CHECK's load step again before the work)"
315
314
  : reason === "no-transport"
316
315
  ? "your previous attempt's TOOL CHECK reported shell_transport: unavailable (this is a fresh launch, so run the TOOL CHECK's shell probe again before the work)"
317
- : "your previous attempt's output could not be machine-read as JSON and was discarded";
316
+ : "your previous attempt's output was discarded by the transport because it contained {...}-shaped fragments the transport could not parse; write plain prose with no JSON-shaped fragments";
318
317
  return "\n\nTRANSPORT RETRY (attempt " + attempt + " of 2): " + why + ". " +
319
318
  "First check existing state (worktree/branch at " + repoPath + "/.worktrees/" + taskId + ", the task branch, dashboard sessions for this task) - " +
320
319
  "if the " + stepName + " work is already complete, report on what was done rather than duplicating side effects. " +
321
- "Then return your report as JSON in exactly the shape specified above.";
320
+ "Then return your report in exactly the shape specified above.";
322
321
  }
323
322
  // parseClassifyFerry — room #26 blocker 42 (2026-09-21). Shape-constrained
324
323
  // ferry parser for the classify-branch agent() call. The schema buys SHAPE,
@@ -2061,12 +2060,12 @@ while (i < STEPS.length) {
2061
2060
  "The returned events are filtered to this task. They contain notes and decisions from prior phases.\n\n";
2062
2061
  }
2063
2062
 
2064
- // Work agent returns the runtime's native envelope {"status": "ok",
2065
- // "result": "<prose>"} with no schema. The runtime requires JSON output;
2066
- // the envelope is its own documented shape, so there is nothing for the
2067
- // agent to improvise. The workflow receives the prose report as a plain
2068
- // string. The verdict is still extracted deterministically from the report
2069
- // text by extractVerdict below — never by an agent.
2063
+ // Work agent returns prose on the schema-less courier; the workflow
2064
+ // consumes the return as a plain string (blocker 43, 2026-09-22: the
2065
+ // prompt names no JSON envelope — nothing parses one, and the runtime's
2066
+ // JSON-candidate scan discards brace-shaped prose, which is what the
2067
+ // transport retry guards). The verdict is still extracted deterministically
2068
+ // from the report text by extractVerdict below — never by an agent.
2070
2069
  var workPromptBase =
2071
2070
  TOOL_CHECK_PREAMBLE +
2072
2071
  "Read the identity file at " + ORCH_PATH + "/identities/" + step.identity + ".md using the read tool, and embody that character fully.\n\n" +
@@ -2079,8 +2078,7 @@ while (i < STEPS.length) {
2079
2078
  "\n## Instructions\n\n" + eventPreamble + instructions + "\n\n" +
2080
2079
  "CONSTRAINT: Do NOT call logevent or upsertagentsession — the workflow handles all phase tracking after your step completes.\n\n" +
2081
2080
  "Stay in character. Do the work thoroughly.\n\n" +
2082
- "Return your work as JSON in exactly this shape: {\"status\": \"ok\", \"result\": \"your report here\"}. " +
2083
- "The result is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
2081
+ "Your report is plain prose describing what you did and found. For verdict steps, end the report with exactly one line: VERDICT: PASS or VERDICT: FAIL.";
2084
2082
  var workKeyBase = "work-" + step.name + (totalReworkCount > 0 ? "-r" + totalReworkCount : "");
2085
2083
  var workerResult = null;
2086
2084
  var workAttempts = [];