@llblab/pi-actors 0.37.1 → 0.38.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.
Files changed (75) hide show
  1. package/BACKLOG.md +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +6 -5
  4. package/dist/index.js +23 -3
  5. package/dist/lib/async-runs.d.ts +5 -0
  6. package/dist/lib/async-runs.js +87 -8
  7. package/dist/lib/command-templates.d.ts +2 -0
  8. package/dist/lib/execution.d.ts +4 -0
  9. package/dist/lib/execution.js +154 -13
  10. package/dist/lib/model-context.d.ts +56 -0
  11. package/dist/lib/model-context.js +220 -0
  12. package/dist/lib/observability.d.ts +2 -0
  13. package/dist/lib/observability.js +32 -6
  14. package/dist/lib/preflight-diagnostics.d.ts +27 -0
  15. package/dist/lib/preflight-diagnostics.js +86 -0
  16. package/dist/lib/prompts.d.ts +1 -1
  17. package/dist/lib/prompts.js +2 -2
  18. package/dist/lib/recipes-context.d.ts +7 -0
  19. package/dist/lib/recipes-context.js +20 -2
  20. package/dist/lib/recipes-discovery.d.ts +1 -0
  21. package/dist/lib/recipes-discovery.js +63 -7
  22. package/dist/lib/recipes-references.d.ts +2 -0
  23. package/dist/lib/recipes-references.js +10 -0
  24. package/dist/lib/tools-local.d.ts +2 -1
  25. package/dist/lib/tools-local.js +6 -4
  26. package/dist/lib/tools-response.js +22 -1
  27. package/dist/lib/tools-spawn.d.ts +2 -1
  28. package/dist/lib/tools-spawn.js +2 -1
  29. package/dist/recipes/lens-swarm.json +15 -2
  30. package/dist/recipes/pipeline-release-readiness.json +22 -3
  31. package/dist/recipes/pipeline-review-readiness.json +22 -3
  32. package/dist/recipes/subagent-judge.json +2 -1
  33. package/dist/recipes/subagent-merge.json +5 -2
  34. package/dist/recipes/subagent-normalize.json +2 -1
  35. package/dist/recipes/subagent-preflight.json +29 -0
  36. package/dist/recipes/subagent-review-coordinator.json +79 -7
  37. package/dist/recipes/subagent-review.json +2 -1
  38. package/dist/recipes/subagent-verify.json +2 -1
  39. package/dist/scripts/async-runner.mjs +84 -10
  40. package/dist/scripts/conformance.mjs +1 -0
  41. package/dist/skills/actors/SKILL.md +4 -4
  42. package/dist/skills/swarm/SKILL.md +2 -2
  43. package/docs/async-runs.md +3 -1
  44. package/docs/command-templates.md +4 -1
  45. package/docs/recipe-library.md +3 -2
  46. package/docs/template-recipes.md +2 -2
  47. package/index.ts +24 -3
  48. package/lib/async-runs.ts +157 -8
  49. package/lib/command-templates.ts +2 -0
  50. package/lib/execution.ts +218 -24
  51. package/lib/model-context.ts +359 -0
  52. package/lib/observability.ts +35 -6
  53. package/lib/preflight-diagnostics.ts +132 -0
  54. package/lib/prompts.ts +2 -2
  55. package/lib/recipes-context.ts +29 -2
  56. package/lib/recipes-discovery.ts +76 -11
  57. package/lib/recipes-references.ts +12 -0
  58. package/lib/tools-local.ts +22 -8
  59. package/lib/tools-response.ts +26 -1
  60. package/lib/tools-spawn.ts +6 -2
  61. package/package.json +1 -1
  62. package/recipes/lens-swarm.json +15 -2
  63. package/recipes/pipeline-release-readiness.json +22 -3
  64. package/recipes/pipeline-review-readiness.json +22 -3
  65. package/recipes/subagent-judge.json +2 -1
  66. package/recipes/subagent-merge.json +5 -2
  67. package/recipes/subagent-normalize.json +2 -1
  68. package/recipes/subagent-preflight.json +29 -0
  69. package/recipes/subagent-review-coordinator.json +79 -7
  70. package/recipes/subagent-review.json +2 -1
  71. package/recipes/subagent-verify.json +2 -1
  72. package/scripts/async-runner.mjs +84 -10
  73. package/scripts/conformance.mjs +1 -0
  74. package/skills/actors/SKILL.md +4 -4
  75. package/skills/swarm/SKILL.md +2 -2
@@ -4,12 +4,14 @@
4
4
  * Owns filename identity discovery across prioritized recipe roots
5
5
  */
6
6
 
7
+ import { execFileSync } from "node:child_process";
7
8
  import { createHash } from "node:crypto";
8
9
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
9
10
  import { join } from "node:path";
10
11
 
11
12
  import * as CommandTemplates from "./command-templates.ts";
12
13
  import type { RegisteredTool } from "./config.ts";
14
+ import * as ModelContext from "./model-context.ts";
13
15
  import type { TemplateRecipeConfig } from "./recipes-references.ts";
14
16
  import * as RecipesReferences from "./recipes-references.ts";
15
17
  import * as Schema from "./schema.ts";
@@ -233,6 +235,61 @@ function filesForSource(source: RecipesDiscoverySource): Array<{
233
235
  : [];
234
236
  }
235
237
 
238
+ const WINDOWS_BROAD_WRITE_PRINCIPALS = [
239
+ "Everyone",
240
+ "BUILTIN\\Users",
241
+ "Authenticated Users",
242
+ "S-1-1-0",
243
+ "S-1-5-11",
244
+ "S-1-5-32-545",
245
+ ];
246
+
247
+ const WINDOWS_WRITE_ACL_PATTERN = /\((?:[^)]*,)?(?:F|M|W|WD|AD|DC|GA|GW)(?:,[^)]*)?\)/i;
248
+
249
+ export function hasBroadWindowsWriteAcl(icaclsOutput: string): boolean {
250
+ return icaclsOutput
251
+ .split(/\r?\n/)
252
+ .some((line) =>
253
+ WINDOWS_BROAD_WRITE_PRINCIPALS.some((principal) =>
254
+ line.includes(principal),
255
+ ) && WINDOWS_WRITE_ACL_PATTERN.test(line),
256
+ );
257
+ }
258
+
259
+ function getWindowsRecipeRootDiagnostics(root: string): string[] {
260
+ try {
261
+ const output = execFileSync("icacls", [root], {
262
+ encoding: "utf8",
263
+ windowsHide: true,
264
+ timeout: 5000,
265
+ });
266
+ if (!hasBroadWindowsWriteAcl(output)) return [];
267
+ return [
268
+ `Recipe root grants write access to broad Windows principals; review ACLs: ${root}`,
269
+ ];
270
+ } catch (error) {
271
+ return [
272
+ `Failed to inspect Windows ACL for recipe root ${root}: ${error instanceof Error ? error.message : String(error)}`,
273
+ ];
274
+ }
275
+ }
276
+
277
+ function getPosixRecipeRootDiagnostics(root: string): string[] {
278
+ const diagnostics: string[] = [];
279
+ const stat = statSync(root);
280
+ if ((stat.mode & 0o002) !== 0) {
281
+ diagnostics.push(
282
+ `Recipe root is world-writable; review permissions: ${root}`,
283
+ );
284
+ }
285
+ if ((stat.mode & 0o020) !== 0) {
286
+ diagnostics.push(
287
+ `Recipe root is group-writable; review ownership and permissions: ${root}`,
288
+ );
289
+ }
290
+ return diagnostics;
291
+ }
292
+
236
293
  function getRecipeRootDiagnostics(sources: RecipesDiscoverySource[]): string[] {
237
294
  const diagnostics: string[] = [];
238
295
  const roots = new Set(
@@ -243,17 +300,11 @@ function getRecipeRootDiagnostics(sources: RecipesDiscoverySource[]): string[] {
243
300
  for (const root of roots) {
244
301
  try {
245
302
  if (!existsSync(root)) continue;
246
- const stat = statSync(root);
247
- if ((stat.mode & 0o002) !== 0) {
248
- diagnostics.push(
249
- `Recipe root is world-writable; review permissions: ${root}`,
250
- );
251
- }
252
- if ((stat.mode & 0o020) !== 0) {
253
- diagnostics.push(
254
- `Recipe root is group-writable; review ownership and permissions: ${root}`,
255
- );
256
- }
303
+ diagnostics.push(
304
+ ...(process.platform === "win32"
305
+ ? getWindowsRecipeRootDiagnostics(root)
306
+ : getPosixRecipeRootDiagnostics(root)),
307
+ );
257
308
  } catch (error) {
258
309
  diagnostics.push(
259
310
  `Failed to inspect recipe root ${root}: ${error instanceof Error ? error.message : String(error)}`,
@@ -701,6 +752,20 @@ export function summarizeDiscovery(
701
752
  invalid: entry.invalid,
702
753
  shadows: entry.shadows,
703
754
  ...(entry.riskLabels.length ? { risk_labels: entry.riskLabels } : {}),
755
+ ...(entry.config &&
756
+ ModelContext.describeRecipeCurrentPolicy({
757
+ args: entry.config.args,
758
+ defaults: entry.config.defaults,
759
+ template: entry.config.template,
760
+ })
761
+ ? {
762
+ current_policy: ModelContext.describeRecipeCurrentPolicy({
763
+ args: entry.config.args,
764
+ defaults: entry.config.defaults,
765
+ template: entry.config.template,
766
+ }),
767
+ }
768
+ : {}),
704
769
  ...(entry.config?.imports ? { imports: entry.config.imports } : {}),
705
770
  ...(recipeUsage(entry.config)
706
771
  ? { usage: recipeUsage(entry.config) }
@@ -52,6 +52,8 @@ export interface TemplateRecipeDefinition {
52
52
  args?: string[];
53
53
  defaults?: Record<string, unknown>;
54
54
  parallel?: boolean;
55
+ concurrency?: number | string;
56
+ min_successful?: number | string;
55
57
  label?: string;
56
58
  when?: boolean | string;
57
59
  timeout?: number | string;
@@ -255,6 +257,8 @@ function getRecipeCommandTemplate(
255
257
  "args",
256
258
  "defaults",
257
259
  "parallel",
260
+ "concurrency",
261
+ "min_successful",
258
262
  "label",
259
263
  "when",
260
264
  "timeout",
@@ -1013,6 +1017,14 @@ export function readResolvedRecipeConfig(
1013
1017
  ...(typeof substituted.parallel === "boolean"
1014
1018
  ? { parallel: substituted.parallel }
1015
1019
  : {}),
1020
+ ...(typeof substituted.concurrency === "number" ||
1021
+ typeof substituted.concurrency === "string"
1022
+ ? { concurrency: substituted.concurrency }
1023
+ : {}),
1024
+ ...(typeof substituted.min_successful === "number" ||
1025
+ typeof substituted.min_successful === "string"
1026
+ ? { min_successful: substituted.min_successful }
1027
+ : {}),
1016
1028
  ...(typeof substituted.label === "string"
1017
1029
  ? { label: substituted.label }
1018
1030
  : {}),
@@ -7,6 +7,7 @@
7
7
  import * as Rooms from "./rooms.ts";
8
8
  import * as AsyncRuns from "./async-runs.ts";
9
9
  import * as CommandTemplates from "./command-templates.ts";
10
+ import * as ModelContext from "./model-context.ts";
10
11
  import type { RegisteredTool } from "./config.ts";
11
12
  import * as Execution from "./execution.ts";
12
13
  import * as Prompts from "./prompts.ts";
@@ -17,7 +18,7 @@ import * as ToolsResponse from "./tools-response.ts";
17
18
 
18
19
  type JsonSchema = Schema.JsonSchema;
19
20
 
20
- export interface RuntimeToolContext {
21
+ export interface RuntimeToolContext extends ModelContext.CurrentModelContext {
21
22
  cwd: string;
22
23
  sessionManager?: { getSessionId?: () => string };
23
24
  }
@@ -178,8 +179,15 @@ export function createRuntimeToolDefinition(
178
179
  ownerId: getRunOwnerId(ctx),
179
180
  run_id: runId,
180
181
  tool: cfg.name,
182
+ policy_values: ModelContext.withCurrentModelValues(
183
+ { ...(cfg.recipe?.values ?? {}), ...values },
184
+ ctx,
185
+ ),
181
186
  values: Schema.normalizeRuntimeValues(
182
- { ...(cfg.recipe?.values ?? {}), ...cfg.defaults, ...values },
187
+ ModelContext.withCurrentModelValues(
188
+ { ...(cfg.recipe?.values ?? {}), ...cfg.defaults, ...values },
189
+ ctx,
190
+ ),
183
191
  cfg.argTypes,
184
192
  ),
185
193
  },
@@ -198,11 +206,14 @@ export function createRuntimeToolDefinition(
198
206
  };
199
207
  }
200
208
  if (isRecipe && recipeTemplate) {
201
- const paramsWithDefaults = {
202
- ...(cfg.recipe?.values ?? {}),
203
- ...cfg.defaults,
204
- ...(params as Record<string, unknown>),
205
- };
209
+ const paramsWithDefaults = ModelContext.withCurrentModelValues(
210
+ {
211
+ ...(cfg.recipe?.values ?? {}),
212
+ ...cfg.defaults,
213
+ ...(params as Record<string, unknown>),
214
+ },
215
+ ctx,
216
+ );
206
217
  return await Execution.executeRegisteredTool(
207
218
  { ...cfg, template: recipeTemplate },
208
219
  Schema.normalizeRuntimeValues(paramsWithDefaults, cfg.argTypes),
@@ -214,7 +225,10 @@ export function createRuntimeToolDefinition(
214
225
  return await Execution.executeRegisteredTool(
215
226
  cfg,
216
227
  Schema.normalizeRuntimeValues(
217
- params as Record<string, unknown>,
228
+ ModelContext.withCurrentModelValues(
229
+ params as Record<string, unknown>,
230
+ ctx,
231
+ ),
218
232
  cfg.argTypes,
219
233
  ),
220
234
  exec,
@@ -40,6 +40,25 @@ function formatFailureCount(value: unknown): number | undefined {
40
40
  return Array.isArray(value) ? value.length : undefined;
41
41
  }
42
42
 
43
+ function compactPolicyAxis(label: string, value: unknown): string | undefined {
44
+ const axis = asRecord(value);
45
+ const source = typeof axis.source === "string" ? axis.source : undefined;
46
+ if (!source || source === "unused") return undefined;
47
+ const renderedValue =
48
+ typeof axis.value === "string" && axis.value.trim()
49
+ ? `:${axis.value.trim()}`
50
+ : "";
51
+ return `${label}=${source}${renderedValue}`;
52
+ }
53
+
54
+ function compactModelPolicy(value: unknown): string[] {
55
+ const policy = asRecord(value);
56
+ return [
57
+ compactPolicyAxis("model", policy.model),
58
+ compactPolicyAxis("thinking", policy.thinking),
59
+ ].filter((token): token is string => Boolean(token));
60
+ }
61
+
43
62
  export function actorRunNextActions(run: unknown): string[] {
44
63
  const id = String(run ?? "").trim();
45
64
  if (!id) return [];
@@ -56,6 +75,7 @@ export function compactAsyncRunStatus(value: unknown): string {
56
75
  const result = asRecord(status.result);
57
76
  const run = String(status.run ?? "<unknown>");
58
77
  const tokens = [`run=${run}`, `status=${String(status.status ?? "unknown")}`];
78
+ tokens.push(...compactModelPolicy(status.model_policy ?? progress.model_policy));
59
79
  if (status.tool) tokens.push(`tool=${String(status.tool)}`);
60
80
  if (status.recipe) tokens.push(`recipe=${String(status.recipe)}`);
61
81
  if (status.retire_when)
@@ -272,10 +292,15 @@ export function compactRecipeRegistry(
272
292
  const recommendations = Array.isArray(summary.recommendations)
273
293
  ? summary.recommendations.length
274
294
  : 0;
295
+ const currentPolicy = Array.isArray(summary.active)
296
+ ? (summary.active as Array<Record<string, unknown>>).filter(
297
+ (entry) => entry.current_policy,
298
+ ).length
299
+ : 0;
275
300
  const nextActions = Array.isArray(summary.next_actions)
276
301
  ? (summary.next_actions as string[])
277
302
  : [];
278
- return `\nrecipes active=${active} drafts=${drafts} shadowed=${shadowed} invalid=${invalid} disabled=${disabled} recommendations=${recommendations} diagnostics=${diagnostics}${compactNextActions(nextActions)}`;
303
+ return `\nrecipes active=${active} drafts=${drafts} shadowed=${shadowed} invalid=${invalid} disabled=${disabled} current_policy=${currentPolicy} recommendations=${recommendations} diagnostics=${diagnostics}${compactNextActions(nextActions)}`;
279
304
  }
280
305
 
281
306
  export const DEFAULT_INSPECT_LINES = Limits.DEFAULT_INSPECT_LINES;
@@ -9,13 +9,14 @@ import { join } from "node:path";
9
9
 
10
10
  import * as AsyncRuns from "./async-runs.ts";
11
11
  import * as Messages from "./messages.ts";
12
+ import * as ModelContext from "./model-context.ts";
12
13
  import * as Paths from "./paths.ts";
13
14
  import * as RecipesDiscovery from "./recipes-discovery.ts";
14
15
  import * as Rooms from "./rooms.ts";
15
16
  import * as Schema from "./schema.ts";
16
17
  import * as ToolsResponse from "./tools-response.ts";
17
18
 
18
- export interface SpawnToolContext {
19
+ export interface SpawnToolContext extends ModelContext.CurrentModelContext {
19
20
  cwd: string;
20
21
  sessionManager?: { getSessionId?: () => string };
21
22
  }
@@ -196,7 +197,10 @@ export function createSpawnToolDefinition<
196
197
  input.template as AsyncRuns.AsyncRunStartParams["template"],
197
198
  }
198
199
  : {}),
199
- values: asRecord(input.values),
200
+ values: ModelContext.withCurrentModelValues(
201
+ asRecord(input.values),
202
+ ctx,
203
+ ),
200
204
  ...(input.artifacts &&
201
205
  typeof input.artifacts === "object" &&
202
206
  !Array.isArray(input.artifacts)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-actors",
3
- "version": "0.37.1",
3
+ "version": "0.38.1",
4
4
  "private": false,
5
5
  "description": "Local Actor Kernel for Pi",
6
6
  "keywords": [
@@ -10,6 +10,10 @@
10
10
  "model:string",
11
11
  "thinking:string",
12
12
  "tools:string",
13
+ "subagent_ttl_ms:int",
14
+ "reviewer_concurrency:string",
15
+ "min_successful_reviewers:int",
16
+ "merge_policy:string",
13
17
  "claim:string",
14
18
  "evidence_policy:string",
15
19
  "risk_policy:string",
@@ -21,12 +25,17 @@
21
25
  "architecture",
22
26
  "operator UX"
23
27
  ],
24
- "thinking": "off",
28
+ "model": "{current_model}",
29
+ "thinking": "{current_thinking}",
25
30
  "tools": "",
31
+ "subagent_ttl_ms": 600000,
32
+ "reviewer_concurrency": "",
33
+ "min_successful_reviewers": 1,
34
+ "merge_policy": "Preserve partial reviewer reports, branch status, and degraded confidence markers. If reviewer evidence is below threshold, do not invent consensus.",
26
35
  "claim": "The reviewed scope has clear, evidence-based findings, risks, and recommended next actions.",
27
36
  "evidence_policy": "Cite inspected files, command outputs, or explicit uncertainty for every material claim.",
28
37
  "risk_policy": "Preserve minority high-impact risks and ideas; separate confirmed issues from hypotheses.",
29
- "output_format": "Markdown sections: Summary, Consensus Findings, Minority Findings, Verification, Judge Notes, Risks, Next Actions."
38
+ "output_format": "Markdown sections: Status (complete/degraded/insufficient_data), Summary, Consensus Findings, Minority Findings, Verification, Judge Notes, Risks, Next Actions."
30
39
  },
31
40
  "mailbox": {
32
41
  "accepts": [
@@ -55,6 +64,10 @@
55
64
  "judge_model": "{model}",
56
65
  "thinking": "{thinking}",
57
66
  "tools": "{tools}",
67
+ "subagent_ttl_ms": "{subagent_ttl_ms}",
68
+ "reviewer_concurrency": "{reviewer_concurrency}",
69
+ "min_successful_reviewers": "{min_successful_reviewers}",
70
+ "merge_policy": "{merge_policy}",
58
71
  "evidence_policy": "{evidence_policy}",
59
72
  "risk_policy": "{risk_policy}",
60
73
  "output_format": "{output_format}"
@@ -20,7 +20,12 @@
20
20
  "verifier_model:string",
21
21
  "merger_model:string",
22
22
  "judge_model:string",
23
- "tools:string"
23
+ "thinking:string",
24
+ "tools:string",
25
+ "subagent_ttl_ms:int",
26
+ "reviewer_concurrency:string",
27
+ "min_successful_reviewers:int",
28
+ "merge_policy:string"
24
29
  ],
25
30
  "defaults": {
26
31
  "scope": ".",
@@ -36,7 +41,16 @@
36
41
  "documentation",
37
42
  "packaged skills"
38
43
  ],
39
- "tools": ""
44
+ "reviewer_model": "{current_model}",
45
+ "verifier_model": "{current_model}",
46
+ "merger_model": "{current_model}",
47
+ "judge_model": "{current_model}",
48
+ "thinking": "{current_thinking}",
49
+ "tools": "",
50
+ "subagent_ttl_ms": 600000,
51
+ "reviewer_concurrency": "",
52
+ "min_successful_reviewers": 1,
53
+ "merge_policy": "Preserve partial reviewer reports, branch status, and degraded confidence markers. If reviewer evidence is below threshold, do not invent consensus."
40
54
  },
41
55
  "mailbox": {
42
56
  "accepts": [
@@ -90,8 +104,13 @@
90
104
  "verifier_model": "{verifier_model}",
91
105
  "merger_model": "{merger_model}",
92
106
  "judge_model": "{judge_model}",
107
+ "thinking": "{thinking}",
93
108
  "tools": "{tools}",
94
- "output_format": "Markdown sections: Release Verdict, Blocking Issues, Package/Docs Risks, Validation Evidence, Publish Notes, Required Follow-up."
109
+ "subagent_ttl_ms": "{subagent_ttl_ms}",
110
+ "reviewer_concurrency": "{reviewer_concurrency}",
111
+ "min_successful_reviewers": "{min_successful_reviewers}",
112
+ "merge_policy": "{merge_policy}",
113
+ "output_format": "Markdown sections: Status (complete/degraded/insufficient_data), Release Verdict, Blocking Issues, Package/Docs Risks, Validation Evidence, Publish Notes, Required Follow-up."
95
114
  }
96
115
  },
97
116
  {
@@ -11,7 +11,12 @@
11
11
  "verifier_model:string",
12
12
  "merger_model:string",
13
13
  "judge_model:string",
14
- "tools:string"
14
+ "thinking:string",
15
+ "tools:string",
16
+ "subagent_ttl_ms:int",
17
+ "reviewer_concurrency:string",
18
+ "min_successful_reviewers:int",
19
+ "merge_policy:string"
15
20
  ],
16
21
  "defaults": {
17
22
  "lenses": [
@@ -21,7 +26,16 @@
21
26
  "operator UX"
22
27
  ],
23
28
  "release_gate": "The scope is safe to ship or hand to the next release step.",
24
- "tools": ""
29
+ "reviewer_model": "{current_model}",
30
+ "verifier_model": "{current_model}",
31
+ "merger_model": "{current_model}",
32
+ "judge_model": "{current_model}",
33
+ "thinking": "{current_thinking}",
34
+ "tools": "",
35
+ "subagent_ttl_ms": 600000,
36
+ "reviewer_concurrency": "",
37
+ "min_successful_reviewers": 1,
38
+ "merge_policy": "Preserve partial reviewer reports, branch status, and degraded confidence markers. If reviewer evidence is below threshold, do not invent consensus."
25
39
  },
26
40
  "mailbox": {
27
41
  "accepts": [
@@ -45,8 +59,13 @@
45
59
  "verifier_model": "{verifier_model}",
46
60
  "merger_model": "{merger_model}",
47
61
  "judge_model": "{judge_model}",
62
+ "thinking": "{thinking}",
48
63
  "tools": "{tools}",
49
- "output_format": "Markdown sections: Ship Verdict, Blocking Findings, Nonblocking Risks, Evidence, Required Follow-up."
64
+ "subagent_ttl_ms": "{subagent_ttl_ms}",
65
+ "reviewer_concurrency": "{reviewer_concurrency}",
66
+ "min_successful_reviewers": "{min_successful_reviewers}",
67
+ "merge_policy": "{merge_policy}",
68
+ "output_format": "Markdown sections: Status (complete/degraded/insufficient_data), Ship Verdict, Blocking Findings, Nonblocking Risks, Evidence, Required Follow-up."
50
69
  }
51
70
  }
52
71
  }
@@ -13,7 +13,8 @@
13
13
  "rubric": "Judge evidence preservation, severity calibration, consensus purity, internal consistency, and merge bias.",
14
14
  "evidence": "Use the provided raw outputs or artifact paths; mark any missing evidence.",
15
15
  "output_format": "Markdown sections: Verdict, Issues, Evidence Preservation, Bias Risks, Required Fixes.",
16
- "thinking": "medium",
16
+ "model": "{current_model}",
17
+ "thinking": "{current_thinking}",
17
18
  "tools": ""
18
19
  },
19
20
  "mailbox": {
@@ -3,6 +3,7 @@
3
3
  "args": [
4
4
  "inputs:string",
5
5
  "mode:enum(consensus-first,risk-first)",
6
+ "merge_policy:string",
6
7
  "risk_policy:string",
7
8
  "output_format:string",
8
9
  "model:string",
@@ -11,9 +12,11 @@
11
12
  ],
12
13
  "defaults": {
13
14
  "mode": "consensus-first",
15
+ "merge_policy": "Preserve partial reviewer evidence, branch status, and degraded confidence markers.",
14
16
  "risk_policy": "Preserve minority severe findings and mark merger-added claims explicitly.",
15
17
  "output_format": "Markdown sections: Summary, Consensus, Minority Findings, Contradictions, Next Actions.",
16
- "thinking": "medium",
18
+ "model": "{current_model}",
19
+ "thinking": "{current_thinking}",
17
20
  "tools": ""
18
21
  },
19
22
  "mailbox": {
@@ -27,5 +30,5 @@
27
30
  "run.failed"
28
31
  ]
29
32
  },
30
- "template": "pi -p --model {model} --thinking {thinking} {tools?--tools:--no-tools} {tools} Merge these subagent outputs using mode {mode}: {inputs}. Risk policy: {risk_policy}. Output format: {output_format}"
33
+ "template": "pi -p --model {model} --thinking {thinking} {tools?--tools:--no-tools} {tools} Merge these subagent outputs using mode {mode}: {inputs}. Merge policy: {merge_policy}. Risk policy: {risk_policy}. Output format: {output_format}"
31
34
  }
@@ -11,7 +11,8 @@
11
11
  "defaults": {
12
12
  "format": "Markdown sections: Summary, Findings, Evidence, Risks, Next Actions.",
13
13
  "preservation_policy": "Do not change meaning, severity, evidence, or uncertainty while normalizing.",
14
- "thinking": "off",
14
+ "model": "{current_model}",
15
+ "thinking": "{current_thinking}",
15
16
  "tools": ""
16
17
  },
17
18
  "mailbox": {
@@ -0,0 +1,29 @@
1
+ {
2
+ "async": true,
3
+ "args": [
4
+ "stage:string",
5
+ "model:string",
6
+ "thinking:string",
7
+ "tools:string",
8
+ "output_format:string"
9
+ ],
10
+ "defaults": {
11
+ "stage": "subagent",
12
+ "model": "{current_model}",
13
+ "thinking": "{current_thinking}",
14
+ "tools": "",
15
+ "output_format": "Reply exactly: ACTOR_PREFLIGHT_OK"
16
+ },
17
+ "mailbox": {
18
+ "accepts": [
19
+ "control.kill"
20
+ ],
21
+ "emits": [
22
+ "preflight.completed",
23
+ "command.done",
24
+ "run.done",
25
+ "run.failed"
26
+ ]
27
+ },
28
+ "template": "pi -p --model {model} --thinking {thinking} {tools?--tools:--no-tools} {tools} Preflight check for stage {stage}. Confirm this model, thinking level, and tool policy can start before expensive fanout. Do not inspect files. {output_format}"
29
+ }