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.
- package/.agents/skills/harness-eval/SKILL.md +1 -1
- package/.agents/skills/harness-governor/SKILL.md +2 -2
- package/.agents/skills/harness-spec/SKILL.md +1 -1
- package/.pi/PACKAGING.md +3 -2
- package/.pi/extensions/custom-header.ts +0 -17
- package/.pi/extensions/pi-model-router-harness.ts +42 -0
- package/.pi/extensions/sentrux-rules-sync.ts +0 -18
- package/.pi/harness/README.md +3 -2
- package/.pi/harness/docs/adrs/0004-defer-ci-agent-smoke.md +1 -1
- package/.pi/harness/docs/adrs/0006-sentrux-dual-layer.md +1 -1
- package/.pi/harness/docs/adrs/0009-sentrux-rules-lifecycle.md +2 -2
- package/.pi/harness/evals/smoke/README.md +1 -1
- package/.pi/harness/evolution/README.md +1 -1
- package/.pi/harness/evolution/chaos-drill.md +1 -1
- package/.pi/prompts/harness-setup.md +38 -35
- package/.pi/scripts/README.md +25 -9
- package/.pi/scripts/harness-cli-verify.sh +4 -2
- package/.pi/scripts/harness-sync-model-router.mjs +84 -0
- package/.pi/scripts/harness-verify.mjs +5 -3
- package/.pi/scripts/sentrux-rules-sync.mjs +2 -2
- package/.pi/scripts/vendor-sync-pi-model-router.sh +47 -0
- package/.pi/settings.example.json +0 -1
- package/.sentrux/rules.toml +1 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +54 -0
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/biome.json +2 -1
- package/package.json +9 -10
- package/vendor/pi-model-router/.prettierignore +4 -0
- package/vendor/pi-model-router/.prettierrc +5 -0
- package/vendor/pi-model-router/AGENTS.md +39 -0
- package/vendor/pi-model-router/LICENSE +21 -0
- package/vendor/pi-model-router/README.md +99 -0
- package/vendor/pi-model-router/UPSTREAM_PIN.md +8 -0
- package/vendor/pi-model-router/docs/ARCHITECTURE.md +54 -0
- package/vendor/pi-model-router/extensions/commands.ts +720 -0
- package/vendor/pi-model-router/extensions/config.ts +348 -0
- package/vendor/pi-model-router/extensions/constants.ts +1 -0
- package/vendor/pi-model-router/extensions/index.ts +457 -0
- package/vendor/pi-model-router/extensions/provider.ts +529 -0
- package/vendor/pi-model-router/extensions/routing.ts +416 -0
- package/vendor/pi-model-router/extensions/state.ts +49 -0
- package/vendor/pi-model-router/extensions/types.ts +86 -0
- package/vendor/pi-model-router/extensions/ui.ts +130 -0
- package/vendor/pi-model-router/model-router.example.json +48 -0
- package/vendor/pi-model-router/package.json +48 -0
- package/vendor/pi-model-router/tsconfig.json +16 -0
- package/.pi/extensions/model-router-bootstrap.ts +0 -174
- 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: `
|
|
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 `
|
|
20
|
-
5. Run `
|
|
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 `
|
|
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/`
|
|
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`
|
|
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(),
|
package/.pi/harness/README.md
CHANGED
|
@@ -17,8 +17,9 @@ This scaffold is intentionally minimal and safe to adopt incrementally.
|
|
|
17
17
|
## Verification
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
21
|
-
|
|
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 (`
|
|
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:** `
|
|
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:** `
|
|
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
|
-
- `
|
|
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 `
|
|
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
|
-
- `
|
|
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;
|
|
61
|
-
bash "$
|
|
62
|
-
#
|
|
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
|
-
#
|
|
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
|
-
|
|
224
|
-
# ultimate-pi checkout:
|
|
225
|
-
# Reinstall everything:
|
|
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
|
-
|
|
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 `
|
|
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
|
-
|
|
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.
|
|
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
|
-
| `@
|
|
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
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
746
|
-
|
|
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 `
|
|
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
|
|
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 `
|
|
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 `
|
|
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. |
|
package/.pi/scripts/README.md
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
8
|
-
- Extensions resolving paths with `resolveHarnessScript()` in `.pi/extensions/lib/harness-paths.ts`
|
|
7
|
+
## Resolve `ultimate-pi` package root (`UP_PKG`)
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
263
|
-
|
|
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
|
|
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
|
|
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(
|
|
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:
|
|
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
|
|
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 });
|