agent-conveyor 0.1.5 → 0.1.7

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.
@@ -76,7 +76,7 @@ export function runTypescriptRuntimeCommand(options) {
76
76
  return errorResult(`unknown command: ${parsed.command}`);
77
77
  }
78
78
  if (parsed.flags.help) {
79
- return textResult([`usage: ${program} ${parsed.command} [-h] [options]`]);
79
+ return textResult(commandHelpText(program, parsed.command));
80
80
  }
81
81
  if (parsed.error) {
82
82
  return errorResult(parsed.error);
@@ -337,6 +337,70 @@ export function runTypescriptRuntimeCommand(options) {
337
337
  return errorResult(error instanceof Error ? error.message : String(error));
338
338
  }
339
339
  }
340
+ function commandHelpText(program, command) {
341
+ const path = "[--path <workerctl.db>]";
342
+ const linesByCommand = {
343
+ criteria: [
344
+ `usage: ${program} criteria <task> [--list|--add --criterion <text> --source <source>|--accept ID|--satisfy ID|--defer ID|--reject ID] ${path} [--json]`,
345
+ "",
346
+ "Examples:",
347
+ ` ${program} criteria my-task --list --json --path /tmp/work/workerctl.db`,
348
+ ` ${program} criteria my-task --add --criterion "Note file exists" --source manager_inferred --status accepted --path /tmp/work/workerctl.db`,
349
+ ` ${program} criteria my-task --satisfy 1 --proof "File exists" --evidence-json '{"artifact":{"path":"docs/note.md"}}' --path /tmp/work/workerctl.db`,
350
+ ],
351
+ "finish-task": [
352
+ `usage: ${program} finish-task <task> --reason <reason> [--require-criteria-audit] ${path}`,
353
+ "",
354
+ "Examples:",
355
+ ` ${program} finish-task my-task --reason "Accepted criteria satisfied" --require-criteria-audit --path /tmp/work/workerctl.db`,
356
+ ],
357
+ "manager-ack": [
358
+ `usage: ${program} manager-ack <task> --from-stdin ${path}`,
359
+ `usage: ${program} manager-ack <task> --json ${path}`,
360
+ "",
361
+ "Example JSON:",
362
+ ` {"task":"my-task","manager_session":"mgr","supervision_contract":"I will supervise through Conveyor and verify criteria before finishing.","will_not_edit_project_files":true}`,
363
+ ],
364
+ nudge: [
365
+ `usage: ${program} nudge <worker-or-session> <message> ${path} [--dry-run]`,
366
+ `usage: ${program} session-nudge <session> <message> ${path} [--dry-run]`,
367
+ "",
368
+ "For task-routed delivery, prefer enqueue-nudge-worker plus dispatch:",
369
+ ` ${program} enqueue-nudge-worker my-task --message "Status and evidence?" --path /tmp/work/workerctl.db`,
370
+ ` ${program} dispatch --once --type nudge_worker --path /tmp/work/workerctl.db`,
371
+ ],
372
+ pair: [
373
+ `usage: ${program} pair --task <task> --worker-name <worker> --manager-name <manager> [options] ${path}`,
374
+ "",
375
+ "Options:",
376
+ " --task-goal <text> Task goal stored in Conveyor state.",
377
+ " --task-prompt <text> Initial worker prompt; defaults to task goal when omitted.",
378
+ " --manager-recipe <recipe> Seed a manager recipe, for example goalbuddy-conveyor.",
379
+ " --manager-acceptance <text> Seed an accepted manager criterion; repeat for multiple criteria.",
380
+ " --manager-tool <tool> Seed an expected manager/worker tool; repeat for multiple tools.",
381
+ " --manager-reference <path> Seed a manager reference path; repeat for multiple references.",
382
+ " --manager-question <text> Seed a manager setup question; repeat for multiple questions.",
383
+ " --manager-guideline <text> Seed a manager guideline; repeat for multiple guidelines.",
384
+ " --cwd <dir> Working directory for both Codex sessions.",
385
+ " --accept-trust Auto-accept the Codex trust prompt for the chosen cwd.",
386
+ " --no-dispatch Do not start Dispatch after launching the pair.",
387
+ " --dry-run Print the launch plan without creating sessions.",
388
+ " --json Emit JSON output.",
389
+ "",
390
+ "Examples:",
391
+ ` ${program} pair --task dogfood --worker-name dogfood-worker --manager-name dogfood-manager --task-goal "Create docs/note.md" --task-prompt "Create docs/note.md" --manager-recipe goalbuddy-conveyor --manager-acceptance "docs/note.md exists" --cwd /tmp/work --path /tmp/work/workerctl.db --accept-trust`,
392
+ ` ${program} pair --task dogfood --worker-name dogfood-worker --manager-name dogfood-manager --path /tmp/work/workerctl.db --dry-run --json`,
393
+ ],
394
+ "worker-ack": [
395
+ `usage: ${program} worker-ack <task> --from-stdin ${path}`,
396
+ `usage: ${program} worker-ack <task> --json ${path}`,
397
+ "",
398
+ "Example JSON:",
399
+ ` {"goal_restatement":"Create docs/dogfood-note.md","proposed_criteria":{"must_have":["note file exists"],"follow_up":[]},"expected_tools":["shell"],"open_questions":[],"ready_to_start":true}`,
400
+ ],
401
+ };
402
+ return linesByCommand[command] ?? [`usage: ${program} ${command} [-h] [options]`];
403
+ }
340
404
  function parseRuntimeArgs(args, env) {
341
405
  const flags = {
342
406
  format: "timeline",
@@ -502,6 +566,7 @@ function parseRuntimeArgs(args, env) {
502
566
  managerObjective: null,
503
567
  managerPermissionsJson: null,
504
568
  managerPermit: [],
569
+ managerRecipe: null,
505
570
  managerReference: [],
506
571
  managerRequireAcks: false,
507
572
  managerTool: [],
@@ -1421,6 +1486,17 @@ function parseRuntimeArgs(args, env) {
1421
1486
  flags.managerMode = value.value;
1422
1487
  index += 1;
1423
1488
  }
1489
+ else if (arg === "--manager-recipe") {
1490
+ if (command !== "pair") {
1491
+ return { command, enabled, error: "Unsupported TypeScript runtime option: --manager-recipe", explicit, flags, task };
1492
+ }
1493
+ const value = valueAfter(queue, index, arg);
1494
+ if (value.error) {
1495
+ return { command, enabled, error: value.error, explicit, flags, task };
1496
+ }
1497
+ flags.managerRecipe = value.value;
1498
+ index += 1;
1499
+ }
1424
1500
  else if (arg === "--manager-objective") {
1425
1501
  if (command !== "pair") {
1426
1502
  return { command, enabled, error: "Unsupported TypeScript runtime option: --manager-objective", explicit, flags, task };
@@ -1555,6 +1631,17 @@ function parseRuntimeArgs(args, env) {
1555
1631
  flags.managerObjective = value.value;
1556
1632
  index += 1;
1557
1633
  }
1634
+ else if (arg === "--recipe") {
1635
+ if (command !== "manager-config") {
1636
+ return { command, enabled, error: "Unsupported TypeScript runtime option: --recipe", explicit, flags, task };
1637
+ }
1638
+ const value = valueAfter(queue, index, arg);
1639
+ if (value.error) {
1640
+ return { command, enabled, error: value.error, explicit, flags, task };
1641
+ }
1642
+ flags.managerRecipe = value.value;
1643
+ index += 1;
1644
+ }
1558
1645
  else if (arg === "--guideline") {
1559
1646
  if (command !== "manager-config") {
1560
1647
  return { command, enabled, error: "Unsupported TypeScript runtime option: --guideline", explicit, flags, task };
@@ -5371,6 +5458,7 @@ function runStartSessionCommand(parsed, options, role) {
5371
5458
  const initialPrompt = role === "manager"
5372
5459
  ? startManagerBootstrapPrompt(database, {
5373
5460
  cwd,
5461
+ dbPath: runtimeDbPath(parsed, options),
5374
5462
  managerName: name,
5375
5463
  taskGoal: parsed.flags.taskGoal,
5376
5464
  taskName: parsed.flags.taskName,
@@ -5697,7 +5785,7 @@ function runPairCommand(parsed, options) {
5697
5785
  return unsupportedRuntimeResult(parsed, "pair requires --task, --worker-name, and --manager-name.");
5698
5786
  }
5699
5787
  const dbPath = runtimeDbPath(parsed, options);
5700
- const dispatch = pairDispatchPayload(parsed, dbPath);
5788
+ const dispatch = pairDispatchPayload(parsed, dbPath, options);
5701
5789
  const packageRoot = packageRootFromRuntimeModule();
5702
5790
  if (parsed.flags.dryRun) {
5703
5791
  return jsonResult({
@@ -5708,6 +5796,18 @@ function runPairCommand(parsed, options) {
5708
5796
  worker: workerName,
5709
5797
  });
5710
5798
  }
5799
+ const codexPreflight = ensureRequiredTool("codex", options);
5800
+ if (codexPreflight) {
5801
+ return codexPreflight;
5802
+ }
5803
+ const tmuxPreflight = ensureTmuxAvailable(options.tmuxRunner ?? defaultTmuxRunner);
5804
+ if (tmuxPreflight) {
5805
+ return tmuxPreflight;
5806
+ }
5807
+ const tmuxAccessPreflight = ensureTmuxServerAccessible(options.tmuxRunner ?? defaultTmuxRunner);
5808
+ if (tmuxAccessPreflight) {
5809
+ return tmuxAccessPreflight;
5810
+ }
5711
5811
  const cwd = parsed.flags.cwd ?? options.cwd ?? process.cwd();
5712
5812
  const database = openRuntimeDatabase(parsed, options);
5713
5813
  let taskId = null;
@@ -5774,6 +5874,7 @@ function runPairCommand(parsed, options) {
5774
5874
  managerObjective: parsed.flags.managerObjective,
5775
5875
  managerPermissionsJson: parsed.flags.managerPermissionsJson,
5776
5876
  managerPermit: parsed.flags.managerPermit,
5877
+ managerRecipe: parsed.flags.managerRecipe,
5777
5878
  managerReference: parsed.flags.managerReference,
5778
5879
  managerRequireAcks: parsed.flags.managerRequireAcks,
5779
5880
  managerTool: parsed.flags.managerTool,
@@ -5824,7 +5925,7 @@ function runPairCommand(parsed, options) {
5824
5925
  acceptTrust: parsed.flags.acceptTrust,
5825
5926
  askForApproval: startup.askForApproval,
5826
5927
  cwd,
5827
- initialPrompt: workerAckTaskPrompt(taskName, parsed.flags.taskPrompt),
5928
+ initialPrompt: workerAckTaskPrompt(taskName, parsed.flags.taskPrompt, dbPath),
5828
5929
  name: workerName,
5829
5930
  role: "worker",
5830
5931
  sandbox: startup.sandbox,
@@ -5852,6 +5953,7 @@ function runPairCommand(parsed, options) {
5852
5953
  cwd,
5853
5954
  initialPrompt: startManagerBootstrapPrompt(database, {
5854
5955
  cwd,
5956
+ dbPath,
5855
5957
  managerName,
5856
5958
  taskGoal: task.goal,
5857
5959
  taskName,
@@ -6011,14 +6113,13 @@ function taskRowForPair(database, taskName) {
6011
6113
  `).get(taskName, taskName);
6012
6114
  return row ?? null;
6013
6115
  }
6014
- function pairDispatchPayload(parsed, dbPath) {
6116
+ function pairDispatchPayload(parsed, dbPath, options) {
6015
6117
  const dispatcherId = parsed.flags.dispatcherId;
6016
6118
  const ensureDispatch = dispatcherId !== null && !parsed.flags.noDispatch;
6017
- const packageRoot = packageRootFromRuntimeModule();
6018
6119
  return {
6019
6120
  dispatchCommand: ensureDispatch
6020
6121
  ? [
6021
- join(packageRoot, "scripts", "workerctl"),
6122
+ workerctlDispatchExecutable(options),
6022
6123
  "dispatch",
6023
6124
  "--watch",
6024
6125
  "--dispatcher-id",
@@ -6030,6 +6131,17 @@ function pairDispatchPayload(parsed, dbPath) {
6030
6131
  ensureDispatch,
6031
6132
  };
6032
6133
  }
6134
+ function workerctlDispatchExecutable(options) {
6135
+ const workerctlPath = commandPath("workerctl", options);
6136
+ if (workerctlPath) {
6137
+ return workerctlPath;
6138
+ }
6139
+ const workerctlScript = join(packageRootFromRuntimeModule(), "scripts", "workerctl");
6140
+ if (pathIsExecutable(workerctlScript)) {
6141
+ return workerctlScript;
6142
+ }
6143
+ throw new Error(`Cannot start Dispatch: workerctl is not on PATH and ${workerctlScript} is not executable.`);
6144
+ }
6033
6145
  function emitPairTelemetry(database, options) {
6034
6146
  emitTelemetrySync(database, {
6035
6147
  actor: "workerctl",
@@ -6053,6 +6165,7 @@ function emitPairTelemetry(database, options) {
6053
6165
  function ensurePairManagerConfig(database, options) {
6054
6166
  const existing = managerConfigSync(database, options.taskId);
6055
6167
  const requested = options.managerMode !== null
6168
+ || options.managerRecipe !== null
6056
6169
  || options.managerObjective !== null
6057
6170
  || options.managerGuideline.length > 0
6058
6171
  || options.managerAcceptance.length > 0
@@ -6073,6 +6186,7 @@ function ensurePairManagerConfig(database, options) {
6073
6186
  if (supervisionMode !== "light" && supervisionMode !== "guided" && supervisionMode !== "strict") {
6074
6187
  throw new Error("manager_mode must be light, guided, or strict");
6075
6188
  }
6189
+ const recipeName = cleanManagerRecipeName(options.managerRecipe, existing?.recipe_name ?? (existing === null ? "custom" : null));
6076
6190
  const objective = options.managerObjective !== null ? options.managerObjective : existing?.objective ?? null;
6077
6191
  const guidelines = options.managerGuideline.length > 0 ? options.managerGuideline : existing?.guidelines ?? [];
6078
6192
  const acceptanceCriteria = options.managerAcceptance.length > 0
@@ -6093,13 +6207,14 @@ function ensurePairManagerConfig(database, options) {
6093
6207
  const requireAcks = options.managerRequireAcks || (existing?.require_acks ?? false);
6094
6208
  database.prepare(`
6095
6209
  insert into manager_configs(
6096
- task_id, supervision_mode, objective, guidelines_json,
6210
+ task_id, recipe_name, supervision_mode, objective, guidelines_json,
6097
6211
  acceptance_criteria_json, reference_paths_json, permissions_json,
6098
6212
  tools_json, epilogues_json, nudge_on_completion, require_acks,
6099
6213
  revision, created_at, updated_at
6100
6214
  )
6101
- values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
6215
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
6102
6216
  on conflict(task_id) do update set
6217
+ recipe_name = excluded.recipe_name,
6103
6218
  supervision_mode = excluded.supervision_mode,
6104
6219
  objective = excluded.objective,
6105
6220
  guidelines_json = excluded.guidelines_json,
@@ -6111,6 +6226,7 @@ function ensurePairManagerConfig(database, options) {
6111
6226
  nudge_on_completion = excluded.nudge_on_completion,
6112
6227
  require_acks = excluded.require_acks,
6113
6228
  revision = case when
6229
+ manager_configs.recipe_name is not excluded.recipe_name or
6114
6230
  manager_configs.supervision_mode is not excluded.supervision_mode or
6115
6231
  manager_configs.objective is not excluded.objective or
6116
6232
  manager_configs.guidelines_json is not excluded.guidelines_json or
@@ -6123,7 +6239,7 @@ function ensurePairManagerConfig(database, options) {
6123
6239
  manager_configs.require_acks is not excluded.require_acks
6124
6240
  then manager_configs.revision + 1 else manager_configs.revision end,
6125
6241
  updated_at = excluded.updated_at
6126
- `).run(options.taskId, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
6242
+ `).run(options.taskId, recipeName, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
6127
6243
  const config = managerConfigSync(database, options.taskId);
6128
6244
  if (config === null) {
6129
6245
  throw new Error(`manager config was not recorded for task ${options.taskId}`);
@@ -6379,20 +6495,24 @@ function spawnCodexAndRegisterPairSession(database, parsed, options, params) {
6379
6495
  tmux_session: registered.tmux_session,
6380
6496
  };
6381
6497
  }
6382
- function workerAckTaskPrompt(taskName, taskPrompt) {
6498
+ function workerAckTaskPrompt(taskName, taskPrompt, dbPath) {
6383
6499
  if (taskPrompt === null) {
6384
6500
  return null;
6385
6501
  }
6386
6502
  const taskRef = taskName ?? "<task>";
6503
+ const pathSuffix = commandPathSuffix(dbPath);
6387
6504
  return [
6388
6505
  taskPrompt,
6389
6506
  "",
6390
6507
  "Before editing files or running implementation work, acknowledge the task contract:",
6391
6508
  "",
6392
- `conveyor worker-ack ${taskRef} --from-stdin`,
6509
+ `conveyor worker-ack ${taskRef} --from-stdin${pathSuffix}`,
6510
+ "",
6511
+ "Use a JSON object like:",
6512
+ "",
6513
+ `{"goal_restatement":"Restate the assigned task.","proposed_criteria":{"must_have":["Current-task proof"],"follow_up":[]},"expected_tools":["shell"],"open_questions":[],"ready_to_start":true}`,
6393
6514
  "",
6394
- "Use a JSON object with goal_restatement, proposed_criteria, expected_tools,",
6395
- "open_questions, and ready_to_start.",
6515
+ "When your implementation is complete, leave a concise final reply with the files changed and verification you ran. Do not call `conveyor finish-task`; the manager owns criteria satisfaction and audited task closeout.",
6396
6516
  ].join("\n");
6397
6517
  }
6398
6518
  function createPairRunSync(database, options) {
@@ -11842,6 +11962,7 @@ function insertCompatEventSync(database, options) {
11842
11962
  }
11843
11963
  function managerConfigMutationRequested(parsed) {
11844
11964
  return parsed.flags.managerMode !== null
11965
+ || parsed.flags.managerRecipe !== null
11845
11966
  || parsed.flags.managerObjective !== null
11846
11967
  || parsed.flags.managerGuideline.length > 0
11847
11968
  || parsed.flags.managerAcceptance.length > 0
@@ -11860,6 +11981,7 @@ function upsertManagerConfigFromParsed(database, options) {
11860
11981
  const parsed = options.parsed;
11861
11982
  const existing = options.existing;
11862
11983
  const supervisionMode = parsed.flags.managerMode ?? existing?.supervision_mode ?? "guided";
11984
+ const recipeName = cleanManagerRecipeName(parsed.flags.managerRecipe, existing?.recipe_name ?? null);
11863
11985
  const objective = parsed.flags.managerObjective !== null ? parsed.flags.managerObjective : existing?.objective ?? null;
11864
11986
  const guidelines = parsed.flags.managerGuideline.length > 0 ? parsed.flags.managerGuideline : existing?.guidelines ?? [];
11865
11987
  const acceptanceCriteria = parsed.flags.managerAcceptance.length > 0
@@ -11880,13 +12002,14 @@ function upsertManagerConfigFromParsed(database, options) {
11880
12002
  const requireAcks = parsed.flags.managerRequireAcks || (existing?.require_acks ?? false);
11881
12003
  database.prepare(`
11882
12004
  insert into manager_configs(
11883
- task_id, supervision_mode, objective, guidelines_json,
12005
+ task_id, recipe_name, supervision_mode, objective, guidelines_json,
11884
12006
  acceptance_criteria_json, reference_paths_json, permissions_json,
11885
12007
  tools_json, epilogues_json, nudge_on_completion, require_acks,
11886
12008
  revision, created_at, updated_at
11887
12009
  )
11888
- values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
12010
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
11889
12011
  on conflict(task_id) do update set
12012
+ recipe_name = excluded.recipe_name,
11890
12013
  supervision_mode = excluded.supervision_mode,
11891
12014
  objective = excluded.objective,
11892
12015
  guidelines_json = excluded.guidelines_json,
@@ -11898,6 +12021,7 @@ function upsertManagerConfigFromParsed(database, options) {
11898
12021
  nudge_on_completion = excluded.nudge_on_completion,
11899
12022
  require_acks = excluded.require_acks,
11900
12023
  revision = case when
12024
+ manager_configs.recipe_name is not excluded.recipe_name or
11901
12025
  manager_configs.supervision_mode is not excluded.supervision_mode or
11902
12026
  manager_configs.objective is not excluded.objective or
11903
12027
  manager_configs.guidelines_json is not excluded.guidelines_json or
@@ -11910,7 +12034,7 @@ function upsertManagerConfigFromParsed(database, options) {
11910
12034
  manager_configs.require_acks is not excluded.require_acks
11911
12035
  then manager_configs.revision + 1 else manager_configs.revision end,
11912
12036
  updated_at = excluded.updated_at
11913
- `).run(options.taskId, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
12037
+ `).run(options.taskId, recipeName, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
11914
12038
  const config = managerConfigSync(database, options.taskId);
11915
12039
  if (config === null) {
11916
12040
  throw new Error(`manager config was not recorded for task ${options.taskId}`);
@@ -11933,6 +12057,16 @@ function cleanManagerNudgeOnCompletion(value) {
11933
12057
  }
11934
12058
  return value;
11935
12059
  }
12060
+ function cleanManagerRecipeName(value, existing) {
12061
+ if (value === null) {
12062
+ return existing;
12063
+ }
12064
+ const normalized = normalizeManagerRecipeName(value);
12065
+ if (normalized === "custom") {
12066
+ return null;
12067
+ }
12068
+ return managerRecipeDefinition(normalized).name;
12069
+ }
11936
12070
  function managerPermissionWarnings(permissions) {
11937
12071
  const warnings = [];
11938
12072
  for (const [key, value] of Object.entries(permissions ?? {})) {
@@ -16618,16 +16752,20 @@ function startManagerBootstrapPrompt(database, options) {
16618
16752
  const goalLine = options.taskGoal ?? context?.goal ?? "No task goal supplied yet.";
16619
16753
  const workerLine = options.workerName ?? "No worker session supplied yet.";
16620
16754
  const workerctl = "conveyor";
16755
+ const pathSuffix = commandPathSuffix(options.dbPath);
16621
16756
  const setupCommand = options.taskName
16622
- ? `${workerctl} manager-config ${taskLine} --questions`
16623
- : `${workerctl} manager-config <task> --questions`;
16624
- const cycleCommand = options.taskName ? `${workerctl} cycle ${taskLine}` : `${workerctl} cycle <task>`;
16757
+ ? `${workerctl} manager-config ${taskLine} --questions${pathSuffix}`
16758
+ : `${workerctl} manager-config <task> --questions${pathSuffix}`;
16759
+ const cycleCommand = options.taskName ? `${workerctl} cycle ${taskLine}${pathSuffix}` : `${workerctl} cycle <task>${pathSuffix}`;
16625
16760
  const managerAckCommand = options.taskName
16626
- ? `${workerctl} manager-ack ${taskLine} --from-stdin`
16627
- : `${workerctl} manager-ack <task> --from-stdin`;
16761
+ ? `${workerctl} manager-ack ${taskLine} --from-stdin${pathSuffix}`
16762
+ : `${workerctl} manager-ack <task> --from-stdin${pathSuffix}`;
16628
16763
  const workerAckCommand = options.taskName
16629
- ? `${workerctl} worker-ack ${taskLine} --json`
16630
- : `${workerctl} worker-ack <task> --json`;
16764
+ ? `${workerctl} worker-ack ${taskLine} --json${pathSuffix}`
16765
+ : `${workerctl} worker-ack <task> --json${pathSuffix}`;
16766
+ const satisfyCriterionCommand = options.taskName
16767
+ ? `${workerctl} criteria ${taskLine} --satisfy <id> --proof "<proof>" --evidence-json '{"status":"pass","command":"<command>","summary":"<what this proved>"}'${pathSuffix}`
16768
+ : `${workerctl} criteria <task> --satisfy <id> --proof "<proof>" --evidence-json '{"status":"pass","command":"<command>","summary":"<what this proved>"}'${pathSuffix}`;
16631
16769
  const config = context ? managerConfigSync(database, context.id) : null;
16632
16770
  const initialSetup = config
16633
16771
  ? seededManagerConfigSetup({ config, cycleCommand, managerAckCommand, workerAckCommand })
@@ -16635,11 +16773,12 @@ function startManagerBootstrapPrompt(database, options) {
16635
16773
  "Initial setup:",
16636
16774
  `1. Run \`${setupCommand}\`.`,
16637
16775
  "2. Ask the user the returned setup questions in this manager Codex chat.",
16638
- `3. Persist the answers with \`${workerctl} manager-config\`.`,
16776
+ `3. Persist the answers with \`${workerctl} manager-config${pathSuffix}\`.`,
16639
16777
  "4. Use `conveyor manager-config --interactive` only when a human is directly running conveyor in a terminal.",
16640
16778
  "",
16641
16779
  "Acknowledgement:",
16642
16780
  `- Before your first cycle, record the supervision contract you are committing to with \`${managerAckCommand}\`.`,
16781
+ ` Example JSON: {"task":"${taskLine}","manager_session":"${options.managerName}","supervision_contract":"I will supervise through Conveyor and verify criteria before finishing.","will_not_edit_project_files":true}`,
16643
16782
  `- Before nudging or finishing, inspect the worker acknowledgement with \`${workerAckCommand}\` when available.`,
16644
16783
  ].join("\n");
16645
16784
  return [
@@ -16662,7 +16801,8 @@ function startManagerBootstrapPrompt(database, options) {
16662
16801
  "- Inspect `manager_context.acceptance_criteria` each cycle.",
16663
16802
  "- If worker progress reveals new edge cases, tests, polish, or scope boundaries, ask the worker to propose must-have vs follow-up criteria.",
16664
16803
  "- Before finishing, compare worker receipts/verification against accepted open criteria.",
16665
- `- When all accepted criteria are satisfied, deferred, or rejected, finish the task with \`${workerctl} finish-task ${taskLine} --reason "Accepted criteria satisfied" --require-criteria-audit\`.`,
16804
+ `- For each accepted criterion that is proven, record evidence with \`${satisfyCriterionCommand}\`.`,
16805
+ `- When all accepted criteria are satisfied, deferred, or rejected, finish the task with \`${workerctl} finish-task ${taskLine} --reason "Accepted criteria satisfied" --require-criteria-audit${pathSuffix}\`.`,
16666
16806
  "- Communicate with the worker only through conveyor session/task commands.",
16667
16807
  "- Do not edit project files unless the user explicitly asks this manager session to change Agent Conveyor itself.",
16668
16808
  ].join("\n");
@@ -16677,7 +16817,7 @@ function seededManagerConfigSetup(options) {
16677
16817
  if (options.config.tools.length > 0) {
16678
16818
  lines.push(`Expected tools: ${options.config.tools.join(", ")}.`);
16679
16819
  }
16680
- lines.push("", "Acknowledgement:", `- Before your first cycle, record the supervision contract you are committing to with \`${options.managerAckCommand}\`.`, `- Before nudging or finishing, inspect the worker acknowledgement with \`${options.workerAckCommand}\` when available.`);
16820
+ lines.push("", "Acknowledgement:", `- Before your first cycle, record the supervision contract you are committing to with \`${options.managerAckCommand}\`.`, ` Example JSON: {"task":"${options.config.task_id}","supervision_contract":"I will supervise through Conveyor and verify criteria before finishing.","will_not_edit_project_files":true}`, `- Before nudging or finishing, inspect the worker acknowledgement with \`${options.workerAckCommand}\` when available.`);
16681
16821
  return lines.join("\n");
16682
16822
  }
16683
16823
  function startManagerTaskContext(database, taskName) {
@@ -16691,6 +16831,9 @@ function startManagerTaskContext(database, taskName) {
16691
16831
  function shellQuote(value) {
16692
16832
  return `'${value.replace(/'/g, "'\"'\"'")}'`;
16693
16833
  }
16834
+ function commandPathSuffix(dbPath) {
16835
+ return dbPath ? ` --path ${shellQuote(dbPath)}` : "";
16836
+ }
16694
16837
  function emitTelemetrySync(database, options) {
16695
16838
  const eventId = `telemetry-${randomUUID()}`;
16696
16839
  const attributesJson = stableJson(options.attributes);
@@ -18149,9 +18292,8 @@ The supported manager/worker setup is session-based:
18149
18292
 
18150
18293
  ${workerctl} worker-ack <task-name> --from-stdin
18151
18294
 
18152
- The JSON should include goal_restatement, proposed_criteria,
18153
- expected_tools, open_questions, and ready_to_start. Proposed criteria should
18154
- separate must-have and follow-up criteria.
18295
+ Example JSON:
18296
+ {"goal_restatement":"Restate the assigned task.","proposed_criteria":{"must_have":["Current-task proof"],"follow_up":[]},"expected_tools":["shell"],"open_questions":[],"ready_to_start":true}
18155
18297
 
18156
18298
  Required fields:
18157
18299
  - worker name
@@ -18238,6 +18380,14 @@ function ensureTmuxAvailable(runner) {
18238
18380
  const detail = (result.stderr || result.stdout || `exit code ${result.status}`).trim();
18239
18381
  return lifecycleWorkerErrorResult(tmuxCommandFailureMessage(["tmux", "-V"], detail));
18240
18382
  }
18383
+ function ensureTmuxServerAccessible(runner) {
18384
+ const result = runner(["tmux", "start-server"], { check: false });
18385
+ if (result.status === 0) {
18386
+ return null;
18387
+ }
18388
+ const detail = (result.stderr || result.stdout || `exit code ${result.status}`).trim();
18389
+ return lifecycleWorkerErrorResult(tmuxCommandFailureMessage(["tmux", "start-server"], detail));
18390
+ }
18241
18391
  const CONTENT_KEYS = new Set(["content", "message", "output", "segment_text", "text"]);
18242
18392
  function redactPayload(value) {
18243
18393
  if (Array.isArray(value)) {