@hassangameryt/freeflow 0.5.0 → 0.7.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 (301) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +4 -5
  4. package/README.md +141 -163
  5. package/capabilities/cognitive-routing/SKILL.md +387 -0
  6. package/capabilities/context-virtualization/SKILL.md +103 -0
  7. package/capabilities/conversation-history/SKILL.md +53 -0
  8. package/command-surface.json +6 -37
  9. package/hooks/freeflow-runtime-context.mjs +50 -541
  10. package/hooks/hooks.json +1 -26
  11. package/hooks/tests/check-runtime-context-hook.sh +114 -308
  12. package/package.json +27 -17
  13. package/pi-extension/dist/cognitive-routing/commands.js +96 -0
  14. package/pi-extension/dist/cognitive-routing/config.js +232 -0
  15. package/pi-extension/dist/cognitive-routing/controller.js +1292 -0
  16. package/pi-extension/dist/cognitive-routing/history.js +451 -0
  17. package/pi-extension/dist/cognitive-routing/host.js +188 -0
  18. package/pi-extension/dist/cognitive-routing/pi-routing-session.js +414 -0
  19. package/pi-extension/dist/cognitive-routing/pi-session-control.js +320 -0
  20. package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
  21. package/pi-extension/dist/cognitive-routing/tool.js +212 -0
  22. package/pi-extension/dist/cognitive-routing/types.js +6 -0
  23. package/pi-extension/dist/context-virtualization/commands.js +89 -0
  24. package/pi-extension/dist/context-virtualization/projector.js +42 -0
  25. package/pi-extension/dist/context-virtualization/runtime.js +356 -0
  26. package/pi-extension/dist/context-virtualization/state.js +57 -0
  27. package/pi-extension/dist/context-virtualization/types.js +10 -0
  28. package/pi-extension/dist/conversation-history/passages.js +66 -0
  29. package/pi-extension/dist/conversation-history/ranking.js +105 -0
  30. package/pi-extension/dist/conversation-history/runtime.js +226 -0
  31. package/pi-extension/dist/conversation-history/search.js +56 -0
  32. package/pi-extension/dist/conversation-history/types.js +1 -0
  33. package/pi-extension/dist/freeflow-context/resolver.js +120 -0
  34. package/pi-extension/dist/freeflow-context/runtime.js +80 -0
  35. package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
  36. package/pi-extension/dist/freeflow-context/tool.js +308 -0
  37. package/pi-extension/dist/freeflow-context/types.js +12 -0
  38. package/pi-extension/dist/freeflow-context/visibility.js +28 -0
  39. package/pi-extension/dist/index.js +564 -129
  40. package/pi-extension/dist/runtime/runtime-context.js +357 -470
  41. package/pi-extension/dist/runtime/runtime-identity.js +5 -0
  42. package/pi-extension/dist/settings/settings-tui.js +78 -0
  43. package/pi-extension/dist/settings/settings-ui.js +572 -826
  44. package/pi-extension/dist/ui/text-component.js +57 -0
  45. package/pi-extension/src/cognitive-routing/commands.ts +129 -0
  46. package/pi-extension/src/cognitive-routing/config.ts +303 -0
  47. package/pi-extension/src/cognitive-routing/controller.ts +1628 -0
  48. package/pi-extension/src/cognitive-routing/history.ts +650 -0
  49. package/pi-extension/src/cognitive-routing/host.ts +266 -0
  50. package/pi-extension/src/cognitive-routing/pi-routing-session.ts +538 -0
  51. package/pi-extension/src/cognitive-routing/pi-session-control.ts +444 -0
  52. package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
  53. package/pi-extension/src/cognitive-routing/tool.ts +273 -0
  54. package/pi-extension/src/cognitive-routing/types.ts +89 -0
  55. package/pi-extension/src/context-virtualization/commands.ts +111 -0
  56. package/pi-extension/src/context-virtualization/projector.ts +62 -0
  57. package/pi-extension/src/context-virtualization/runtime.ts +406 -0
  58. package/pi-extension/src/context-virtualization/state.ts +79 -0
  59. package/pi-extension/src/context-virtualization/types.ts +92 -0
  60. package/pi-extension/src/conversation-history/passages.ts +81 -0
  61. package/pi-extension/src/conversation-history/ranking.ts +155 -0
  62. package/pi-extension/src/conversation-history/runtime.ts +250 -0
  63. package/pi-extension/src/conversation-history/search.ts +79 -0
  64. package/pi-extension/src/conversation-history/types.ts +31 -0
  65. package/pi-extension/src/freeflow-context/resolver.ts +139 -0
  66. package/pi-extension/src/freeflow-context/runtime.ts +100 -0
  67. package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
  68. package/pi-extension/src/freeflow-context/tool.ts +360 -0
  69. package/pi-extension/src/freeflow-context/types.ts +70 -0
  70. package/pi-extension/src/freeflow-context/visibility.ts +53 -0
  71. package/pi-extension/src/index.ts +597 -135
  72. package/pi-extension/src/runtime/runtime-context.ts +373 -491
  73. package/pi-extension/src/runtime/runtime-identity.ts +8 -0
  74. package/pi-extension/src/settings/settings-tui.ts +93 -0
  75. package/pi-extension/src/settings/settings-ui.ts +679 -910
  76. package/pi-extension/src/ui/text-component.ts +66 -0
  77. package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
  78. package/pi-extension/tests/cognitive-routing/controller.test.js +1128 -0
  79. package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1142 -0
  80. package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
  81. package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
  82. package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
  83. package/pi-extension/tests/cognitive-routing/pi-normal-lifecycle.test.js +434 -0
  84. package/pi-extension/tests/cognitive-routing/pi-session-control.test.js +174 -0
  85. package/pi-extension/tests/cognitive-routing/pi-session-history.test.js +91 -0
  86. package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +279 -0
  87. package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
  88. package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
  89. package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
  90. package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
  91. package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
  92. package/pi-extension/tests/conversation-history/search.test.js +97 -0
  93. package/pi-extension/tests/integration/mode-free-core.test.js +218 -0
  94. package/pi-extension/tests/integration/pi-extension.test.js +532 -3701
  95. package/pi-extension/tests/integration/prompt-architecture.test.js +350 -0
  96. package/pi-extension/tests/integration/unaffected-regressions.test.js +411 -0
  97. package/runtime/prompts/cognitive-routing.md +10 -0
  98. package/runtime/prompts/context-virtualization.md +3 -0
  99. package/runtime/prompts/conversation-history.md +3 -0
  100. package/runtime/prompts/core.md +84 -0
  101. package/runtime/prompts/interaction-contract.md +11 -0
  102. package/skills/action-selection/SKILL.md +140 -0
  103. package/skills/action-selection/references/trajectory-stalls.md +71 -0
  104. package/skills/bypass/SKILL.md +109 -38
  105. package/skills/commit-work/SKILL.md +94 -55
  106. package/skills/commit-work/references/git-state-edges.md +94 -0
  107. package/skills/commit-work/references/simple-push.md +92 -0
  108. package/skills/commit-work/references/staging-decisions.md +79 -46
  109. package/skills/decision-gate/SKILL.md +80 -22
  110. package/skills/design-for-depth/SKILL.md +206 -60
  111. package/skills/design-for-depth/references/design-pressure-signals.md +108 -240
  112. package/skills/design-for-depth/references/interface-design-loop.md +77 -97
  113. package/skills/design-for-depth/references/module-and-dependency-design.md +147 -0
  114. package/skills/design-for-depth/references/software-design-philosophy.md +128 -174
  115. package/skills/design-for-depth/references/state-and-failure-boundaries.md +136 -0
  116. package/skills/diagnose-failure/SKILL.md +200 -48
  117. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +18 -6
  118. package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +13 -5
  119. package/skills/discuss/SKILL.md +119 -65
  120. package/skills/discuss/references/discussion-continuity.md +123 -0
  121. package/skills/evaluate-skill/SKILL.md +166 -52
  122. package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +43 -3
  123. package/skills/evaluate-skill/references/evaluation-design.md +56 -30
  124. package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
  125. package/skills/evaluate-skill/references/review-and-revision.md +62 -21
  126. package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
  127. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
  128. package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
  129. package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
  130. package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
  131. package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
  132. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
  133. package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
  134. package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
  135. package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
  136. package/skills/execute-work/SKILL.md +99 -57
  137. package/skills/execute-work/references/code-practices.md +4 -4
  138. package/skills/execute-work/references/execute-work-edges.md +62 -0
  139. package/skills/finish-branch/SKILL.md +2 -2
  140. package/skills/finish-branch/references/integration-options.md +1 -1
  141. package/skills/handoff/SKILL.md +3 -3
  142. package/skills/launch-work/SKILL.md +1 -1
  143. package/skills/launch-work/references/launch-readiness.md +2 -2
  144. package/skills/migration-work/SKILL.md +2 -2
  145. package/skills/migration-work/references/migration-lifecycle.md +1 -1
  146. package/skills/release-work/SKILL.md +1 -1
  147. package/skills/release-work/references/release-evidence.md +1 -1
  148. package/skills/review-artifact/SKILL.md +129 -66
  149. package/skills/review-artifact/references/adjudicate-artifact-review.md +101 -0
  150. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +159 -0
  151. package/skills/review-work/SKILL.md +113 -68
  152. package/skills/review-work/references/adjudicate-work-review.md +97 -0
  153. package/skills/review-work/references/independent-work-reviewer-contract.md +139 -0
  154. package/skills/review-work/references/security-risk-lens.md +18 -16
  155. package/skills/setup-freeflow/SKILL.md +16 -17
  156. package/skills/setup-freeflow/references/activation-contract.md +24 -30
  157. package/skills/setup-freeflow/references/host-setup.md +6 -7
  158. package/skills/simplify-code/SKILL.md +97 -39
  159. package/skills/simplify-code/references/simplification-patterns.md +1 -1
  160. package/skills/tdd/SKILL.md +100 -53
  161. package/skills/tdd/references/test-design.md +3 -3
  162. package/skills/track-work/SKILL.md +195 -58
  163. package/skills/track-work/references/working-record-format.md +515 -0
  164. package/skills/track-work/scripts/lib/document.mjs +713 -0
  165. package/skills/track-work/scripts/lib/format.mjs +166 -0
  166. package/skills/track-work/scripts/lib/store.mjs +233 -0
  167. package/skills/track-work/scripts/lib/transitions.mjs +790 -0
  168. package/skills/track-work/scripts/lib/views.mjs +40 -0
  169. package/skills/track-work/scripts/working-record.mjs +316 -0
  170. package/skills/verify-work/SKILL.md +57 -19
  171. package/skills/verify-work/references/browser-runtime-evidence.md +2 -2
  172. package/skills/verify-work/references/integration-evidence.md +1 -7
  173. package/skills/verify-work/references/performance-evidence.md +2 -2
  174. package/skills/workflow/SKILL.md +137 -55
  175. package/skills/workflow/references/domain-skill-composition.md +26 -40
  176. package/skills/write-plan/SKILL.md +1 -1
  177. package/skills/write-skill/SKILL.md +218 -61
  178. package/skills/write-skill/references/activation-boundaries.md +63 -21
  179. package/skills/write-skill/references/agent-first-instructions.md +61 -27
  180. package/skills/write-skill/references/progressive-disclosure.md +97 -33
  181. package/skills/write-skill/references/skill-dependency-graphs.md +190 -0
  182. package/capabilities/output-router/SKILL.md +0 -206
  183. package/capabilities/output-router/references/safety-policy.md +0 -40
  184. package/capabilities/output-router/references/setup.md +0 -110
  185. package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
  186. package/pi-extension/dist/output-router/native-safety-net.js +0 -216
  187. package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
  188. package/pi-extension/dist/output-router/renderers.js +0 -1023
  189. package/pi-extension/dist/output-router/router-tools.js +0 -554
  190. package/pi-extension/dist/output-router/schemas.js +0 -383
  191. package/pi-extension/dist/output-router/status.js +0 -744
  192. package/pi-extension/dist/output-router/utils.js +0 -502
  193. package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
  194. package/pi-extension/src/output-router/native-safety-net.ts +0 -248
  195. package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
  196. package/pi-extension/src/output-router/renderers.ts +0 -1108
  197. package/pi-extension/src/output-router/router-tools.ts +0 -579
  198. package/pi-extension/src/output-router/schemas.ts +0 -387
  199. package/pi-extension/src/output-router/status.ts +0 -791
  200. package/pi-extension/src/output-router/utils.ts +0 -554
  201. package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
  202. package/pi-extension/tests/output-router/search.test.js +0 -722
  203. package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
  204. package/router/dist/benchmarks/benchmark-harness.js +0 -92
  205. package/router/dist/benchmarks/benchmarks.d.ts +0 -109
  206. package/router/dist/benchmarks/benchmarks.js +0 -979
  207. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
  208. package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
  209. package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
  210. package/router/dist/benchmarks/command-benchmarks.js +0 -698
  211. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
  212. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
  213. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
  214. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
  215. package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
  216. package/router/dist/benchmarks/context-saving-baseline.js +0 -470
  217. package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
  218. package/router/dist/benchmarks/index-benchmarks.js +0 -862
  219. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
  220. package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
  221. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
  222. package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
  223. package/router/dist/config/config.d.ts +0 -103
  224. package/router/dist/config/config.js +0 -632
  225. package/router/dist/config/router-contract.d.ts +0 -10
  226. package/router/dist/config/router-contract.js +0 -54
  227. package/router/dist/config/schema.d.ts +0 -27
  228. package/router/dist/config/schema.js +0 -648
  229. package/router/dist/config/types.d.ts +0 -573
  230. package/router/dist/config/types.js +0 -41
  231. package/router/dist/evidence/bounded-evidence.d.ts +0 -40
  232. package/router/dist/evidence/bounded-evidence.js +0 -323
  233. package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
  234. package/router/dist/evidence/evidence-range-selector.js +0 -232
  235. package/router/dist/evidence/evidence-search.d.ts +0 -27
  236. package/router/dist/evidence/evidence-search.js +0 -490
  237. package/router/dist/evidence/evidence.d.ts +0 -38
  238. package/router/dist/evidence/evidence.js +0 -200
  239. package/router/dist/evidence/failure-contracts.d.ts +0 -37
  240. package/router/dist/evidence/failure-contracts.js +0 -166
  241. package/router/dist/evidence/line-ranges.d.ts +0 -24
  242. package/router/dist/evidence/line-ranges.js +0 -22
  243. package/router/dist/experiments/local-index.d.ts +0 -64
  244. package/router/dist/experiments/local-index.js +0 -581
  245. package/router/dist/index.d.ts +0 -30
  246. package/router/dist/index.js +0 -32
  247. package/router/dist/local/local-traversal.d.ts +0 -18
  248. package/router/dist/local/local-traversal.js +0 -334
  249. package/router/dist/processing/engine.d.ts +0 -132
  250. package/router/dist/processing/engine.js +0 -533
  251. package/router/dist/processing/reducers.d.ts +0 -280
  252. package/router/dist/processing/reducers.js +0 -1673
  253. package/router/dist/processing/renderers.d.ts +0 -31
  254. package/router/dist/processing/renderers.js +0 -195
  255. package/router/dist/processing/scripts.d.ts +0 -91
  256. package/router/dist/processing/scripts.js +0 -386
  257. package/router/dist/repo/repo-traversal.d.ts +0 -18
  258. package/router/dist/repo/repo-traversal.js +0 -245
  259. package/router/dist/routing/observed-reducers.d.ts +0 -41
  260. package/router/dist/routing/observed-reducers.js +0 -661
  261. package/router/dist/routing/observed-routing.d.ts +0 -26
  262. package/router/dist/routing/observed-routing.js +0 -378
  263. package/router/dist/routing/parsers.d.ts +0 -16
  264. package/router/dist/routing/parsers.js +0 -521
  265. package/router/dist/routing/run-filters.d.ts +0 -60
  266. package/router/dist/routing/run-filters.js +0 -238
  267. package/router/dist/routing/run-reducers.d.ts +0 -49
  268. package/router/dist/routing/run-reducers.js +0 -122
  269. package/router/dist/sandbox/adapter-roots.d.ts +0 -46
  270. package/router/dist/sandbox/adapter-roots.js +0 -66
  271. package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
  272. package/router/dist/sandbox/eryx-python-adapter.js +0 -868
  273. package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
  274. package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
  275. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
  276. package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
  277. package/router/dist/sandbox/script-sandbox.d.ts +0 -134
  278. package/router/dist/sandbox/script-sandbox.js +0 -337
  279. package/router/dist/setup/script-transform-adapters.d.ts +0 -32
  280. package/router/dist/setup/script-transform-adapters.js +0 -278
  281. package/router/dist/tools/batch.d.ts +0 -33
  282. package/router/dist/tools/batch.js +0 -586
  283. package/router/dist/tools/run.d.ts +0 -62
  284. package/router/dist/tools/run.js +0 -1304
  285. package/router/dist/tools/search.d.ts +0 -66
  286. package/router/dist/tools/search.js +0 -1364
  287. package/router/dist/transform/engine.d.ts +0 -168
  288. package/router/dist/transform/engine.js +0 -2072
  289. package/router/dist/vault/vault-index.d.ts +0 -125
  290. package/router/dist/vault/vault-index.js +0 -416
  291. package/router/dist/vault/vault.d.ts +0 -138
  292. package/router/dist/vault/vault.js +0 -630
  293. package/runtime/interaction-contract.md +0 -16
  294. package/skills/discuss/references/checkpoints.md +0 -66
  295. package/skills/execute-work/references/execution-loop.md +0 -77
  296. package/skills/mode-contract/SKILL.md +0 -104
  297. package/skills/review-artifact/references/reviewer-prompt.md +0 -148
  298. package/skills/review-work/references/reviewer-prompt.md +0 -134
  299. package/skills/track-work/references/working-record-schema.md +0 -378
  300. package/skills/workflow/references/workflow-loop.md +0 -92
  301. /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
@@ -1,51 +1,92 @@
1
1
  # Review And Revision
2
2
 
3
- Read this after canonical evidence and deterministic grades exist, when evidence conflicts, meaning still needs judgment, or a revision/rerun boundary must be chosen.
3
+ Read this after canonical evidence and deterministic grades exist, when evidence conflicts, meaning remains unresolved, the failed boundary must be classified, or revision and rerun scope must be chosen.
4
4
 
5
5
  ## Use The Strongest Evidence
6
6
 
7
- 1. Filesystem state, typed workspace manifests, diffs, and changed paths.
8
- 2. Structured events, tool activity, usage, process results, logs, and saved reports.
9
- 3. Final response.
10
- 4. Full transcript when earlier surfaces cannot answer the question.
11
- 5. Subject self-assessment.
7
+ Prefer, in order:
12
8
 
13
- Lower-priority evidence cannot repair a contradiction above it. If the response claims success but a required file is absent, preserve both facts and grade the file observation.
9
+ 1. filesystem state, typed workspace manifests, diffs, and changed paths;
10
+ 2. structured events, tool activity, usage, process results, logs, and saved reports;
11
+ 3. final response;
12
+ 4. full transcript when stronger surfaces cannot answer the question;
13
+ 5. subject self-assessment.
14
+
15
+ Lower-priority evidence cannot repair a contradiction above it.
16
+
17
+ If a response claims success but a required file is absent, preserve both facts and judge from the stronger artifact evidence.
14
18
 
15
19
  ## Keep Deterministic Facts Separate
16
20
 
17
- Built-in checks cover exact reads, typed paths, changed paths, file or response text, JSON states, valid turn scope, and factual transitions. Missing evidence remains unavailable. A failed check remains behavioral evidence; it does not relabel a complete run as infrastructure failure.
21
+ Built-in checks establish exact observable facts. Missing evidence remains unavailable. A failed check remains behavioral evidence and does not relabel a complete run as infrastructure failure.
22
+
23
+ The active agent or user may judge:
18
24
 
19
- The active agent or user may judge reasoning quality, authority preservation, architectural fitness, recommendation quality, or semantic completeness. Record cited evidence, uncertainty, and limits outside the canonical run and deterministic grade. Do not turn that judgment into evaluator-owned readiness state.
25
+ - reasoning quality;
26
+ - authority preservation;
27
+ - architectural fitness;
28
+ - recommendation quality;
29
+ - semantic completeness.
20
30
 
21
- ## Diagnose Before Editing
31
+ Keep semantic judgment, cited evidence, uncertainty, and limits outside canonical run and deterministic grade state.
22
32
 
23
- Classify the failed boundary:
33
+ Do not turn semantic judgment into evaluator-owned readiness or promotion status.
34
+
35
+ ## Diagnose The Failed Boundary
36
+
37
+ Classify before revising:
24
38
 
25
39
  - activation timing;
26
40
  - description language unavailable before body read;
27
41
  - first-read body comprehension;
28
42
  - undeclared, undelivered, unread, or ambient-only dependency;
29
- - normal guidance hidden behind an unclear resource boundary;
43
+ - normal guidance hidden behind the wrong resource boundary;
30
44
  - nearby behavior that hijacks the task;
31
45
  - retained-use or multi-turn failure;
32
- - wording, placement, example, or stop-condition pressure;
33
- - fixture, environment, isolation, host, or deterministic-check failure.
46
+ - wording, placement, example, repetition, or stop-condition pressure;
47
+ - fixture, environment, isolation, host, runner, or deterministic-check failure.
48
+
49
+ Do not add broad prose before identifying which boundary failed.
34
50
 
35
- Do not add broad prose before identifying the failed boundary.
51
+ ## Return Revision To Write Skill
36
52
 
37
- ## Revise One Pressure Point
53
+ When evidence supports a skill change:
38
54
 
39
- Change one measured point when possible: description cues, first-read wording, rule placement, dependency declaration, resource boundary, example, stop condition, or the group when evidence proves the evaluation is wrong.
55
+ 1. name the exact failed boundary;
56
+ 2. cite the canonical evidence;
57
+ 3. identify one measured pressure point;
58
+ 4. preserve unrelated instructions and fixed criteria;
59
+ 5. return the revision target to [Write Skill](../../write-skill/SKILL.md).
40
60
 
41
- Keep unrelated instructions and fixed criteria stable. If the criterion changes, the old result no longer answers the same question.
61
+ Write Skill owns package revision.
62
+
63
+ Evaluate Skill does not edit the skill or replace its baseline while evaluating it.
64
+
65
+ When evidence proves the group, fixture, or criterion is wrong, revise the evaluation instead. Preserve the old result and state that it no longer answers the revised question.
42
66
 
43
67
  ## Rerun The Complete Group
44
68
 
45
- After a measured skill change or resolved infrastructure cause, run the complete fixed group with both variants. Do not rerun only the preferred variant, reuse a settled control as a new sample, adopt partial evidence as comparable, or rerun merely to erase a failure.
69
+ After a measured skill revision or resolved infrastructure cause:
70
+
71
+ - rerun the complete fixed group;
72
+ - run both baseline and candidate;
73
+ - keep every result visible;
74
+ - do not reuse an earlier baseline run as a fresh counterpart;
75
+ - do not rerun only the preferred variant;
76
+ - do not use partial evidence as a comparable full result;
77
+ - do not rerun merely to erase failure.
46
78
 
47
- For variance, use independent complete invocations and keep every result visible.
79
+ For variance, use independent complete invocations rather than repeated preferred variants.
48
80
 
49
81
  ## Report
50
82
 
51
- Report the failed boundary and evidence, exact revision or evaluation correction, criteria that stayed fixed, old and new result paths, and remaining unsupported claims. The user decides the next authoring or use action.
83
+ Report:
84
+
85
+ - failed boundary and evidence;
86
+ - exact skill revision or evaluation correction;
87
+ - criteria that remained fixed;
88
+ - old and new result paths;
89
+ - deterministic transitions;
90
+ - remaining unsupported claims.
91
+
92
+ The user decides whether to revise further, use, publish, or reject the skill.
@@ -4,6 +4,20 @@ import path from "node:path";
4
4
  const ID = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
5
5
  const EVALUATION_TYPES = new Set(["description", "body", "end-to-end"]);
6
6
  const VARIANTS = ["baseline", "candidate"];
7
+ const EVALUATION_HOSTS = new Set(["pi", "piflow"]);
8
+ const RESERVED_ENVIRONMENT_KEYS = new Set([
9
+ "PATH",
10
+ "HOME",
11
+ "PWD",
12
+ "OLDPWD",
13
+ "SHELL",
14
+ "BASH_ENV",
15
+ "NODE_OPTIONS",
16
+ "NODE_PATH",
17
+ "PI_PACKAGE_DIR",
18
+ "PIFLOW_CODING_AGENT_DIR",
19
+ "PIFLOW_CODING_AGENT_SESSION_DIR",
20
+ ]);
7
21
 
8
22
  export class DefinitionError extends Error {
9
23
  constructor(code, message, definitionPath = null) {
@@ -129,6 +143,102 @@ function validateEnvironment(value, label, definitionPath) {
129
143
  }
130
144
  }
131
145
 
146
+ function validateRuntime(value, definitionPath) {
147
+ const runtime = requireExactKeys(
148
+ value,
149
+ ["host", "extensions", "environment", "session"],
150
+ [],
151
+ "group.runtime",
152
+ definitionPath,
153
+ );
154
+ if (!EVALUATION_HOSTS.has(runtime.host)) {
155
+ fail("invalid-definition", "group.runtime.host must be pi or piflow", definitionPath);
156
+ }
157
+ if (!Array.isArray(runtime.extensions)) {
158
+ fail("invalid-definition", "group.runtime.extensions must be an array", definitionPath);
159
+ }
160
+ const bundleIds = new Set();
161
+ for (const [index, entry] of runtime.extensions.entries()) {
162
+ const bundle = requireExactKeys(
163
+ entry,
164
+ ["entry", "resources"],
165
+ [],
166
+ `group.runtime.extensions[${index}]`,
167
+ definitionPath,
168
+ );
169
+ requireSafeRelativePath(bundle.entry, `group.runtime.extensions[${index}].entry`, definitionPath);
170
+ const resources = requireStringArray(
171
+ bundle.resources,
172
+ `group.runtime.extensions[${index}].resources`,
173
+ definitionPath,
174
+ { paths: true, unique: true },
175
+ );
176
+ if (resources.length === 0) {
177
+ fail("invalid-definition", `group.runtime.extensions[${index}].resources must not be empty`, definitionPath);
178
+ }
179
+ const bundleId = `${bundle.entry}\u0000${resources.join("\u0000")}`;
180
+ if (bundleIds.has(bundleId)) {
181
+ fail("invalid-definition", "group.runtime.extensions contains duplicate bundles", definitionPath);
182
+ }
183
+ bundleIds.add(bundleId);
184
+ }
185
+ if (typeof runtime.session !== "boolean") {
186
+ fail("invalid-definition", "group.runtime.session must be a boolean", definitionPath);
187
+ }
188
+ const environment = requireExactKeys(
189
+ runtime.environment,
190
+ ["literal", "inherit"],
191
+ [],
192
+ "group.runtime.environment",
193
+ definitionPath,
194
+ );
195
+ const literal = requireObject(environment.literal, "group.runtime.environment.literal", definitionPath);
196
+ const inherited = requireStringArray(environment.inherit, "group.runtime.environment.inherit", definitionPath, {
197
+ unique: true,
198
+ });
199
+ const literalKeys = new Set(Object.keys(literal).map((key) => key.toUpperCase()));
200
+ for (const [key, value] of Object.entries(literal)) {
201
+ const normalizedKey = key.toUpperCase();
202
+ if (
203
+ !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) ||
204
+ isBlockedEnvironmentKey(normalizedKey) ||
205
+ /TOKEN|SECRET|PASSWORD|API[_-]?KEY|PRIVATE[_-]?KEY|CREDENTIAL/i.test(key)
206
+ ) {
207
+ fail(
208
+ "invalid-definition",
209
+ `group.runtime.environment.literal contains a reserved or secret-like key: ${key}`,
210
+ definitionPath,
211
+ );
212
+ }
213
+ if (typeof value !== "string") {
214
+ fail("invalid-definition", `group.runtime.environment.literal.${key} must be a string`, definitionPath);
215
+ }
216
+ }
217
+ for (const key of inherited) {
218
+ const normalizedKey = key.toUpperCase();
219
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || isBlockedEnvironmentKey(normalizedKey)) {
220
+ fail("invalid-definition", `group.runtime.environment.inherit contains an invalid key: ${key}`, definitionPath);
221
+ }
222
+ if (literalKeys.has(normalizedKey)) {
223
+ fail(
224
+ "invalid-definition",
225
+ `group.runtime.environment key is declared as both literal and inherited: ${key}`,
226
+ definitionPath,
227
+ );
228
+ }
229
+ }
230
+ }
231
+
232
+ function isBlockedEnvironmentKey(normalizedKey) {
233
+ return (
234
+ RESERVED_ENVIRONMENT_KEYS.has(normalizedKey) ||
235
+ normalizedKey.startsWith("SKILL_EVAL_") ||
236
+ normalizedKey.startsWith("PI_") ||
237
+ normalizedKey.startsWith("LD_") ||
238
+ normalizedKey.startsWith("DYLD_")
239
+ );
240
+ }
241
+
132
242
  function validateExpectations(value, definitionPath) {
133
243
  if (!Array.isArray(value)) fail("invalid-definition", "group.expectations must be an array", definitionPath);
134
244
  const ids = new Set();
@@ -164,7 +274,7 @@ function validateGroup(value, definitionPath) {
164
274
  "expectations",
165
275
  "review_questions",
166
276
  ],
167
- ["model"],
277
+ ["model", "runtime"],
168
278
  "group",
169
279
  definitionPath,
170
280
  );
@@ -177,12 +287,13 @@ function validateGroup(value, definitionPath) {
177
287
  validateInput(group.input, definitionPath);
178
288
  if (group.fixture !== null) requireSafeRelativePath(group.fixture, "group.fixture", definitionPath);
179
289
  requireStringArray(group.tools, "group.tools", definitionPath, { unique: true });
290
+ if (Object.hasOwn(group, "runtime")) validateRuntime(group.runtime, definitionPath);
180
291
  const variants = requireExactKeys(group.variants, VARIANTS, [], "group.variants", definitionPath);
181
292
  for (const variant of VARIANTS) validateEnvironment(variants[variant], `group.variants.${variant}`, definitionPath);
182
- if (variants.candidate.target === null) {
293
+ if (variants.candidate.target === null && variants.candidate.skills.length > 0) {
183
294
  fail(
184
295
  "invalid-definition",
185
- "group.variants.candidate.target must identify the candidate target skill",
296
+ "group.variants.candidate.target must identify the candidate target skill when candidate skills are declared",
186
297
  definitionPath,
187
298
  );
188
299
  }
@@ -1,4 +1,5 @@
1
- import { realpath } from "node:fs/promises";
1
+ import { createHash } from "node:crypto";
2
+ import { readFile, realpath } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
 
4
5
  import {
@@ -16,6 +17,10 @@ import {
16
17
  } from "./grade-support.mjs";
17
18
 
18
19
  const ACTIVATION_EXPECTATIONS = new Set(["never", "on-turn", "by-turn", "not-before-turn"]);
20
+ const TOOL_CALL_EXPECTATIONS = new Set(["called", "succeeded", "failed", "not-called"]);
21
+ const CONTEXT_TEXT_EXPECTATIONS = new Set(["contains", "not-contains", "equals"]);
22
+ const CONTEXT_SURFACES = new Set(["system-prompt", "provider-context"]);
23
+ const CONTEXT_REQUEST_SELECTORS = new Set(["first", "last"]);
19
24
 
20
25
  export async function gradeSkillRead(group, runs, expectation) {
21
26
  const turn = expectation.turn ?? null;
@@ -100,6 +105,95 @@ export async function gradeResourceRead(group, runs, expectation) {
100
105
  );
101
106
  }
102
107
 
108
+ export async function gradeContextText(group, runs, expectation) {
109
+ const turn = expectation.turn ?? null;
110
+ const surface = expectation.surface ?? "system-prompt";
111
+ const request = expectation.request ?? "last";
112
+ if (
113
+ !validBodyExpectation(group, expectation, turn) ||
114
+ !CONTEXT_SURFACES.has(surface) ||
115
+ (!CONTEXT_REQUEST_SELECTORS.has(request) && !Number.isInteger(request)) ||
116
+ (Number.isInteger(request) && request < 1) ||
117
+ !CONTEXT_TEXT_EXPECTATIONS.has(expectation.expect) ||
118
+ typeof expectation.value !== "string"
119
+ ) {
120
+ return { error: "invalid context-text expectation" };
121
+ }
122
+
123
+ const expected = { expect: expectation.expect, value: expectation.value, surface, request, turn };
124
+ const run = runs[expectation.variant];
125
+ if (!run || run.state !== "complete") return unavailableCheck(expectation, expected);
126
+ const observed = await contextObservation(run, turn, surface, request);
127
+ if (observed === null) return unavailableCheck(expectation, expected);
128
+ const passed = textMatches(expectation.expect, expectation.value, observed.text);
129
+ return completedCheck(expectation, expected, compactContextObservation(observed, passed), passed);
130
+ }
131
+
132
+ export async function gradeToolCall(group, runs, expectation) {
133
+ const turn = expectation.turn ?? null;
134
+ const contains = expectation.argumentContains ?? [];
135
+ const notContains = expectation.argumentNotContains ?? [];
136
+ if (
137
+ !validBodyExpectation(group, expectation, turn) ||
138
+ typeof expectation.tool !== "string" ||
139
+ expectation.tool.trim() === "" ||
140
+ !TOOL_CALL_EXPECTATIONS.has(expectation.expect) ||
141
+ !Array.isArray(contains) ||
142
+ !contains.every((value) => typeof value === "string") ||
143
+ !Array.isArray(notContains) ||
144
+ !notContains.every((value) => typeof value === "string")
145
+ ) {
146
+ return { error: "invalid tool-call expectation" };
147
+ }
148
+
149
+ const expected = {
150
+ tool: expectation.tool,
151
+ expect: expectation.expect,
152
+ turn,
153
+ argumentContains: contains,
154
+ argumentNotContains: notContains,
155
+ };
156
+ const run = runs[expectation.variant];
157
+ if (!run || run.state !== "complete") return unavailableCheck(expectation, expected);
158
+
159
+ const calls = toolCalls(run, turn).filter((call) => call.toolName === expectation.tool);
160
+ const matchingCalls = calls.filter((call) => {
161
+ const argumentsText = JSON.stringify(call.args ?? null);
162
+ return (
163
+ contains.every((value) => argumentsText.includes(value)) &&
164
+ notContains.every((value) => !argumentsText.includes(value))
165
+ );
166
+ });
167
+ const succeededCalls = matchingCalls.filter((call) => call.completed === true && call.isError !== true);
168
+ const failedCalls = matchingCalls.filter((call) => call.completed === true && call.isError === true);
169
+ let passed;
170
+ if (expectation.expect === "called") {
171
+ passed = matchingCalls.length > 0;
172
+ } else if (expectation.expect === "succeeded") {
173
+ passed = succeededCalls.length > 0;
174
+ } else if (expectation.expect === "failed") {
175
+ passed = failedCalls.length > 0;
176
+ } else if (contains.length > 0 || notContains.length > 0) {
177
+ passed = matchingCalls.length === 0;
178
+ } else {
179
+ passed = calls.length === 0;
180
+ }
181
+ const observed = {
182
+ tool: expectation.tool,
183
+ turn,
184
+ callCount: calls.length,
185
+ matchingCallCount: matchingCalls.length,
186
+ succeededCount: succeededCalls.length,
187
+ failedCount: failedCalls.length,
188
+ calls: calls.map((call) => ({
189
+ args: call.args ?? null,
190
+ completed: call.completed ?? null,
191
+ isError: call.isError ?? null,
192
+ })),
193
+ };
194
+ return completedCheck(expectation, expected, observed, passed);
195
+ }
196
+
103
197
  export async function gradeResponseText(group, runs, expectation) {
104
198
  const turn = expectation.turn ?? null;
105
199
  if (
@@ -123,6 +217,67 @@ export async function gradeResponseText(group, runs, expectation) {
123
217
  );
124
218
  }
125
219
 
220
+ function compactContextObservation(observation, matched) {
221
+ return {
222
+ surface: observation.surface,
223
+ turn: observation.turn,
224
+ request: observation.request,
225
+ characters: observation.characters,
226
+ sha256: createHash("sha256").update(observation.text, "utf8").digest("hex"),
227
+ matched,
228
+ preview: observation.text.slice(0, 240),
229
+ };
230
+ }
231
+
232
+ async function contextObservation(run, turn, surface, request) {
233
+ const observations = await loadContextObservations(run);
234
+ if (observations === null) return null;
235
+ const matching = observations.filter((entry) => entry.surface === surface);
236
+ const inTurn = turn === null ? matching : matching.filter((entry) => entry.turn === turn);
237
+ if (inTurn.length === 0) return null;
238
+ let observation;
239
+ if (request === "first") observation = inTurn[0];
240
+ else if (request === "last") observation = inTurn.at(-1);
241
+ else observation = inTurn.find((entry) => (entry.requestInTurn ?? 1) === request);
242
+ const text = surface === "system-prompt" ? (observation?.text ?? observation?.systemPrompt) : observation?.text;
243
+ if (!observation || typeof text !== "string") return null;
244
+ return {
245
+ surface,
246
+ turn: observation.turn ?? turn,
247
+ request: observation.requestInTurn ?? 1,
248
+ characters: observation.characters ?? text.length,
249
+ text,
250
+ };
251
+ }
252
+
253
+ async function loadContextObservations(run) {
254
+ const artifact = run.contextObservationArtifact;
255
+ if (!artifact || typeof artifact.path !== "string" || typeof artifact.sha256 !== "string") return null;
256
+ const contents = await readFile(artifact.path, "utf8");
257
+ const actualHash = createHash("sha256").update(contents, "utf8").digest("hex");
258
+ if (actualHash !== artifact.sha256) throw new Error("context observation artifact changed after run persistence");
259
+ const observations = [];
260
+ for (const line of contents.split("\n").filter(Boolean)) {
261
+ try {
262
+ observations.push(JSON.parse(line));
263
+ } catch (error) {
264
+ throw new Error(
265
+ `context observation artifact is malformed: ${error instanceof Error ? error.message : String(error)}`,
266
+ );
267
+ }
268
+ }
269
+ return observations;
270
+ }
271
+
272
+ function toolCalls(run, turn) {
273
+ if (turn === null) {
274
+ if (Array.isArray(run.turns)) return run.turns.flatMap((entry) => entry.toolActivity ?? []);
275
+ return Array.isArray(run.toolActivity) ? run.toolActivity : [];
276
+ }
277
+ if (!Array.isArray(run.turns)) return turn === 1 && Array.isArray(run.toolActivity) ? run.toolActivity : [];
278
+ return run.turns.find((entry) => entry.turn === turn)?.toolActivity ?? [];
279
+ }
280
+
126
281
  function activationMatches(expectation, observed) {
127
282
  if (expectation.expect === "never") return !observed.targetRead;
128
283
  if (!Number.isInteger(expectation.turn) || expectation.turn < 1) return false;
@@ -1,5 +1,11 @@
1
1
  import { gradeComparisons } from "./grade-comparison.mjs";
2
- import { gradeResourceRead, gradeResponseText, gradeSkillRead } from "./grade-interaction.mjs";
2
+ import {
3
+ gradeContextText,
4
+ gradeResourceRead,
5
+ gradeResponseText,
6
+ gradeSkillRead,
7
+ gradeToolCall,
8
+ } from "./grade-interaction.mjs";
3
9
  import { gradeChangedPaths, gradeFileText, gradeJson, gradePath } from "./grade-workspace.mjs";
4
10
 
5
11
  const GRADERS = new Map([
@@ -10,6 +16,8 @@ const GRADERS = new Map([
10
16
  ["file-text", gradeFileText],
11
17
  ["json", gradeJson],
12
18
  ["response-text", gradeResponseText],
19
+ ["context-text", gradeContextText],
20
+ ["tool-call", gradeToolCall],
13
21
  ]);
14
22
 
15
23
  /**