ultimate-pi 0.2.7 → 0.3.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 (50) hide show
  1. package/.agents/skills/harness-eval/SKILL.md +1 -1
  2. package/.agents/skills/harness-governor/SKILL.md +2 -2
  3. package/.agents/skills/harness-spec/SKILL.md +1 -1
  4. package/.pi/PACKAGING.md +3 -2
  5. package/.pi/extensions/custom-header.ts +0 -17
  6. package/.pi/extensions/pi-model-router-harness.ts +42 -0
  7. package/.pi/extensions/sentrux-rules-sync.ts +0 -18
  8. package/.pi/harness/README.md +3 -2
  9. package/.pi/harness/docs/adrs/0004-defer-ci-agent-smoke.md +1 -1
  10. package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +1 -1
  11. package/.pi/harness/docs/adrs/0009-sentrux-rules-lifecycle.md +2 -2
  12. package/.pi/harness/evals/smoke/README.md +1 -1
  13. package/.pi/harness/evolution/README.md +1 -1
  14. package/.pi/harness/evolution/chaos-drill.md +1 -1
  15. package/.pi/prompts/harness-setup.md +38 -35
  16. package/.pi/scripts/README.md +25 -9
  17. package/.pi/scripts/harness-cli-verify.sh +4 -2
  18. package/.pi/scripts/harness-sync-model-router.mjs +84 -0
  19. package/.pi/scripts/harness-verify.mjs +5 -3
  20. package/.pi/scripts/sentrux-rules-sync.mjs +2 -2
  21. package/.pi/scripts/vendor-sync-pi-model-router.sh +47 -0
  22. package/.pi/settings.example.json +0 -1
  23. package/.sentrux/rules.toml +1 -1
  24. package/AGENTS.md +1 -1
  25. package/CHANGELOG.md +54 -0
  26. package/README.md +1 -1
  27. package/THIRD_PARTY_NOTICES.md +8 -0
  28. package/biome.json +2 -1
  29. package/package.json +9 -10
  30. package/vendor/pi-model-router/.prettierignore +4 -0
  31. package/vendor/pi-model-router/.prettierrc +5 -0
  32. package/vendor/pi-model-router/AGENTS.md +39 -0
  33. package/vendor/pi-model-router/LICENSE +21 -0
  34. package/vendor/pi-model-router/README.md +99 -0
  35. package/vendor/pi-model-router/UPSTREAM_PIN.md +8 -0
  36. package/vendor/pi-model-router/docs/ARCHITECTURE.md +54 -0
  37. package/vendor/pi-model-router/extensions/commands.ts +720 -0
  38. package/vendor/pi-model-router/extensions/config.ts +348 -0
  39. package/vendor/pi-model-router/extensions/constants.ts +1 -0
  40. package/vendor/pi-model-router/extensions/index.ts +457 -0
  41. package/vendor/pi-model-router/extensions/provider.ts +529 -0
  42. package/vendor/pi-model-router/extensions/routing.ts +416 -0
  43. package/vendor/pi-model-router/extensions/state.ts +49 -0
  44. package/vendor/pi-model-router/extensions/types.ts +86 -0
  45. package/vendor/pi-model-router/extensions/ui.ts +130 -0
  46. package/vendor/pi-model-router/model-router.example.json +48 -0
  47. package/vendor/pi-model-router/package.json +48 -0
  48. package/vendor/pi-model-router/tsconfig.json +16 -0
  49. package/.pi/extensions/model-router-bootstrap.ts +0 -174
  50. package/.sentrux/.harness-rules-meta.json +0 -5
@@ -17,7 +17,7 @@ description: Run harness evaluation phase and emit EvalVerdict artifacts. Use wi
17
17
  2. Gather evidence: tests, diff scope, policy state, debate consensus packet.
18
18
  3. Emit verdict via `pi.appendEntry('harness-eval-verdict', { ... })` pattern (session custom entry).
19
19
  4. When Sentrux enabled, ensure `harness-sentrux-signal` exists (stub or MCP) per ADR 0006.
20
- 5. Deterministic checks: `npm run harness:verify` and project test script.
20
+ 5. Deterministic checks: `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` (see `.pi/scripts/README.md`) and project test script.
21
21
 
22
22
  ## Verdict values
23
23
 
@@ -16,8 +16,8 @@ description: Enforce harness governance phases, policy gates, budgets, and promo
16
16
  1. Read current phase from `/harness-policy-status` or session `harness-policy-state`.
17
17
  2. Check ADRs: constitution (0001), eval promotion (0003), Sentrux (0006), drift (0007), rules lifecycle (0009).
18
18
  3. For promotion: require eval pass, no abort lock, debate consensus if escalated, Sentrux when `HARNESS_SENTRUX_REQUIRED=true`.
19
- 4. After architecture changes: edit `.pi/harness/sentrux/architecture.manifest.json`, then `npm run harness:sentrux-sync` (or `/harness-sentrux-sync`).
20
- 5. Run `npm run harness:verify` before claiming release readiness.
19
+ 4. After architecture changes: edit `.pi/harness/sentrux/architecture.manifest.json`, then `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --force` (see `.pi/scripts/README.md` for `UP_PKG`) or `/harness-sentrux-sync`.
20
+ 5. Run `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` before claiming release readiness.
21
21
 
22
22
  ## Spec Distiller integration
23
23
 
@@ -16,7 +16,7 @@ description: Draft or refine harness artifact contracts under .pi/harness/specs.
16
16
  1. Read `.pi/harness/specs/README.md` for versioning rules (`contract_version`, optional fields only for compatible changes).
17
17
  2. Edit or add schema under `.pi/harness/specs/`.
18
18
  3. Update affected extensions to emit matching custom entries.
19
- 4. Run `npm run harness:verify`.
19
+ 4. Run `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` (see `.pi/scripts/README.md`).
20
20
  5. Add or update an ADR under `.pi/harness/docs/adrs/` for breaking changes.
21
21
 
22
22
  ## Rules
package/.pi/PACKAGING.md CHANGED
@@ -12,7 +12,7 @@ Aligned with [pi packages](https://github.com/badlogic/pi-mono/blob/main/package
12
12
 
13
13
  Pi does **not** define `scripts`, `agents`, or `providers` in the manifest.
14
14
 
15
- - **Harness scripts** → `.pi/scripts/` (npm `harness:*` scripts; see `.pi/scripts/README.md`)
15
+ - **Harness scripts** → `.pi/scripts/` run via `node` / `bash` and `$UP_PKG` (see `.pi/scripts/README.md`); do not require npm script aliases in consumer `package.json`
16
16
  - **Subagent agents** → `.pi/agents/**/*.md` (loaded by `@tintinweb/pi-subagents` from the **project** `.pi/agents/`; `/harness-setup` seeds them from the installed package)
17
17
  - **Providers** → install via `bundledDependencies` + user settings, not a separate manifest directory
18
18
 
@@ -22,6 +22,7 @@ We use an explicit allowlist (not the whole `.pi/` tree) so dev-only artifacts n
22
22
 
23
23
  - No `.pi/harness/runs/`, local `model-router.json`, or `firecrawl/.env`
24
24
  - Ship `.pi/settings.example.json`, not `.pi/settings.json` (dev checkout uses `".."` local package)
25
+ - Include **`vendor/pi-model-router/`** ([`pi-model-router`](https://github.com/yeliu84/pi-model-router), MIT) — see repo [`THIRD_PARTY_NOTICES.md`](../THIRD_PARTY_NOTICES.md); refresh with `npm run vendor:sync-router`
25
26
 
26
27
  ## Settings
27
28
 
@@ -34,4 +35,4 @@ We use an explicit allowlist (not the whole `.pi/` tree) so dev-only artifacts n
34
35
 
35
36
  Runtime pi extensions are regular `dependencies` (installed by `npm install` when pi installs the package). We do **not** use `bundledDependencies`: bundling pre-installs `node_modules` and breaks `npm install -g` / `pi update` for native modules such as `koffi` (empty stub dir, postinstall fails).
36
37
 
37
- `@mariozechner/pi-coding-agent` is a `peerDependency` (provided by the pi CLI).
38
+ `@mariozechner/pi-coding-agent` (and sibling `@mariozechner/pi-ai`, `pi-tui`, `pi-agent-core` used by the vendored router) are provided by the Pi install / hoisted from the peer; ultimate-pi lists the latter three as `devDependencies` for `npm run check:ts`.
@@ -90,23 +90,6 @@ function ansiCell(
90
90
  }
91
91
 
92
92
  async function loadBanner(): Promise<string[]> {
93
- // #region agent log
94
- fetch("http://127.0.0.1:7928/ingest/a5d40896-34cb-4f12-97db-df7ada0b22f0", {
95
- method: "POST",
96
- headers: {
97
- "Content-Type": "application/json",
98
- "X-Debug-Session-Id": "7737a8",
99
- },
100
- body: JSON.stringify({
101
- sessionId: "7737a8",
102
- hypothesisId: "B",
103
- location: "custom-header.ts:loadBanner",
104
- message: "banner path",
105
- data: { imagePath, cwd: process.cwd() },
106
- timestamp: Date.now(),
107
- }),
108
- }).catch(() => {});
109
- // #endregion
110
93
  const Jimp = getJimpRuntime();
111
94
  const image = await Jimp.read(imagePath);
112
95
  resizeImageCompat(image, PIXEL_WIDTH, PIXEL_HEIGHT);
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Vendored [pi-model-router](https://github.com/yeliu84/pi-model-router), gated behind
3
+ * a project-local `.pi/model-router.json` from `/harness-setup` so the extension
4
+ * (and built-in fallback tiers) never load before harness bootstrap.
5
+ */
6
+
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
10
+ import vendorModelRouter from "../../vendor/pi-model-router/extensions/index.js";
11
+
12
+ function isHarnessRouterReady(cwd: string): boolean {
13
+ const path = join(cwd, ".pi", "model-router.json");
14
+ if (!existsSync(path)) {
15
+ return false;
16
+ }
17
+ try {
18
+ const data: unknown = JSON.parse(readFileSync(path, "utf8"));
19
+ if (typeof data !== "object" || data === null) {
20
+ return false;
21
+ }
22
+ const profiles = (data as { profiles?: unknown }).profiles;
23
+ return (
24
+ typeof profiles === "object" &&
25
+ profiles !== null &&
26
+ Object.keys(profiles).length > 0
27
+ );
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ export default function piModelRouterHarness(pi: ExtensionAPI) {
34
+ const cwd = process.cwd();
35
+ if (!isHarnessRouterReady(cwd)) {
36
+ console.warn(
37
+ "[ultimate-pi] Model router disabled until `.pi/model-router.json` exists (generate via /harness-setup Step 3.5).",
38
+ );
39
+ return;
40
+ }
41
+ vendorModelRouter(pi);
42
+ }
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import { spawn } from "node:child_process";
6
- import { existsSync } from "node:fs";
7
6
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
8
7
  import { resolveHarnessScript } from "./lib/harness-paths.js";
9
8
 
@@ -17,23 +16,6 @@ function resolveSyncScript(): string {
17
16
 
18
17
  function runSync(args: string[]): Promise<{ code: number; output: string }> {
19
18
  const syncScript = resolveSyncScript();
20
- // #region agent log
21
- fetch("http://127.0.0.1:7928/ingest/a5d40896-34cb-4f12-97db-df7ada0b22f0", {
22
- method: "POST",
23
- headers: {
24
- "Content-Type": "application/json",
25
- "X-Debug-Session-Id": "7737a8",
26
- },
27
- body: JSON.stringify({
28
- sessionId: "7737a8",
29
- hypothesisId: "C",
30
- location: "sentrux-rules-sync.ts:runSync",
31
- message: "sync script path",
32
- data: { syncScript, cwd: process.cwd(), exists: existsSync(syncScript) },
33
- timestamp: Date.now(),
34
- }),
35
- }).catch(() => {});
36
- // #endregion
37
19
  return new Promise((resolve) => {
38
20
  const child = spawn(process.execPath, [syncScript, ...args], {
39
21
  cwd: process.cwd(),
@@ -17,8 +17,9 @@ This scaffold is intentionally minimal and safe to adopt incrementally.
17
17
  ## Verification
18
18
 
19
19
  ```bash
20
- npm run harness:verify
21
- npm run harness:sentrux-sync # after editing sentrux/architecture.manifest.json
20
+ UP_PKG="$(node -p "require('path').dirname(require.resolve('ultimate-pi/package.json'))")"
21
+ node "$UP_PKG/.pi/scripts/harness-verify.mjs"
22
+ node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --force # after editing sentrux/architecture.manifest.json
22
23
  ```
23
24
 
24
25
  ## Governance Extensions
@@ -15,7 +15,7 @@ Running full agent smoke or A/B harness comparisons in CI has high token cost an
15
15
  2. Deterministic schema/fixture CI is green for ≥4 weeks.
16
16
  3. At least 20 manual harness runs with `harness_run_completed` in PostHog.
17
17
 
18
- Phase 2 ships **deterministic** eval fixtures only (`npm run harness:verify`).
18
+ Phase 2 ships **deterministic** eval fixtures only (`node "$UP_PKG/.pi/scripts/harness-verify.mjs"`; see `.pi/scripts/README.md`).
19
19
 
20
20
  ## Consequences
21
21
 
@@ -10,7 +10,7 @@ Evaluator trust requires both programmatic gates (policy, budget, integrity) and
10
10
  ## Decision
11
11
 
12
12
  1. **Rules file:** `.sentrux/rules.toml` synced from manifest — see [ADR 0009](0009-sentrux-rules-lifecycle.md).
13
- 2. **CLI gate:** `npm run harness:verify` fails if `HARNESS_SENTRUX_REQUIRED=true` and no `harness-sentrux-signal` stub/file exists for the run (placeholder until MCP wired).
13
+ 2. **CLI gate:** `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` fails if `HARNESS_SENTRUX_REQUIRED=true` and no `harness-sentrux-signal` stub/file exists for the run (placeholder until MCP wired). Resolve `$UP_PKG` via [.pi/scripts/README.md](../../../scripts/README.md).
14
14
  3. **MCP layer (Q2+):** Evaluator sessions must record at least one Sentrux observation before `harness_eval_verdict` promotion when Sentrux is enabled.
15
15
  4. Observations flow through `observation-bus.ts` as `HarnessObservation` envelopes.
16
16
  5. PostHog event: `harness_sentrux_signal` with `signal_type` and `score` only — no secrets.
@@ -11,13 +11,13 @@ Sentrux enforces architecture via [`.sentrux/rules.toml`](https://sentrux.dev/do
11
11
 
12
12
  1. **Canonical source:** [`.pi/harness/sentrux/architecture.manifest.json`](../../sentrux/architecture.manifest.json) — layers, boundaries, global constraints.
13
13
  2. **Generated artifact:** `.sentrux/rules.toml` — committed to git; managed block between `harness:managed:start/end` markers.
14
- 3. **Sync command:** `npm run harness:sentrux-sync` (`.pi/scripts/sentrux-rules-sync.mjs`).
14
+ 3. **Sync command:** `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --force` (resolve `$UP_PKG` via [.pi/scripts/README.md](../../../scripts/README.md)).
15
15
  4. **Pi command:** `/harness-sentrux-sync` via `sentrux-rules-sync.ts` extension.
16
16
  5. **When to sync:**
17
17
  - `/harness-setup` Step 2.8 (after sentrux install)
18
18
  - After editing `architecture.manifest.json`
19
19
  - On `agent_end` when harness phase is `plan` or `merge`
20
- - `npm run harness:verify` fails if manifest hash ≠ last sync (`--check`)
20
+ - `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` fails if manifest hash ≠ last sync (`--check`)
21
21
  6. **Custom rules:** TOML outside the managed block is preserved on sync.
22
22
 
23
23
  ## Consequences
@@ -1,5 +1,5 @@
1
1
  # Deterministic harness smoke evals
2
2
 
3
- No LLM calls. Used by `npm run harness:verify` and CI.
3
+ No LLM calls. Used by `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` and CI (see `.pi/scripts/README.md` for `UP_PKG`).
4
4
 
5
5
  Fixtures validate JSON schemas and golden expectations for trust-layer artifacts.
@@ -5,7 +5,7 @@ Self-healing and meta-optimization read **JSONL first** (`.pi/harness/runs/*/eve
5
5
  ## Components
6
6
 
7
7
  - `self-healing-rules.json` — pattern → suggested remediation
8
- - `meta-optimizer.mjs` — scans run index, proposes router/tuning deltas
8
+ - `meta-optimizer.mjs` — scans run index, proposes router/tuning deltas; run `node "$UP_PKG/.pi/harness/evolution/meta-optimizer.mjs"` (see `.pi/scripts/README.md`).
9
9
  - `chaos-drill.md` — manual chaos / failure injection checklist
10
10
 
11
11
  PostHog `harness_*` events are for dashboards; JSONL is the optimization source of truth per ADR 0008.
@@ -18,7 +18,7 @@ Run quarterly or before major harness releases. **No automation in Phase 2.**
18
18
  ## Pass criteria
19
19
 
20
20
  - All five scenarios produce expected custom entries and matching `harness_*` PostHog events within 60s.
21
- - `npm run harness:verify` still passes after drill.
21
+ - `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` still passes after drill (see `.pi/scripts/README.md`).
22
22
 
23
23
  ## Rollback
24
24
 
@@ -41,6 +41,8 @@ echo "ultimate-pi package: $UP_PKG"
41
41
 
42
42
  For extension package names, read **`$UP_PKG/.pi/settings.example.json`** (shipped template). Merge its `packages` array into the **project** `.pi/settings.json` if missing — do not copy the repo-dev `.pi/settings.json` from the package (it may contain `".."` and is not published).
43
43
 
44
+ If `require.resolve('ultimate-pi/package.json')` fails (bare clone without resolving the package name), run from **this repository root**: `UP_PKG="$(pwd)"`.
45
+
44
46
  ## Step 0.5 — Graphify (skip if `--skip-graphify`)
45
47
 
46
48
  **Critical:** `graphify . --wiki` and `graphify . --update` are **invalid** CLI (error: `unknown command '.'`). Use only:
@@ -57,12 +59,12 @@ Run from the **project root** (the external repo root, not ultimate-pi unless th
57
59
  ```bash
58
60
  mkdir -p ./raw .pi/harness/specs .pi/harness/runs .pi/harness/incidents .pi/harness/debates
59
61
 
60
- # Bundled with ultimate-pi harness; copy path if bootstrap runs from a linked harness checkout
61
- bash "$(node -p "require('path').join(require('path').dirname(require.resolve('ultimate-pi/package.json')),'.pi/scripts/harness-graphify-bootstrap.sh')")"
62
- # In ultimate-pi checkout: npm run harness:graphify-bootstrap
62
+ # Bundled with ultimate-pi harness; $UP_PKG is set in Step 0
63
+ bash "$UP_PKG/.pi/scripts/harness-graphify-bootstrap.sh"
64
+ # Developing ultimate-pi from repo root: UP_PKG="$(pwd)" then same command
63
65
 
64
66
  # Pass --force when $ARGUMENTS contains --force to rebuild an existing graph:
65
- # npm run harness:graphify-bootstrap -- --force
67
+ # bash "$UP_PKG/.pi/scripts/harness-graphify-bootstrap.sh" --force
66
68
  ```
67
69
 
68
70
  If the bootstrap script is missing, run it from the installed ultimate-pi package (`.pi/scripts/` inside the npm package), or execute equivalent steps manually:
@@ -220,9 +222,9 @@ If user chose **cloud**, skip all 1.5.x steps. Just note:
220
222
  Run the bundled verifier from the **project root**. It installs missing npm globals, fixes common **Linux system dependencies** (Chrome libs for `agent-browser`), runs smoke tests, and exits non-zero if a required tool fails.
221
223
 
222
224
  ```bash
223
- npm run harness:cli-verify
224
- # ultimate-pi checkout: npm run harness:cli-verify
225
- # Reinstall everything: npm run harness:cli-verify -- --force
225
+ bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"
226
+ # ultimate-pi checkout: same (ensure Step 0 set UP_PKG="$(pwd)" or used require.resolve)
227
+ # Reinstall everything: bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh" --force
226
228
  ```
227
229
 
228
230
  **Required (script must exit 0):** firecrawl-cli, ctx7, biome, ast-grep (`sg`), sentrux (when harness manifest present).
@@ -237,14 +239,14 @@ sudo apt-get install -y libnss3 libnspr4 libgbm1 libatk1.0-0 libatk-bridge2.0-0
237
239
  libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
238
240
  libasound2 libpango-1.0-0 libcairo2 libx11-6 libxcb1 libxext6 fonts-liberation
239
241
  agent-browser install --with-deps
240
- npm run harness:cli-verify
242
+ bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"
241
243
  ```
242
244
 
243
245
  **Do not continue** past Step 2 if `harness-cli-verify.sh` exits non-zero.
244
246
 
245
247
  ### Manual reference (if script missing in target repo)
246
248
 
247
- Use `npm run harness:cli-verify` from the installed ultimate-pi package, or install tools individually:
249
+ Use `bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"` (see Step 0 for `UP_PKG`), or install tools individually:
248
250
 
249
251
  ### 2.1 — firecrawl-cli (Web Search + Scrape + Crawl + Interact + Download + Parse)
250
252
 
@@ -420,10 +422,7 @@ Configure MCP server in `.pi/mcp.json` (see Step 4.3).
420
422
 
421
423
  Generate architectural rules from the harness manifest (creates/updates `.sentrux/rules.toml`):
422
424
  ```bash
423
- # From ultimate-pi checkout:
424
- npm run harness:sentrux-sync
425
- # From an external project (after pi install npm:ultimate-pi):
426
- npm run harness:sentrux-sync
425
+ node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --force
427
426
  # Or in pi: /harness-sentrux-sync
428
427
  ```
429
428
 
@@ -441,7 +440,9 @@ sentrux gate --save . 2>/dev/null || echo "Baseline will be saved on first gate
441
440
 
442
441
  ## Step 3 — Pi Extension Packages
443
442
 
444
- Bundled extensions load from the installed `ultimate-pi` package. Optionally install the companion lockfile used in development:
443
+ Bundled extensions load from the installed `ultimate-pi` package. **Per-turn model routing** comes from a **vendored** fork of [`yeliu84/pi-model-router`](https://github.com/yeliu84/pi-model-router) in `vendor/pi-model-router/`, wired through [`.pi/extensions/pi-model-router-harness.ts`](.pi/extensions/pi-model-router-harness.ts). The harness **gates** activation on `.pi/model-router.json` (Step **3.5** below) so `router/auto` and built-in tiers such as `openai/gpt-5.4-pro` cannot load prematurely. Attribution: see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) and `vendor/pi-model-router/UPSTREAM_PIN.md`. Maintainer refresh: `npm run vendor:sync-router`.
444
+
445
+ Optionally install the companion lockfile used in development:
445
446
 
446
447
  ```bash
447
448
  UP_PKG="$(node -p "require('path').dirname(require.resolve('ultimate-pi/package.json'))")"
@@ -453,7 +454,7 @@ else
453
454
  fi
454
455
  ```
455
456
 
456
- Merge extension entries from `$UP_PKG/.pi/settings.example.json` into this project's `.pi/settings.json` `packages` array (add any missing `npm:…` entries; keep existing user packages).
457
+ Merge extension entries from `$UP_PKG/.pi/settings.example.json` into this project's `.pi/settings.json` `packages` array (add any missing `npm:…` entries; keep existing user packages). **Do not add** `npm:@yeliu84/pi-model-router` (superseded by the vendored router).
457
458
 
458
459
  Verify each package:
459
460
 
@@ -462,7 +463,8 @@ Verify each package:
462
463
  | `@posthog/pi` | Analytics event capture | F0 |
463
464
  | `pi-lean-ctx` | Context runtime (read/bash/find/grep/MCP bridge) | F0 |
464
465
  | `@tintinweb/pi-subagents` | L4 critic sub-agent spawn/control | P16 |
465
- | `@yeliu84/pi-model-router` | Per-turn intelligent model routing (auto high/medium/low tier selection) | F0 |
466
+ | `@sting8k/pi-vcc` | VCC compaction / conversation memory | Shipped |
467
+ | `pi-model-router` | Vendored (`vendor/`); activates after `.pi/model-router.json` exists | F0 |
466
468
 
467
469
  ## Step 3.5 — Model Router Configuration (Dynamic)
468
470
 
@@ -475,11 +477,12 @@ The script below:
475
477
  3. Only writes if file doesn't exist yet (safe to re-run, will skip existing)
476
478
 
477
479
  ```bash
478
- # Verify package installed first
479
- ls "$UP_PKG/node_modules/@yeliu84/pi-model-router/package.json" 2>/dev/null \
480
- || ls "$UP_PKG/.pi/npm/node_modules/@yeliu84/pi-model-router/package.json" 2>/dev/null \
481
- && echo "model-router package" \
482
- || echo " model-router package — reinstall ultimate-pi or run npm install in $UP_PKG/.pi/npm"
480
+ UP_PKG="$(node -p "require('path').dirname(require.resolve('ultimate-pi/package.json'))")"
481
+
482
+ # Verify vendored extension source ships with ultimate-pi
483
+ ls "$UP_PKG/vendor/pi-model-router/extensions/index.ts" 2>/dev/null \
484
+ && echo " vendored pi-model-router" \
485
+ || echo "✗ missing vendor/pi-model-router"
483
486
 
484
487
  # Generate config from detected providers (only if missing)
485
488
  if [ -f .pi/model-router.json ]; then
@@ -587,15 +590,16 @@ console.log(` Medium tier: ${mediumModel}`);
587
590
  console.log(` Low tier: ${lowModel}`);
588
591
  GENDONE
589
592
  fi
590
- ```
591
593
 
592
- Do NOT block. If generation fails, warn in report and continue.
594
+ # Merge router defaults after config exists (never adds npm packages — router is vendored)
595
+ node "$UP_PKG/.pi/scripts/harness-sync-model-router.mjs"
596
+ ```
593
597
 
594
- **Router is opt-in** ultimate-pi no longer forces `defaultProvider: router` on install. After generating `model-router.json`, tell the user to enable routing when ready:
598
+ Do NOT block. If generation fails, warn in report and continue (defaults script clears `defaultProvider` if it pointed at `router` while no config file exists).
595
599
 
596
- > `/router profile auto`
600
+ **Router onboarding** — The vendored extension starts only after `.pi/model-router.json` appears. Running the script above prepares that file plus optional Pi defaults (**`router` / `auto`**) via `harness-sync-model-router.mjs` when `defaultProvider` was unset—then **`/reload`**.
597
601
 
598
- The pi TUI will intercept this and activate the `auto` profile. Then continue to Step 3.6.
602
+ Manual override: **`/router profile auto`** anytime after reload if they changed defaults.
599
603
 
600
604
  ## Step 3.6 — Seed `.pi/agents` (pi-subagents)
601
605
 
@@ -702,7 +706,7 @@ Created: $(date +%Y-%m-%d)
702
706
  Re-run CLI verification (must pass unless `--skip-tools`):
703
707
 
704
708
  ```bash
705
- npm run harness:cli-verify
709
+ bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"
706
710
  ```
707
711
 
708
712
  Then run the remaining checks:
@@ -741,10 +745,9 @@ print(f'✓ knowledge graph built ({n} nodes)' if n else '✗ graph.json has 0 n
741
745
  " 2>/dev/null || echo "✗ no graph built yet"
742
746
  graphify hook status 2>/dev/null && echo "✓ graphify git hooks installed" || echo "✗ graphify git hooks not installed"
743
747
 
744
- # model router
745
- ls "$UP_PKG/node_modules/@yeliu84/pi-model-router/package.json" 2>/dev/null \
746
- || ls "$UP_PKG/.pi/npm/node_modules/@yeliu84/pi-model-router/package.json" 2>/dev/null \
747
- && echo "✓ model-router package" || echo "✗ model-router package"
748
+ # vendored model router
749
+ ls "$UP_PKG/vendor/pi-model-router/extensions/index.ts" 2>/dev/null \
750
+ && echo "✓ vendored pi-model-router" || echo "✗ vendor/pi-model-router missing"
748
751
  ls .pi/model-router.json 2>/dev/null && echo "✓ model-router config" || echo "✗ model-router config"
749
752
 
750
753
  # raw folder for graphify sources
@@ -801,7 +804,7 @@ Output summary table:
801
804
 
802
805
  Next steps:
803
806
  1. If tools missing: re-run with `--force` or install individually
804
- 2. If graph not built: run `npm run harness:graphify-bootstrap` (or `graphify update .` from project root)
807
+ 2. If graph not built: run `bash "$UP_PKG/.pi/scripts/harness-graphify-bootstrap.sh"` (or `graphify update .` from project root)
805
808
  3. If hooks not installed: run `graphify hook install`
806
809
  4. If gh not authenticated: `gh auth login`
807
810
  5. If self-hosted Firecrawl unhealthy: `docker compose -f firecrawl/docker-compose.yaml logs`
@@ -811,9 +814,9 @@ Next steps:
811
814
  ## Guard Rails
812
815
 
813
816
  - **Internet required**: Several tools need npm registry access. Block if offline.
814
- - **CLI verify script**: Step 2 and Step 5 use `npm run harness:cli-verify` (`.pi/scripts/harness-cli-verify.sh`) — installs npm globals, Linux Chrome system libs for `agent-browser`, and smoke-tests each tool. Block on non-zero exit.
817
+ - **CLI verify script**: Step 2 and Step 5 run `bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"` — installs npm globals, Linux Chrome system libs for `agent-browser`, and smoke-tests each tool. Block on non-zero exit.
815
818
  - **Graphify requires Python 3.10+**: Check `python3 --version`. Block if too old.
816
- - **Graphify bootstrap is mandatory** (unless `--skip-graphify`): Run `npm run harness:graphify-bootstrap`. Never use `graphify . --wiki`. Initial setup must run `graphify update .` and verify `graphify-out/graph.json` has nodes.
819
+ - **Graphify bootstrap is mandatory** (unless `--skip-graphify`): Run `bash "$UP_PKG/.pi/scripts/harness-graphify-bootstrap.sh"`. Never use `graphify . --wiki`. Initial setup must run `graphify update .` and verify `graphify-out/graph.json` has nodes.
817
820
  - **Python packages (Graphify)**: Before install, detect via PATH, `pip`/`pip3 show graphifyy`, `uv`, or apt. Prefer `uv tool install graphifyy`.
818
821
  - **Node.js >= 18 required**: Some pi packages use modern Node APIs.
819
822
  - **Docker required for self-hosted**: Step 1.5 needs Docker Engine + Compose. Block if install fails.
@@ -836,7 +839,7 @@ Next steps:
836
839
  | Graphify install fails | Show installer output. Retry `uv tool install graphifyy` or `pip3 install --user graphifyy`. Ensure `~/.local/bin` is on PATH. |
837
840
  | `graphify update .` fails | Block setup. Corpus may have no code files, or graphify not on PATH. Show stderr. |
838
841
  | Invalid `graphify .` usage | Replace with `graphify update .` — the `.` subcommand does not exist. |
839
- | graphify-out empty / 0 nodes | Re-run `npm run harness:graphify-bootstrap -- --force` from project root. |
842
+ | graphify-out empty / 0 nodes | Re-run `bash "$UP_PKG/.pi/scripts/harness-graphify-bootstrap.sh" --force` from project root. |
840
843
  | graphify hook install fails | Hooks need `.git/` directory. Verify inside git repo. Manual: `git config core.hooksPath .pi/git-hooks` |
841
844
  | firecrawl auth failed | Show manual login instructions. Continue with other tools. |
842
845
  | gh not installed | Show GitHub CLI install link. Skip label creation. |
@@ -2,16 +2,32 @@
2
2
 
3
3
  These scripts ship inside the `ultimate-pi` npm package under `.pi/scripts/`.
4
4
 
5
- Pi's package manifest (`package.json` → `pi`) only loads **extensions**, **skills**, **prompts**, and **themes** — there is no `scripts` field. Harness scripts are invoked via:
5
+ Pi's package manifest (`package.json` → `pi`) only loads **extensions**, **skills**, **prompts**, and **themes** — there is no `scripts` field. **Do not rely on npm `harness:*` scripts** in the consuming project's `package.json`; external repos that install `ultimate-pi` may not define them.
6
6
 
7
- - `npm run harness:*` (see root `package.json`)
8
- - Extensions resolving paths with `resolveHarnessScript()` in `.pi/extensions/lib/harness-paths.ts`
7
+ ## Resolve `ultimate-pi` package root (`UP_PKG`)
9
8
 
10
- | Script | npm script |
11
- |--------|------------|
12
- | `harness-graphify-bootstrap.sh` | `harness:graphify-bootstrap` |
13
- | `harness-cli-verify.sh` | `harness:cli-verify` |
14
- | `harness-verify.mjs` | `harness:verify` |
15
- | `sentrux-rules-sync.mjs` | `harness:sentrux-sync` |
9
+ **Consumer repo** (`ultimate-pi` in `node_modules`):
10
+
11
+ ```bash
12
+ UP_PKG="$(node -p "require('path').dirname(require.resolve('ultimate-pi/package.json'))")"
13
+ ```
14
+
15
+ **Developing this repo** (clone of `ultimate-pi`): from the repo root, `UP_PKG="$(pwd)"` (or the same `require.resolve` after `npm install`).
16
+
17
+ From **Typescript extensions**, use `resolveHarnessScript()` / `getHarnessPackageRoot()` in `.pi/extensions/lib/harness-paths.ts`.
18
+
19
+ ## Invocations (from the consuming project root)
20
+
21
+ | Action | Command |
22
+ |--------|---------|
23
+ | Graphify bootstrap | `bash "$UP_PKG/.pi/scripts/harness-graphify-bootstrap.sh"` |
24
+ | CLI tool install + smoke tests | `bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"` |
25
+ | Deterministic harness checks | `node "$UP_PKG/.pi/scripts/harness-verify.mjs"` |
26
+ | Sentrux rules from manifest | `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --force` |
27
+ | Model-router / Pi defaults | `harness-sync-model-router.mjs` (Step 3.5 of `/harness-setup`) |
28
+ | Vendor router sync (this repo only) | `bash .pi/scripts/vendor-sync-pi-model-router.sh` or `npm run vendor:sync-router` |
29
+ | Meta-optimizer (JSONL proposals) | `node "$UP_PKG/.pi/harness/evolution/meta-optimizer.mjs"` |
30
+
31
+ Pass `--force` to shell scripts that support it (e.g. `harness-graphify-bootstrap.sh --force`, `harness-cli-verify.sh --force`).
16
32
 
17
33
  Repo-root `scripts/` (e.g. `regen_graphify_html.py`) is dev-only and excluded from the npm tarball via `.npmignore`.
@@ -259,8 +259,10 @@ verify_sentrux() {
259
259
  return
260
260
  fi
261
261
  sentrux plugin add-standard 2>/dev/null || warn "sentrux plugin add-standard skipped"
262
- if [ -f package.json ] && grep -q harness:sentrux-sync package.json 2>/dev/null; then
263
- npm run harness:sentrux-sync 2>/dev/null || warn "npm run harness:sentrux-sync failed (needs package.json scripts)"
262
+ _sync_script="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/sentrux-rules-sync.mjs"
263
+ if [ -f "$_sync_script" ]; then
264
+ node "$_sync_script" --force 2>/dev/null ||
265
+ warn "sentrux rules sync failed (see .pi/scripts/README.md)"
264
266
  fi
265
267
  if sentrux check . &>/dev/null; then
266
268
  pass "sentrux $(sentrux --version 2>/dev/null | head -1)"
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * After `.pi/model-router.json` exists, set sensible Pi defaults (`router` / `auto`)
4
+ * when the project has no `defaultProvider`. Does **not** add/remove npm packages
5
+ * — model routing ships vendored inside ultimate-pi.
6
+ */
7
+
8
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
9
+ import { join, dirname } from "node:path";
10
+
11
+ function loadSettings(settingsPath) {
12
+ if (!existsSync(settingsPath)) {
13
+ return null;
14
+ }
15
+ try {
16
+ return JSON.parse(readFileSync(settingsPath, "utf8"));
17
+ } catch {
18
+ console.error("[harness-model-router] Invalid JSON:", settingsPath);
19
+ process.exit(1);
20
+ }
21
+ }
22
+
23
+ function saveSettings(settingsPath, data) {
24
+ mkdirSync(dirname(settingsPath), { recursive: true });
25
+ writeFileSync(
26
+ settingsPath,
27
+ `${JSON.stringify(data, null, "\t")}\n`,
28
+ "utf8",
29
+ );
30
+ }
31
+
32
+ function main() {
33
+ const root = process.cwd();
34
+ const configPath = join(root, ".pi", "model-router.json");
35
+ const settingsPath = join(root, ".pi", "settings.json");
36
+ const hasConfig = existsSync(configPath);
37
+
38
+ const settings = loadSettings(settingsPath);
39
+ if (!settings) {
40
+ console.warn(
41
+ "[harness-model-router] No .pi/settings.json — skipping (merge Step 3 first)",
42
+ );
43
+ process.exit(0);
44
+ }
45
+
46
+ let changed = false;
47
+
48
+ if (!hasConfig) {
49
+ if (settings.defaultProvider === "router") {
50
+ delete settings.defaultProvider;
51
+ delete settings.defaultModel;
52
+ changed = true;
53
+ }
54
+ if (changed) {
55
+ saveSettings(settingsPath, settings);
56
+ console.warn(
57
+ "⚠ No .pi/model-router.json — cleared router defaultProvider if present",
58
+ );
59
+ } else {
60
+ console.log("[harness-model-router] No config file; nothing to do");
61
+ }
62
+ process.exit(0);
63
+ }
64
+
65
+ const noProjectDefault =
66
+ settings.defaultProvider == null || settings.defaultProvider === "";
67
+
68
+ if (noProjectDefault) {
69
+ settings.defaultProvider = "router";
70
+ settings.defaultModel = "auto";
71
+ changed = true;
72
+ }
73
+
74
+ if (changed) {
75
+ saveSettings(settingsPath, settings);
76
+ console.log(
77
+ "✓ Router defaults set (`router` / `auto`) — run /reload in pi when ready",
78
+ );
79
+ } else {
80
+ console.log("[harness-model-router] Defaults unchanged (user set defaultProvider)");
81
+ }
82
+ }
83
+
84
+ main();
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * harness:verify — deterministic harness contract checks (no LLM).
3
+ * harness-verify — deterministic harness contract checks (no LLM).
4
4
  */
5
5
 
6
6
  import { readFile, access } from "node:fs/promises";
@@ -122,12 +122,14 @@ async function checkSentruxRules() {
122
122
  "--check",
123
123
  ]);
124
124
  if (checkCode !== 0) {
125
- fail(checkOut.trim() || "sentrux rules.toml out of date — run harness:sentrux-sync");
125
+ fail(checkOut.trim() || "sentrux rules.toml out of date — run node \"$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs\" --force (see .pi/scripts/README.md for UP_PKG)");
126
126
  }
127
127
  ok("sentrux rules.toml in sync with manifest");
128
128
 
129
129
  if (!(await fileExists(SENTRUX_RULES))) {
130
- fail("missing .sentrux/rules.toml — run npm run harness:sentrux-sync");
130
+ fail(
131
+ "missing .sentrux/rules.toml — run node \"$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs\" --force (resolve UP_PKG via .pi/scripts/README.md)",
132
+ );
131
133
  }
132
134
  ok(".sentrux/rules.toml present");
133
135
  }
@@ -80,7 +80,7 @@ function renderManagedBlock(manifest) {
80
80
  function mergeRules(existing, managedBlock) {
81
81
  const header = `# Sentrux rules — ${new Date().toISOString().slice(0, 10)}
82
82
  # Docs: https://sentrux.dev/docs/rules-engine/
83
- # Sync: npm run harness:sentrux-sync (or /harness-sentrux-sync in pi)
83
+ # Sync: node $UP_PKG/.pi/scripts/sentrux-rules-sync.mjs --force (see .pi/scripts/README.md for UP_PKG) or /harness-sentrux-sync in pi
84
84
  #
85
85
  # Custom rules: add TOML below the managed block; they are preserved on sync.
86
86
 
@@ -168,7 +168,7 @@ async function main() {
168
168
  if (checkOnly) process.exit(0);
169
169
  } else if (checkOnly) {
170
170
  fail(
171
- "rules.toml out of date — run npm run harness:sentrux-sync",
171
+ "rules.toml out of date — run node \"$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs\" --force (see .pi/scripts/README.md for UP_PKG)",
172
172
  );
173
173
  } else {
174
174
  await mkdir(join(ROOT, ".sentrux"), { recursive: true });