ultimate-pi 0.10.1 → 0.12.0

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 (135) hide show
  1. package/.agents/skills/harness-debate-plan/SKILL.md +44 -0
  2. package/.agents/skills/harness-decisions/SKILL.md +3 -3
  3. package/.agents/skills/harness-orchestration/SKILL.md +59 -25
  4. package/.agents/skills/harness-plan/SKILL.md +16 -15
  5. package/.pi/agents/harness/adversary.md +0 -1
  6. package/.pi/agents/harness/evaluator.md +0 -1
  7. package/.pi/agents/harness/executor.md +1 -2
  8. package/.pi/agents/harness/incident-recorder.md +0 -1
  9. package/.pi/agents/harness/meta-optimizer.md +0 -1
  10. package/.pi/agents/harness/planning/decompose.md +83 -0
  11. package/.pi/agents/harness/planning/execution-plan-author.md +30 -0
  12. package/.pi/agents/harness/planning/hypothesis-validator.md +23 -0
  13. package/.pi/agents/harness/planning/hypothesis.md +89 -0
  14. package/.pi/agents/harness/planning/plan-adversary.md +18 -0
  15. package/.pi/agents/harness/planning/plan-evaluator.md +18 -0
  16. package/.pi/agents/harness/planning/review-integrator.md +23 -0
  17. package/.pi/agents/harness/planning/scout-graphify.md +54 -0
  18. package/.pi/agents/harness/planning/scout-semantic.md +47 -0
  19. package/.pi/agents/harness/planning/scout-structure.md +50 -0
  20. package/.pi/agents/harness/planning/sprint-contract-auditor.md +18 -0
  21. package/.pi/agents/harness/planning/stack-researcher.md +24 -0
  22. package/.pi/agents/harness/tie-breaker.md +0 -1
  23. package/.pi/agents/harness/trace-librarian.md +0 -1
  24. package/.pi/extensions/debate-orchestrator.ts +90 -53
  25. package/.pi/extensions/harness-ask-user.ts +5 -0
  26. package/.pi/extensions/harness-plan-approval.ts +137 -3
  27. package/.pi/extensions/harness-run-context.ts +146 -6
  28. package/.pi/extensions/harness-subagents.ts +10 -5
  29. package/.pi/extensions/harness-web-tools.ts +2 -0
  30. package/.pi/extensions/lib/extension-load-guard.ts +39 -0
  31. package/.pi/extensions/lib/harness-posthog.ts +6 -1
  32. package/.pi/extensions/lib/harness-spawn-budget.ts +75 -0
  33. package/.pi/extensions/lib/harness-subagent-auth.ts +123 -0
  34. package/.pi/extensions/lib/{harness-subagents/harness-subagent-policy.ts → harness-subagent-policy.ts} +34 -9
  35. package/.pi/extensions/lib/harness-subagent-precheck.ts +95 -0
  36. package/.pi/extensions/lib/harness-subagents-bridge.ts +176 -0
  37. package/.pi/extensions/lib/plan-approval/create-plan.ts +9 -7
  38. package/.pi/extensions/lib/plan-approval/plan-review.ts +393 -0
  39. package/.pi/extensions/lib/plan-approval/schema.ts +16 -1
  40. package/.pi/extensions/lib/plan-approval/types.ts +16 -0
  41. package/.pi/extensions/lib/plan-approval/validate.ts +2 -0
  42. package/.pi/extensions/lib/plan-debate-envelope.ts +84 -0
  43. package/.pi/extensions/lib/{harness-subagents/spawn-policy.ts → spawn-policy.ts} +2 -5
  44. package/.pi/extensions/policy-gate.ts +1 -1
  45. package/.pi/extensions/review-integrity.ts +48 -29
  46. package/.pi/extensions/ultimate-pi-vcc.ts +5 -0
  47. package/.pi/harness/agents.manifest.json +126 -82
  48. package/.pi/harness/docs/adrs/0032-harness-command-orchestration.md +7 -6
  49. package/.pi/harness/docs/adrs/0033-parent-orchestrated-planning.md +34 -0
  50. package/.pi/harness/docs/adrs/0034-darwin-plan-research-pipeline.md +41 -0
  51. package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +27 -0
  52. package/.pi/harness/docs/adrs/README.md +2 -0
  53. package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/artifacts/review-round-r1.yaml +25 -0
  54. package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/artifacts/review-round-r4.yaml +26 -0
  55. package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/artifacts/sprint-audit-r4.yaml +5 -0
  56. package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/plan-packet.yaml +196 -0
  57. package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/plan-review.md +14 -0
  58. package/.pi/harness/evals/smoke/fixtures/plan-phase/minimal-med/research-brief.yaml +32 -0
  59. package/.pi/harness/evals/smoke/run-context.fixture.json +1 -1
  60. package/.pi/harness/evals/smoke/smoke-harness-plan.mjs +88 -0
  61. package/.pi/harness/specs/README.md +1 -1
  62. package/.pi/harness/specs/harness-posthog-event.schema.json +6 -1
  63. package/.pi/harness/specs/harness-spawn-context.schema.json +2 -1
  64. package/.pi/harness/specs/plan-adversary-brief.schema.json +45 -0
  65. package/.pi/harness/specs/plan-decomposition-brief.schema.json +108 -0
  66. package/.pi/harness/specs/plan-execution-plan-brief.schema.json +13 -0
  67. package/.pi/harness/specs/plan-execution-plan.schema.json +255 -0
  68. package/.pi/harness/specs/plan-hypothesis-brief.schema.json +96 -0
  69. package/.pi/harness/specs/plan-hypothesis-eval.schema.json +61 -0
  70. package/.pi/harness/specs/plan-packet.schema.json +14 -5
  71. package/.pi/harness/specs/plan-review-round-draft.schema.json +68 -0
  72. package/.pi/harness/specs/plan-sprint-audit-turn.schema.json +29 -0
  73. package/.pi/harness/specs/plan-stack-brief.schema.json +65 -0
  74. package/.pi/harness/specs/plan-validation-turn.schema.json +42 -0
  75. package/.pi/harness/specs/round-result.schema.json +16 -9
  76. package/.pi/lib/debate-orchestrator-types.ts +38 -0
  77. package/.pi/lib/harness-agent-discovery.mjs +81 -0
  78. package/.pi/lib/harness-run-context.ts +76 -38
  79. package/.pi/lib/harness-yaml.mjs +73 -0
  80. package/.pi/lib/harness-yaml.ts +90 -0
  81. package/.pi/prompts/harness-auto.md +13 -11
  82. package/.pi/prompts/harness-critic.md +2 -2
  83. package/.pi/prompts/harness-eval.md +3 -3
  84. package/.pi/prompts/harness-incident.md +2 -2
  85. package/.pi/prompts/harness-plan.md +106 -37
  86. package/.pi/prompts/harness-review.md +2 -2
  87. package/.pi/prompts/harness-router-tune.md +1 -1
  88. package/.pi/prompts/harness-run.md +2 -2
  89. package/.pi/prompts/harness-setup.md +15 -6
  90. package/.pi/prompts/harness-trace.md +2 -2
  91. package/.pi/scripts/harness-agents-manifest.mjs +1 -1
  92. package/.pi/scripts/harness-resolve-up-pkg.mjs +13 -0
  93. package/.pi/scripts/harness-verify.mjs +28 -19
  94. package/.pi/scripts/validate-plan-dag.mjs +258 -0
  95. package/.pi/scripts/vendor-sync-pi-subagents.sh +19 -0
  96. package/CHANGELOG.md +24 -0
  97. package/THIRD_PARTY_NOTICES.md +8 -0
  98. package/biome.json +4 -1
  99. package/package.json +6 -4
  100. package/.pi/agents/harness/planner.md +0 -54
  101. package/.pi/extensions/lib/harness-subagents/agent-loader.ts +0 -126
  102. package/.pi/extensions/lib/harness-subagents/agent-manifest.ts +0 -119
  103. package/.pi/extensions/lib/harness-subagents/agent-parser.ts +0 -87
  104. package/.pi/extensions/lib/harness-subagents/blackboard-tool.ts +0 -118
  105. package/.pi/extensions/lib/harness-subagents/blackboard.ts +0 -175
  106. package/.pi/extensions/lib/harness-subagents/parent-ask-user-bridge.ts +0 -10
  107. package/.pi/extensions/lib/harness-subagents/parent-harness-ui-bridge.ts +0 -310
  108. package/.pi/extensions/lib/harness-subagents/parent-harness-ui-hooks.ts +0 -59
  109. package/.pi/extensions/lib/harness-subagents/types-blackboard.ts +0 -27
  110. package/.pi/extensions/lib/harness-subagents/vendored/agent-manager.ts +0 -558
  111. package/.pi/extensions/lib/harness-subagents/vendored/agent-runner.ts +0 -684
  112. package/.pi/extensions/lib/harness-subagents/vendored/agent-types.ts +0 -175
  113. package/.pi/extensions/lib/harness-subagents/vendored/context.ts +0 -59
  114. package/.pi/extensions/lib/harness-subagents/vendored/cross-extension-rpc.ts +0 -134
  115. package/.pi/extensions/lib/harness-subagents/vendored/custom-agents.ts +0 -5
  116. package/.pi/extensions/lib/harness-subagents/vendored/default-agents.ts +0 -123
  117. package/.pi/extensions/lib/harness-subagents/vendored/env.ts +0 -43
  118. package/.pi/extensions/lib/harness-subagents/vendored/group-join.ts +0 -144
  119. package/.pi/extensions/lib/harness-subagents/vendored/index.ts +0 -2494
  120. package/.pi/extensions/lib/harness-subagents/vendored/invocation-config.ts +0 -52
  121. package/.pi/extensions/lib/harness-subagents/vendored/memory.ts +0 -182
  122. package/.pi/extensions/lib/harness-subagents/vendored/model-resolver.ts +0 -92
  123. package/.pi/extensions/lib/harness-subagents/vendored/output-file.ts +0 -115
  124. package/.pi/extensions/lib/harness-subagents/vendored/prompts.ts +0 -103
  125. package/.pi/extensions/lib/harness-subagents/vendored/schedule-store.ts +0 -177
  126. package/.pi/extensions/lib/harness-subagents/vendored/schedule.ts +0 -416
  127. package/.pi/extensions/lib/harness-subagents/vendored/settings.ts +0 -210
  128. package/.pi/extensions/lib/harness-subagents/vendored/skill-loader.ts +0 -108
  129. package/.pi/extensions/lib/harness-subagents/vendored/types.ts +0 -187
  130. package/.pi/extensions/lib/harness-subagents/vendored/ui/agent-widget.ts +0 -639
  131. package/.pi/extensions/lib/harness-subagents/vendored/ui/conversation-viewer.ts +0 -324
  132. package/.pi/extensions/lib/harness-subagents/vendored/ui/schedule-menu.ts +0 -110
  133. package/.pi/extensions/lib/harness-subagents/vendored/usage.ts +0 -71
  134. package/.pi/extensions/lib/harness-subagents/vendored/worktree.ts +0 -195
  135. /package/.pi/extensions/{00-ultimate-pi-system-prompt.ts → custom-system-prompt.ts} +0 -0
@@ -13,6 +13,21 @@ export const ApprovePlanParamsSchema = Type.Object({
13
13
  description: "Short summary shown above the plan body.",
14
14
  }),
15
15
  ),
16
+ research_brief: Type.Optional(
17
+ Type.Object(
18
+ {
19
+ decomposition: Type.Optional(
20
+ Type.Union([Type.Object({}), Type.Null()]),
21
+ ),
22
+ hypothesis: Type.Optional(Type.Union([Type.Object({}), Type.Null()])),
23
+ eval: Type.Optional(Type.Union([Type.Object({}), Type.Null()])),
24
+ },
25
+ {
26
+ description:
27
+ "Optional Darwin research: decomposition, hypothesis, eval (plan-review.md only).",
28
+ },
29
+ ),
30
+ ),
16
31
  options: Type.Optional(
17
32
  Type.Array(
18
33
  Type.Union([
@@ -30,7 +45,7 @@ export const ApprovePlanParamsSchema = Type.Object({
30
45
  });
31
46
 
32
47
  export const PROMPT_SNIPPET =
33
- "approve_plan({ plan_packet: { ...PlanPacket fields... }, human_summary?: string })";
48
+ "approve_plan({ plan_packet: { ...PlanPacket fields... }, human_summary?: string, research_brief?: { decomposition, hypothesis, eval } })";
34
49
 
35
50
  export const PROMPT_GUIDELINES = [
36
51
  "Call approve_plan once with the complete plan_packet when ready for user approval.",
@@ -7,9 +7,23 @@ export const DEFAULT_PLAN_APPROVAL_OPTIONS = [
7
7
  "Cancel",
8
8
  ] as const;
9
9
 
10
+ /** Optional Darwin research artifacts from /harness-plan (research-brief.yaml, not in plan-packet). */
11
+ export interface PlanResearchBrief {
12
+ decomposition?: Record<string, unknown> | null;
13
+ hypothesis?: Record<string, unknown> | null;
14
+ eval?: Record<string, unknown> | null;
15
+ stack?: Record<string, unknown> | null;
16
+ debate?: {
17
+ rounds?: Record<string, unknown>[];
18
+ hypothesis_validations?: Record<string, unknown>[];
19
+ } | null;
20
+ dag_validation?: Record<string, unknown> | null;
21
+ }
22
+
10
23
  export interface ApprovePlanParams {
11
24
  plan_packet: PlanPacketLike;
12
25
  human_summary?: string;
26
+ research_brief?: PlanResearchBrief | null;
13
27
  options?: Array<string | { title: string; description?: string }>;
14
28
  displayMode?: "overlay" | "inline";
15
29
  }
@@ -17,6 +31,7 @@ export interface ApprovePlanParams {
17
31
  export interface ValidatedApprovePlanParams {
18
32
  plan_packet: PlanPacketLike;
19
33
  human_summary?: string;
34
+ research_brief?: PlanResearchBrief | null;
20
35
  options: { title: string; description?: string }[];
21
36
  displayMode: "overlay" | "inline";
22
37
  }
@@ -24,6 +39,7 @@ export interface ValidatedApprovePlanParams {
24
39
  export interface ApprovePlanToolDetails {
25
40
  plan_packet: PlanPacketLike;
26
41
  human_summary?: string;
42
+ research_brief?: PlanResearchBrief | null;
27
43
  options: string[];
28
44
  response: AskResponse | null;
29
45
  cancelled: boolean;
@@ -34,6 +34,7 @@ export function validateApprovePlanParams(
34
34
  return {
35
35
  plan_packet: packet as PlanPacketLike,
36
36
  human_summary: params.human_summary?.trim() || undefined,
37
+ research_brief: params.research_brief ?? undefined,
37
38
  options,
38
39
  displayMode: params.displayMode ?? "overlay",
39
40
  };
@@ -47,6 +48,7 @@ export function toApprovePlanToolDetails(
47
48
  return {
48
49
  plan_packet: validated.plan_packet,
49
50
  human_summary: validated.human_summary,
51
+ research_brief: validated.research_brief ?? null,
50
52
  options: validated.options.map((o) => o.title),
51
53
  response,
52
54
  cancelled,
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Plan Review Gate — convert integrator YAML to debate bus round JSON.
3
+ */
4
+
5
+ import type { DebateParticipant } from "../../lib/debate-orchestrator-types.js";
6
+
7
+ export interface PlanReviewRoundDraft {
8
+ schema_version: string;
9
+ round_index: number;
10
+ debate_round_focus?: string;
11
+ round_summary?: string;
12
+ validation_summary?: string;
13
+ adversary_summary?: string;
14
+ disputes?: string[];
15
+ recommended_packet_patches?: Array<{ path: string; value: unknown }>;
16
+ review_gate_ready?: boolean;
17
+ participants?: DebateParticipant[];
18
+ claims?: string[];
19
+ rebuttals?: string[];
20
+ evidence_refs?: string[];
21
+ token_usage?: {
22
+ per_agent: Record<string, number>;
23
+ round_total: number;
24
+ };
25
+ consensus_delta?: number;
26
+ severity_scores?: {
27
+ correctness: number;
28
+ security: number;
29
+ architecture: number;
30
+ test_integrity: number;
31
+ };
32
+ }
33
+
34
+ export function buildPlanReviewRoundEnvelope(
35
+ draft: PlanReviewRoundDraft,
36
+ opts: { runId: string; debateId: string },
37
+ ): {
38
+ protocol: "pi-debate-bus/v1";
39
+ kind: "round";
40
+ correlation: {
41
+ run_id: string;
42
+ debate_id: string;
43
+ round_index: number;
44
+ sender: DebateParticipant;
45
+ };
46
+ payload: {
47
+ participants: DebateParticipant[];
48
+ claims: string[];
49
+ rebuttals: string[];
50
+ evidence_refs: string[];
51
+ token_usage: { per_agent: Record<string, number>; round_total: number };
52
+ consensus_delta: number;
53
+ severity_scores?: PlanReviewRoundDraft["severity_scores"];
54
+ };
55
+ } {
56
+ const participants = (draft.participants ?? [
57
+ "PlanEvaluatorAgent",
58
+ "PlanAdversaryAgent",
59
+ "ReviewIntegratorAgent",
60
+ ]) as DebateParticipant[];
61
+
62
+ return {
63
+ protocol: "pi-debate-bus/v1",
64
+ kind: "round",
65
+ correlation: {
66
+ run_id: opts.runId,
67
+ debate_id: opts.debateId,
68
+ round_index: draft.round_index,
69
+ sender: "ReviewIntegratorAgent",
70
+ },
71
+ payload: {
72
+ participants,
73
+ claims: draft.claims ?? [draft.round_summary ?? "review round"],
74
+ rebuttals: draft.rebuttals ?? draft.disputes ?? [],
75
+ evidence_refs: draft.evidence_refs ?? [],
76
+ token_usage: draft.token_usage ?? {
77
+ per_agent: { ReviewIntegratorAgent: 0 },
78
+ round_total: 0,
79
+ },
80
+ consensus_delta: draft.consensus_delta ?? 0,
81
+ severity_scores: draft.severity_scores,
82
+ },
83
+ };
84
+ }
@@ -7,10 +7,10 @@ export const SUBAGENT_BLOCKED_TOOLS = new Set([
7
7
  "get_subagent_result",
8
8
  "steer_subagent",
9
9
  "blackboard",
10
+ "subagent",
10
11
  ]);
11
12
 
12
13
  const ASK_USER_ALLOWED_AGENT_TYPES = new Set([
13
- "harness/planner",
14
14
  "harness/evaluator",
15
15
  "harness/adversary",
16
16
  "harness/tie-breaker",
@@ -42,12 +42,9 @@ export function evaluateSubagentToolCall(
42
42
  };
43
43
  }
44
44
  if (toolName === "approve_plan" || toolName === "create_plan") {
45
- if (agentType === "harness/planner") {
46
- return { action: "allow" };
47
- }
48
45
  return {
49
46
  action: "block",
50
- reason: `Tool "${toolName}" is only available for harness/planner.`,
47
+ reason: `Tool "${toolName}" is only available in the parent harness orchestrator session.`,
51
48
  };
52
49
  }
53
50
  return { action: "allow" };
@@ -243,7 +243,7 @@ export default function policyGate(pi: ExtensionAPI) {
243
243
 
244
244
  const planPhaseHint =
245
245
  state.phase === "plan"
246
- ? "\nPlan phase: present the full PlanPacket in chat, call ask_user (Approve / Request changes / Cancel), then write only the canonical plan-packet.json after Approve."
246
+ ? "\nPlan phase: scouts decompose hypothesis stack-researcher execution-plan-author validate-plan-dag 4-round plan debate approve_plan create_plan (YAML plan-packet.yaml). Post-execute: /harness-critic."
247
247
  : "";
248
248
 
249
249
  return {
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * review-integrity — enforce evaluator/adversary isolation from executor session.
3
3
  *
4
- * Parent orchestrators spawn review agents in isolated subagent sessions.
5
- * Direct review tools in the executor session are blocked; Agent/get_subagent_result
6
- * for harness review agents remain allowed.
4
+ * Parent orchestrators spawn review agents in isolated subprocesses via `subagent`.
5
+ * Direct review tools in the executor session are blocked.
7
6
  */
8
7
 
9
8
  import { appendFile, mkdir } from "node:fs/promises";
@@ -15,12 +14,6 @@ type HarnessPhase = "plan" | "execute" | "evaluate" | "adversary" | "merge";
15
14
  const INCIDENTS_DIR = join(process.cwd(), ".pi", "harness", "incidents");
16
15
  const INCIDENT_FILE = join(INCIDENTS_DIR, "review-integrity.jsonl");
17
16
 
18
- const ORCHESTRATION_TOOLS = new Set([
19
- "Agent",
20
- "get_subagent_result",
21
- "steer_subagent",
22
- ]);
23
-
24
17
  const REVIEW_SUBAGENT_TYPES = new Set([
25
18
  "harness/evaluator",
26
19
  "harness/adversary",
@@ -104,15 +97,45 @@ function restoreState(ctx: {
104
97
  };
105
98
  }
106
99
 
107
- function subagentTypeFromInput(
100
+ function agentsFromSubagentInput(
108
101
  input: Record<string, unknown> | undefined,
109
- ): string {
110
- if (!input) return "";
111
- const direct = input.subagent_type;
112
- if (typeof direct === "string") return direct;
113
- const nested = input as { subagentType?: string };
114
- if (typeof nested.subagentType === "string") return nested.subagentType;
115
- return "";
102
+ ): string[] {
103
+ if (!input) return [];
104
+ const names: string[] = [];
105
+ if (typeof input.agent === "string") names.push(input.agent);
106
+ const tasks = input.tasks;
107
+ if (Array.isArray(tasks)) {
108
+ for (const t of tasks) {
109
+ if (
110
+ t &&
111
+ typeof t === "object" &&
112
+ typeof (t as { agent?: string }).agent === "string"
113
+ ) {
114
+ names.push((t as { agent: string }).agent);
115
+ }
116
+ }
117
+ }
118
+ const chain = input.chain;
119
+ if (Array.isArray(chain)) {
120
+ for (const c of chain) {
121
+ if (
122
+ c &&
123
+ typeof c === "object" &&
124
+ typeof (c as { agent?: string }).agent === "string"
125
+ ) {
126
+ names.push((c as { agent: string }).agent);
127
+ }
128
+ }
129
+ }
130
+ const agg = input.aggregator;
131
+ if (
132
+ agg &&
133
+ typeof agg === "object" &&
134
+ typeof (agg as { agent?: string }).agent === "string"
135
+ ) {
136
+ names.push((agg as { agent: string }).agent);
137
+ }
138
+ return names;
116
139
  }
117
140
 
118
141
  async function appendIncident(payload: Record<string, unknown>): Promise<void> {
@@ -178,26 +201,26 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
178
201
  customType: "harness-review-integrity-hint",
179
202
  display: true,
180
203
  content: [
181
- "Review phase in executor session: spawn harness/evaluator or harness/adversary via Agent (isolated subagent context).",
182
- "Do not run review checks directly in this session — use get_subagent_result after spawn.",
204
+ "Review phase in executor session: spawn harness/evaluator or harness/adversary via subagent (isolated subprocess).",
205
+ "Do not run review checks directly in this session.",
183
206
  ].join("\n"),
184
207
  },
185
208
  };
186
209
  });
187
210
 
188
211
  pi.on("tool_call", async (event, ctx) => {
189
- if (event.toolName === "Agent") {
190
- const subagentType = subagentTypeFromInput(
212
+ if (event.toolName === "subagent") {
213
+ const agents = agentsFromSubagentInput(
191
214
  event.input as Record<string, unknown> | undefined,
192
215
  );
193
- if (subagentType === EXECUTOR_SUBAGENT_TYPE) {
216
+ if (agents.includes(EXECUTOR_SUBAGENT_TYPE)) {
194
217
  state.executorSessionId = ctx.sessionManager.getSessionId();
195
218
  state.violationActive = false;
196
219
  state.updatedAt = nowIso();
197
220
  persist();
198
221
  return undefined;
199
222
  }
200
- if (REVIEW_SUBAGENT_TYPES.has(subagentType)) {
223
+ if (agents.some((a) => REVIEW_SUBAGENT_TYPES.has(a))) {
201
224
  state.violationActive = false;
202
225
  state.updatedAt = nowIso();
203
226
  persist();
@@ -207,10 +230,6 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
207
230
 
208
231
  if (!state.violationActive) return undefined;
209
232
 
210
- if (ORCHESTRATION_TOOLS.has(event.toolName)) {
211
- return undefined;
212
- }
213
-
214
233
  await appendIncident({
215
234
  type: "review_integrity_violation",
216
235
  session_id: ctx.sessionManager.getSessionId(),
@@ -218,13 +237,13 @@ export default function reviewIntegrity(pi: ExtensionAPI) {
218
237
  reason:
219
238
  "direct tool use in review phase while sharing executor session context",
220
239
  mitigation:
221
- "spawn harness/evaluator or harness/adversary via Agent instead",
240
+ "spawn harness/evaluator or harness/adversary via subagent instead",
222
241
  });
223
242
 
224
243
  return {
225
244
  block: true,
226
245
  reason:
227
- "review-integrity: tool blocked in review phase — spawn an isolated review subagent via Agent.",
246
+ "review-integrity: tool blocked in review phase — spawn an isolated review subagent via subagent.",
228
247
  };
229
248
  });
230
249
 
@@ -11,7 +11,12 @@
11
11
 
12
12
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
13
13
  import registerVcc from "../../vendor/pi-vcc/index.js";
14
+ import { claimExtensionLoad } from "./lib/extension-load-guard.js";
15
+
16
+ // @ts-expect-error pi extensions run as ESM
17
+ const MODULE_URL = import.meta.url;
14
18
 
15
19
  export default function ultimatePiVcc(pi: ExtensionAPI): void {
20
+ if (!claimExtensionLoad("ultimate-pi-vcc", MODULE_URL)) return;
16
21
  registerVcc(pi);
17
22
  }
@@ -1,84 +1,128 @@
1
1
  {
2
- "schema_version": "1.0.0",
3
- "package": "ultimate-pi",
4
- "package_version": "0.9.0",
5
- "generated_at": "2026-05-17T10:06:28.388Z",
6
- "agents": {
7
- "pi-pi/agent-expert": {
8
- "path": ".pi/agents/pi-pi/agent-expert.md",
9
- "sha256": "86561eb092b92fa43f221bfc6305de8d5afe10d43c5f577b9bf15a71bda051c6"
10
- },
11
- "pi-pi/cli-expert": {
12
- "path": ".pi/agents/pi-pi/cli-expert.md",
13
- "sha256": "6ecdbc37c60f1da7c68d504187454c95197dd19bd7091d97d136c6fb9e866838"
14
- },
15
- "pi-pi/config-expert": {
16
- "path": ".pi/agents/pi-pi/config-expert.md",
17
- "sha256": "c23b9b70a4c326cca2d139f18de48f8db2e0e28fa5ceb8205600f25430822a40"
18
- },
19
- "pi-pi/ext-expert": {
20
- "path": ".pi/agents/pi-pi/ext-expert.md",
21
- "sha256": "47c64a9e2cffe00a50cac5541b0edc89fe8bcbd66ec3bb302eecc10d405a977f"
22
- },
23
- "pi-pi/keybinding-expert": {
24
- "path": ".pi/agents/pi-pi/keybinding-expert.md",
25
- "sha256": "bb83f5fd2178075c8374ef28c360339f7de9faeedf811670b43a536c5f65c58e"
26
- },
27
- "pi-pi/pi-orchestrator": {
28
- "path": ".pi/agents/pi-pi/pi-orchestrator.md",
29
- "sha256": "1323fc262112030320bdd7d7866fd69e1b861377bb30fd3553a5e3a4398f9090"
30
- },
31
- "pi-pi/prompt-expert": {
32
- "path": ".pi/agents/pi-pi/prompt-expert.md",
33
- "sha256": "0d9f5e3e8ab162149cac8f08e159a7b2150a11f53ebe7021e72f8277fa004d0c"
34
- },
35
- "pi-pi/skill-expert": {
36
- "path": ".pi/agents/pi-pi/skill-expert.md",
37
- "sha256": "91732a2479097a2645b6af56171d5cdc1ed67a0896ca54bc4badba250341698f"
38
- },
39
- "pi-pi/theme-expert": {
40
- "path": ".pi/agents/pi-pi/theme-expert.md",
41
- "sha256": "3d256049203356d87c36eac2232c0ad6261fec8af02eb15d3144b18a400ed64d"
42
- },
43
- "pi-pi/tui-expert": {
44
- "path": ".pi/agents/pi-pi/tui-expert.md",
45
- "sha256": "a619b2ee3d3d94fe599abb61db0904f90d30335ec426851c3f1efdf2e5ce5390"
46
- },
47
- "harness/adversary": {
48
- "path": ".pi/agents/harness/adversary.md",
49
- "sha256": "b965f90610ca942d08b656f1aee839266d08a92beb174b8761dd5e840694a899"
50
- },
51
- "harness/evaluator": {
52
- "path": ".pi/agents/harness/evaluator.md",
53
- "sha256": "6c0de777a10de26dba4a6feb5641495fa5c2d31072a8b0e597a5ecc9921f129f"
54
- },
55
- "harness/executor": {
56
- "path": ".pi/agents/harness/executor.md",
57
- "sha256": "5af3ec2be4d64a738834e36d480a36c2bee4359e8cd5a2e1aac49be4cff79589"
58
- },
59
- "harness/incident-recorder": {
60
- "path": ".pi/agents/harness/incident-recorder.md",
61
- "sha256": "2de405f77b62dde38f331665bff220a3ef131c3c1cd42eebee364000fc83352b"
62
- },
63
- "harness/meta-optimizer": {
64
- "path": ".pi/agents/harness/meta-optimizer.md",
65
- "sha256": "ef2fb950e18e3a6439e91a68f764fc7ec922cd2d6b35de8f656f376854974d04"
66
- },
67
- "harness/planner": {
68
- "path": ".pi/agents/harness/planner.md",
69
- "sha256": "eb0459a1fcb018e4ca8d4339141e294828fa7014879d9a64258ae01abc13d3ad"
70
- },
71
- "harness/sentrux-bootstrap": {
72
- "path": ".pi/agents/harness/sentrux-bootstrap.md",
73
- "sha256": "3a0b43b94386a7c541b8a806a37524a5e53f1c8049270db7a420680df5799eeb"
74
- },
75
- "harness/tie-breaker": {
76
- "path": ".pi/agents/harness/tie-breaker.md",
77
- "sha256": "651f50b9e2c7903c542700e94908b1fcd026ebed12aa1f1d6ec481df3567e34f"
78
- },
79
- "harness/trace-librarian": {
80
- "path": ".pi/agents/harness/trace-librarian.md",
81
- "sha256": "d63fe08a2ea0466c0fd89fff4da03ac1d9d3580c306381cee251c89d4e8fdb97"
82
- }
83
- }
2
+ "schema_version": "1.0.0",
3
+ "package": "ultimate-pi",
4
+ "package_version": "0.11.0",
5
+ "generated_at": "2026-05-18T09:43:44.563Z",
6
+ "agents": {
7
+ "pi-pi/agent-expert": {
8
+ "path": ".pi/agents/pi-pi/agent-expert.md",
9
+ "sha256": "86561eb092b92fa43f221bfc6305de8d5afe10d43c5f577b9bf15a71bda051c6"
10
+ },
11
+ "pi-pi/cli-expert": {
12
+ "path": ".pi/agents/pi-pi/cli-expert.md",
13
+ "sha256": "6ecdbc37c60f1da7c68d504187454c95197dd19bd7091d97d136c6fb9e866838"
14
+ },
15
+ "pi-pi/config-expert": {
16
+ "path": ".pi/agents/pi-pi/config-expert.md",
17
+ "sha256": "c23b9b70a4c326cca2d139f18de48f8db2e0e28fa5ceb8205600f25430822a40"
18
+ },
19
+ "pi-pi/ext-expert": {
20
+ "path": ".pi/agents/pi-pi/ext-expert.md",
21
+ "sha256": "47c64a9e2cffe00a50cac5541b0edc89fe8bcbd66ec3bb302eecc10d405a977f"
22
+ },
23
+ "pi-pi/keybinding-expert": {
24
+ "path": ".pi/agents/pi-pi/keybinding-expert.md",
25
+ "sha256": "bb83f5fd2178075c8374ef28c360339f7de9faeedf811670b43a536c5f65c58e"
26
+ },
27
+ "pi-pi/pi-orchestrator": {
28
+ "path": ".pi/agents/pi-pi/pi-orchestrator.md",
29
+ "sha256": "1323fc262112030320bdd7d7866fd69e1b861377bb30fd3553a5e3a4398f9090"
30
+ },
31
+ "pi-pi/prompt-expert": {
32
+ "path": ".pi/agents/pi-pi/prompt-expert.md",
33
+ "sha256": "0d9f5e3e8ab162149cac8f08e159a7b2150a11f53ebe7021e72f8277fa004d0c"
34
+ },
35
+ "pi-pi/skill-expert": {
36
+ "path": ".pi/agents/pi-pi/skill-expert.md",
37
+ "sha256": "91732a2479097a2645b6af56171d5cdc1ed67a0896ca54bc4badba250341698f"
38
+ },
39
+ "pi-pi/theme-expert": {
40
+ "path": ".pi/agents/pi-pi/theme-expert.md",
41
+ "sha256": "3d256049203356d87c36eac2232c0ad6261fec8af02eb15d3144b18a400ed64d"
42
+ },
43
+ "pi-pi/tui-expert": {
44
+ "path": ".pi/agents/pi-pi/tui-expert.md",
45
+ "sha256": "a619b2ee3d3d94fe599abb61db0904f90d30335ec426851c3f1efdf2e5ce5390"
46
+ },
47
+ "harness/adversary": {
48
+ "path": ".pi/agents/harness/adversary.md",
49
+ "sha256": "dd2ef87139cb175d795f4d7bde78dca1a181d2e42c3c3bd0d48832cf5069aa29"
50
+ },
51
+ "harness/evaluator": {
52
+ "path": ".pi/agents/harness/evaluator.md",
53
+ "sha256": "2b8039fd79f9177fdafd5319a53a96812719d4f1f68e2de70632030142649cfe"
54
+ },
55
+ "harness/executor": {
56
+ "path": ".pi/agents/harness/executor.md",
57
+ "sha256": "b549e9fc802ba23857a1bc6b2ff36f3c169e708fe5ec13857b3bcfe841384f1f"
58
+ },
59
+ "harness/incident-recorder": {
60
+ "path": ".pi/agents/harness/incident-recorder.md",
61
+ "sha256": "d7577c911a9e6c9607eb64f76337aab85c4eb9a92e7cd917eb8d989ef3cd1de5"
62
+ },
63
+ "harness/meta-optimizer": {
64
+ "path": ".pi/agents/harness/meta-optimizer.md",
65
+ "sha256": "a4eed88084c7cfb5ace3edc72b72d7ead4134b3eae0d444b391decfe2640a632"
66
+ },
67
+ "harness/sentrux-bootstrap": {
68
+ "path": ".pi/agents/harness/sentrux-bootstrap.md",
69
+ "sha256": "3a0b43b94386a7c541b8a806a37524a5e53f1c8049270db7a420680df5799eeb"
70
+ },
71
+ "harness/tie-breaker": {
72
+ "path": ".pi/agents/harness/tie-breaker.md",
73
+ "sha256": "68f02b86e95927f06d7f963e1f61f193159bbef1ba4558d90c84d5457d62b3f7"
74
+ },
75
+ "harness/trace-librarian": {
76
+ "path": ".pi/agents/harness/trace-librarian.md",
77
+ "sha256": "03b499a948b8467f1cfe2b4e63190feb7b8b9d96461055638e774253b9b6b2d4"
78
+ },
79
+ "harness/planning/decompose": {
80
+ "path": ".pi/agents/harness/planning/decompose.md",
81
+ "sha256": "1b3f85d956d2e203ec87045a731c47f8b40f75b63fce8916fda91cefc39244a8"
82
+ },
83
+ "harness/planning/execution-plan-author": {
84
+ "path": ".pi/agents/harness/planning/execution-plan-author.md",
85
+ "sha256": "a69fb2e8bda9336e71ce9536071f9c8a2f4abd9d9d88930c6a8be29bdc9c5f62"
86
+ },
87
+ "harness/planning/hypothesis-validator": {
88
+ "path": ".pi/agents/harness/planning/hypothesis-validator.md",
89
+ "sha256": "f75312439c441ccee72692d41f44b6e733df08e06c89e930740fc256bed3ba02"
90
+ },
91
+ "harness/planning/hypothesis": {
92
+ "path": ".pi/agents/harness/planning/hypothesis.md",
93
+ "sha256": "b20c527d15c2243cd5d3a8f16cea6d44bdfd16e01915d42f3b830bf9938e5f8b"
94
+ },
95
+ "harness/planning/plan-adversary": {
96
+ "path": ".pi/agents/harness/planning/plan-adversary.md",
97
+ "sha256": "685926c638ae1377361d7cafda5e400be19cb3880510d8f6d389a5876647575f"
98
+ },
99
+ "harness/planning/plan-evaluator": {
100
+ "path": ".pi/agents/harness/planning/plan-evaluator.md",
101
+ "sha256": "44fd52389d7e43dd5093653cba9694900561318ee5f00e3bc05c3ecef5d43621"
102
+ },
103
+ "harness/planning/review-integrator": {
104
+ "path": ".pi/agents/harness/planning/review-integrator.md",
105
+ "sha256": "d0e8214539d0a78b9e5add70e61dd4e4de36def64172cda18d9b70727e7600ca"
106
+ },
107
+ "harness/planning/scout-graphify": {
108
+ "path": ".pi/agents/harness/planning/scout-graphify.md",
109
+ "sha256": "b59916a26afccfe105e29c0bd8637ac54275e8afef1c6cc88a58bd05b0325473"
110
+ },
111
+ "harness/planning/scout-semantic": {
112
+ "path": ".pi/agents/harness/planning/scout-semantic.md",
113
+ "sha256": "47b7ea3e65b20a65e6d0ff11b6d5daff59b47a9ed618b8a3b6282f2eb0460572"
114
+ },
115
+ "harness/planning/scout-structure": {
116
+ "path": ".pi/agents/harness/planning/scout-structure.md",
117
+ "sha256": "e67b7cd75519e5ae36e1bb5f49ca158888c28d365465863aee50a9b2e8e5b7d7"
118
+ },
119
+ "harness/planning/sprint-contract-auditor": {
120
+ "path": ".pi/agents/harness/planning/sprint-contract-auditor.md",
121
+ "sha256": "f613a4fa937d76936fa01155d4e7956a81878f300100f99f6a78915b0af6f7c7"
122
+ },
123
+ "harness/planning/stack-researcher": {
124
+ "path": ".pi/agents/harness/planning/stack-researcher.md",
125
+ "sha256": "90e2ff1348f54bebc8c0392407bf1bb4d794c942fd8d6f342d80b191c945b34e"
126
+ }
127
+ }
84
128
  }
@@ -5,16 +5,16 @@
5
5
 
6
6
  ## Context
7
7
 
8
- Harness slash prompts duplicated logic already defined in `harness/*` agents. Commands did not invoke the `Agent` tool. Review docs told users to fork a new Pi session even though subagents already provide isolated context.
8
+ Harness slash prompts duplicated logic already defined in `harness/*` agents. The in-process `Agent` / `createAgentSession` stack was heavy and unstable. Review docs told users to fork a new Pi session even though subprocess subagents already provide isolation.
9
9
 
10
10
  ## Decision
11
11
 
12
12
  1. **Slash commands** (prompt templates) are orchestrators: spawn `harness/*` agents once, perform policy-gated writes, emit handoff blocks. Command identity is captured on Pi **`input`** as `harness-turn` (raw `/harness-*`), not from expanded prompt markdown.
13
- 2. **Agents** perform multi-turn reads and emit structured JSON drafts. **Planner** runs clarification and plan approval via `ask_user` (parent UI bridge); planner does not write `plan-packet.json`.
13
+ 2. **Agents** perform multi-turn reads and emit structured JSON drafts. **Planning** (`harness/planning/*`) scouts and plan-adversary are read-only; parent orchestrator runs `ask_user`, `approve_plan`, and `create_plan` (see ADR 0033).
14
14
  3. **HarnessSpawnContext** is injected in `[HarnessRunContext]`; orchestrator copies it into spawn prompts. Subagents do not receive `[HarnessActivePlan]` injection.
15
- 4. **Review isolation** uses `Agent` spawn with `inherit_context: false`. `review-integrity` allows `Agent` / `get_subagent_result` for evaluator/adversary/tie-breaker.
16
- 5. **Subagent policy** blocks mutating tools for read-only phase agents; `ask_user` allowed for planner/evaluator/adversary/tie-breaker only.
17
- 6. **Parent** does not duplicate planner `ask_user` or re-spawn for clarification. `get_subagent_result` syncs `harness-plan-approval` from subagent sessions.
15
+ 4. **Review isolation** uses native `subagent` (vendored pi-subagents: isolated `pi --mode json` subprocess). `review-integrity` allows `subagent` when `agent` is evaluator/adversary/tie-breaker; bridge blocks plan-phase mutating spawns and nested `subagent` in children.
16
+ 5. **Subagent policy** blocks mutating tools for read-only phase agents; `ask_user` bridged for evaluator/adversary/tie-breaker only (not planning scouts).
17
+ 6. **Parent** owns plan-phase `ask_user`, `approve_plan`, and `create_plan` per ADR 0033.
18
18
 
19
19
  ## Consequences
20
20
 
@@ -32,6 +32,7 @@ Harness slash prompts duplicated logic already defined in `harness/*` agents. Co
32
32
 
33
33
  - `.pi/prompts/harness-*.md`
34
34
  - `.pi/agents/harness/*.md`
35
- - `.pi/extensions/lib/harness-subagents/harness-subagent-policy.ts`
35
+ - `vendor/pi-subagents/src/subagents.ts`, `.pi/extensions/lib/harness-subagents-bridge.ts`
36
+ - `.pi/extensions/lib/harness-subagent-policy.ts`
36
37
  - `.pi/extensions/review-integrity.ts`
37
38
  - `.pi/lib/harness-agent-output.ts`
@@ -0,0 +1,34 @@
1
+ # ADR 0033: Parent-orchestrated harness planning
2
+
3
+ - **Status:** Accepted
4
+ - **Date:** 2026-05-17
5
+
6
+ ## Context
7
+
8
+ `/harness-plan` previously delegated the full plan lifecycle to a single `harness/planner` subagent. Plans and approval UI were largely invisible in the parent transcript until subprocess completion, and the orchestrator could not call `ask_user` / `approve_plan` / `create_plan` directly.
9
+
10
+ ## Decision
11
+
12
+ 1. **Parent orchestrator** runs `/harness-plan`: parallel read-only scouts under `harness/planning/*`, parent-built `PlanPacket`, `ask_user`, `harness/planning/plan-adversary`, then parent `approve_plan` + `create_plan`.
13
+ 2. **Planning agents** live in `.pi/agents/harness/planning/` (`scout-graphify`, `scout-structure`, `scout-semantic`, `plan-adversary`). Deprecated `harness/planner` shim retained at old path for one release.
14
+ 3. **`approve_plan` and `create_plan`** are parent-session tools only; subagents cannot call them.
15
+ 4. **`classifyHarnessAgent`** treats `harness/planning/*` as read-only (planner kind).
16
+
17
+ ## Consequences
18
+
19
+ ### Positive
20
+
21
+ - Full plan visible in parent session; editor `plan-review.md` path surfaced from parent.
22
+ - Specialized scouts (graphify, ast-grep, ck) run in parallel with clear JSON contracts.
23
+ - Pre-approval adversary separate from post-run `harness/adversary`.
24
+
25
+ ### Negative
26
+
27
+ - More subagent spawns per plan (3 scouts + adversary) vs one planner.
28
+ - Parent prompt must parse multiple JSON blocks and handle partial scout failure.
29
+
30
+ ## References
31
+
32
+ - `.pi/prompts/harness-plan.md`
33
+ - `.pi/agents/harness/planning/`
34
+ - ADR 0032