oh-my-knowledge 0.23.0 → 0.25.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 (196) hide show
  1. package/README.md +146 -84
  2. package/README.zh.md +144 -83
  3. package/dist/src/analysis/report-diagnostics.d.ts +3 -2
  4. package/dist/src/analysis/report-diagnostics.d.ts.map +1 -1
  5. package/dist/src/analysis/report-diagnostics.js +107 -80
  6. package/dist/src/analysis/report-diagnostics.js.map +1 -1
  7. package/dist/src/analysis/sample-diagnostics.d.ts +4 -1
  8. package/dist/src/analysis/sample-diagnostics.d.ts.map +1 -1
  9. package/dist/src/analysis/sample-diagnostics.js +123 -29
  10. package/dist/src/analysis/sample-diagnostics.js.map +1 -1
  11. package/dist/src/analysis/saturation.d.ts +2 -2
  12. package/dist/src/analysis/saturation.js +2 -2
  13. package/dist/src/authoring/evolver.d.ts +12 -4
  14. package/dist/src/authoring/evolver.d.ts.map +1 -1
  15. package/dist/src/authoring/evolver.js +35 -10
  16. package/dist/src/authoring/evolver.js.map +1 -1
  17. package/dist/src/cli/i18n-dict.d.ts +1 -1
  18. package/dist/src/cli/i18n-dict.d.ts.map +1 -1
  19. package/dist/src/cli/i18n-dict.js +241 -64
  20. package/dist/src/cli/i18n-dict.js.map +1 -1
  21. package/dist/src/cli/index.js +267 -152
  22. package/dist/src/cli/index.js.map +1 -1
  23. package/dist/src/cli/parse-run-config.d.ts +32 -9
  24. package/dist/src/cli/parse-run-config.d.ts.map +1 -1
  25. package/dist/src/cli/parse-run-config.js +80 -25
  26. package/dist/src/cli/parse-run-config.js.map +1 -1
  27. package/dist/src/cli/parse-strict.d.ts +20 -0
  28. package/dist/src/cli/parse-strict.d.ts.map +1 -0
  29. package/dist/src/cli/parse-strict.js +25 -0
  30. package/dist/src/cli/parse-strict.js.map +1 -0
  31. package/dist/src/cli/progress.d.ts +1 -0
  32. package/dist/src/cli/progress.d.ts.map +1 -1
  33. package/dist/src/cli/progress.js +8 -1
  34. package/dist/src/cli/progress.js.map +1 -1
  35. package/dist/src/doctor/index.d.ts +19 -0
  36. package/dist/src/doctor/index.d.ts.map +1 -0
  37. package/dist/src/doctor/index.js +182 -0
  38. package/dist/src/doctor/index.js.map +1 -0
  39. package/dist/src/doctor/preflight.d.ts +32 -0
  40. package/dist/src/doctor/preflight.d.ts.map +1 -0
  41. package/dist/src/doctor/preflight.js +32 -0
  42. package/dist/src/doctor/preflight.js.map +1 -0
  43. package/dist/src/doctor/renderer.d.ts +13 -0
  44. package/dist/src/doctor/renderer.d.ts.map +1 -0
  45. package/dist/src/doctor/renderer.js +69 -0
  46. package/dist/src/doctor/renderer.js.map +1 -0
  47. package/dist/src/doctor/rules.d.ts +30 -0
  48. package/dist/src/doctor/rules.d.ts.map +1 -0
  49. package/dist/src/doctor/rules.js +216 -0
  50. package/dist/src/doctor/rules.js.map +1 -0
  51. package/dist/src/eval-core/bootstrap.d.ts +1 -1
  52. package/dist/src/eval-core/bootstrap.js +1 -1
  53. package/dist/src/eval-core/cache.d.ts +7 -5
  54. package/dist/src/eval-core/cache.d.ts.map +1 -1
  55. package/dist/src/eval-core/cache.js +11 -7
  56. package/dist/src/eval-core/cache.js.map +1 -1
  57. package/dist/src/eval-core/comparability.d.ts +11 -0
  58. package/dist/src/eval-core/comparability.d.ts.map +1 -0
  59. package/dist/src/eval-core/comparability.js +296 -0
  60. package/dist/src/eval-core/comparability.js.map +1 -0
  61. package/dist/src/eval-core/dependency-checker.js +1 -1
  62. package/dist/src/eval-core/dependency-checker.js.map +1 -1
  63. package/dist/src/eval-core/evaluation-execution.d.ts +23 -7
  64. package/dist/src/eval-core/evaluation-execution.d.ts.map +1 -1
  65. package/dist/src/eval-core/evaluation-execution.js +53 -21
  66. package/dist/src/eval-core/evaluation-execution.js.map +1 -1
  67. package/dist/src/eval-core/evaluation-job.d.ts +3 -5
  68. package/dist/src/eval-core/evaluation-job.d.ts.map +1 -1
  69. package/dist/src/eval-core/evaluation-job.js +2 -4
  70. package/dist/src/eval-core/evaluation-job.js.map +1 -1
  71. package/dist/src/eval-core/evaluation-reporting.d.ts +3 -1
  72. package/dist/src/eval-core/evaluation-reporting.d.ts.map +1 -1
  73. package/dist/src/eval-core/evaluation-reporting.js +67 -9
  74. package/dist/src/eval-core/evaluation-reporting.js.map +1 -1
  75. package/dist/src/eval-core/execution-strategy.js +2 -2
  76. package/dist/src/eval-core/execution-strategy.js.map +1 -1
  77. package/dist/src/eval-core/schema.d.ts.map +1 -1
  78. package/dist/src/eval-core/schema.js +20 -2
  79. package/dist/src/eval-core/schema.js.map +1 -1
  80. package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts +113 -0
  81. package/dist/src/eval-workflows/batch-evaluation-workflow.d.ts.map +1 -0
  82. package/dist/src/eval-workflows/batch-evaluation-workflow.js +217 -0
  83. package/dist/src/eval-workflows/batch-evaluation-workflow.js.map +1 -0
  84. package/dist/src/eval-workflows/evaluation-pipeline.d.ts +6 -4
  85. package/dist/src/eval-workflows/evaluation-pipeline.d.ts.map +1 -1
  86. package/dist/src/eval-workflows/evaluation-pipeline.js +44 -38
  87. package/dist/src/eval-workflows/evaluation-pipeline.js.map +1 -1
  88. package/dist/src/eval-workflows/evaluation-preparation.d.ts +4 -17
  89. package/dist/src/eval-workflows/evaluation-preparation.d.ts.map +1 -1
  90. package/dist/src/eval-workflows/evaluation-preparation.js +3 -18
  91. package/dist/src/eval-workflows/evaluation-preparation.js.map +1 -1
  92. package/dist/src/eval-workflows/run-evaluation.d.ts +27 -23
  93. package/dist/src/eval-workflows/run-evaluation.d.ts.map +1 -1
  94. package/dist/src/eval-workflows/run-evaluation.js +137 -20
  95. package/dist/src/eval-workflows/run-evaluation.js.map +1 -1
  96. package/dist/src/executors/claude-cli.d.ts.map +1 -1
  97. package/dist/src/executors/claude-cli.js +11 -6
  98. package/dist/src/executors/claude-cli.js.map +1 -1
  99. package/dist/src/executors/codex-cli-trace.d.ts +10 -0
  100. package/dist/src/executors/codex-cli-trace.d.ts.map +1 -0
  101. package/dist/src/executors/codex-cli-trace.js +123 -0
  102. package/dist/src/executors/codex-cli-trace.js.map +1 -0
  103. package/dist/src/executors/codex-cli.d.ts +18 -0
  104. package/dist/src/executors/codex-cli.d.ts.map +1 -0
  105. package/dist/src/executors/codex-cli.js +254 -0
  106. package/dist/src/executors/codex-cli.js.map +1 -0
  107. package/dist/src/executors/codex-sdk.d.ts +18 -0
  108. package/dist/src/executors/codex-sdk.d.ts.map +1 -0
  109. package/dist/src/executors/codex-sdk.js +214 -0
  110. package/dist/src/executors/codex-sdk.js.map +1 -0
  111. package/dist/src/executors/gemini.d.ts.map +1 -1
  112. package/dist/src/executors/gemini.js +28 -24
  113. package/dist/src/executors/gemini.js.map +1 -1
  114. package/dist/src/executors/index.d.ts.map +1 -1
  115. package/dist/src/executors/index.js +7 -2
  116. package/dist/src/executors/index.js.map +1 -1
  117. package/dist/src/executors/runtime-fingerprint.d.ts +7 -0
  118. package/dist/src/executors/runtime-fingerprint.d.ts.map +1 -0
  119. package/dist/src/executors/runtime-fingerprint.js +277 -0
  120. package/dist/src/executors/runtime-fingerprint.js.map +1 -0
  121. package/dist/src/executors/script.d.ts.map +1 -1
  122. package/dist/src/executors/script.js +47 -55
  123. package/dist/src/executors/script.js.map +1 -1
  124. package/dist/src/executors/shared.d.ts +78 -1
  125. package/dist/src/executors/shared.d.ts.map +1 -1
  126. package/dist/src/executors/shared.js +203 -1
  127. package/dist/src/executors/shared.js.map +1 -1
  128. package/dist/src/grading/assertions.d.ts.map +1 -1
  129. package/dist/src/grading/assertions.js +22 -7
  130. package/dist/src/grading/assertions.js.map +1 -1
  131. package/dist/src/grading/gold-cli.js +4 -4
  132. package/dist/src/grading/gold-cli.js.map +1 -1
  133. package/dist/src/grading/human-gold.d.ts +1 -1
  134. package/dist/src/grading/human-gold.js +1 -1
  135. package/dist/src/grading/index.d.ts +20 -15
  136. package/dist/src/grading/index.d.ts.map +1 -1
  137. package/dist/src/grading/index.js +40 -16
  138. package/dist/src/grading/index.js.map +1 -1
  139. package/dist/src/grading/judge.d.ts +1 -1
  140. package/dist/src/grading/judge.d.ts.map +1 -1
  141. package/dist/src/grading/judge.js +76 -7
  142. package/dist/src/grading/judge.js.map +1 -1
  143. package/dist/src/inputs/eval-config.js +65 -7
  144. package/dist/src/inputs/eval-config.js.map +1 -1
  145. package/dist/src/inputs/skill-loader.d.ts +1 -1
  146. package/dist/src/inputs/skill-loader.d.ts.map +1 -1
  147. package/dist/src/inputs/skill-loader.js +1 -1
  148. package/dist/src/inputs/skill-loader.js.map +1 -1
  149. package/dist/src/renderer/html-renderer.d.ts +5 -4
  150. package/dist/src/renderer/html-renderer.d.ts.map +1 -1
  151. package/dist/src/renderer/html-renderer.js +240 -96
  152. package/dist/src/renderer/html-renderer.js.map +1 -1
  153. package/dist/src/renderer/layout.d.ts +2 -1
  154. package/dist/src/renderer/layout.d.ts.map +1 -1
  155. package/dist/src/renderer/layout.js +30 -42
  156. package/dist/src/renderer/layout.js.map +1 -1
  157. package/dist/src/renderer/summary.d.ts +3 -3
  158. package/dist/src/renderer/summary.d.ts.map +1 -1
  159. package/dist/src/renderer/summary.js +233 -43
  160. package/dist/src/renderer/summary.js.map +1 -1
  161. package/dist/src/renderer/trends.d.ts.map +1 -1
  162. package/dist/src/renderer/trends.js +5 -3
  163. package/dist/src/renderer/trends.js.map +1 -1
  164. package/dist/src/server/report-server.js +4 -4
  165. package/dist/src/server/report-server.js.map +1 -1
  166. package/dist/src/server/report-store.d.ts +7 -5
  167. package/dist/src/server/report-store.d.ts.map +1 -1
  168. package/dist/src/server/report-store.js +39 -11
  169. package/dist/src/server/report-store.js.map +1 -1
  170. package/dist/src/types/doctor.d.ts +95 -0
  171. package/dist/src/types/doctor.d.ts.map +1 -0
  172. package/dist/src/types/doctor.js +2 -0
  173. package/dist/src/types/doctor.js.map +1 -0
  174. package/dist/src/types/eval.d.ts +40 -19
  175. package/dist/src/types/eval.d.ts.map +1 -1
  176. package/dist/src/types/executor.d.ts +38 -0
  177. package/dist/src/types/executor.d.ts.map +1 -1
  178. package/dist/src/types/index.d.ts +1 -0
  179. package/dist/src/types/index.d.ts.map +1 -1
  180. package/dist/src/types/index.js +1 -0
  181. package/dist/src/types/index.js.map +1 -1
  182. package/dist/src/types/judge.d.ts +21 -0
  183. package/dist/src/types/judge.d.ts.map +1 -1
  184. package/dist/src/types/report.d.ts +100 -35
  185. package/dist/src/types/report.d.ts.map +1 -1
  186. package/dist/src/types/storage.d.ts +7 -7
  187. package/dist/src/types/storage.d.ts.map +1 -1
  188. package/package.json +6 -5
  189. package/dist/src/eval-workflows/each-evaluation-workflow.d.ts +0 -153
  190. package/dist/src/eval-workflows/each-evaluation-workflow.d.ts.map +0 -1
  191. package/dist/src/eval-workflows/each-evaluation-workflow.js +0 -178
  192. package/dist/src/eval-workflows/each-evaluation-workflow.js.map +0 -1
  193. package/dist/src/executors/openai-cli.d.ts +0 -3
  194. package/dist/src/executors/openai-cli.d.ts.map +0 -1
  195. package/dist/src/executors/openai-cli.js +0 -60
  196. package/dist/src/executors/openai-cli.js.map +0 -1
package/README.md CHANGED
@@ -1,55 +1,22 @@
1
1
  # oh-my-knowledge
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/oh-my-knowledge.svg)](https://www.npmjs.com/package/oh-my-knowledge)
4
+ [![npm weekly downloads](https://img.shields.io/npm/dw/oh-my-knowledge.svg)](https://www.npmjs.com/package/oh-my-knowledge)
4
5
  [![CI](https://github.com/lizhiyao/oh-my-knowledge/actions/workflows/ci.yml/badge.svg)](https://github.com/lizhiyao/oh-my-knowledge/actions/workflows/ci.yml)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
6
7
  [![Node.js Version](https://img.shields.io/node/v/oh-my-knowledge.svg)](https://nodejs.org)
7
8
 
8
9
  **English** | [简体中文](./README.zh.md)
9
10
 
10
- **omk** — LLM evaluation framework with built-in statistical rigor. Bootstrap CI / Krippendorff α / length-debias / saturation curves out of the box. Native support for Claude Code skills, prompts, agents, and RAG.
11
+ **omk** — The knowledge you give your LLM what's it actually worth?
12
+ omk answers with objective data, not gut feeling.
11
13
 
12
- **Fix the model, vary the knowledge artifact, let the data speak.**
14
+ **Fix the model, vary the knowledge artifact.**
13
15
 
14
- ## Why this tool
15
-
16
- Teams doing knowledge engineering produce lots of knowledge artifacts (skills today, but also prompts, agents, workflows…). When someone asks "why is v2 better than v1", you need objective data instead of gut feeling. `oh-my-knowledge` solves this with controlled experiments: **same model, same test samples, only the knowledge artifact changes.**
17
-
18
- ## Key features
19
-
20
- - **Controlled-variable offline bench** — fix the model and samples, vary only the artifact; works with Claude Code skills, CLAUDE.md prompts, RAG knowledge bases, or any markdown-based instruction
21
- - **Six-dimension scoring** — separate signals for Fact / Behavior / LLM-judge / Cost / Efficiency / Stability, so a regression in one axis isn't hidden by gains in another
22
- - **Production session observability** — parse Claude Code session JSONL traces, measure per-skill failure rate, latency, token cost, and knowledge-gap signals on real user sessions
23
- - **Knowledge-gap detection** — severity-weighted signals (explicit markers / failed searches / hedging language / repeated failures) quantify risk exposure instead of claiming completeness
24
- - **Pre-merge CI gate** — `omk bench gate` enforces three-layer all-pass (fact + behavior + llm-judge) semantics, catching single-layer regressions a composite score would hide
25
- - **One-line ship/no-ship verdict** — `omk bench verdict <reportId>` aggregates bootstrap CI / three-layer ci-gate / saturation / human α into a six-tier verdict (PROGRESS / CAUTIOUS / REGRESS / NOISE / UNDERPOWERED / SOLO) plus an action recommendation; the exit code reflects whether to ship
26
-
27
- ### Statistical rigor
28
-
29
- The biggest LLM-eval failure mode is "confident bias" — narrow CIs around the wrong answer. omk's statistical layer ships four pieces so conclusions can be externally audited:
30
-
31
- - **Bootstrap CI** (`--bootstrap`) — distribution-free confidence intervals. The t-test breaks on ordinal LLM scores; bootstrap resamples raw observations and stays valid at small N (< 30) and on skewed data. Pairwise diff CI not crossing 0 = significant.
32
- - **Human Gold + Krippendorff α** (`--gold-dir`) — bring an external annotation as anchor. CI tells you "is the judge stable", α tells you "is the judge correct" — two complementary axes. omk warns when the gold annotator and the judge are the same model (would inflate α).
33
- - **Length-controlled judge prompt** (default ON) — research shows LLM judges over-weight verbosity. omk's judge prompt explicitly states "length is not a quality signal"; template hash is `v3-cot-length` so older reports (with the legacy hash) are visibly different. `omk bench debias-validate length <reportId>` re-judges with the opposite setting and reports the score shift.
34
- - **Saturation curve** — answers "have I run enough samples?". With `--repeat ≥ 5` we accumulate cumulative N → bootstrap CI; when CI shrink rate stays under 5% across 3 windows, more samples buy nothing. The HTML report inlines the SVG curve plus a verdict.
35
-
36
- ## Why omk over alternatives
37
-
38
- | | omk | promptfoo | DeepEval | RAGAS | LangSmith |
39
- |--|--|--|--|--|--|
40
- | Bootstrap CI | ✓ | ✗ | ✗ | ✗ | ✗ |
41
- | Krippendorff α (judge ↔ human) | ✓ | ✗ | ✗ | ✗ | ✗ |
42
- | Length-debias judge prompt | ✓ default | ✗ | ✗ | ✗ | ✗ |
43
- | Saturation curve | ✓ | ✗ | ✗ | ✗ | ✗ |
44
- | Three-layer scoring isolation | ✓ | ✗ | partial | ✗ | ✗ |
45
- | Per-variant skill isolation (construct validity) | ✓ default | ✗ | ✗ | ✗ | ✗ |
46
- | Native Claude Code skill | ✓ | ✗ | ✗ | ✗ | ✗ |
47
- | Full Chinese docs | ✓ | ✗ | ✗ | ✗ | ✗ |
48
- | Hosted SaaS dashboard | ✗ | ✗ | ✓ | ✗ | ✓ |
49
-
50
- omk's moat is **statistical rigor** — every conclusion is auditable by a researcher. If you need a hosted SaaS dashboard, choose LangSmith. If you want quick local prompt iteration without statistics, choose promptfoo. **If you ship to production and someone will ask "why should I trust this number?", choose omk**.
16
+ <a id="statistical-rigor"></a>
17
+ > Built-in: Bootstrap CI · Krippendorff α (judge ↔ human) · length-debias · saturation curves · construct-validity isolation. [Why these matter →](docs/statistical-rigor.md)
51
18
 
52
- Full comparison with 7 tools across 25+ dimensions: [docs/comparison.md](docs/comparison.md)
19
+ ![omk report](./assets/screenshots/report-overview.png)
53
20
 
54
21
  ## Quick start
55
22
 
@@ -70,46 +37,93 @@ cd my-eval
70
37
  omk bench run --dry-run
71
38
 
72
39
  # run the evaluation (auto-discovers everything under skills/)
73
- omk bench run
40
+ omk bench run # → HTML report with verdict in 5 minutes
41
+ # (omk doctor + LLM connectivity check both run as mandatory gates;
42
+ # --skip-connectivity available for connectivity, doctor is unconditional)
74
43
 
75
44
  # CLI output language: zh (default) / en — flag wins over env
76
45
  omk bench run --lang en
77
46
  OMK_LANG=en omk bench report
78
47
  ```
79
48
 
80
- ## Use inside Claude Code
49
+ ## Use inside AI Coding Agents
81
50
 
82
- After installing omk, talk to it in natural language from Claude Code:
51
+ ### Use inside Claude Code
83
52
 
84
- ```
53
+ When the `omk` skill is available in Claude Code, you can invoke it directly like this:
54
+
55
+ ```bash
85
56
  /omk eval # evaluate the artifact(s) in the current project
86
57
  /omk evolve # auto-iterate to improve an artifact
87
58
  /omk gen-samples # generate test cases
88
59
  ```
89
60
 
90
- You can also just say "compare v1 vs v2 for me" or "improve this artifact" omk picks the right command.
61
+ You can also just say "compare v1 vs v2 for me" or "improve this artifact" and omk picks the right command.
62
+
63
+ ### Use inside Codex
64
+
65
+ Codex does not support Claude Code style `/omk ...` slash commands by default. In Codex, the usual pattern is to ask the agent to run the `omk` CLI directly, for example:
66
+
67
+ ```bash
68
+ omk bench run
69
+ omk bench evolve
70
+ omk bench gen-samples skills/my-skill.md
71
+ ```
72
+
73
+ You can also describe the goal in natural language, such as "compare v1 vs v2" or "generate test cases for this skill".
74
+
75
+ ## Why this tool
76
+
77
+ Teams doing knowledge engineering produce lots of knowledge artifacts (skills today, but also prompts, agents, workflows…). When someone asks "why is v2 better than v1", you need objective data instead of gut feeling. `oh-my-knowledge` solves this with controlled experiments: **same model, same test samples, only the knowledge artifact changes.**
78
+
79
+ ## Key features
80
+
81
+ - **Pre-evaluation health check** — `omk doctor` runs as a mandatory gate before `bench run` / `bench gate`; checks skill readability, metadata, dependencies, samples contract — pure static, zero LLM calls (like lint + typecheck for knowledge artifacts). Executor / judge connectivity is a separate phase, controllable via `--skip-connectivity`
82
+ - **Controlled-variable offline bench** — fix the model and samples, vary only the artifact; works with Claude Code skills, CLAUDE.md prompts, RAG knowledge bases, or any markdown-based instruction
83
+ - **Six-dimension scoring** — separate signals for Fact / Behavior / LLM-judge / Cost / Efficiency / Stability, so a regression in one axis isn't hidden by gains in another
84
+ - **Production session observability** — parse Claude Code session JSONL traces, measure per-skill failure rate, latency, token cost, and knowledge-gap signals on real user sessions
85
+ - **Knowledge-gap detection** — severity-weighted signals (explicit markers / failed searches / hedging language / repeated failures) quantify risk exposure instead of claiming completeness
86
+ - **Pre-merge CI gate** — `omk bench gate` enforces three-layer all-pass (fact + behavior + llm-judge) semantics, catching single-layer regressions a composite score would hide
87
+ - **One-line ship/no-ship verdict** — `omk bench verdict <reportId>` aggregates bootstrap CI / three-layer ci-gate / saturation / human α into a six-tier verdict (PROGRESS / CAUTIOUS / REGRESS / NOISE / UNDERPOWERED / SOLO) plus an action recommendation; the exit code reflects whether to ship
88
+
89
+ ## Why omk over alternatives
90
+
91
+ | | omk | promptfoo | DeepEval | LangSmith |
92
+ |--|--|--|--|--|
93
+ | Bootstrap CI | ✓ default | ✗ | ✗ | ✗ |
94
+ | Krippendorff α (judge ↔ human) | ✓ default | ✗ | ✗ | ✗ |
95
+ | Length-debias judge prompt | ✓ default | ✗ | ✗ | ✗ |
96
+ | Saturation curve | ✓ | ✗ | ✗ | ✗ |
97
+ | Three-layer scoring isolation | ✓ | ✗ | partial | ✗ |
98
+ | Per-variant skill isolation (construct validity) | ✓ default | ✗ | ✗ | ✗ |
99
+ | Native Claude Code skill | ✓ | ✗ | ✗ | ✗ |
100
+ | Hosted SaaS dashboard | ✗ | ✗ | ✓ | ✓ |
101
+
102
+ omk's moat is **default-on safety net** — Bootstrap CI, judge ↔ human α, and length-debias aren't advanced flags; they're the default. Other tools let you opt into confidence intervals; omk makes them unavoidable. Need a hosted SaaS dashboard? Choose LangSmith. Want quick local prompt iteration without statistics? Choose promptfoo. **Shipping to production and someone will ask "why should I trust this number?" Choose omk.**
103
+
104
+ RAG-specific evals: see RAGAS (separate niche, complementary to omk). Full comparison with 7 tools across 25+ dimensions: [docs/comparison.md](docs/comparison.md).
91
105
 
92
106
  ## Features
93
107
 
94
108
  | Feature | What it does |
95
109
  |---|---|
96
- | **21+ assertion types** | substring, regex, JSON Schema, ROUGE/BLEU/Levenshtein similarity, agent tool-call assertions, semantic similarity, custom JS, and more |
97
- | **Assertion negation + composition** | universal `not: true` field + `assert-set` (any/all) with arbitrary nesting |
98
- | **Six-dim evaluation** | Fact / Behavior / LLM-judge / Cost / Efficiency / Stability shown independently |
99
- | **Statistical rigor** | Bootstrap CI / Krippendorff α / length-debias / saturation curve |
100
- | **Construct-validity isolation** | `--strict-baseline` (default ON) cuts three contamination channels so baseline doesn't silently see the skill it's being compared against: (1) SDK skill auto-discovery, (2) subagent Skill tool, (3) cwd file-system access via the `skills/<name>/` symlink that's normally there for the treatment variant. eval.yaml `allowedSkills` for per-variant whitelists |
101
- | **Sample design science** | Sample schema with `capability` / `difficulty` / `construct` / `provenance` metadata fields (HF Dataset Cards style). `bench diagnose` shows coverage breakdown + flags `rubric_clarity_low` (short rubric without grading keywords) / `capability_thin` (capability supported by ≤ N×0.2 samples). `bench gen-samples` auto-stamps provenance. See [docs/sample-design-spec.md](docs/sample-design-spec.md) for the 8 industry-gap mapping |
102
110
  | **One-line verdict** | `omk bench verdict <id>` six-tier verdict + ship recommendation + exit-code routing; HTML pill shares the same rules |
103
- | **RAG metrics** | `faithfulness` / `answer_relevancy` / `context_recall` — anti-hallucination + answer relevance + context coverage; auto-inherits length-debias |
111
+ | **Six-dim evaluation** | Fact / Behavior / LLM-judge / Cost / Efficiency / Stability shown independently |
112
+ | **Multi-executor** | Claude CLI / Claude SDK / Codex CLI / Codex SDK / OpenAI / Gemini / any custom command |
113
+ | **21+ assertion types** | substring, regex, JSON Schema, ROUGE/BLEU/Levenshtein similarity, agent tool-call assertions, semantic similarity, custom JS, and more |
114
+ | **Statistical rigor** | Bootstrap CI / Krippendorff α / length-debias / saturation curve — all on by default. [Details →](docs/statistical-rigor.md) |
104
115
  | **Sample diagnostics** | `omk bench diagnose <id>` — 7 issue kinds (low discrimination / duplicates / ambiguous rubric / cost outliers / etc.) + 0-100 healthScore |
105
116
  | **Failure clustering** | `omk bench failures <id>` — single LLM call clusters failed samples and emits per-cluster fixes |
117
+ | **RAG metrics** | `faithfulness` / `answer_relevancy` / `context_recall` — anti-hallucination + answer relevance + context coverage; auto-inherits length-debias |
106
118
  | **Hard budget caps** | `--budget-usd / --budget-per-sample-usd / --budget-per-sample-ms` — abort on total-cost overrun, flag per-sample overruns; partial report persisted |
107
- | **Multi-executor** | Claude CLI / Claude SDK / OpenAI / Gemini / any custom command |
119
+ | **Construct-validity isolation** | `--strict-baseline` (default ON) cuts three contamination channels so baseline doesn't silently see the skill it's being compared against: (1) SDK skill auto-discovery, (2) subagent Skill tool, (3) cwd file-system access via the `skills/<name>/` symlink that's normally there for the treatment variant. eval.yaml `allowedSkills` for per-variant whitelists |
120
+ | **Sample design science** | Sample schema with `capability` / `difficulty` / `construct` / `provenance` metadata fields (HF Dataset Cards style). `bench diagnose` shows coverage breakdown + flags `rubric_clarity_low` (short rubric without grading keywords) / `capability_thin` (capability supported by ≤ N×0.2 samples). `bench gen-samples` auto-stamps provenance. See [docs/sample-design-spec.md](docs/sample-design-spec.md) for the 8 industry-gap mapping |
108
121
  | **Multi-judge ensemble** | `--judge-models claude:opus,openai:gpt-4o` cross-vendor scoring + agreement metrics |
109
122
  | **MCP URL fetching** | pull content from private-doc URLs via an MCP server (SSO-protected knowledge bases, etc.) |
110
123
  | **Blind A/B** | `--blind` hides variant names; HTML report has a reveal button |
111
- | **Parallel execution** | `--concurrency N` runs N tasks at once |
112
124
  | **Multi-run variance** | `--repeat N` repeats the eval and computes mean / SD / CI / t-test |
125
+ | **Parallel execution** | `--concurrency N` runs N tasks at once |
126
+ | **Assertion negation + composition** | universal `not: true` field + `assert-set` (any/all) with arbitrary nesting |
113
127
  | **Auto analysis** | detects low-discrimination assertions, flat scores, all-pass / all-fail, expensive samples |
114
128
  | **Traceability** | reports carry CLI version, Node version, artifact version fingerprint, judge prompt hash |
115
129
  | **EN / ZH switch** | one-click language toggle in the HTML report |
@@ -135,8 +149,8 @@ flowchart TD
135
149
  end
136
150
 
137
151
  subgraph Exec["④ Executor (fixed model)"]
138
- E["claude / claude-sdk / openai / gemini<br/>anthropic-api / openai-api / custom"]
139
- T["claude-sdk extracts<br/>turns / toolCalls trace"]
152
+ E["claude / claude-sdk / codex / openai / gemini<br/>anthropic-api / openai-api / custom"]
153
+ T["claude-sdk / codex extract<br/>turns / toolCalls trace"]
140
154
  E -.-> T
141
155
  end
142
156
 
@@ -373,14 +387,16 @@ options:
373
387
  --control <expr> control-group variant expression (experiment role = control)
374
388
  --treatment <v1,v2> treatment-group variant expressions, comma-separated
375
389
  at least one of --control / --treatment is required
376
- (unless you use --config or --each)
390
+ (unless you use --config or --batch)
377
391
  special values: baseline (empty artifact), git:name (git HEAD),
378
392
  git:ref:name (specific commit), path with "/" (read file directly)
379
393
  --config <path> YAML/JSON config file (evaluation-as-code); declares
380
394
  samples + variants + model + executor in one file; CLI
381
395
  flags override config fields when both are provided
382
- --model <name> model under test (default: sonnet)
383
- --judge-model <name> judge model (default: haiku)
396
+ --model <name> task execution model (default: sonnet)
397
+ --judge-models <list> judge config; 1 entry = single judge (default
398
+ claude:haiku), ≥ 2 entries = ensemble. Format:
399
+ `executor:model[,executor:model]`
384
400
  --output-dir <path> output dir (default: ~/.oh-my-knowledge/reports/)
385
401
  --no-judge skip the LLM judge
386
402
  --no-cache disable result cache (on by default; identical inputs reuse)
@@ -390,16 +406,17 @@ options:
390
406
  --timeout <sec> per-task executor timeout (default: 120)
391
407
  --repeat <n> repeat N times for variance analysis (default: 1)
392
408
  --executor <name> executor (default: claude); supports custom commands
393
- --skip-preflight skip evaluation model reachability check
409
+ --skip-connectivity skip the LLM connectivity check (doctor still runs;
410
+ doctor is mandatory and has no skip flag).
411
+ Auto-applied on --resume (the original run already
412
+ verified connectivity).
394
413
  --mcp-config <path> MCP config for fetching private-doc URLs via MCP Server
395
414
  (default: .mcp.json in cwd)
396
415
  --no-serve don't auto-start the report server after the run
397
416
  --verbose print per-sample details (duration, tokens, output preview)
398
- --each batch mode: evaluate each artifact independently vs baseline
417
+ --batch batch mode: evaluate each artifact independently vs baseline
399
418
  requires {name}.eval-samples.json paired with each artifact
400
419
  --judge-repeat <n> run the LLM judge N times per (sample × dimension) and report stddev
401
- --judge-models <list> multi-judge ensemble: "executor1:model1,executor2:model2"
402
- ≥ 2 judges enables ensemble + inter-judge agreement output
403
420
  --bootstrap enable distribution-free CIs: bootstrap CI per variant +
404
421
  pairwise diff CI (CI containing 0 = not significant)
405
422
  --bootstrap-samples N bootstrap resample count (default 1000)
@@ -418,11 +435,34 @@ options:
418
435
 
419
436
  **eval.yaml budget**: declare `budget: { totalUSD?, perSampleUSD?, perSampleMs? }` (all optional, must be ≥ 0). CLI flags of the same name override the config values.
420
437
 
438
+ **eval.yaml experiment-design fields**: the same flags above can be set in `eval.yaml` for reproducible experiment configuration (CLI > eval.yaml > default):
439
+
440
+ ```yaml
441
+ samples: ./eval-samples.yaml
442
+ model: sonnet
443
+ repeat: 5 # multi-run variance, ≥ 1
444
+ judgeRepeat: 3 # per (sample × dim) judge self-consistency, ≥ 1
445
+ bootstrap: true # distribution-free CI per variant
446
+ bootstrapSamples: 2000 # default 1000, ≥ 100
447
+ goldDir: ./gold # post-run α / κ / Pearson against human anchor
448
+ lengthDebias: true # default; set false to reproduce pre-v0.21 hash
449
+ strictBaseline: true # default; set false to disable skill isolation
450
+ noJudge: false # default; set true to skip LLM judge entirely
451
+ judgeModels: # 1 entry = single judge; ≥ 2 = ensemble
452
+ - { executor: claude, model: opus }
453
+ - { executor: openai-api, model: gpt-4o }
454
+ variants:
455
+ - { name: baseline, role: control, artifact: baseline }
456
+ - { name: my-skill, role: treatment, artifact: ./skills/my-skill.md }
457
+ ```
458
+
459
+ **Field entry points**: `bench run` reads every field above. `bench gate` goes through `parseRunConfig` and picks up the shared subset (`variants` / `executor` / `model` / `judgeModels` — both single-judge and ensemble — / `noJudge` / `noCache` / `blind` / `strictBaseline` / `budget` / `mcpConfig` / `variantAllowedSkills`); the experiment-design fields handled by `handleRun` (`repeat` / `judgeRepeat` / `bootstrap` / `bootstrapSamples` / `goldDir` / `lengthDebias`) are intentionally not read by `gate` and can be extended later. Other subcommands (`evolve` / `verdict` / `diff` / `analyze` / …) do not read `eval.yaml`.
460
+
421
461
  **Difference from `cost_max` / `latency_max` assertions**: assertions are **per-sample scoring rules** (exceeding the cap fails that one assertion, the run continues); budget caps are **workflow-level hard limits** (`totalUSD` overrun aborts the run and persists a partial report; per-sample overruns fail the offending sample but the run continues). Assertions answer "is quality acceptable?"; budgets answer "are cost/time within the envelope?".
422
462
 
423
- ### `omk bench run --each` (batch mode)
463
+ ### `omk bench run --batch` (batch mode)
424
464
 
425
- When `skills/` contains several **independent** artifacts, use `--each` to evaluate each one against baseline and produce a merged report.
465
+ When `skills/` contains several **independent** artifacts, use `--batch` to evaluate each one against baseline and produce a BatchEvaluationReport with child EvaluationReports.
426
466
 
427
467
  ```
428
468
  skills/
@@ -442,8 +482,8 @@ Pairing rules:
442
482
  - artifacts without paired samples are skipped with a warning
443
483
 
444
484
  ```bash
445
- omk bench run --each
446
- omk bench run --each --dry-run
485
+ omk bench run --batch
486
+ omk bench run --batch --dry-run
447
487
  ```
448
488
 
449
489
  ### `omk bench gen-samples` (generate test cases)
@@ -455,7 +495,7 @@ Reads an artifact's content and uses an LLM to auto-generate eval-samples. Revie
455
495
  omk bench gen-samples skills/my-skill.md
456
496
 
457
497
  # batch-generate for every artifact under skills/ that lacks samples
458
- omk bench gen-samples --each
498
+ omk bench gen-samples --batch
459
499
 
460
500
  # specify sample count
461
501
  omk bench gen-samples skills/my-skill.md --count 10
@@ -464,10 +504,10 @@ omk bench gen-samples skills/my-skill.md --count 10
464
504
  Options:
465
505
 
466
506
  ```
467
- --each batch-generate for every artifact missing samples
507
+ --batch batch-generate for every artifact missing samples
468
508
  --count <n> samples per artifact (default: 5)
469
509
  --model <name> model used for generation (default: sonnet)
470
- --skill-dir <path> artifact dir (default: skills), used with --each
510
+ --skill-dir <path> artifact dir (default: skills), used with --batch
471
511
  ```
472
512
 
473
513
  ### `omk bench evolve` (self-iterating improvement)
@@ -505,6 +545,26 @@ omk bench gate [options]
505
545
  independently to fact / behavior / judge
506
546
  ```
507
547
 
548
+ ### `omk doctor` (pre-evaluation health check)
549
+
550
+ Pure static / zero-LLM checks — analogous to lint + typecheck in the SE toolchain. Runs as a mandatory gate before `bench run` / `bench gate` so a typo'd YAML or missing dependency aborts with an actionable error instead of producing a garbage-in verdict. Also runnable standalone for local iteration or CI.
551
+
552
+ ```bash
553
+ omk doctor # batch check every skill in current dir / ./skills
554
+ omk doctor skills/v1.md # single file
555
+ omk doctor skills/ --json # JSON output for CI consumption
556
+ omk doctor --gate; echo $? # silent mode — exit 1 if any fatal check fails
557
+ ```
558
+
559
+ What `doctor` checks:
560
+
561
+ - **skill readable** — file exists, content non-empty, has minimum length
562
+ - **skill metadata** — front-matter (if present) is valid YAML; directory-skills have `SKILL.md`
563
+ - **dependencies present** — referenced CLI tools, files, env vars all available (reuses `preflightDependencies`)
564
+ - **samples ↔ skill contract** — when samples are provided, validate they're non-empty and have prompt fields (warn-level)
565
+
566
+ Executor / judge connectivity is verified by a separate evaluation preflight phase, not by doctor — clean boundary: doctor is static, eval is dynamic. `bench run` / `bench gate` abort with `exit 1` and stderr `doctor failed:` prefix when doctor fails. **Doctor is mandatory and not skippable** (static checks have no cost reason to skip); LLM connectivity is separately controllable via `--skip-connectivity` (auto-skipped on `--resume`).
567
+
508
568
  ### `omk bench report`
509
569
 
510
570
  Start the report server to browse historical reports, submit feedback, and delete reports.
@@ -549,7 +609,7 @@ Re-judges every (sample × variant) of an existing report with the OPPOSITE leng
549
609
  ```bash
550
610
  omk bench debias-validate length <reportId> [options]
551
611
  --variant <name> check a single variant only
552
- --judge-model <id> override the report's judge model
612
+ --judge-models <executor:model> override the report's judge (single-judge only)
553
613
  --bootstrap-samples N bootstrap iterations (default 1000)
554
614
  --seed N deterministic seed
555
615
  ```
@@ -605,8 +665,7 @@ When 14 of 50 samples failed, reading them one by one is slow. This command send
605
665
 
606
666
  ```bash
607
667
  omk bench failures <reportId> [options]
608
- --judge-executor <name> executor (default: claude)
609
- --judge-model <id> clustering model (default: from report.meta.judgeModel)
668
+ --judge-models <executor:model> clustering judge (default: from report.meta.judgeModels[0]; single-judge only)
610
669
  --max-clusters <n> maximum clusters (default 5)
611
670
  --threshold <num> failure score threshold (default 3)
612
671
  --max-feed <n> max failures fed to LLM (default 50; takes the worst)
@@ -671,13 +730,16 @@ The command writes `~/.oh-my-knowledge/analyses/<timestamp>-skill-health.json`.
671
730
  |---|---|---|
672
731
  | `claude` | default | invokes `claude -p` via Claude CLI |
673
732
  | `claude-sdk` | structured output | uses Claude Agent SDK — no stdout parsing, avoids buffer truncation |
674
- | `openai` | cross-vendor comparison | invokes `openai api` CLI |
733
+ | `codex` | OpenAI agent CLI | invokes `codex exec --json` (`@openai/codex` npm); best-effort tool trace; **costUSD not reported** (codex CLI does not emit USD; check usage externally) |
734
+ | `codex-sdk` | OpenAI agent SDK | uses `@openai/codex-sdk` with its bundled `@openai/codex` binary and streamed SDK events; **costUSD not reported** |
675
735
  | `gemini` | cross-vendor comparison | invokes `gemini` CLI |
676
736
  | `anthropic-api` | no CLI needed | calls Anthropic HTTP API directly (needs `ANTHROPIC_API_KEY`) |
677
737
  | `openai-api` | no CLI needed | calls OpenAI HTTP API directly (needs `OPENAI_API_KEY`) |
678
738
 
679
739
  API-direct executors support custom base URLs via env: `ANTHROPIC_BASE_URL`, `OPENAI_BASE_URL`.
680
740
 
741
+ Codex construct-validity notes: (1) `codex` uses the `codex` binary on `PATH`; `codex-sdk` uses the bundled `@openai/codex` binary resolved by `@openai/codex-sdk`. Reports persist per-variant `meta.executorRuntimes`, `meta.executorRuntime`, and per-judge `meta.judgeModels[].runtime` fingerprints (binary or SDK version + capability snapshot), and `bench diff` / `bench verdict` warn when strict comparability cannot be audited. If runtime fingerprints differ, treat results as an executor-runtime comparison, not only prompt/template behavior. (2) Both executors isolate user-level config: `codex` passes `--ephemeral` + `--ignore-user-config`; `codex-sdk` redirects `$CODEX_HOME` to a per-process tmp dir (auth.json symlinked through). User-level `~/.codex/config.toml` does not leak into eval runs in either case.
742
+
681
743
  ### Custom executor
682
744
 
683
745
  Any shell command can serve as an executor, communicating via stdin/stdout JSON:
@@ -721,7 +783,7 @@ skills/
721
783
  | `./path/to/file.md` | path with `/`: read the file directly as an artifact |
722
784
  | `variant@/path/to/project` | attach a run dir to any variant; supports `name@cwd`, `git:name@cwd`, `/file.md@cwd` |
723
785
 
724
- When both `--control` and `--treatment` are omitted, use `--config eval.yaml` or `--each`. With `--each`, `baseline` is auto-added as control and every discovered artifact becomes a treatment.
786
+ When both `--control` and `--treatment` are omitted, use `--config eval.yaml` or `--batch`. With `--batch`, `baseline` is auto-added as control and every discovered artifact becomes a treatment.
725
787
 
726
788
  ```bash
727
789
  # explicit: one control, one or more treatments
@@ -862,25 +924,25 @@ omk bench run \
862
924
  export OPENAI_API_KEY="your Zhipu API key"
863
925
  export OPENAI_BASE_URL="https://open.bigmodel.cn/api/paas/v4"
864
926
  omk bench run --executor openai-api --model glm-4-plus \
865
- --judge-model glm-4-plus --no-cache
927
+ --judge-models openai-api:glm-4-plus --no-cache
866
928
 
867
929
  # Qwen (Alibaba)
868
930
  export OPENAI_API_KEY="your Qwen API key"
869
931
  export OPENAI_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
870
932
  omk bench run --executor openai-api --model qwen-plus \
871
- --judge-model qwen-plus
933
+ --judge-models openai-api:qwen-plus
872
934
 
873
935
  # DeepSeek
874
936
  export OPENAI_API_KEY="your DeepSeek API key"
875
937
  export OPENAI_BASE_URL="https://api.deepseek.com"
876
938
  omk bench run --executor openai-api --model deepseek-chat \
877
- --judge-model deepseek-chat
939
+ --judge-models openai-api:deepseek-chat
878
940
 
879
941
  # Moonshot (Kimi)
880
942
  export OPENAI_API_KEY="your Moonshot API key"
881
943
  export OPENAI_BASE_URL="https://api.moonshot.cn/v1"
882
944
  omk bench run --executor openai-api --model moonshot-v1-8k \
883
- --judge-model moonshot-v1-8k
945
+ --judge-models openai-api:moonshot-v1-8k
884
946
  ```
885
947
 
886
948
  **Ollama local model:**
@@ -890,11 +952,11 @@ omk bench run --executor "python examples/custom-executor/ollama-executor.py" \
890
952
  --model llama3 --no-judge
891
953
  ```
892
954
 
893
- **About the judge model:**
955
+ **About the judge:**
894
956
 
895
- - `--judge-model` picks the model used by the LLM judge (default `haiku`)
896
- - `--judge-executor` picks the executor the judge uses (defaults to `--executor`)
897
- - If you don't have Claude, point `--judge-executor` and `--judge-model` at whatever model you have
957
+ - `--judge-models <list>` picks the LLM judge(s). Format: `executor:model[,executor:model]`. Default: `${executor}:haiku` (or claude:haiku when no `--executor` set)
958
+ - 1 entry = single judge; 2 entries = multi-judge ensemble + inter-judge agreement
959
+ - If you don't have Claude, point `--judge-models` at whatever you have, e.g. `--judge-models openai-api:glm-4-plus`
898
960
  - Add `--no-judge` to skip the LLM judge and rely on assertions alone
899
961
 
900
962
  ## Environment variables
@@ -927,4 +989,4 @@ This tool is designed for **local trusted environments** (dev machines, CI pipel
927
989
 
928
990
  ---
929
991
 
930
- See [CHANGELOG](./CHANGELOG.md) for release notes. Contributions welcome — see [CONTRIBUTING](./CONTRIBUTING.md).
992
+ See [GitHub Releases](https://github.com/lizhiyao/oh-my-knowledge/releases) for release notes. Contributions welcome — see [CONTRIBUTING](./CONTRIBUTING.md).