ultimate-pi 0.18.1 → 0.19.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 (284) hide show
  1. package/.agents/skills/harness-debate-plan/SKILL.md +1 -1
  2. package/.agents/skills/harness-decisions/SKILL.md +1 -2
  3. package/.agents/skills/harness-governor/SKILL.md +6 -5
  4. package/.pi/PACKAGING.md +4 -4
  5. package/.pi/SYSTEM.md +54 -120
  6. package/.pi/agents/harness/incident-recorder.md +0 -1
  7. package/.pi/agents/harness/planning/decompose.md +0 -2
  8. package/.pi/agents/harness/planning/execution-plan-author.md +0 -2
  9. package/.pi/agents/harness/planning/hypothesis-validator.md +0 -2
  10. package/.pi/agents/harness/planning/hypothesis.md +0 -2
  11. package/.pi/agents/harness/planning/implementation-researcher.md +0 -2
  12. package/.pi/agents/harness/planning/plan-adversary.md +0 -2
  13. package/.pi/agents/harness/planning/plan-evaluator.md +1 -3
  14. package/.pi/agents/harness/planning/planning-context.md +0 -2
  15. package/.pi/agents/harness/planning/review-integrator.md +0 -2
  16. package/.pi/agents/harness/planning/sprint-contract-auditor.md +0 -2
  17. package/.pi/agents/harness/planning/stack-researcher.md +0 -2
  18. package/.pi/agents/harness/reviewing/adversary.md +0 -2
  19. package/.pi/agents/harness/reviewing/evaluator.md +0 -2
  20. package/.pi/agents/harness/reviewing/tie-breaker.md +0 -2
  21. package/.pi/agents/harness/running/executor.md +0 -2
  22. package/.pi/agents/harness/sentrux-bootstrap.md +0 -1
  23. package/.pi/agents/harness/sentrux-steward.md +0 -2
  24. package/.pi/agents/harness/trace-librarian.md +0 -1
  25. package/.pi/extensions/00-posthog-network-bootstrap.ts +1 -1
  26. package/.pi/extensions/agt-kill-switch.ts +57 -0
  27. package/.pi/extensions/agt-prompt-guard.ts +32 -0
  28. package/.pi/extensions/custom-footer.ts +46 -145
  29. package/.pi/extensions/custom-header.ts +1 -1
  30. package/.pi/extensions/custom-system-prompt.ts +1 -1
  31. package/.pi/extensions/debate-orchestrator.ts +6 -6
  32. package/.pi/extensions/harness-ask-user.ts +7 -7
  33. package/.pi/extensions/harness-debate-tools.ts +26 -42
  34. package/.pi/extensions/harness-lens.ts +94 -0
  35. package/.pi/extensions/harness-plan-approval.ts +11 -11
  36. package/.pi/extensions/harness-run-context.ts +1070 -876
  37. package/.pi/extensions/harness-subagent-governance.ts +8 -0
  38. package/.pi/extensions/harness-subagent-submit.ts +34 -163
  39. package/.pi/extensions/harness-subagents.ts +3 -3
  40. package/.pi/extensions/harness-telemetry.ts +2 -2
  41. package/.pi/extensions/harness-web-tools.ts +2 -2
  42. package/.pi/extensions/policy-gate.ts +25 -5
  43. package/.pi/extensions/sentrux-rules-sync.ts +1 -1
  44. package/.pi/extensions/subagent-governance.ts +92 -0
  45. package/.pi/extensions/trace-recorder.ts +1 -1
  46. package/.pi/extensions/{ultimate-pi-vcc.ts → vcc-compaction.ts} +1 -1
  47. package/.pi/harness/README.md +6 -2
  48. package/.pi/harness/agents.manifest.json +22 -25
  49. package/.pi/harness/agents.policy.yaml +275 -0
  50. package/.pi/harness/docs/adrs/0030-inhouse-vcc-compaction.md +1 -1
  51. package/.pi/harness/docs/adrs/0035-plan-phase-review-gate.md +1 -1
  52. package/.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md +49 -0
  53. package/.pi/harness/docs/adrs/0046-agt-policy-engine.md +51 -0
  54. package/.pi/harness/docs/adrs/0047-agt-layered-security.md +39 -0
  55. package/.pi/harness/docs/adrs/0048-tool-call-hook-order.md +25 -0
  56. package/.pi/harness/docs/adrs/0049-agents-policy-manifest.md +36 -0
  57. package/.pi/harness/docs/adrs/README.md +5 -0
  58. package/.pi/harness/evolution/README.md +1 -2
  59. package/.pi/harness/examples/agents.policy.project.yaml +19 -0
  60. package/.pi/harness/examples/policies/custom-deny-bash.yaml +9 -0
  61. package/.pi/harness/policies/bash-denylists.yaml +5 -0
  62. package/.pi/harness/policies/defaults.yaml +51 -0
  63. package/.pi/harness/policies/orchestrator.yaml +18 -0
  64. package/.pi/harness/policies/phases.yaml +10 -0
  65. package/.pi/harness/policies/roles.yaml +5 -0
  66. package/.pi/harness/policies/web-guard.yaml +5 -0
  67. package/.pi/harness/policies/workflow-sequences.yaml +9 -0
  68. package/.pi/harness/sentrux/architecture.manifest.json +26 -4
  69. package/.pi/harness/specs/observation.schema.json +2 -1
  70. package/.pi/lib/agents-policy.d.mts +70 -0
  71. package/.pi/lib/agents-policy.mjs +325 -0
  72. package/.pi/lib/agents-policy.ts +19 -0
  73. package/.pi/lib/agt/audit-run-sink.ts +52 -0
  74. package/.pi/lib/agt/build-evaluation-context.ts +285 -0
  75. package/.pi/lib/agt/config.ts +28 -0
  76. package/.pi/lib/agt/delegation.ts +69 -0
  77. package/.pi/lib/agt/evaluate-policy.ts +56 -0
  78. package/.pi/lib/agt/identity-registry.ts +41 -0
  79. package/.pi/lib/agt/index.ts +55 -0
  80. package/.pi/lib/agt/kill-switch-state.ts +11 -0
  81. package/.pi/lib/agt/legacy-evaluate.ts +101 -0
  82. package/.pi/lib/agt/policy-engine.ts +154 -0
  83. package/.pi/lib/agt/rings.ts +21 -0
  84. package/.pi/lib/agt/sre-hooks.ts +45 -0
  85. package/.pi/lib/agt/trust-run-store.ts +26 -0
  86. package/.pi/lib/agt/workflow-history.ts +29 -0
  87. package/.pi/lib/agt-governance-active.ts +14 -0
  88. package/.pi/lib/agt-tool-guard.ts +78 -0
  89. package/.pi/lib/ask-user/dialog.ts +314 -0
  90. package/.pi/{extensions/lib → lib}/debate-bus-core.ts +10 -10
  91. package/.pi/{extensions/lib → lib}/debate-bus-state.ts +1 -1
  92. package/.pi/{extensions/lib → lib}/extension-load-guard.ts +13 -2
  93. package/.pi/lib/harness-agt-tool-guard.ts +5 -0
  94. package/.pi/{extensions/lib → lib}/harness-artifact-gate.ts +1 -1
  95. package/.pi/lib/harness-debate-core-deps.ts +14 -0
  96. package/.pi/lib/harness-debate-workflow-deps.ts +43 -0
  97. package/.pi/lib/harness-lens/.gitattributes +1 -0
  98. package/.pi/lib/harness-lens/clients/edit-autopatch.ts +88 -0
  99. package/.pi/lib/harness-lens/clients/file-kinds.ts +380 -0
  100. package/.pi/lib/harness-lens/clients/file-time.ts +215 -0
  101. package/.pi/lib/harness-lens/clients/file-utils.ts +484 -0
  102. package/.pi/lib/harness-lens/clients/format-service.ts +276 -0
  103. package/.pi/lib/harness-lens/clients/formatters.ts +1000 -0
  104. package/.pi/lib/harness-lens/clients/git-guard.ts +31 -0
  105. package/.pi/lib/harness-lens/clients/indent-retarget.ts +90 -0
  106. package/.pi/lib/harness-lens/clients/installer/index.ts +2368 -0
  107. package/.pi/lib/harness-lens/clients/latency-logger.ts +80 -0
  108. package/.pi/lib/harness-lens/clients/lens-config.ts +43 -0
  109. package/.pi/lib/harness-lens/clients/lens-events.ts +164 -0
  110. package/.pi/lib/harness-lens/clients/lsp/aggregation.ts +91 -0
  111. package/.pi/lib/harness-lens/clients/lsp/client.ts +1466 -0
  112. package/.pi/lib/harness-lens/clients/lsp/config.ts +216 -0
  113. package/.pi/lib/harness-lens/clients/lsp/edits.ts +297 -0
  114. package/.pi/lib/harness-lens/clients/lsp/index.ts +1355 -0
  115. package/.pi/lib/harness-lens/clients/lsp/interactive-install.ts +424 -0
  116. package/.pi/lib/harness-lens/clients/lsp/language.ts +223 -0
  117. package/.pi/lib/harness-lens/clients/lsp/launch.ts +939 -0
  118. package/.pi/lib/harness-lens/clients/lsp/lsp-index.ts +11 -0
  119. package/.pi/lib/harness-lens/clients/lsp/path-utils.ts +12 -0
  120. package/.pi/lib/harness-lens/clients/lsp/server-strategies.ts +81 -0
  121. package/.pi/lib/harness-lens/clients/lsp/server.ts +1971 -0
  122. package/.pi/lib/harness-lens/clients/path-utils.ts +182 -0
  123. package/.pi/lib/harness-lens/clients/pipeline.ts +360 -0
  124. package/.pi/lib/harness-lens/clients/project-profile.ts +117 -0
  125. package/.pi/lib/harness-lens/clients/runtime-agent-end.ts +112 -0
  126. package/.pi/lib/harness-lens/clients/runtime-config.ts +33 -0
  127. package/.pi/lib/harness-lens/clients/runtime-coordinator.ts +186 -0
  128. package/.pi/lib/harness-lens/clients/runtime-tool-result.ts +171 -0
  129. package/.pi/lib/harness-lens/clients/safe-spawn.ts +339 -0
  130. package/.pi/lib/harness-lens/clients/secrets-scanner.ts +214 -0
  131. package/.pi/lib/harness-lens/clients/tool-policy.ts +2072 -0
  132. package/.pi/lib/harness-lens/clients/types.ts +59 -0
  133. package/.pi/lib/harness-lens/clients/widget-state.ts +283 -0
  134. package/.pi/lib/harness-lens/index.ts +532 -0
  135. package/.pi/lib/harness-lens/tools/lsp-diagnostics.ts +706 -0
  136. package/.pi/lib/harness-lens/tools/lsp-navigation.ts +1246 -0
  137. package/.pi/{extensions/lib → lib}/harness-posthog.ts +3 -0
  138. package/.pi/lib/harness-run-context-responses.ts +9 -0
  139. package/.pi/lib/harness-run-context.ts +0 -2
  140. package/.pi/{extensions/lib/spawn-policy.ts → lib/harness-spawn-policy.ts} +1 -0
  141. package/.pi/{extensions/lib → lib}/harness-spawn-topology.ts +1 -1
  142. package/.pi/lib/harness-subagent-auth.ts +51 -0
  143. package/.pi/{extensions/lib → lib}/harness-subagent-precheck.ts +10 -7
  144. package/.pi/{extensions/lib → lib}/harness-subagent-submit-pipeline.ts +3 -3
  145. package/.pi/lib/harness-subagent-submit-register.ts +163 -0
  146. package/.pi/{extensions/lib → lib}/harness-subagent-submit-registry.ts +1 -37
  147. package/.pi/{extensions/lib → lib}/harness-subagents-bridge.ts +53 -14
  148. package/.pi/{extensions/lib → lib}/harness-subprocess-bootstrap.ts +1 -1
  149. package/.pi/{extensions/lib → lib}/plan-approval/create-plan.ts +2 -2
  150. package/.pi/{extensions/lib → lib}/plan-approval/format-plan.ts +2 -2
  151. package/.pi/{extensions/lib → lib}/plan-approval/plan-review.ts +162 -201
  152. package/.pi/{extensions/lib → lib}/plan-approval/render.ts +1 -1
  153. package/.pi/{extensions/lib → lib}/plan-approval/resolve-disk.ts +2 -2
  154. package/.pi/{extensions/lib → lib}/plan-approval/types.ts +1 -1
  155. package/.pi/{extensions/lib → lib}/plan-approval/validate.ts +3 -3
  156. package/.pi/{extensions/lib → lib}/plan-debate-envelope.ts +1 -1
  157. package/.pi/{extensions/lib → lib}/plan-debate-gate.ts +1 -1
  158. package/.pi/{extensions/lib → lib}/plan-debate-lane.ts +1 -4
  159. package/.pi/{extensions/lib → lib}/plan-messenger.ts +1 -1
  160. package/.pi/prompts/harness-plan.md +1 -1
  161. package/.pi/prompts/harness-setup.md +37 -64
  162. package/.pi/scripts/README.md +2 -5
  163. package/.pi/scripts/generate-agents-policy-yaml.mjs +148 -0
  164. package/.pi/scripts/harness-agents-manifest.mjs +60 -3
  165. package/.pi/scripts/harness-agt-doctor.ts +36 -0
  166. package/.pi/scripts/harness-cli-verify.sh +9 -2
  167. package/.pi/scripts/harness-verify.mjs +113 -39
  168. package/.pi/scripts/harness-web-policy-guard.mjs +2 -2
  169. package/.pi/scripts/validate-plan-dag.mjs +65 -74
  170. package/.pi/scripts/vendor-pi-vcc-settings.stub.ts +2 -2
  171. package/.pi/scripts/vendor-sync-pi-vcc.sh +1 -1
  172. package/.pi/skills/architecture/broker-domain/SKILL.md +65 -0
  173. package/.pi/skills/architecture/cqrs/SKILL.md +63 -0
  174. package/.pi/skills/architecture/event-driven/SKILL.md +60 -0
  175. package/.pi/skills/architecture/hexagonal-ports-adapters/SKILL.md +66 -0
  176. package/.pi/skills/architecture/layered/SKILL.md +68 -0
  177. package/.pi/skills/architecture/microkernel/SKILL.md +62 -0
  178. package/.pi/skills/architecture/microservices/SKILL.md +64 -0
  179. package/.pi/skills/architecture/modular-monolith/SKILL.md +65 -0
  180. package/.pi/skills/architecture/orchestration-driven-soa/SKILL.md +61 -0
  181. package/.pi/skills/architecture/pipeline/SKILL.md +63 -0
  182. package/.pi/skills/architecture/service-based/SKILL.md +64 -0
  183. package/.pi/skills/architecture/service-mesh/SKILL.md +60 -0
  184. package/.pi/skills/architecture/space-based/SKILL.md +60 -0
  185. package/.pi/skills/ast-grep/SKILL.md +40 -321
  186. package/.pi/skills/delivery/debugging-discipline/SKILL.md +36 -0
  187. package/.pi/skills/delivery/documentation-update/SKILL.md +33 -0
  188. package/.pi/skills/delivery/requirements-to-implementation/SKILL.md +34 -0
  189. package/.pi/skills/delivery/risk-based-verification/SKILL.md +43 -0
  190. package/.pi/skills/delivery/tradeoff-analysis/SKILL.md +34 -0
  191. package/.pi/skills/engineering/api-contract-design/SKILL.md +38 -0
  192. package/.pi/skills/engineering/cohesion-coupling/SKILL.md +43 -0
  193. package/.pi/skills/engineering/complexity-control/SKILL.md +31 -0
  194. package/.pi/skills/engineering/defensive-programming/SKILL.md +38 -0
  195. package/.pi/skills/engineering/dependency-management/SKILL.md +29 -0
  196. package/.pi/skills/engineering/domain-modeling/SKILL.md +32 -0
  197. package/.pi/skills/engineering/error-handling/SKILL.md +37 -0
  198. package/.pi/skills/engineering/legacy-code-seams/SKILL.md +35 -0
  199. package/.pi/skills/engineering/naming-and-intent/SKILL.md +29 -0
  200. package/.pi/skills/engineering/refactoring-safe-evolution/SKILL.md +35 -0
  201. package/.pi/skills/engineering/routine-function-design/SKILL.md +34 -0
  202. package/.pi/skills/engineering/small-change-discipline/SKILL.md +35 -0
  203. package/.pi/skills/lsp-navigation/SKILL.md +89 -0
  204. package/.pi/skills/quality/code-review-self-check/SKILL.md +35 -0
  205. package/.pi/skills/quality/privacy-data-handling/SKILL.md +26 -0
  206. package/.pi/skills/quality/security-review/SKILL.md +34 -0
  207. package/.pi/skills/quality/test-strategy/SKILL.md +33 -0
  208. package/.pi/skills/quality/testability-design/SKILL.md +33 -0
  209. package/.pi/skills/systems/concurrency-safety/SKILL.md +32 -0
  210. package/.pi/skills/systems/data-modeling-migrations/SKILL.md +31 -0
  211. package/.pi/skills/systems/observability-instrumentation/SKILL.md +32 -0
  212. package/.pi/skills/systems/performance-measurement/SKILL.md +35 -0
  213. package/.pi/skills/systems/reliability-design/SKILL.md +32 -0
  214. package/.sentrux/rules.toml +20 -4
  215. package/AGENTS.md +5 -0
  216. package/CHANGELOG.md +14 -0
  217. package/README.md +3 -12
  218. package/THIRD_PARTY_NOTICES.md +12 -21
  219. package/package.json +15 -7
  220. package/vendor/pi-subagents/src/agents.ts +45 -1
  221. package/vendor/pi-subagents/src/subagents.ts +866 -811
  222. package/vendor/pi-vcc/src/core/brief.ts +68 -99
  223. package/vendor/pi-vcc/src/core/settings.ts +2 -2
  224. package/.agents/skills/caveman/SKILL.md +0 -67
  225. package/.pi/agents/harness/meta-optimizer.md +0 -36
  226. package/.pi/extensions/lib/ask-user/dialog.ts +0 -260
  227. package/.pi/extensions/lib/harness-subagent-auth.ts +0 -207
  228. package/.pi/extensions/lib/harness-subagent-policy.ts +0 -236
  229. package/.pi/extensions/pi-model-router-harness.ts +0 -42
  230. package/.pi/harness/evolution/meta-optimizer.mjs +0 -99
  231. package/.pi/harness/specs/router-tuning-proposal.schema.json +0 -114
  232. package/.pi/model-router.example.json +0 -36
  233. package/.pi/prompts/harness-critic.md +0 -10
  234. package/.pi/prompts/harness-eval.md +0 -10
  235. package/.pi/prompts/harness-router-tune.md +0 -52
  236. package/.pi/scripts/harness-generate-model-router.mjs +0 -327
  237. package/.pi/scripts/harness-model-router-routing.test.mjs +0 -97
  238. package/.pi/scripts/harness-sync-model-router.mjs +0 -97
  239. package/.pi/scripts/vendor-sync-pi-model-router.sh +0 -47
  240. package/vendor/pi-model-router/.prettierignore +0 -4
  241. package/vendor/pi-model-router/.prettierrc +0 -5
  242. package/vendor/pi-model-router/AGENTS.md +0 -39
  243. package/vendor/pi-model-router/LICENSE +0 -21
  244. package/vendor/pi-model-router/README.md +0 -99
  245. package/vendor/pi-model-router/UPSTREAM_PIN.md +0 -10
  246. package/vendor/pi-model-router/docs/ARCHITECTURE.md +0 -54
  247. package/vendor/pi-model-router/extensions/commands.ts +0 -720
  248. package/vendor/pi-model-router/extensions/config.ts +0 -348
  249. package/vendor/pi-model-router/extensions/constants.ts +0 -1
  250. package/vendor/pi-model-router/extensions/index.ts +0 -478
  251. package/vendor/pi-model-router/extensions/provider.ts +0 -580
  252. package/vendor/pi-model-router/extensions/routing.ts +0 -564
  253. package/vendor/pi-model-router/extensions/state.ts +0 -52
  254. package/vendor/pi-model-router/extensions/types.ts +0 -95
  255. package/vendor/pi-model-router/extensions/ui.ts +0 -144
  256. package/vendor/pi-model-router/model-router.example.json +0 -48
  257. package/vendor/pi-model-router/package.json +0 -48
  258. package/vendor/pi-model-router/tsconfig.json +0 -16
  259. /package/.pi/{prompts → harness/docs}/planning-rubrics.md +0 -0
  260. /package/.pi/{extensions/lib → lib}/ask-user/fallback.ts +0 -0
  261. /package/.pi/{extensions/lib → lib}/ask-user/render.ts +0 -0
  262. /package/.pi/{extensions/lib → lib}/ask-user/schema.ts +0 -0
  263. /package/.pi/{extensions/lib → lib}/ask-user/types.ts +0 -0
  264. /package/.pi/{extensions/lib → lib}/ask-user/validate-core.mjs +0 -0
  265. /package/.pi/{extensions/lib → lib}/ask-user/validate.ts +0 -0
  266. /package/.pi/{extensions/lib → lib}/harness-cocoindex-refresh.ts +0 -0
  267. /package/.pi/{extensions/lib → lib}/harness-paths.ts +0 -0
  268. /package/.pi/{extensions/lib → lib}/harness-spawn-budget.ts +0 -0
  269. /package/.pi/{extensions/lib → lib}/harness-vcc-settings.ts +0 -0
  270. /package/.pi/{extensions/lib → lib}/harness-web/run-cli.ts +0 -0
  271. /package/.pi/{extensions/lib → lib}/plan-approval/dialog.ts +0 -0
  272. /package/.pi/{extensions/lib → lib}/plan-approval/schema.ts +0 -0
  273. /package/.pi/{extensions/lib → lib}/plan-approval-readiness.ts +0 -0
  274. /package/.pi/{extensions/lib → lib}/plan-debate-eligibility.ts +0 -0
  275. /package/.pi/{extensions/lib → lib}/plan-debate-focus.ts +0 -0
  276. /package/.pi/{extensions/lib → lib}/plan-debate-id.ts +0 -0
  277. /package/.pi/{extensions/lib → lib}/plan-debate-lanes.ts +0 -0
  278. /package/.pi/{extensions/lib → lib}/plan-debate-round-status.ts +0 -0
  279. /package/.pi/{extensions/lib → lib}/plan-debate-write-guard.ts +0 -0
  280. /package/.pi/{extensions/lib → lib}/plan-review-gate.ts +0 -0
  281. /package/.pi/{extensions/lib → lib}/plan-review-integrator-rules.ts +0 -0
  282. /package/.pi/{extensions/lib → lib}/plan-scope-guard.ts +0 -0
  283. /package/.pi/{extensions/lib → lib}/posthog-client.ts +0 -0
  284. /package/.pi/{extensions/lib → lib}/posthog-node.d.ts +0 -0
@@ -14,7 +14,6 @@ Bootstraps the complete ultimate-pi agentic harness: Graphify knowledge graph, C
14
14
  | Pitfall | Correct approach |
15
15
  |---------|------------------|
16
16
  | `UP_PKG="$(pwd)"` in an **external** repo | Wrong — scripts live in the npm package. Resolve via `harness-resolve-up-pkg.mjs` (see Step 0). |
17
- | Provider detection from `OPENAI_*` / `ANTHROPIC_*` env only | Wrong for pi users — keys live in `~/.pi/agent/auth.json`. Use `harness-generate-model-router.mjs` (Pi `ModelRegistry.getAvailable()`). |
18
17
  | Re-running 2.1–2.8 manually after CLI verify | Wasteful — trust `harness-cli-verify.sh` output; only fix reported ✗ lines. |
19
18
  | Overwriting `AGENTS.md` after graphify | Graphify appends a section — **merge**, do not replace (Step 4.3). |
20
19
  | `sentrux-rules-sync` without project manifest | Use **`harness-sentrux-bootstrap.mjs`** (Step 4.2) — seeds manifest + idempotent rules sync. |
@@ -154,9 +153,9 @@ bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh"
154
153
  # Reinstall everything: bash "$UP_PKG/.pi/scripts/harness-cli-verify.sh" --force
155
154
  ```
156
155
 
157
- **Required (script must exit 0):** scrapling + harness-web smoke, ctx7, biome, ast-grep (`sg`), sentrux (when harness manifest present).
156
+ **Required (script must exit 0):** scrapling + harness-web smoke, ctx7, ast-grep (`sg`), sentrux (when harness manifest present).
158
157
 
159
- **Warnings allowed:** gh (if not authenticated), agent-browser (if OS libs need manual `sudo apt-get install`), cocoindex-code (empty corpus on tiny repos; first `[full]` install downloads local embedding model).
158
+ **Warnings allowed:** biome (optional; skipped for non-JS/TS repos or if install fails), gh (if not authenticated), agent-browser (if OS libs need manual `sudo apt-get install`), cocoindex-code (empty corpus on tiny repos; first `[full]` install downloads local embedding model).
160
159
 
161
160
  If the script reports **agent-browser shared library errors** on Linux/WSL, run the fix it prints, then re-verify:
162
161
 
@@ -251,21 +250,21 @@ ccc status
251
250
 
252
251
  Verify: `ccc doctor` and `ccc search --limit 3 "export function"` (no `--refresh`).
253
252
 
254
- ### 2.5 — biome (Lint + Format Gate)
253
+ ### 2.5 — biome (Optional, JS/TS-focused lint + format)
255
254
 
256
- ```bash
257
- if ! command -v biome &>/dev/null || [ "$FORCE" = "true" ]; then
258
- npm install -g @biomejs/biome
259
- fi
260
- ```
255
+ Biome is **not a hard requirement** for harness setup. Install/use it when the target project is JS/TS (for example, has `package.json` or already uses `biome.json`). For other stacks, skip and use the repo's native formatter/linter.
261
256
 
262
- Check if project already has biome config:
263
257
  ```bash
264
- ls biome.json 2>/dev/null && echo "biome.json found — using project config" || echo "No biome.json using defaults"
258
+ if [ -f package.json ] || [ -f biome.json ]; then
259
+ if ! command -v biome &>/dev/null || [ "$FORCE" = "true" ]; then
260
+ npm install -g @biomejs/biome
261
+ fi
262
+ biome --version
263
+ else
264
+ echo "Skipping biome (non-JS/TS repo; optional tool)"
265
+ fi
265
266
  ```
266
267
 
267
- Verify: `biome --version`
268
-
269
268
  ### 2.6 — ast-grep (AST-Aware Structural Code Search)
270
269
 
271
270
  ```bash
@@ -327,7 +326,14 @@ sentrux plugin add-standard 2>/dev/null || echo "Plugins already installed or fa
327
326
 
328
327
  ## Step 3 — Pi Extension Packages
329
328
 
330
- Bundled extensions load from the installed `ultimate-pi` package. **Session-locked 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 router picks **one concrete model** when the session starts (from the first user prompt + system prompt complexity), then changes **thinking level only** each turn. The harness **gates** activation on `.pi/model-router.json` (Step **3.5** below) so `router/auto` 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`.
329
+ Bundled extensions load from the installed `ultimate-pi` package. The harness lens wrapper at `.pi/extensions/harness-lens.ts` loads `.pi/extensions/lib/harness-lens/` for edit autopatch, secrets blocking, deferred format, and LSP tools. Structural search uses shell `sg` (installed globally by setup); architecture gates use Sentrux. See [ADR 0045](.pi/harness/docs/adrs/0045-harness-lens-minimal-contract.md).
330
+
331
+ Harness lens findings are **complementary** to Sentrux:
332
+
333
+ - **Harness lens:** fast edit-time and turn-time code feedback; standalone lens widgets/health telemetry are disabled, and findings flow through the harness PostHog telemetry layer.
334
+ - **Sentrux:** architecture-quality signal and gate (`.sentrux/rules.toml`, `sentrux-signal.yaml`, harness review/evaluate inputs).
335
+
336
+ Do not treat harness lens as a replacement for Sentrux. If a future lens change adds architecture-boundary gating that duplicates Sentrux, keep Sentrux authoritative and disable/remove the overlapping lens path.
331
337
 
332
338
  Optionally install the companion lockfile used in development:
333
339
 
@@ -341,51 +347,19 @@ else
341
347
  fi
342
348
  ```
343
349
 
344
- 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).
350
+ 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).
345
351
 
346
352
  Verify each package:
347
353
 
348
354
  | Package | Purpose | Phase |
349
355
  |---------|---------|-------|
350
356
  | `@posthog/pi` | Analytics event capture | F0 |
351
- | `pi-lean-ctx` | Context runtime (read/bash/find/grep/MCP bridge) | F0 |
357
+ | `context-mode` | Context runtime and MCP context-saving tools | F0 |
352
358
  | `harness-subagents` (bundled extension) | L4 `subagent` tool, subprocess spawns, package agents | P16 |
353
359
  | Vendored `pi-vcc` (`vendor/pi-vcc`, `.pi/extensions/ultimate-pi-vcc.ts`) | VCC compaction / `vcc_recall` — env-only: `HARNESS_VCC_COMPACTION` (default on), `HARNESS_VCC_DEBUG` | Shipped |
354
- | `pi-model-router` | Vendored (`vendor/`); activates after `.pi/model-router.json` exists | F0 |
355
-
356
- ## Step 3.5 — Model Router Configuration (Dynamic)
357
-
358
- `.pi/model-router.json` is **user-specific** (gitignored). Generate from **Pi authenticated providers** (`~/.pi/agent/auth.json`, OAuth, env) — **not** env-var guessing alone.
359
-
360
- Pi API (see `packages/coding-agent` docs / SDK example `02-custom-model.ts`):
361
-
362
- - `AuthStorage.create()` → credentials store
363
- - `ModelRegistry.create(authStorage)` → registry
364
- - `await modelRegistry.getAvailable()` → models with working auth (same as interactive pi)
365
-
366
- ```bash
367
- # Verify vendored extension source ships with ultimate-pi
368
- ls "$UP_PKG/vendor/pi-model-router/extensions/index.ts" 2>/dev/null \
369
- && echo "✓ vendored pi-model-router" \
370
- || echo "✗ missing vendor/pi-model-router"
371
-
372
- # Generate from Pi registry (skips if .pi/model-router.json exists; --force to regenerate)
373
- node "$UP_PKG/.pi/scripts/harness-generate-model-router.mjs"
374
- # Preview only: node "$UP_PKG/.pi/scripts/harness-generate-model-router.mjs" --dry-run
375
-
376
- # Merge router defaults after config exists (never adds npm packages — router is vendored)
377
- node "$UP_PKG/.pi/scripts/harness-sync-model-router.mjs"
378
- ```
379
-
380
- If generation prints "No authenticated Pi providers": warn in report — user should run **`/login`** in pi (or `pi login`) then re-run Step 3.5. Do **not** infer providers from `OPENAI_API_KEY` alone; pi sessions often use `opencode-go` via auth.json without those env vars.
381
-
382
- Do NOT block setup. If no config is written, `harness-sync-model-router.mjs` clears a premature `defaultProvider: "router"` in `.pi/settings.json`.
383
-
384
- **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`**, or whatever `defaultProfile` is) via `harness-sync-model-router.mjs` when `defaultProvider` was unset—then **`/reload`**. Generated profiles use **one model SKU per profile**; high/medium/low tiers differ in **thinking** only. Subagents resolve their subprocess model from the **agent system prompt** complexity (same lock rules).
385
-
386
- Manual override: **`/router profile auto`** or **`/router profile opencode-go`** anytime after reload if they changed defaults.
360
+ | Harness lens (`.pi/extensions/harness-lens.ts` → `.pi/extensions/lib/harness-lens/index.ts`) | Edit autopatch, secrets block, deferred format, LSP tools; PostHog lens telemetry; Sentrux remains architecture gate; `sg` is shell-only | F0 |
387
361
 
388
- ## Step 3.6 — Harness agents (package-resolved)
362
+ ## Step 3.5 — Harness agents (package-resolved)
389
363
 
390
364
  `harness-subagents` loads agents from the installed **`ultimate-pi`** package (`$UP_PKG/.pi/agents/**`) with namespaced ids (`harness/running/executor`, `harness/reviewing/evaluator`, `pi-pi/agent-expert`). **Do not copy** agents into the project unless you want a deliberate override.
391
365
 
@@ -500,10 +474,9 @@ Ensure `.gitignore` contains harness runtime entries (see repo root `.gitignore`
500
474
  !.pi/harness/incidents/README.md
501
475
  .pi/harness/debates/*
502
476
  !.pi/harness/debates/README.md
503
- .pi/harness/router/proposals/*
504
477
 
505
- # Model router config (user-specific generated from env)
506
- .pi/model-router.json
478
+ # Harness lens runtime config/cache and local diagnostics state
479
+ .pi/harness/.lens/
507
480
 
508
481
  # sentrux baselines and local meta (rules.toml is committed)
509
482
  .sentrux/*
@@ -564,7 +537,7 @@ Created: $(date +%Y-%m-%d)
564
537
  - .pi/harness/specs/ → Harness contracts and schema docs
565
538
  - .pi/harness/incidents/ → Incident and override records
566
539
  - `.agents/skills/` (npm package) → Harness skills (no copy into `.pi/skills/` needed)
567
- - `.pi/agents/` → Optional per-repo agent overrides (package agents load automatically — see Step 3.6)
540
+ - `.pi/agents/` → Optional per-repo agent overrides (package agents load automatically — see Step 3.5)
568
541
 
569
542
  ## Graphify-First Workflow
570
543
 
@@ -580,7 +553,7 @@ Created: $(date +%Y-%m-%d)
580
553
  - Decisions and incidents in `.pi/harness/` with structured artifacts
581
554
  - `GRAPHIFY_VIZ_NODE_LIMIT=200000 graphify update .` after significant code changes
582
555
  - ast-grep (`sg`) is the default code search tool — use `sg -p 'pattern'` for structural search, never grep for code
583
- - Create `.sg/rules/` for project-wide code quality rules
556
+ - Use shell `sg` for structural search; project-specific ast-grep rule dirs are optional in the **target repo**, not a harness template default
584
557
  ```
585
558
 
586
559
  ## Step 5 — Verification
@@ -627,10 +600,11 @@ print(f'✓ knowledge graph built ({n} nodes)' if n else '✗ graph.json has 0 n
627
600
  " 2>/dev/null || echo "✗ no graph built yet"
628
601
  graphify hook status 2>/dev/null && echo "✓ graphify git hooks installed" || echo "✗ graphify git hooks not installed"
629
602
 
630
- # vendored model router
631
- ls "$UP_PKG/vendor/pi-model-router/extensions/index.ts" 2>/dev/null \
632
- && echo "✓ vendored pi-model-router" || echo "✗ vendor/pi-model-router missing"
633
- ls .pi/model-router.json 2>/dev/null && echo "✓ model-router config" || echo "✗ model-router config"
603
+ # harness lens extension
604
+ ls "$UP_PKG/.pi/extensions/harness-lens.ts" 2>/dev/null \
605
+ && echo "✓ harness lens wrapper" || echo "✗ harness lens wrapper missing"
606
+ ls "$UP_PKG/.pi/extensions/lib/harness-lens/index.ts" 2>/dev/null \
607
+ && echo "✓ harness lens upstream pin" || echo "✗ harness lens upstream pin missing"
634
608
 
635
609
  # raw folder for graphify sources
636
610
  ls -d ./raw 2>/dev/null && echo "✓ ./raw directory exists" || echo "! ./raw directory missing"
@@ -672,13 +646,13 @@ Output summary table:
672
646
  | ctx7 | ✓/✗ | Login: yes/no |
673
647
  | agent-browser | ✓/✗ | Config: .pi/harness/browser.json |
674
648
  | cocoindex-code | ✓/✗ | `ccc status`; index auto-refreshed before harness scouts |
675
- | biome | ✓/✗ | Project config: found/default |
649
+ | biome | ✓/✗/skip | Optional; JS/TS-focused (skip on non-JS/TS stacks) |
676
650
  | ast-grep | ✓/✗ | AST-aware code search (`sg`)
677
651
  | gh CLI | ✓/✗ | Auth: yes/no |
678
652
  | sentrux | ✓/✗ | CLI + plugins; rules via Step 4.2 bootstrap |
679
653
  | Sentrux rules.toml | ✓/✗ | `.sentrux/rules.toml` synced from manifest |
680
- | pi extensions | ✓/✗ | 4 packages |
681
- | model router | ✓/✗ | Package + config verified, activation via `/router profile auto` (or `opencode-go`) |
654
+ | pi extensions | ✓/✗ | bundled extensions + harness lens wrapper |
655
+ | harness lens | ✓/✗ | `.pi/extensions/harness-lens.ts`; PostHog owns lens telemetry; complements Sentrux architecture signal |
682
656
  | `.env` | ✓/✗/ask | Created / keys appended / user declined |
683
657
 
684
658
  | .gitignore | ✓/✗ | entries added (incl. `.env`) |
@@ -728,11 +702,10 @@ Next steps:
728
702
  | gh not installed | Show GitHub CLI install link. Skip label creation. |
729
703
  | pi packages install fail | Show error output. Check npm permissions. |
730
704
  | graph already exists | Report node count. Refresh with `graphify update .` unless user passed `--force`. |
731
- | biome.json missing | Create minimal config. |
705
+ | biome.json missing | No action required. Biome is optional; use project-native tooling. |
732
706
  | settings.json not writable | Warn. Settings won't persist across sessions. |
733
707
  | No internet | Block for tool installs. Continue for graphify-only steps if `--skip-tools`. |
734
708
  | sentrux install fails | Show install script output. Fallback: download from https://github.com/sentrux/sentrux/releases/latest |
735
- | No model-router.json / "No authenticated Pi providers" | Run `/login` in pi, then `node "$UP_PKG/.pi/scripts/harness-generate-model-router.mjs" --force` |
736
709
  | UP_PKG not found | `pi install npm:ultimate-pi` or `npm i -g ultimate-pi`; verify with `node "$UP_PKG/.pi/scripts/harness-resolve-up-pkg.mjs"` |
737
710
  | No `.env` at project root | `ask_user` create vs skip; on create: `harness-sync-env.mjs --create-missing` |
738
711
 
@@ -14,7 +14,7 @@ UP_PKG="$(node -p "require('path').dirname(require.resolve('ultimate-pi/package.
14
14
 
15
15
  **Developing this repo** (clone of `ultimate-pi`): from the repo root, `UP_PKG="$(pwd)"` (or the same `require.resolve` after `npm install`).
16
16
 
17
- From **Typescript extensions**, use `resolveHarnessScript()` / `getHarnessPackageRoot()` in `.pi/extensions/lib/harness-paths.ts`.
17
+ From **Typescript extensions**, use `resolveHarnessScript()` / `getHarnessPackageRoot()` in `.pi/lib/harness-paths.ts`.
18
18
 
19
19
  ## Invocations (from the consuming project root)
20
20
 
@@ -29,11 +29,8 @@ From **Typescript extensions**, use `resolveHarnessScript()` / `getHarnessPackag
29
29
  | Sentrux rules drift check (CI) | `node "$UP_PKG/.pi/scripts/sentrux-rules-sync.mjs" --check` |
30
30
  | Sentrux run/review check or gate (root-resolving) | `node "$UP_PKG/.pi/scripts/harness-sentrux-cli.mjs" check` / `gate [--save]` |
31
31
  | Resolve package root (`UP_PKG`) | `node "$UP_PKG/.pi/scripts/harness-resolve-up-pkg.mjs"` |
32
- | Model-router config (Pi auth) | `node "$UP_PKG/.pi/scripts/harness-generate-model-router.mjs"` |
33
32
  | Project `.env` (append-only) | `node "$UP_PKG/.pi/scripts/harness-sync-env.mjs"` (`--create-missing` after user confirms) |
34
- | Model-router / Pi defaults | `harness-sync-model-router.mjs` (Step 3.5 of `/harness-setup`) |
35
- | Vendor router sync (this repo only) | `bash .pi/scripts/vendor-sync-pi-model-router.sh` or `npm run vendor:sync-router` |
36
- | Meta-optimizer (JSONL proposals) | `node "$UP_PKG/.pi/harness/evolution/meta-optimizer.mjs"` |
33
+ | Harness lens extension | `.pi/extensions/harness-lens.ts` → `.pi/lib/harness-lens/index.ts` (loaded by `.pi/extensions`; PostHog owns lens telemetry) |
37
34
 
38
35
  Pass `--force` to shell scripts that support it (e.g. `harness-graphify-bootstrap.sh --force`, `harness-cli-verify.sh --force`).
39
36
 
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Generate .pi/harness/agents.policy.yaml from harness agent .md frontmatter + submit registry.
4
+ */
5
+
6
+ import { readFile, writeFile } from "node:fs/promises";
7
+ import { join, dirname } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+ import { parse as parseYaml } from "yaml";
10
+ import { walkAgentsDir } from "../lib/harness-agent-discovery.mjs";
11
+
12
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
13
+ const AGENTS_DIR = join(ROOT, ".pi", "agents");
14
+ const OUT = join(ROOT, ".pi", "harness", "agents.policy.yaml");
15
+
16
+ const SUBMIT_BY_AGENT = {
17
+ "harness/planning/planning-context": ["submit_planning_context"],
18
+ "harness/planning/decompose": ["submit_decomposition_brief", "submit_human_required"],
19
+ "harness/planning/hypothesis": ["submit_hypothesis_brief"],
20
+ "harness/planning/hypothesis-validator": ["submit_hypothesis_validation"],
21
+ "harness/planning/plan-evaluator": ["submit_validation_turn"],
22
+ "harness/planning/plan-adversary": ["submit_adversary_brief"],
23
+ "harness/planning/sprint-contract-auditor": ["submit_sprint_audit"],
24
+ "harness/planning/review-integrator": ["submit_review_round_draft"],
25
+ "harness/planning/implementation-researcher": ["submit_implementation_research"],
26
+ "harness/planning/stack-researcher": ["submit_stack_brief"],
27
+ "harness/planning/execution-plan-author": ["submit_execution_plan_brief"],
28
+ "harness/running/executor": ["submit_executor_handoff"],
29
+ "harness/reviewing/evaluator": ["submit_eval_verdict"],
30
+ "harness/reviewing/adversary": ["submit_adversary_report"],
31
+ "harness/reviewing/tie-breaker": ["submit_human_required"],
32
+ "harness/trace-librarian": ["submit_human_required"],
33
+ "harness/incident-recorder": ["submit_human_required"],
34
+ "harness/sentrux-steward": ["submit_sentrux_manifest_proposal"],
35
+ };
36
+
37
+ function parseFrontmatter(content) {
38
+ const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
39
+ if (!m) return {};
40
+ return parseYaml(m[1]) ?? {};
41
+ }
42
+
43
+ function kindFor(id) {
44
+ if (id.startsWith("harness/planning/")) return "planner";
45
+ if (id === "harness/running/executor") return "executor";
46
+ if (id === "harness/reviewing/evaluator") return "evaluator";
47
+ if (id === "harness/reviewing/adversary") return "adversary";
48
+ if (id === "harness/reviewing/tie-breaker") return "tie_breaker";
49
+ if (id === "harness/trace-librarian") return "trace";
50
+ if (id === "harness/incident-recorder") return "incident";
51
+ if (id === "harness/sentrux-steward" || id === "harness/sentrux-bootstrap")
52
+ return "planner";
53
+ return "other";
54
+ }
55
+
56
+ const KIND_BASE = {
57
+ planner: ["read", "grep", "find", "ls"],
58
+ executor: ["read", "write", "edit", "bash", "grep", "find", "ls"],
59
+ evaluator: ["read", "grep", "find", "ls"],
60
+ adversary: ["read", "grep", "find", "ls"],
61
+ tie_breaker: ["read", "grep", "find", "ls"],
62
+ trace: ["read", "grep", "find", "ls"],
63
+ incident: ["read", "grep", "find", "ls"],
64
+ other: ["read", "grep", "find", "ls"],
65
+ };
66
+
67
+ function csvTools(fm) {
68
+ const raw = fm.tools;
69
+ if (!raw) return [];
70
+ return String(raw)
71
+ .split(",")
72
+ .map((t) => t.trim())
73
+ .filter(Boolean);
74
+ }
75
+
76
+ async function main() {
77
+ const files = new Map();
78
+ walkAgentsDir(AGENTS_DIR, "package", files);
79
+
80
+ const kinds = {
81
+ planner: { tools: KIND_BASE.planner, extensions: false, read_only: true },
82
+ executor: { tools: KIND_BASE.executor, extensions: true, read_only: false },
83
+ evaluator: { tools: KIND_BASE.evaluator, extensions: false, read_only: true },
84
+ adversary: { tools: KIND_BASE.adversary, extensions: false, read_only: true },
85
+ tie_breaker: {
86
+ tools: KIND_BASE.tie_breaker,
87
+ extensions: false,
88
+ read_only: true,
89
+ },
90
+ trace: { tools: KIND_BASE.trace, extensions: false, read_only: true },
91
+ incident: { tools: KIND_BASE.incident, extensions: false, read_only: true },
92
+ other: { tools: KIND_BASE.other, extensions: false, read_only: true },
93
+ };
94
+
95
+ const agents = {};
96
+
97
+ for (const [id, file] of files) {
98
+ if (!id.startsWith("harness/")) continue;
99
+ const fm = parseFrontmatter(file.content);
100
+ const kind = kindFor(id);
101
+ const base = new Set(KIND_BASE[kind] ?? KIND_BASE.other);
102
+ const fromFm = csvTools(fm);
103
+ const submit = SUBMIT_BY_AGENT[id] ?? [];
104
+ const toolsAdd = [...new Set([...fromFm, ...submit])].filter(
105
+ (t) => !base.has(t),
106
+ );
107
+ const entry = { kind };
108
+ if (toolsAdd.length > 0) entry.tools_add = toolsAdd;
109
+ if (fm.extensions === false) entry.extensions = false;
110
+ if (fm.extensions === true) entry.extensions = true;
111
+ if (typeof fm.max_turns === "number") entry.max_turns = fm.max_turns;
112
+ if (typeof fm.thinking === "string") entry.thinking = fm.thinking;
113
+ if (submit.length === 1) entry.submit_tool = submit[0];
114
+ agents[id] = entry;
115
+ }
116
+
117
+ // plan-synthesizer: parent-only, minimal policy for spawn if ever used
118
+ agents["harness/planning/plan-synthesizer"] = {
119
+ kind: "planner",
120
+ tools_add: [
121
+ "submit_decomposition_brief",
122
+ "submit_hypothesis_brief",
123
+ "submit_execution_plan_brief",
124
+ ],
125
+ extensions: false,
126
+ };
127
+
128
+ const doc = {
129
+ apiVersion: "harness.toolkit/v1",
130
+ kinds,
131
+ agents,
132
+ };
133
+
134
+ const yaml = [
135
+ "# Generated/maintained SSOT for harness agent tools (see ADR 0049).",
136
+ "# Regenerate hints: node .pi/scripts/generate-agents-policy-yaml.mjs",
137
+ "",
138
+ ];
139
+ const { stringify } = await import("yaml");
140
+ yaml.push(stringify(doc));
141
+ await writeFile(OUT, yaml.join("\n"), "utf8");
142
+ console.log(`Wrote ${OUT} (${Object.keys(agents).length} harness agents)`);
143
+ }
144
+
145
+ main().catch((err) => {
146
+ console.error(err);
147
+ process.exit(1);
148
+ });
@@ -7,6 +7,7 @@
7
7
  * node .pi/scripts/harness-agents-manifest.mjs --check
8
8
  */
9
9
 
10
+ import { existsSync } from "node:fs";
10
11
  import { readFile, writeFile } from "node:fs/promises";
11
12
  import { join, dirname } from "node:path";
12
13
  import { fileURLToPath } from "node:url";
@@ -15,6 +16,10 @@ import {
15
16
  sha256Content,
16
17
  walkAgentsDir,
17
18
  } from "../lib/harness-agent-discovery.mjs";
19
+ import {
20
+ loadAgentsPolicyMerged,
21
+ packageAgentsPolicyPath,
22
+ } from "../lib/agents-policy.mjs";
18
23
 
19
24
  const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
20
25
  const MANIFEST_PATH = join(ROOT, ".pi", "harness", "agents.manifest.json");
@@ -27,7 +32,7 @@ async function readPackageMeta() {
27
32
  return { name: pkg.name ?? "ultimate-pi", version: pkg.version ?? "0.0.0" };
28
33
  }
29
34
 
30
- function buildManifest(packageFiles, packageName, packageVersion) {
35
+ async function buildManifest(packageFiles, packageName, packageVersion) {
31
36
  const agents = {};
32
37
  for (const f of packageFiles.values()) {
33
38
  agents[f.id] = {
@@ -35,11 +40,17 @@ function buildManifest(packageFiles, packageName, packageVersion) {
35
40
  sha256: sha256Content(f.content),
36
41
  };
37
42
  }
43
+ const policyPath = packageAgentsPolicyPath(ROOT);
44
+ let policy_sha256;
45
+ if (existsSync(policyPath)) {
46
+ policy_sha256 = sha256Content(await readFile(policyPath, "utf-8"));
47
+ }
38
48
  return {
39
49
  schema_version: "1.0.0",
40
50
  package: packageName,
41
51
  package_version: packageVersion,
42
52
  generated_at: new Date().toISOString(),
53
+ ...(policy_sha256 ? { policy_sha256 } : {}),
43
54
  agents,
44
55
  };
45
56
  }
@@ -68,6 +79,37 @@ function getDriftReport(manifest, packageFiles) {
68
79
  return { ok: items.length === 0, items };
69
80
  }
70
81
 
82
+ function frontmatterHasToolLists(content) {
83
+ const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
84
+ if (!m) return false;
85
+ return /^tools:/m.test(m[1]) || /^disallowed_tools:/m.test(m[1]);
86
+ }
87
+
88
+ function verifyAgentsPolicy(packageFiles) {
89
+ const items = [];
90
+ const policyPath = packageAgentsPolicyPath(ROOT);
91
+ if (!existsSync(policyPath)) {
92
+ return { ok: false, items: [{ id: "*", kind: "missing_agents_policy_yaml" }] };
93
+ }
94
+ const merged = loadAgentsPolicyMerged(ROOT, ROOT);
95
+ for (const [id, file] of packageFiles) {
96
+ if (!id.startsWith("harness/")) continue;
97
+ if (frontmatterHasToolLists(file.content)) {
98
+ items.push({ id, kind: "frontmatter_tools" });
99
+ }
100
+ if (!merged.agents.has(id)) {
101
+ items.push({ id, kind: "missing_policy_entry" });
102
+ }
103
+ }
104
+ for (const id of merged.agents.keys()) {
105
+ if (!id.startsWith("harness/")) continue;
106
+ if (!packageFiles.has(id)) {
107
+ items.push({ id, kind: "orphan_policy_entry" });
108
+ }
109
+ }
110
+ return { ok: items.length === 0, items };
111
+ }
112
+
71
113
  async function loadPackageFiles() {
72
114
  const files = new Map();
73
115
  walkAgentsDir(PACKAGE_AGENTS, "package", files);
@@ -81,7 +123,7 @@ async function main() {
81
123
  const mode = process.argv.includes("--check") ? "check" : "write";
82
124
  const { name, version } = await readPackageMeta();
83
125
  const packageFiles = await loadPackageFiles();
84
- const built = buildManifest(packageFiles, name, version);
126
+ const built = await buildManifest(packageFiles, name, version);
85
127
 
86
128
  if (mode === "write") {
87
129
  await writeFile(MANIFEST_PATH, `${JSON.stringify(built, null, "\t")}\n`, "utf-8");
@@ -107,6 +149,19 @@ async function main() {
107
149
  process.exit(1);
108
150
  }
109
151
 
152
+ const policyCheck = verifyAgentsPolicy(packageFiles);
153
+ if (!policyCheck.ok) {
154
+ for (const item of policyCheck.items) {
155
+ console.error(`policy: ${item.id} (${item.kind})`);
156
+ }
157
+ process.exit(1);
158
+ }
159
+
160
+ if (built.policy_sha256 && onDisk.policy_sha256 !== built.policy_sha256) {
161
+ console.error("policy_sha256 mismatch — regenerate manifest with --write");
162
+ process.exit(1);
163
+ }
164
+
110
165
  if (onDisk.package_version !== version) {
111
166
  console.error(
112
167
  `package_version mismatch: manifest=${onDisk.package_version} package=${version}`,
@@ -114,7 +169,9 @@ async function main() {
114
169
  process.exit(1);
115
170
  }
116
171
 
117
- console.log(`agents.manifest.json OK (${Object.keys(built.agents).length} agents)`);
172
+ console.log(
173
+ `agents.manifest.json OK (${Object.keys(built.agents).length} agents, policy aligned)`,
174
+ );
118
175
  }
119
176
 
120
177
  main().catch((err) => {
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env npx tsx
2
+ import { readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { doctorHarnessPolicies } from "../lib/agt/policy-engine.js";
6
+
7
+ const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
8
+ const doc = doctorHarnessPolicies(ROOT);
9
+ if (!doc.ok) {
10
+ console.error("AGT policy doctor failed:");
11
+ for (const e of doc.errors) console.error(` - ${e}`);
12
+ process.exit(1);
13
+ }
14
+ const pkg = JSON.parse(readFileSync(join(ROOT, "package.json"), "utf-8")) as {
15
+ files?: string[];
16
+ };
17
+ const files = pkg.files ?? [];
18
+ if (
19
+ !files.some(
20
+ (f: string) =>
21
+ f === ".pi/harness/policies" || f.startsWith(".pi/harness/policies/"),
22
+ )
23
+ ) {
24
+ console.error("package.json files[] missing .pi/harness/policies");
25
+ process.exit(1);
26
+ }
27
+ if (
28
+ !files.includes(".pi/lib") &&
29
+ !files.some((f) => f.startsWith(".pi/lib/"))
30
+ ) {
31
+ console.error("package.json files[] missing .pi/lib (ships .pi/lib/agt)");
32
+ process.exit(1);
33
+ }
34
+ console.log(
35
+ `AGT doctor OK (${doc.loaded.length} policies at ${doc.policyDir})`,
36
+ );
@@ -262,11 +262,18 @@ verify_cocoindex() {
262
262
 
263
263
  verify_biome() {
264
264
  log "[biome]"
265
- npm_global_install "@biomejs/biome" "biome" || { fail "biome npm install"; return; }
265
+ if [ ! -f "${ROOT}/package.json" ] && [ ! -f "${ROOT}/biome.json" ]; then
266
+ warn "biome skipped (non-JS/TS repo detected; optional tool)"
267
+ return
268
+ fi
269
+ npm_global_install "@biomejs/biome" "biome" || {
270
+ warn "biome npm install failed (optional — use your stack's formatter/linter)"
271
+ return
272
+ }
266
273
  if biome --version &>/dev/null; then
267
274
  pass "biome $(biome --version 2>/dev/null | head -1)"
268
275
  else
269
- fail "biome --version failed"
276
+ warn "biome --version failed (optional — use your stack's formatter/linter)"
270
277
  fi
271
278
  }
272
279