ultimate-pi 0.7.0 → 0.9.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 (115) hide show
  1. package/.agents/skills/harness-decisions/SKILL.md +20 -1
  2. package/.agents/skills/harness-eval/SKILL.md +11 -13
  3. package/.agents/skills/harness-orchestration/SKILL.md +36 -30
  4. package/.agents/skills/harness-plan/SKILL.md +13 -18
  5. package/.pi/PACKAGING.md +1 -1
  6. package/.pi/agents/harness/adversary.md +20 -12
  7. package/.pi/agents/harness/evaluator.md +25 -14
  8. package/.pi/agents/harness/executor.md +27 -16
  9. package/.pi/agents/harness/incident-recorder.md +37 -0
  10. package/.pi/agents/harness/meta-optimizer.md +18 -15
  11. package/.pi/agents/harness/planner.md +26 -30
  12. package/.pi/agents/harness/tie-breaker.md +4 -2
  13. package/.pi/agents/harness/trace-librarian.md +18 -11
  14. package/.pi/agents/pi-pi/ext-expert.md +1 -1
  15. package/.pi/agents/pi-pi/keybinding-expert.md +1 -1
  16. package/.pi/agents/pi-pi/tui-expert.md +3 -3
  17. package/.pi/extensions/00-ultimate-pi-system-prompt.ts +2 -2
  18. package/.pi/extensions/budget-guard.ts +47 -18
  19. package/.pi/extensions/custom-footer.ts +8 -3
  20. package/.pi/extensions/custom-header.ts +2 -2
  21. package/.pi/extensions/debate-orchestrator.ts +1 -1
  22. package/.pi/extensions/dotenv-loader.ts +1 -1
  23. package/.pi/extensions/drift-monitor.ts +1 -1
  24. package/.pi/extensions/harness-ask-user.ts +1 -1
  25. package/.pi/extensions/harness-live-widget.ts +1 -1
  26. package/.pi/extensions/harness-run-context.ts +197 -33
  27. package/.pi/extensions/harness-telemetry.ts +1 -1
  28. package/.pi/extensions/harness-web-guard.ts +1 -1
  29. package/.pi/extensions/harness-web-tools.ts +1 -1
  30. package/.pi/extensions/lib/ask-user/dialog.ts +2 -2
  31. package/.pi/extensions/lib/ask-user/fallback.ts +1 -1
  32. package/.pi/extensions/lib/ask-user/render.ts +3 -3
  33. package/.pi/extensions/lib/harness-subagents/agent-loader.ts +1 -1
  34. package/.pi/extensions/lib/harness-subagents/agent-parser.ts +1 -1
  35. package/.pi/extensions/lib/harness-subagents/blackboard-tool.ts +1 -1
  36. package/.pi/extensions/lib/harness-subagents/harness-subagent-policy.ts +134 -0
  37. package/.pi/extensions/lib/harness-subagents/parent-ask-user-bridge.ts +89 -0
  38. package/.pi/extensions/lib/harness-subagents/spawn-policy.ts +20 -2
  39. package/.pi/extensions/lib/harness-subagents/vendored/agent-manager.ts +3 -2
  40. package/.pi/extensions/lib/harness-subagents/vendored/agent-runner.ts +44 -24
  41. package/.pi/extensions/lib/harness-subagents/vendored/context.ts +1 -1
  42. package/.pi/extensions/lib/harness-subagents/vendored/env.ts +1 -1
  43. package/.pi/extensions/lib/harness-subagents/vendored/index.ts +23 -2
  44. package/.pi/extensions/lib/harness-subagents/vendored/output-file.ts +1 -1
  45. package/.pi/extensions/lib/harness-subagents/vendored/schedule.ts +1 -1
  46. package/.pi/extensions/lib/harness-subagents/vendored/settings.ts +1 -1
  47. package/.pi/extensions/lib/harness-subagents/vendored/skill-loader.ts +1 -1
  48. package/.pi/extensions/lib/harness-subagents/vendored/types.ts +2 -2
  49. package/.pi/extensions/lib/harness-subagents/vendored/ui/agent-widget.ts +1 -1
  50. package/.pi/extensions/lib/harness-subagents/vendored/ui/conversation-viewer.ts +2 -2
  51. package/.pi/extensions/lib/harness-subagents/vendored/ui/schedule-menu.ts +1 -1
  52. package/.pi/extensions/observation-bus.ts +1 -1
  53. package/.pi/extensions/pi-model-router-harness.ts +1 -1
  54. package/.pi/extensions/policy-gate.ts +90 -20
  55. package/.pi/extensions/provider-payload-sanitize.ts +1 -1
  56. package/.pi/extensions/review-integrity.ts +76 -22
  57. package/.pi/extensions/sentrux-rules-sync.ts +1 -1
  58. package/.pi/extensions/soundboard.ts +1 -1
  59. package/.pi/extensions/test-diff-integrity.ts +1 -1
  60. package/.pi/extensions/trace-recorder.ts +1 -1
  61. package/.pi/extensions/ultimate-pi-vcc.ts +1 -1
  62. package/.pi/harness/agents.manifest.json +82 -78
  63. package/.pi/harness/docs/adrs/0031-harness-run-context.md +6 -3
  64. package/.pi/harness/docs/adrs/0032-harness-command-orchestration.md +37 -0
  65. package/.pi/harness/docs/adrs/README.md +1 -0
  66. package/.pi/harness/specs/budget-exhausted-event.schema.json +3 -1
  67. package/.pi/harness/specs/harness-spawn-context.schema.json +65 -0
  68. package/.pi/harness/specs/harness-turn.schema.json +18 -0
  69. package/.pi/lib/harness-agent-output.ts +41 -0
  70. package/.pi/lib/harness-run-context.ts +516 -37
  71. package/.pi/lib/harness-ui-state.ts +1 -1
  72. package/.pi/prompts/harness-auto.md +36 -61
  73. package/.pi/prompts/harness-critic.md +15 -28
  74. package/.pi/prompts/harness-eval.md +19 -27
  75. package/.pi/prompts/harness-incident.md +15 -34
  76. package/.pi/prompts/harness-plan.md +28 -49
  77. package/.pi/prompts/harness-review.md +16 -30
  78. package/.pi/prompts/harness-router-tune.md +16 -38
  79. package/.pi/prompts/harness-run.md +21 -38
  80. package/.pi/prompts/harness-setup.md +2 -0
  81. package/.pi/prompts/harness-trace.md +13 -30
  82. package/.pi/scripts/harness-generate-model-router.mjs +16 -13
  83. package/.pi/scripts/harness-verify.mjs +17 -0
  84. package/.pi/scripts/vendor-sync-pi-model-router.sh +10 -10
  85. package/CHANGELOG.md +25 -1
  86. package/README.md +4 -5
  87. package/THIRD_PARTY_NOTICES.md +1 -1
  88. package/package.json +13 -8
  89. package/vendor/pi-model-router/UPSTREAM_PIN.md +1 -1
  90. package/vendor/pi-model-router/extensions/commands.ts +2 -2
  91. package/vendor/pi-model-router/extensions/config.ts +2 -2
  92. package/vendor/pi-model-router/extensions/index.ts +1 -1
  93. package/vendor/pi-model-router/extensions/provider.ts +2 -2
  94. package/vendor/pi-model-router/extensions/routing.ts +2 -2
  95. package/vendor/pi-model-router/extensions/types.ts +1 -1
  96. package/vendor/pi-model-router/extensions/ui.ts +1 -1
  97. package/vendor/pi-model-router/package.json +4 -4
  98. package/vendor/pi-vcc/index.ts +1 -1
  99. package/vendor/pi-vcc/package.json +1 -1
  100. package/vendor/pi-vcc/src/commands/pi-vcc.ts +1 -1
  101. package/vendor/pi-vcc/src/commands/vcc-recall.ts +1 -1
  102. package/vendor/pi-vcc/src/core/content.ts +1 -1
  103. package/vendor/pi-vcc/src/core/load-messages.ts +1 -1
  104. package/vendor/pi-vcc/src/core/normalize.ts +1 -1
  105. package/vendor/pi-vcc/src/core/render-entries.ts +1 -1
  106. package/vendor/pi-vcc/src/core/report.ts +1 -1
  107. package/vendor/pi-vcc/src/core/search-entries.ts +1 -1
  108. package/vendor/pi-vcc/src/core/summarize.ts +1 -1
  109. package/vendor/pi-vcc/src/hooks/before-compact.ts +2 -2
  110. package/vendor/pi-vcc/src/tools/recall.ts +1 -1
  111. package/vendor/pi-vcc/src/types.ts +1 -1
  112. package/vendor/pi-vcc/tests/fixtures.ts +1 -1
  113. package/vendor/pi-vcc/tests/render-entries.test.ts +1 -1
  114. package/vendor/pi-vcc/tests/search-entries.test.ts +1 -1
  115. package/vendor/pi-vcc/tests/support/load-session.ts +2 -2
@@ -385,6 +385,8 @@ Manual override: **`/router profile auto`** anytime after reload if they changed
385
385
 
386
386
  `harness-subagents` loads agents from the installed **`ultimate-pi`** package (`$UP_PKG/.pi/agents/**`) with namespaced ids (`harness/planner`, `pi-pi/agent-expert`). **Do not copy** agents into the project unless you want a deliberate override.
387
387
 
388
+ **Slash commands are orchestrators:** `/harness-plan`, `/harness-run`, etc. spawn `harness/*` agents via the `Agent` tool — bootstrap stays **script-first**; only optionally spawn `harness/sentrux-bootstrap` for Sentrux (see Step 4.2).
389
+
388
390
  Optional per-repo overrides: place `.md` files at the **same relative path** (e.g. `.pi/agents/harness/planner.md` overrides the package planner).
389
391
 
390
392
  Verify manifest drift after `pi update ultimate-pi`:
@@ -5,45 +5,28 @@ argument-hint: "[--run <run-id>] [--phase plan|execute|evaluate|adversary|merge]
5
5
 
6
6
  # harness-trace
7
7
 
8
- Retrieve and summarize trace artifacts for a run.
8
+ Orchestrator spawn `harness/trace-librarian`.
9
9
 
10
10
  ## Step 0 — Parse arguments
11
11
 
12
- Read `$ARGUMENTS` and parse:
13
-
14
12
  - optional: `--run <run-id>` (recovery only)
15
13
  - optional: `--phase plan|execute|evaluate|adversary|merge`
16
14
 
17
- On the happy path, **omit `--run`**. Phase traces live at `trace-<phase>.json` under the active run directory.
18
-
19
- ## Process
20
-
21
- 1. Collect run artifacts from canonical harness locations and provided trace refs.
22
- 2. Build phase timeline with policy and gate decision points.
23
- 3. Report completeness gaps against strict gate artifact requirements.
24
-
25
- ## Requirements
26
-
27
- - Use `.pi/harness/runs/` and external trace references as source of truth pointers.
28
- - Include phase timeline, artifact refs, and policy decisions.
29
- - Highlight missing artifacts that violate strict gate requirements.
30
-
31
- ## Guardrails
15
+ Happy path: omit `--run`.
32
16
 
33
- - Do not overthink simple trace lookups; prioritize completeness and stable references.
34
- - Only report artifacts for the requested run and optional phase filter.
35
- - Never infer artifact existence without verifying source pointers.
17
+ ## Orchestration (required)
36
18
 
37
- ## Output
19
+ 1. Build `HarnessSpawnContext` with `mode: trace`, `run_dir`, optional phase filter.
20
+ 2. Spawn:
38
21
 
39
- - Replay-ready timeline summary.
40
- - Artifact index (`plan`, `run`, `eval`, `adversary`, `consensus`, `incident`, `rollback`).
41
- - Any integrity or completeness gaps.
22
+ ```
23
+ Agent({ subagent_type: "harness/trace-librarian", prompt: "…" })
24
+ ```
42
25
 
43
- ## Completion behavior
26
+ 3. `get_subagent_result` — present timeline and artifact index to user.
44
27
 
45
- Always end with:
28
+ ## Completion
46
29
 
47
- - `trace_completeness` (`complete` or `incomplete`)
48
- - missing artifact checklist (if any)
49
- - most likely next command (`/harness-incident`, `/harness-review`, or `/harness-critic`)
30
+ - `trace_completeness`: `complete` or `incomplete`
31
+ - Missing artifact checklist
32
+ - `next_command` hint (`/harness-incident`, `/harness-review`, or `/harness-critic`)
@@ -3,13 +3,13 @@
3
3
  * Generate `.pi/model-router.json` from Pi's authenticated providers (auth.json + env),
4
4
  * not from raw env-var heuristics alone.
5
5
  *
6
- * Uses @mariozechner/pi-coding-agent ModelRegistry.getAvailable() — same source as /login.
6
+ * Uses @earendil-works/pi-coding-agent ModelRegistry.getAvailable() — same source as /login.
7
7
  *
8
8
  * Usage: node harness-generate-model-router.mjs [--force] [--dry-run]
9
9
  * --force overwrite existing .pi/model-router.json
10
10
  * --dry-run print JSON to stdout, do not write
11
11
  *
12
- * Requires @mariozechner/pi-coding-agent (peer of ultimate-pi; bundled with pi).
12
+ * Requires @earendil-works/pi-coding-agent (peer of ultimate-pi; bundled with pi).
13
13
  */
14
14
 
15
15
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
@@ -66,26 +66,29 @@ function fail(msg) {
66
66
  }
67
67
 
68
68
  async function loadPiCodingAgent() {
69
- const agentRoots = [
70
- join(UP_PKG, "node_modules", "@mariozechner", "pi-coding-agent"),
71
- join(UP_PKG, ".pi", "npm", "node_modules", "@mariozechner", "pi-coding-agent"),
72
- ];
69
+ const scopes = ["@earendil-works", "@mariozechner"];
70
+ const agentRoots = scopes.flatMap((scope) => [
71
+ join(UP_PKG, "node_modules", scope, "pi-coding-agent"),
72
+ join(UP_PKG, ".pi", "npm", "node_modules", scope, "pi-coding-agent"),
73
+ ]);
73
74
  for (const root of agentRoots) {
74
75
  const entry = join(root, "dist", "index.js");
75
76
  if (existsSync(entry)) {
76
77
  return import(pathToFileURL(entry).href);
77
78
  }
78
79
  }
79
- for (const base of [UP_PKG, process.cwd()]) {
80
- try {
81
- const req = createRequire(join(base, "package.json"));
82
- return req("@mariozechner/pi-coding-agent");
83
- } catch {
84
- /* try next */
80
+ for (const spec of ["@earendil-works/pi-coding-agent", "@mariozechner/pi-coding-agent"]) {
81
+ for (const base of [UP_PKG, process.cwd()]) {
82
+ try {
83
+ const req = createRequire(join(base, "package.json"));
84
+ return req(spec);
85
+ } catch {
86
+ /* try next */
87
+ }
85
88
  }
86
89
  }
87
90
  fail(
88
- "@mariozechner/pi-coding-agent not found (install pi or npm i in ultimate-pi). Peer: @mariozechner/pi-coding-agent",
91
+ "@earendil-works/pi-coding-agent not found (install pi or npm i in ultimate-pi). Peer: @earendil-works/pi-coding-agent",
89
92
  );
90
93
  }
91
94
 
@@ -21,6 +21,8 @@ const REQUIRED_SCHEMAS = [
21
21
  "observation.schema.json",
22
22
  "run-trace.schema.json",
23
23
  "eval-verdict.schema.json",
24
+ "harness-spawn-context.schema.json",
25
+ "harness-turn.schema.json",
24
26
  ];
25
27
 
26
28
  const REQUIRED_ADRS = [
@@ -34,6 +36,7 @@ const REQUIRED_ADRS = [
34
36
  "0008-harness-posthog-telemetry.md",
35
37
  "0009-sentrux-rules-lifecycle.md",
36
38
  "0031-harness-run-context.md",
39
+ "0032-harness-command-orchestration.md",
37
40
  ];
38
41
 
39
42
  const REQUIRED_EXTENSIONS = [
@@ -199,6 +202,20 @@ async function main() {
199
202
  if (!(await fileExists(runCtxLib))) fail("missing lib/harness-run-context.ts");
200
203
  ok("lib/harness-run-context.ts");
201
204
 
205
+ const policyGateSrc = await readFile(
206
+ join(ROOT, ".pi", "extensions", "policy-gate.ts"),
207
+ "utf-8",
208
+ );
209
+ if (!policyGateSrc.includes("isPlanPhaseAllowedMutation")) {
210
+ fail(
211
+ "policy-gate.ts must use isPlanPhaseAllowedMutation (plan-phase scoped writes)",
212
+ );
213
+ }
214
+ if (!policyGateSrc.includes('pi.on("tool_call", async (event, ctx)')) {
215
+ fail("policy-gate tool_call must receive ctx for run context");
216
+ }
217
+ ok("policy-gate plan-phase writes");
218
+
202
219
  const runCtxFixture = join(SMOKE, "run-context.fixture.json");
203
220
  if (!(await fileExists(runCtxFixture))) {
204
221
  fail("missing run-context.fixture.json");
@@ -11,19 +11,19 @@ rm -rf "$VEND/.git"
11
11
 
12
12
  for f in "$VEND"/extensions/*.ts; do
13
13
  sed -i \
14
- -e "s|'@earendil-works/pi-agent-core'|'@mariozechner/pi-agent-core'|g" \
15
- -e "s|'@earendil-works/pi-ai'|'@mariozechner/pi-ai'|g" \
16
- -e "s|'@earendil-works/pi-coding-agent'|'@mariozechner/pi-coding-agent'|g" \
17
- -e "s|'@earendil-works/pi-tui'|'@mariozechner/pi-tui'|g" \
14
+ -e "s|'@earendil-works/pi-agent-core'|'@earendil-works/pi-agent-core'|g" \
15
+ -e "s|'@earendil-works/pi-ai'|'@earendil-works/pi-ai'|g" \
16
+ -e "s|'@earendil-works/pi-coding-agent'|'@earendil-works/pi-coding-agent'|g" \
17
+ -e "s|'@earendil-works/pi-tui'|'@earendil-works/pi-tui'|g" \
18
18
  "$f"
19
19
  done
20
20
 
21
- # Align package.json peers with @mariozechner (upstream lists @earendil-works)
21
+ # Align package.json peers with @earendil-works (upstream lists @earendil-works)
22
22
  sed -i \
23
- -e 's|"@earendil-works/pi-agent-core"|"@mariozechner/pi-agent-core"|g' \
24
- -e 's|"@earendil-works/pi-ai"|"@mariozechner/pi-ai"|g' \
25
- -e 's|"@earendil-works/pi-coding-agent"|"@mariozechner/pi-coding-agent"|g' \
26
- -e 's|"@earendil-works/pi-tui"|"@mariozechner/pi-tui"|g' \
23
+ -e 's|"@earendil-works/pi-agent-core"|"@earendil-works/pi-agent-core"|g' \
24
+ -e 's|"@earendil-works/pi-ai"|"@earendil-works/pi-ai"|g' \
25
+ -e 's|"@earendil-works/pi-coding-agent"|"@earendil-works/pi-coding-agent"|g' \
26
+ -e 's|"@earendil-works/pi-tui"|"@earendil-works/pi-tui"|g' \
27
27
  "$VEND/package.json"
28
28
 
29
29
  python3 -c "
@@ -40,7 +40,7 @@ cat >"$VEND/UPSTREAM_PIN.md" <<EOF
40
40
  - **Repository:** https://github.com/yeliu84/pi-model-router
41
41
  - **License:** MIT (\`LICENSE\` in this tree)
42
42
  - **Pinned upstream commit:** \`$COMMIT\`
43
- - **Local changes:** \`extensions/*.ts\` imports use \`@mariozechner/*\` and relative paths end in \`.js\` for TypeScript nodenext.
43
+ - **Local changes:** \`extensions/*.ts\` imports use \`@earendil-works/*\` and relative paths end in \`.js\` for TypeScript nodenext.
44
44
  EOF
45
45
 
46
46
  rm -f "$VEND/package-lock.json"
package/CHANGELOG.md CHANGED
@@ -4,6 +4,30 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [v0.9.0] — 2026-05-17
8
+
9
+ ### ✨ Features
10
+
11
+ - **Harness plan UX:** Pi-native `harness-turn` routing on `input` (no expanded-prompt matching); subagent `ask_user` bridged to parent UI; plan-phase budget cap 80k with debounced exhaustion events; thin `harness-plan` orchestrator with `harness-plan-commit`; `harness-turn.schema.json` and tests.
12
+
13
+ ## [v0.8.0] — 2026-05-17
14
+
15
+ ### ✨ Features
16
+
17
+ - **Harness command orchestration:** slash prompts spawn `harness/*` agents with required `HarnessSpawnContext`; subagent tool policy; L4 review via isolated subagents (not session fork); ADR 0032.
18
+
19
+ ### 🐛 Fixes
20
+
21
+ - **Policy gate / harness-plan:** allow scoped writes to `plan-packet.json` in plan phase after `ask_user` approval; block project source edits until execute; promote `/harness-auto` to execute phase mid-turn after approved plan write.
22
+
23
+ ### 📖 Documentation
24
+
25
+ - **Harness plan workflow:** present full plan → Approve via `ask_user` → persist packet; `--quick` does not skip approval (ADR 0031).
26
+
27
+ ### 🔧 Chores
28
+
29
+ - **pi-coding-agent:** migrate peer/dev deps to `@earendil-works/pi-coding-agent` 0.74.1.
30
+
7
31
  ## [v0.7.0] — 2026-05-17
8
32
 
9
33
  ### ✨ Features
@@ -110,7 +134,7 @@ All notable changes to this project are documented in this file.
110
134
 
111
135
  - Remove `npm:@yeliu84/pi-model-router` from package dependencies; add `THIRD_PARTY_NOTICES.md`
112
136
  - `harness-sync-model-router.mjs` adjusts Pi defaults only (no package toggling)
113
- - `check:ts` uses ES2023; devDependency on `@mariozechner/pi-ai`, `pi-tui`, `pi-agent-core` for vendored typecheck
137
+ - `check:ts` uses ES2023; devDependency on `@earendil-works/pi-ai`, `pi-tui`, `pi-agent-core` for vendored typecheck
114
138
 
115
139
  ### 🐛 Fixes
116
140
 
package/README.md CHANGED
@@ -45,7 +45,7 @@ If something blocks, inspect status (no run id needed):
45
45
  | `/harness-auto "<task>"` | End-to-end pipeline (recommended) |
46
46
  | `/harness-plan "<task>"` | Create or **revise** the active plan in context (no plan path to copy) |
47
47
  | `/harness-run` | Execute the active plan from context (**no `--plan`** on happy path) |
48
- | `/harness-eval` | Eval for active run (optional `--run`; **new session** after execute) |
48
+ | `/harness-eval` | Eval for active run (optional `--run`; spawns isolated `harness/evaluator`) |
49
49
  | `/harness-review` | Independent review (optional `--run`) |
50
50
  | `/harness-critic` | Adversarial review (optional `--run`) |
51
51
  | `/harness-trace` | Trace summary (optional `--run`) |
@@ -63,7 +63,6 @@ Use this when you want each step separate:
63
63
  ```text
64
64
  /harness-plan "your task"
65
65
  /harness-run
66
- # New Pi session (review isolation):
67
66
  /harness-eval
68
67
  /harness-review
69
68
  /harness-critic
@@ -78,7 +77,7 @@ Recovery: `--run` and `--plan` remain for scripts; `/harness-use-run` and `/harn
78
77
  - **System prompt** — [`.pi/extensions/00-ultimate-pi-system-prompt.ts`](.pi/extensions/00-ultimate-pi-system-prompt.ts) sets the base prompt from packaged [`.pi/SYSTEM.md`](.pi/SYSTEM.md), or from your workspace override **`.pi/system.md`** (lowercase) if you create one. Nothing is copied into your project by default. After upgrading the package or editing either file, run **`/reload`**.
79
78
  - **Model routing (vendored + gated)** — [`pi-model-router`](https://github.com/yeliu84/pi-model-router) ships inside this package (`vendor/pi-model-router/`). [`.pi/extensions/pi-model-router-harness.ts`](.pi/extensions/pi-model-router-harness.ts) activates it **only after** `.pi/model-router.json` exists (generation: `/harness-setup` Step 3.5), so **`router/auto` does not appear** beforehand. See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). [`.pi/scripts/harness-sync-model-router.mjs`](.pi/scripts/harness-sync-model-router.mjs) may set **`defaultProvider`/`defaultModel`** to **`router`/`auto`** when the project sets no default — run **`/reload`** afterward. Do **not** add `npm:@yeliu84/pi-model-router` to `.pi/settings.json`; it duplicates the fork. Maintainer refresh: **`npm run vendor:sync-router`**.
80
79
  - **Active run + plan context** — PlanPacket lives at a fixed path per run; the extension injects it for `/harness-plan` (revise) and `/harness-run` (execute). Session state plus `.pi/harness/active-run.json`; no run ids or plan paths to copy.
81
- - **Review isolation** — run evaluate/review/critic in a **new session** after execute (see troubleshooting).
80
+ - **Review isolation** — `/harness-eval`, `/harness-review`, and `/harness-critic` spawn isolated subagents (`inherit_context: false`); stay in the same session (see ADR 0032).
82
81
  - **Concurrent plans** — a second `/harness-plan` while a run is active is blocked until `/harness-abort` or `/harness-new-run` (except drift replan / amend after `needs_clarification`).
83
82
  - **Plan before mutate** — write/edit/shell that changes the repo is blocked until execute phase.
84
83
  - **No auto-merge** — you decide when to open or merge a PR.
@@ -91,10 +90,10 @@ Optional: copy [`.env.example`](.env.example) to `.env` if you use PostHog or ot
91
90
  | Problem | Try |
92
91
  |---------|-----|
93
92
  | Setup fails | `node --version` (need 18+), rerun `/harness-setup` |
94
- | "No active run" on eval | Finish plan+run first, or `/harness-run-status`; open a new session for eval |
93
+ | "No active run" on eval | Finish plan+run first, or `/harness-run-status` |
95
94
  | Forgot where you left off | `/harness-run-status` |
96
95
  | Second plan rejected | `/harness-abort` or `/harness-new-run` |
97
- | Blocked in evaluate/review | Run review in a fresh session (isolation from execute) |
96
+ | Blocked in evaluate/review | Spawn review via Agent (`harness/evaluator` / `harness/adversary`); do not run review tools inline in execute phase |
98
97
  | High plan drift | `harness-drift-replan` or abort then replan (ADR 0007) |
99
98
  | Budget / scope stop | `/harness-budget-status`, narrow the task or split the plan |
100
99
  | Test integrity warning | `/harness-test-integrity-last`, fix or justify test changes |
@@ -5,7 +5,7 @@
5
5
  - **Project:** https://github.com/yeliu84/pi-model-router
6
6
  - **License:** MIT ([vendor/pi-model-router/LICENSE](vendor/pi-model-router/LICENSE))
7
7
  - **Pinned revision:** See [vendor/pi-model-router/UPSTREAM_PIN.md](vendor/pi-model-router/UPSTREAM_PIN.md)
8
- - ultimate-pi loads it from [`vendor/pi-model-router`](vendor/pi-model-router); import specifiers were adapted for `@mariozechner/pi-coding-agent` and related Pi packages.
8
+ - ultimate-pi loads it from [`vendor/pi-model-router`](vendor/pi-model-router); import specifiers were adapted for `@earendil-works/pi-coding-agent` and related Pi packages.
9
9
 
10
10
  ## pi-vcc (vendored)
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-pi",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Ultimate AI coding harness for pi.dev — extensible skills, Obsidian wiki knowledge layer, compressed context, deterministic output",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -70,7 +70,7 @@
70
70
  "vendor/pi-vcc"
71
71
  ],
72
72
  "peerDependencies": {
73
- "@mariozechner/pi-coding-agent": "*"
73
+ "@earendil-works/pi-coding-agent": "*"
74
74
  },
75
75
  "scripts": {
76
76
  "check:ts": "tsc --noEmit --target ES2023 --lib ES2023 --moduleResolution nodenext --module nodenext --skipLibCheck .pi/extensions/00-ultimate-pi-system-prompt.ts .pi/lib/harness-run-context.ts .pi/lib/harness-ui-state.ts .pi/extensions/harness-run-context.ts .pi/extensions/lib/harness-vcc-settings.ts .pi/extensions/dotenv-loader.ts .pi/extensions/lib/posthog-node.d.ts .pi/extensions/lib/harness-posthog.ts .pi/extensions/lib/harness-paths.ts .pi/extensions/pi-model-router-harness.ts .pi/extensions/provider-payload-sanitize.ts .pi/extensions/harness-telemetry.ts .pi/extensions/harness-ask-user.ts .pi/extensions/lib/ask-user/schema.ts .pi/extensions/lib/ask-user/types.ts .pi/extensions/lib/ask-user/validate.ts .pi/extensions/lib/ask-user/dialog.ts .pi/extensions/lib/ask-user/fallback.ts .pi/extensions/lib/ask-user/render.ts .pi/extensions/trace-recorder.ts .pi/extensions/observation-bus.ts .pi/extensions/drift-monitor.ts .pi/extensions/policy-gate.ts .pi/extensions/budget-guard.ts .pi/extensions/debate-orchestrator.ts .pi/extensions/harness-live-widget.ts .pi/extensions/sentrux-rules-sync.ts .pi/extensions/custom-header.ts .pi/extensions/lib/harness-subagents/agent-loader.ts .pi/extensions/lib/harness-subagents/agent-parser.ts .pi/extensions/lib/harness-subagents/agent-manifest.ts .pi/extensions/lib/harness-subagents/blackboard.ts .pi/extensions/lib/harness-subagents/blackboard-tool.ts .pi/extensions/lib/harness-subagents/spawn-policy.ts .pi/extensions/lib/harness-subagents/types-blackboard.ts .pi/extensions/harness-web-tools.ts .pi/extensions/harness-web-guard.ts .pi/extensions/lib/harness-web/run-cli.ts",
@@ -82,7 +82,7 @@
82
82
  "format": "biome format --write",
83
83
  "format:check": "biome format",
84
84
  "prepare": "lefthook install",
85
- "test": "node --test test/harness-verify.test.mjs test/harness-ask-user.test.mjs test/harness-subagents-loader.test.mjs test/sentrux-rules-sync.test.mjs && npx -y tsx --test test/harness-vcc-settings.test.ts",
85
+ "test": "node --test test/harness-verify.test.mjs test/harness-ask-user.test.mjs test/harness-subagents-loader.test.mjs test/sentrux-rules-sync.test.mjs test/harness-budget-guard.test.mjs && npx -y tsx --test test/harness-vcc-settings.test.ts test/harness-plan-phase-policy.test.mjs test/harness-subagent-policy.test.mjs test/harness-turn-routing.test.mjs",
86
86
  "test:vcc": "npx -y tsx --test vendor/pi-vcc/tests/*.test.ts",
87
87
  "harness:sentrux-bootstrap": "node .pi/scripts/harness-sentrux-bootstrap.mjs",
88
88
  "harness:sentrux-sync": "node .pi/scripts/sentrux-rules-sync.mjs --force",
@@ -90,20 +90,25 @@
90
90
  },
91
91
  "devDependencies": {
92
92
  "@biomejs/biome": "2.4.14",
93
- "@mariozechner/pi-agent-core": "0.73.0",
94
- "@mariozechner/pi-ai": "0.73.0",
95
- "@mariozechner/pi-coding-agent": "0.73.0",
96
- "@mariozechner/pi-tui": "0.73.0",
93
+ "@earendil-works/pi-agent-core": "0.74.1",
94
+ "@earendil-works/pi-ai": "0.74.1",
95
+ "@earendil-works/pi-coding-agent": "0.74.1",
96
+ "@earendil-works/pi-tui": "0.74.1",
97
97
  "@sinclair/typebox": "^0.34.49",
98
98
  "lefthook": "2.1.6",
99
99
  "typescript": "^6.0.3"
100
100
  },
101
101
  "dependencies": {
102
102
  "@posthog/pi": "latest",
103
- "asciify-image": "^0.1.10",
104
103
  "croner": "^9.0.0",
105
104
  "jimp": "^1.6.1",
106
105
  "nanoid": "^5.1.5",
107
106
  "posthog-node": "^5.30.6"
107
+ },
108
+ "overrides": {
109
+ "@mariozechner/pi-agent-core": "npm:@earendil-works/pi-agent-core@0.74.1",
110
+ "@mariozechner/pi-ai": "npm:@earendil-works/pi-ai@0.74.1",
111
+ "@mariozechner/pi-coding-agent": "npm:@earendil-works/pi-coding-agent@0.74.1",
112
+ "@mariozechner/pi-tui": "npm:@earendil-works/pi-tui@0.74.1"
108
113
  }
109
114
  }
@@ -3,6 +3,6 @@
3
3
  - **Repository:** https://github.com/yeliu84/pi-model-router
4
4
  - **License:** MIT (`LICENSE` in this tree)
5
5
  - **Pinned upstream commit:** `8c60095da0e753c242c4be9bb617b85f4dd3255c`
6
- - **Local changes:** TypeScript imports in `extensions/*.ts` use `@mariozechner/*`; relative imports end in `.js` for NodeNext; `package.json` peerDependencies list `@mariozechner/*`.
6
+ - **Local changes:** TypeScript imports in `extensions/*.ts` use `@earendil-works/*`; relative imports end in `.js` for NodeNext; `package.json` peerDependencies list `@earendil-works/*`.
7
7
 
8
8
  **Refresh upstream:** run `npm run vendor:sync-router` from ultimate-pi root (updates this file with the latest commit SHA).
@@ -1,8 +1,8 @@
1
1
  import type {
2
2
  ExtensionAPI,
3
3
  ExtensionContext,
4
- } from '@mariozechner/pi-coding-agent';
5
- import type { AutocompleteItem } from '@mariozechner/pi-tui';
4
+ } from '@earendil-works/pi-coding-agent';
5
+ import type { AutocompleteItem } from '@earendil-works/pi-tui';
6
6
  import type {
7
7
  RouterConfig,
8
8
  RouterPinByProfile,
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- import { getAgentDir } from '@mariozechner/pi-coding-agent';
4
- import type { ThinkingLevel } from '@mariozechner/pi-agent-core';
3
+ import { getAgentDir } from '@earendil-works/pi-coding-agent';
4
+ import type { ThinkingLevel } from '@earendil-works/pi-agent-core';
5
5
  import type {
6
6
  RouterConfig,
7
7
  RouterProfile,
@@ -1,7 +1,7 @@
1
1
  import type {
2
2
  ExtensionAPI,
3
3
  ExtensionContext,
4
- } from '@mariozechner/pi-coding-agent';
4
+ } from '@earendil-works/pi-coding-agent';
5
5
  import {
6
6
  type RouterConfig,
7
7
  type RouterPersistedState,
@@ -8,11 +8,11 @@ import {
8
8
  type Model,
9
9
  type SimpleStreamOptions,
10
10
  type Message,
11
- } from '@mariozechner/pi-ai';
11
+ } from '@earendil-works/pi-ai';
12
12
  import type {
13
13
  ExtensionAPI,
14
14
  ExtensionContext,
15
- } from '@mariozechner/pi-coding-agent';
15
+ } from '@earendil-works/pi-coding-agent';
16
16
  import type {
17
17
  RouterConfig,
18
18
  RoutingDecision,
@@ -1,5 +1,5 @@
1
- import { streamSimple, type Context, type Message } from '@mariozechner/pi-ai';
2
- import type { ExtensionContext } from '@mariozechner/pi-coding-agent';
1
+ import { streamSimple, type Context, type Message } from '@earendil-works/pi-ai';
2
+ import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
3
3
  import type {
4
4
  RouterTier,
5
5
  RouterPhase,
@@ -1,4 +1,4 @@
1
- import type { ThinkingLevel } from '@mariozechner/pi-agent-core';
1
+ import type { ThinkingLevel } from '@earendil-works/pi-agent-core';
2
2
 
3
3
  export type RouterTier = 'high' | 'medium' | 'low';
4
4
  export type RouterPin = RouterTier | 'auto';
@@ -1,4 +1,4 @@
1
- import type { ExtensionContext } from '@mariozechner/pi-coding-agent';
1
+ import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
2
2
  import type {
3
3
  RoutingDecision,
4
4
  RouterConfig,
@@ -35,10 +35,10 @@
35
35
  "prepublishOnly": "npm run tsc"
36
36
  },
37
37
  "peerDependencies": {
38
- "@mariozechner/pi-agent-core": "*",
39
- "@mariozechner/pi-ai": "*",
40
- "@mariozechner/pi-coding-agent": "*",
41
- "@mariozechner/pi-tui": "*",
38
+ "@earendil-works/pi-agent-core": "*",
39
+ "@earendil-works/pi-ai": "*",
40
+ "@earendil-works/pi-coding-agent": "*",
41
+ "@earendil-works/pi-tui": "*",
42
42
  "@sinclair/typebox": "*"
43
43
  },
44
44
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { registerBeforeCompactHook } from "./src/hooks/before-compact";
3
3
  import { registerPiVccCommand } from "./src/commands/pi-vcc";
4
4
  import { registerVccRecallCommand } from "./src/commands/vcc-recall";
@@ -15,7 +15,7 @@
15
15
  "url": "git+https://github.com/sting8k/pi-vcc.git"
16
16
  },
17
17
  "peerDependencies": {
18
- "@mariozechner/pi-coding-agent": "*",
18
+ "@earendil-works/pi-coding-agent": "*",
19
19
  "@sinclair/typebox": "*"
20
20
  },
21
21
  "pi": {
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { getLastCompactionStats, PI_VCC_COMPACT_INSTRUCTION } from "../hooks/before-compact";
3
3
 
4
4
  const formatTokens = (n: number): string => {
@@ -1,4 +1,4 @@
1
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { loadAllMessages } from "../core/load-messages";
3
3
  import { searchEntries } from "../core/search-entries";
4
4
  import { formatRecallOutput } from "../core/format-recall";
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
 
3
3
  export const clip = (text: string, max = 200): string => {
4
4
  if (text.length <= max) return text;
@@ -1,5 +1,5 @@
1
1
  import { readFileSync } from "fs";
2
- import type { Message } from "@mariozechner/pi-ai";
2
+ import type { Message } from "@earendil-works/pi-ai";
3
3
  import { renderMessage, type RenderedEntry } from "./render-entries";
4
4
 
5
5
  export interface LoadedMessages {
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
  import type { NormalizedBlock } from "../types";
3
3
  import { textOf } from "./content";
4
4
  import { sanitize } from "./sanitize";
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
  import { clip, textOf } from "./content";
3
3
  import { summarizeToolArgs } from "./tool-args";
4
4
  import { extractPath } from "./tool-args";
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
  import { buildSections } from "./build-sections";
3
3
  import { clip } from "./content";
4
4
  import { normalize } from "./normalize";
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
  import type { RenderedEntry } from "./render-entries";
3
3
  import { textOf } from "./content";
4
4
 
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
  import type { FileOps } from "../types";
3
3
  import { normalize } from "./normalize";
4
4
  import { filterNoise } from "./filter-noise";
@@ -1,5 +1,5 @@
1
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
- import { convertToLlm } from "@mariozechner/pi-coding-agent";
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { convertToLlm } from "@earendil-works/pi-coding-agent";
3
3
  import { writeFileSync } from "fs";
4
4
  import { compile } from "../core/summarize";
5
5
  import { loadSettings, type PiVccSettings } from "../core/settings";
@@ -1,5 +1,5 @@
1
1
  import { Type } from "@sinclair/typebox";
2
- import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
3
  import { loadAllMessages } from "../core/load-messages";
4
4
  import { searchEntries } from "../core/search-entries";
5
5
  import { formatRecallOutput } from "../core/format-recall";
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
 
3
3
  export interface FileOps {
4
4
  readFiles?: string[];
@@ -1,4 +1,4 @@
1
- import type { Message } from "@mariozechner/pi-ai";
1
+ import type { Message } from "@earendil-works/pi-ai";
2
2
 
3
3
  const ts = Date.now();
4
4
  const assistBase = {
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect } from "bun:test";
2
2
  import { renderMessage } from "../src/core/render-entries";
3
- import type { Message } from "@mariozechner/pi-ai";
3
+ import type { Message } from "@earendil-works/pi-ai";
4
4
  import { userMsg, assistantText, assistantWithToolCall, toolResult } from "./fixtures";
5
5
 
6
6
  describe("renderMessage", () => {
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect } from "bun:test";
2
2
  import { searchEntries } from "../src/core/search-entries";
3
3
  import type { RenderedEntry } from "../src/core/render-entries";
4
- import type { Message } from "@mariozechner/pi-ai";
4
+ import type { Message } from "@earendil-works/pi-ai";
5
5
 
6
6
  const entries: RenderedEntry[] = [
7
7
  { index: 0, role: "user", summary: "Fix login bug" },
@@ -1,5 +1,5 @@
1
- import { buildSessionContext, loadEntriesFromFile } from "../../node_modules/@mariozechner/pi-coding-agent/dist/core/session-manager.js";
2
- import type { Message } from "@mariozechner/pi-ai";
1
+ import { buildSessionContext, loadEntriesFromFile } from "../../node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js";
2
+ import type { Message } from "@earendil-works/pi-ai";
3
3
 
4
4
  export interface LoadedSession {
5
5
  messageCount: number;