oh-my-knowledge 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +448 -0
- package/package.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# oh-my-knowledge
|
|
2
|
+
|
|
3
|
+
Knowledge artifact evaluation toolkit — benchmark your skills with objective data.
|
|
4
|
+
|
|
5
|
+
English | [中文](./README.zh-CN.md)
|
|
6
|
+
|
|
7
|
+
**Fixed model, variable knowledge artifact, data speaks.**
|
|
8
|
+
|
|
9
|
+
## Why
|
|
10
|
+
|
|
11
|
+
Teams building AI skills (system prompts, knowledge packages, rule sets) need objective data to prove v2 is better than v1. `oh-my-knowledge` runs controlled experiments: same model, same test cases, only the knowledge artifact changes.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Install globally
|
|
17
|
+
npm i -g oh-my-knowledge
|
|
18
|
+
|
|
19
|
+
# Scaffold a new eval project
|
|
20
|
+
omk bench init my-eval
|
|
21
|
+
cd my-eval
|
|
22
|
+
|
|
23
|
+
# Preview the evaluation plan
|
|
24
|
+
omk bench run --dry-run
|
|
25
|
+
|
|
26
|
+
# Run the evaluation
|
|
27
|
+
omk bench run --variants v1,v2
|
|
28
|
+
|
|
29
|
+
# View the report
|
|
30
|
+
omk bench report
|
|
31
|
+
# Open http://127.0.0.1:7799
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
eval-samples.json skills/v1.md skills/v2.md
|
|
38
|
+
│ │ │
|
|
39
|
+
└────────┬───────────┘ │
|
|
40
|
+
│ │
|
|
41
|
+
┌──────▼──────┐ ┌──────▼──────┐
|
|
42
|
+
│ sample + │ │ sample + │
|
|
43
|
+
│ skill v1 │ │ skill v2 │
|
|
44
|
+
└──────┬──────┘ └──────┬──────┘
|
|
45
|
+
│ │
|
|
46
|
+
┌──────▼──────┐ ┌──────▼──────┐
|
|
47
|
+
│ Executor │ │ Executor │
|
|
48
|
+
│ claude │ │ claude │
|
|
49
|
+
│ openai │ │ openai │
|
|
50
|
+
│ gemini │ │ gemini │
|
|
51
|
+
└──────┬──────┘ └──────┬──────┘
|
|
52
|
+
│ │
|
|
53
|
+
┌──────▼──────────────────────▼──────┐
|
|
54
|
+
│ Grading │
|
|
55
|
+
│ ┌─────────────┐ ┌──────────────┐ │
|
|
56
|
+
│ │ Assertions │ │ LLM Judge │ │
|
|
57
|
+
│ │ (18 types) │ │ (rubric or │ │
|
|
58
|
+
│ │ │ │ dimensions) │ │
|
|
59
|
+
│ └─────────────┘ └──────────────┘ │
|
|
60
|
+
└──────────────────┬─────────────────┘
|
|
61
|
+
│
|
|
62
|
+
┌─────────▼─────────┐
|
|
63
|
+
│ Report + Analysis │
|
|
64
|
+
│ (JSON/HTML) │
|
|
65
|
+
└───────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Eval Sample Format
|
|
69
|
+
|
|
70
|
+
Supports both JSON and YAML (`eval-samples.json`, `eval-samples.yaml`, `eval-samples.yml`).
|
|
71
|
+
|
|
72
|
+
The file contains an array of sample objects. Each sample represents one test case for evaluating a skill.
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
[
|
|
76
|
+
{
|
|
77
|
+
"sample_id": "s001",
|
|
78
|
+
"prompt": "Review this code",
|
|
79
|
+
"context": "function auth(u, p) { db.query('SELECT * FROM users WHERE name=' + u); }",
|
|
80
|
+
"rubric": "Should identify SQL injection and suggest parameterized queries",
|
|
81
|
+
"assertions": [
|
|
82
|
+
{ "type": "contains", "value": "SQL injection", "weight": 1 },
|
|
83
|
+
{ "type": "contains", "value": "parameterized", "weight": 1 },
|
|
84
|
+
{ "type": "not_contains", "value": "looks good", "weight": 0.5 },
|
|
85
|
+
{ "type": "json_valid" },
|
|
86
|
+
{ "type": "cost_max", "value": 0.01 },
|
|
87
|
+
{ "type": "custom", "fn": "my-assertion.mjs", "weight": 1 }
|
|
88
|
+
],
|
|
89
|
+
"dimensions": {
|
|
90
|
+
"security": "Should identify injection vulnerability",
|
|
91
|
+
"actionability": "Should provide concrete fix with code"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Field Reference
|
|
98
|
+
|
|
99
|
+
| Field | Type | Required | Description |
|
|
100
|
+
|-------|------|----------|-------------|
|
|
101
|
+
| `sample_id` | `string` | **Yes** | Unique identifier for the sample (e.g., `"s001"`). Used in reports and analysis to reference this test case. |
|
|
102
|
+
| `prompt` | `string` | **Yes** | The user prompt sent to the model. This is the task or question the model should answer. |
|
|
103
|
+
| `context` | `string` | No | Additional context appended to the prompt (e.g., code snippet, document text). If provided, it is wrapped in a code block and concatenated after `prompt`. |
|
|
104
|
+
| `rubric` | `string` | No | Natural language scoring criteria for the LLM judge. The judge model reads this rubric and scores the output 1-5. Use when you need semantic/qualitative evaluation. |
|
|
105
|
+
| `assertions` | `array` | No | List of deterministic and async checks applied to the model output. Each assertion is an object with a `type` field (see [Assertion Types](#assertion-types)). |
|
|
106
|
+
| `assertions[].type` | `string` | **Yes** | The assertion type (e.g., `"contains"`, `"json_valid"`, `"custom"`). See full list below. |
|
|
107
|
+
| `assertions[].value` | `string\|number` | Varies | The value to check against. Required for `contains`, `starts_with`, `equals`, `min_length`, `cost_max`, etc. |
|
|
108
|
+
| `assertions[].values` | `array` | Varies | Array of strings. Required for `contains_all` and `contains_any`. |
|
|
109
|
+
| `assertions[].pattern` | `string` | Varies | Regex pattern. Required for `regex` type. |
|
|
110
|
+
| `assertions[].flags` | `string` | No | Regex flags (default: `"i"`). Only used with `regex` type. |
|
|
111
|
+
| `assertions[].schema` | `object` | Varies | JSON Schema object. Required for `json_schema` type. Validated via [ajv](https://ajv.js.org/) (full JSON Schema spec). |
|
|
112
|
+
| `assertions[].reference` | `string` | Varies | Reference text for semantic comparison. Required for `semantic_similarity` type. |
|
|
113
|
+
| `assertions[].threshold` | `number` | No | Minimum score (1-5) to consider a semantic similarity match passing. Default: `3`. |
|
|
114
|
+
| `assertions[].fn` | `string` | Varies | Path to a `.mjs` file exporting the check function. Required for `custom` type. Resolved relative to the samples file directory. |
|
|
115
|
+
| `assertions[].weight` | `number` | No | Weight of this assertion in the composite score calculation. Default: `1`. Higher weight = more influence on the final assertion score. |
|
|
116
|
+
| `dimensions` | `object` | No | Key-value map for multi-dimensional LLM scoring. Each key is a dimension name (e.g., `"security"`), and the value is the rubric text the LLM judge uses to score that dimension (1-5). Scores are averaged into a single LLM score. |
|
|
117
|
+
|
|
118
|
+
**Scoring priority:** If both `assertions` and `rubric`/`dimensions` are present, the composite score is a 50/50 weighted average. If only one is present, that score is used directly. If none are present, the score is 0.
|
|
119
|
+
|
|
120
|
+
**Prompt construction:** The final prompt sent to the model is: `prompt` alone if no `context`, or `prompt + "\n\n```\n" + context + "\n```"` if `context` is provided.
|
|
121
|
+
|
|
122
|
+
### Grading Strategy
|
|
123
|
+
|
|
124
|
+
Each sample can use up to three grading methods. They can be used alone or combined.
|
|
125
|
+
|
|
126
|
+
#### 1. Assertions (deterministic scoring)
|
|
127
|
+
|
|
128
|
+
Assertions are rule-based checks that run locally without any LLM calls (except `semantic_similarity` and `custom`). Each assertion produces a **pass/fail** result.
|
|
129
|
+
|
|
130
|
+
**How the assertion score is calculated:**
|
|
131
|
+
|
|
132
|
+
1. Each assertion has a `weight` (default: 1)
|
|
133
|
+
2. Sum the weights of all passing assertions → `passedWeight`
|
|
134
|
+
3. Sum the weights of all assertions → `totalWeight`
|
|
135
|
+
4. Compute ratio: `passedWeight / totalWeight` (0.0 ~ 1.0)
|
|
136
|
+
5. Normalize to 1-5 scale: **`score = 1 + ratio × 4`**
|
|
137
|
+
|
|
138
|
+
Example: 3 assertions (weight 1 each), 2 pass → ratio = 2/3 → score = 1 + 2.67 = **3.67**
|
|
139
|
+
|
|
140
|
+
#### 2. Rubric (single LLM judge)
|
|
141
|
+
|
|
142
|
+
A judge model (default: `haiku`, configurable via `--judge-model`) reads the model output and scores it against the rubric text. Returns an integer score from **1** (fail) to **5** (excellent) with a brief reason.
|
|
143
|
+
|
|
144
|
+
Only one of `rubric` or `dimensions` should be used per sample. If both are present, `dimensions` takes priority.
|
|
145
|
+
|
|
146
|
+
#### 3. Dimensions (multi-dimensional LLM judge)
|
|
147
|
+
|
|
148
|
+
Each dimension is scored independently by the judge model (1-5). The dimension scores are **averaged** to produce a single LLM score.
|
|
149
|
+
|
|
150
|
+
Example: `security: 5`, `actionability: 3` → LLM score = **(5 + 3) / 2 = 4.0**
|
|
151
|
+
|
|
152
|
+
#### Composite Score
|
|
153
|
+
|
|
154
|
+
| What's present | Composite score formula |
|
|
155
|
+
|----------------|----------------------|
|
|
156
|
+
| Assertions only | `assertionScore` |
|
|
157
|
+
| LLM only (rubric or dimensions) | `llmScore` |
|
|
158
|
+
| Both | `(assertionScore + llmScore) / 2` |
|
|
159
|
+
| Neither | `0` |
|
|
160
|
+
|
|
161
|
+
All scores are on a **1-5 scale**. A score of 0 means no grading criteria were defined.
|
|
162
|
+
|
|
163
|
+
### Assertion Types
|
|
164
|
+
|
|
165
|
+
**Deterministic (sync, no LLM):**
|
|
166
|
+
|
|
167
|
+
| Type | Fields | Description |
|
|
168
|
+
|------|--------|-------------|
|
|
169
|
+
| `contains` | `value`, `weight` | Output contains substring (case-insensitive) |
|
|
170
|
+
| `not_contains` | `value`, `weight` | Output does NOT contain substring |
|
|
171
|
+
| `regex` | `pattern`, `flags`, `weight` | Output matches regex |
|
|
172
|
+
| `min_length` | `value`, `weight` | Output length >= value |
|
|
173
|
+
| `max_length` | `value`, `weight` | Output length <= value |
|
|
174
|
+
| `json_valid` | `weight` | Output is valid JSON |
|
|
175
|
+
| `json_schema` | `schema`, `weight` | Output matches JSON Schema (full spec via ajv) |
|
|
176
|
+
| `starts_with` | `value`, `weight` | Output starts with string (case-insensitive) |
|
|
177
|
+
| `ends_with` | `value`, `weight` | Output ends with string (case-insensitive) |
|
|
178
|
+
| `equals` | `value`, `weight` | Output exactly equals value (after trim) |
|
|
179
|
+
| `not_equals` | `value`, `weight` | Output does not equal value (after trim) |
|
|
180
|
+
| `word_count_min` | `value`, `weight` | Word count >= value |
|
|
181
|
+
| `word_count_max` | `value`, `weight` | Word count <= value |
|
|
182
|
+
| `contains_all` | `values`, `weight` | Output contains ALL substrings |
|
|
183
|
+
| `contains_any` | `values`, `weight` | Output contains at least one substring |
|
|
184
|
+
| `cost_max` | `value`, `weight` | Execution cost (USD) <= value |
|
|
185
|
+
| `latency_max` | `value`, `weight` | Execution latency (ms) <= value |
|
|
186
|
+
|
|
187
|
+
**Async (LLM-based):**
|
|
188
|
+
|
|
189
|
+
| Type | Fields | Description |
|
|
190
|
+
|------|--------|-------------|
|
|
191
|
+
| `semantic_similarity` | `reference`, `threshold`, `weight` | LLM judges similarity to reference text (threshold default: 3) |
|
|
192
|
+
| `custom` | `fn`, `weight` | Load external JS function (see below) |
|
|
193
|
+
|
|
194
|
+
### Custom Assertions
|
|
195
|
+
|
|
196
|
+
Create a `.mjs` file that exports a function:
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
// my-assertion.mjs
|
|
200
|
+
export default function(output, { sample, assertion }) {
|
|
201
|
+
const hasKeyword = output.includes('SQL');
|
|
202
|
+
return { pass: hasKeyword, message: 'Checked for SQL keyword' };
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Reference it in your sample: `{ "type": "custom", "fn": "my-assertion.mjs" }`. The `fn` path is resolved relative to the samples file directory.
|
|
207
|
+
|
|
208
|
+
## Report Example
|
|
209
|
+
|
|
210
|
+
After running `omk bench run --variants v1,v2`, the tool outputs a JSON report (also saved to `~/.oh-my-knowledge/reports/`):
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"id": "2026-03-24T15-30-45-v1-v2",
|
|
215
|
+
"meta": {
|
|
216
|
+
"variants": ["v1", "v2"],
|
|
217
|
+
"model": "sonnet",
|
|
218
|
+
"judgeModel": "haiku",
|
|
219
|
+
"executor": "claude",
|
|
220
|
+
"sampleCount": 3,
|
|
221
|
+
"taskCount": 6,
|
|
222
|
+
"totalCostUSD": 0.0234,
|
|
223
|
+
"timestamp": "2026-03-24T15:30:45.000Z",
|
|
224
|
+
"cliVersion": "0.3.0",
|
|
225
|
+
"nodeVersion": "v22.0.0",
|
|
226
|
+
"skillHashes": { "v1": "a1b2c3d4e5f6", "v2": "f6e5d4c3b2a1" }
|
|
227
|
+
},
|
|
228
|
+
"summary": {
|
|
229
|
+
"v1": {
|
|
230
|
+
"totalSamples": 3,
|
|
231
|
+
"successCount": 3,
|
|
232
|
+
"errorCount": 0,
|
|
233
|
+
"avgCompositeScore": 3.67,
|
|
234
|
+
"avgAssertionScore": 3.0,
|
|
235
|
+
"avgLlmScore": 4.33,
|
|
236
|
+
"avgDurationMs": 2500,
|
|
237
|
+
"avgTotalTokens": 1850,
|
|
238
|
+
"totalCostUSD": 0.0112
|
|
239
|
+
},
|
|
240
|
+
"v2": {
|
|
241
|
+
"totalSamples": 3,
|
|
242
|
+
"successCount": 3,
|
|
243
|
+
"errorCount": 0,
|
|
244
|
+
"avgCompositeScore": 4.5,
|
|
245
|
+
"avgAssertionScore": 5.0,
|
|
246
|
+
"avgLlmScore": 4.0,
|
|
247
|
+
"avgDurationMs": 2800,
|
|
248
|
+
"avgTotalTokens": 2100,
|
|
249
|
+
"totalCostUSD": 0.0122
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"results": [
|
|
253
|
+
{
|
|
254
|
+
"sample_id": "s001",
|
|
255
|
+
"variants": {
|
|
256
|
+
"v1": {
|
|
257
|
+
"ok": true,
|
|
258
|
+
"compositeScore": 3.5,
|
|
259
|
+
"assertions": {
|
|
260
|
+
"passed": 1,
|
|
261
|
+
"total": 2,
|
|
262
|
+
"score": 3.0,
|
|
263
|
+
"details": [
|
|
264
|
+
{ "type": "contains", "value": "SQL injection", "weight": 1, "passed": true },
|
|
265
|
+
{ "type": "contains", "value": "parameterized", "weight": 1, "passed": false }
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
"llmScore": 4,
|
|
269
|
+
"llmReason": "Identified the vulnerability but did not provide a complete fix",
|
|
270
|
+
"durationMs": 2300,
|
|
271
|
+
"inputTokens": 850,
|
|
272
|
+
"outputTokens": 1200,
|
|
273
|
+
"totalTokens": 2050,
|
|
274
|
+
"costUSD": 0.0038,
|
|
275
|
+
"outputPreview": "This code has a SQL injection vulnerability..."
|
|
276
|
+
},
|
|
277
|
+
"v2": {
|
|
278
|
+
"ok": true,
|
|
279
|
+
"compositeScore": 4.5,
|
|
280
|
+
"assertions": {
|
|
281
|
+
"passed": 2,
|
|
282
|
+
"total": 2,
|
|
283
|
+
"score": 5.0,
|
|
284
|
+
"details": [
|
|
285
|
+
{ "type": "contains", "value": "SQL injection", "weight": 1, "passed": true },
|
|
286
|
+
{ "type": "contains", "value": "parameterized", "weight": 1, "passed": true }
|
|
287
|
+
]
|
|
288
|
+
},
|
|
289
|
+
"llmScore": 4,
|
|
290
|
+
"llmReason": "Thorough analysis with actionable fix code",
|
|
291
|
+
"durationMs": 2600,
|
|
292
|
+
"inputTokens": 900,
|
|
293
|
+
"outputTokens": 1400,
|
|
294
|
+
"totalTokens": 2300,
|
|
295
|
+
"costUSD": 0.0042,
|
|
296
|
+
"outputPreview": "## Security Issue: SQL Injection\n\nThe code is vulnerable..."
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
],
|
|
301
|
+
"analysis": {
|
|
302
|
+
"insights": [
|
|
303
|
+
{
|
|
304
|
+
"type": "uniform_scores",
|
|
305
|
+
"severity": "info",
|
|
306
|
+
"message": "1/3 samples show score difference < 0.5 between variants"
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
"suggestions": []
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Reading the report:**
|
|
315
|
+
|
|
316
|
+
- **`summary`** gives a quick comparison — in this example, v2 scores higher (4.5 vs 3.67) because it passes more assertions
|
|
317
|
+
- **`results`** shows per-sample detail — you can see exactly which assertions passed/failed and why
|
|
318
|
+
- **`analysis`** flags patterns — here it notes one sample has similar scores across variants
|
|
319
|
+
- View the HTML version at `http://127.0.0.1:7799/run/{id}` after running `omk bench report`
|
|
320
|
+
|
|
321
|
+
## CLI Reference
|
|
322
|
+
|
|
323
|
+
### `omk bench run`
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
omk bench run [options]
|
|
327
|
+
|
|
328
|
+
Options:
|
|
329
|
+
--samples <path> Sample file (default: eval-samples.json, auto-detects .yaml/.yml)
|
|
330
|
+
--skill-dir <path> Skill directory (default: skills)
|
|
331
|
+
--variants <v1,v2> Variant names (default: v1,v2)
|
|
332
|
+
--model <name> Model under test (default: sonnet)
|
|
333
|
+
--judge-model <name> Judge model (default: haiku)
|
|
334
|
+
--output-dir <path> Output directory (default: ~/.oh-my-knowledge/reports/)
|
|
335
|
+
--no-judge Skip LLM judging
|
|
336
|
+
--dry-run Preview only
|
|
337
|
+
--blind Blind A/B mode: hide variant names in report
|
|
338
|
+
--concurrency <n> Number of parallel tasks (default: 1)
|
|
339
|
+
--repeat <n> Run evaluation N times for variance analysis (default: 1)
|
|
340
|
+
--executor <name> Executor (default: claude)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### `omk bench ci`
|
|
344
|
+
|
|
345
|
+
Run evaluation in CI and exit with pass/fail code.
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
omk bench ci [options]
|
|
349
|
+
|
|
350
|
+
Options:
|
|
351
|
+
(same as "bench run", plus:)
|
|
352
|
+
--threshold <number> Minimum composite score to pass (default: 3.5)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Exit code 0 = all variants pass, 1 = at least one variant below threshold.
|
|
356
|
+
|
|
357
|
+
### `omk bench report`
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
omk bench report [options]
|
|
361
|
+
|
|
362
|
+
Options:
|
|
363
|
+
--port <number> Server port (default: 7799)
|
|
364
|
+
--reports-dir <path> Reports directory (default: ~/.oh-my-knowledge/reports/)
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### `omk bench init`
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
omk bench init [dir] # Scaffold a new eval project
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Features
|
|
374
|
+
|
|
375
|
+
### Blind A/B Testing
|
|
376
|
+
|
|
377
|
+
Use `--blind` to hide variant names in reports. Variants are randomly labeled as "Variant A", "Variant B", etc. A reveal button in the HTML report shows the mapping.
|
|
378
|
+
|
|
379
|
+
### Parallel Execution
|
|
380
|
+
|
|
381
|
+
Use `--concurrency N` to run N tasks in parallel. Tasks maintain interleaved scheduling order to reduce time bias.
|
|
382
|
+
|
|
383
|
+
### Multi-run Variance Analysis
|
|
384
|
+
|
|
385
|
+
Use `--repeat N` to run the evaluation N times. The report includes:
|
|
386
|
+
- Per-variant mean, standard deviation, 95% confidence interval
|
|
387
|
+
- Pairwise Welch's t-test between variants (significance at p < 0.05)
|
|
388
|
+
|
|
389
|
+
### Auto-analysis
|
|
390
|
+
|
|
391
|
+
After each evaluation, the toolkit automatically detects:
|
|
392
|
+
- **Low-discrimination assertions**: assertions with identical results across all variants
|
|
393
|
+
- **Uniform scores**: samples where variants score within 0.5 of each other
|
|
394
|
+
- **All-pass / all-fail**: assertions that may be too loose or too strict
|
|
395
|
+
- **High-cost samples**: samples with disproportionately high cost
|
|
396
|
+
|
|
397
|
+
Insights and suggestions are shown in the HTML report.
|
|
398
|
+
|
|
399
|
+
### Human Feedback
|
|
400
|
+
|
|
401
|
+
The HTML report includes star rating (1-5) and comment forms for each sample-variant pair. Feedback is persisted to the report JSON via `POST /api/run/:id/feedback`.
|
|
402
|
+
|
|
403
|
+
### Traceability
|
|
404
|
+
|
|
405
|
+
Reports include `cliVersion`, `nodeVersion`, and `skillHashes` (SHA-256 of each skill file) in metadata for reproducibility.
|
|
406
|
+
|
|
407
|
+
## Executors
|
|
408
|
+
|
|
409
|
+
Use `--executor` to select which model provider to use.
|
|
410
|
+
|
|
411
|
+
| Executor | CLI Tool | Default Model | Auth |
|
|
412
|
+
|----------|----------|---------------|------|
|
|
413
|
+
| `claude` | `claude -p` | `sonnet` | Claude Max plan or API key |
|
|
414
|
+
| `openai` | `openai api chat.completions.create` | `gpt-4o` | `OPENAI_API_KEY` env var |
|
|
415
|
+
| `gemini` | `gemini` (stdin pipe) | Default Gemini model | Google account or `GOOGLE_API_KEY` |
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
# Use OpenAI
|
|
419
|
+
omk bench run --executor openai --model gpt-4o --variants v1,v2
|
|
420
|
+
|
|
421
|
+
# Use Gemini
|
|
422
|
+
omk bench run --executor gemini --model gemini-2.5-pro --variants v1,v2
|
|
423
|
+
|
|
424
|
+
# Compare the same skill across providers (run separately, compare reports)
|
|
425
|
+
omk bench run --executor claude --model sonnet --variants v1,v2
|
|
426
|
+
omk bench run --executor openai --model gpt-4o --variants v1,v2
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Prerequisites:**
|
|
430
|
+
- **claude**: Install [Claude Code](https://claude.ai/code) and authenticate
|
|
431
|
+
- **openai**: `pip install openai` and set `OPENAI_API_KEY`
|
|
432
|
+
- **gemini**: `npm i -g @google/gemini-cli` and authenticate with Google
|
|
433
|
+
|
|
434
|
+
## Environment Variables
|
|
435
|
+
|
|
436
|
+
| Variable | Description |
|
|
437
|
+
|----------|-------------|
|
|
438
|
+
| `CCV_PROXY_URL` | Route requests through cc-viewer proxy for real-time visualization |
|
|
439
|
+
| `OMK_BENCH_PORT` | Report server port (default: 7799) |
|
|
440
|
+
|
|
441
|
+
## Requirements
|
|
442
|
+
|
|
443
|
+
- Node.js >= 20
|
|
444
|
+
- `claude` CLI installed and authenticated (Max plan works, no API key needed)
|
|
445
|
+
|
|
446
|
+
## License
|
|
447
|
+
|
|
448
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "oh-my-knowledge",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Knowledge artifact evaluation toolkit — benchmark your skills with objective data",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"knowledge-engineering",
|
|
7
|
+
"skill-evaluation",
|
|
8
|
+
"benchmark",
|
|
9
|
+
"llm",
|
|
10
|
+
"ai",
|
|
11
|
+
"claude"
|
|
12
|
+
],
|
|
13
|
+
"author": "lizhiyao",
|
|
14
|
+
"license": "MIT"
|
|
15
|
+
}
|