@runecraft/grimoire 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/catalog.json +9 -0
- package/dist/grimoire.js +1758 -0
- package/package.json +54 -0
- package/references/definition-of-done.md +67 -0
- package/references/testing-patterns.md +260 -0
- package/skills/code-review-and-quality/README.md +13 -0
- package/skills/code-review-and-quality/SKILL.md +389 -0
- package/skills/code-simplification/README.md +13 -0
- package/skills/code-simplification/SKILL.md +338 -0
- package/skills/debugging-and-error-recovery/README.md +13 -0
- package/skills/debugging-and-error-recovery/SKILL.md +343 -0
- package/skills/debugging-and-error-recovery/scripts/__pycache__/triage_state.cpython-314.pyc +0 -0
- package/skills/debugging-and-error-recovery/scripts/triage_state.py +206 -0
- package/skills/deprecation-and-migration/README.md +13 -0
- package/skills/deprecation-and-migration/SKILL.md +248 -0
- package/skills/deprecation-and-migration/scripts/__pycache__/migration_tracker.cpython-314.pyc +0 -0
- package/skills/deprecation-and-migration/scripts/migration_tracker.py +237 -0
- package/skills/doubt-driven-development/README.md +13 -0
- package/skills/doubt-driven-development/SKILL.md +251 -0
- package/skills/git-commit-learning/.skill-meta.json +14 -0
- package/skills/git-commit-learning/README.md +205 -0
- package/skills/git-commit-learning/SKILL.md +435 -0
- package/skills/git-commit-learning/references/commit-patterns.md +595 -0
- package/skills/git-worktree/README.md +13 -0
- package/skills/git-worktree/SKILL.md +220 -0
- package/skills/idea-refine/README.md +13 -0
- package/skills/idea-refine/SKILL.md +186 -0
- package/skills/interview-me/README.md +13 -0
- package/skills/interview-me/SKILL.md +233 -0
- package/skills/linkedin-audit/SKILL.md +98 -0
- package/skills/linkedin-audit/references/dashboard-spec.md +43 -0
- package/skills/memory-management/README.md +13 -0
- package/skills/memory-management/SKILL.md +198 -0
- package/skills/security-and-hardening/README.md +13 -0
- package/skills/security-and-hardening/SKILL.md +472 -0
- package/skills/shipping-and-launch/README.md +13 -0
- package/skills/shipping-and-launch/SKILL.md +317 -0
- package/skills/skill-forge/README.md +153 -0
- package/skills/skill-forge/SKILL.md +291 -0
- package/skills/skill-forge/assets/SKILL.template.md +73 -0
- package/skills/skill-forge/references/authoring-patterns.md +249 -0
- package/skills/skill-forge/references/description-optimization.md +171 -0
- package/skills/skill-forge/references/output-evaluation.md +276 -0
- package/skills/skill-forge/references/scripts-guide.md +232 -0
- package/skills/skill-forge/references/spec.md +175 -0
- package/skills/skill-forge/scripts/validate.py +536 -0
- package/skills/spec-driven/.skill-meta.json +14 -0
- package/skills/spec-driven/README.md +335 -0
- package/skills/spec-driven/SKILL.md +174 -0
- package/skills/spec-driven/references/code-analysis.md +98 -0
- package/skills/spec-driven/references/coding-principles.md +56 -0
- package/skills/spec-driven/references/context-limits.md +31 -0
- package/skills/spec-driven/references/design.md +199 -0
- package/skills/spec-driven/references/discuss.md +136 -0
- package/skills/spec-driven/references/implement.md +425 -0
- package/skills/spec-driven/references/lessons.md +113 -0
- package/skills/spec-driven/references/memory.md +126 -0
- package/skills/spec-driven/references/specify.md +210 -0
- package/skills/spec-driven/references/sub-agents.md +96 -0
- package/skills/spec-driven/references/tasks.md +484 -0
- package/skills/spec-driven/references/validate.md +350 -0
- package/skills/spec-driven/scripts/__pycache__/lessons.cpython-314.pyc +0 -0
- package/skills/spec-driven/scripts/lessons.py +370 -0
- package/skills/spec-loop/README.md +36 -0
- package/skills/spec-loop/SKILL.md +61 -0
- package/skills/test-driven-development/README.md +13 -0
- package/skills/test-driven-development/SKILL.md +388 -0
- package/skills/typescript-patterns/README.md +13 -0
- package/skills/typescript-patterns/SKILL.md +346 -0
- package/skills/using-agent-skills/README.md +13 -0
- package/skills/using-agent-skills/SKILL.md +187 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Description Optimization (Trigger Eval)
|
|
2
|
+
|
|
3
|
+
> Read this in Phase 5 (OPTIMIZE) when you need to systematically improve a skill's triggering accuracy. The description is the only thing the agent sees at startup — if it doesn't trigger on the right prompts, nothing else matters.
|
|
4
|
+
|
|
5
|
+
## How triggering works
|
|
6
|
+
|
|
7
|
+
Agents use progressive disclosure. At startup they load only `name` and `description` of each skill — just enough to decide when a skill might be relevant. When a user's task matches, the agent reads the full `SKILL.md` and follows the instructions.
|
|
8
|
+
|
|
9
|
+
The description carries the entire burden of triggering. If it doesn't convey when the skill is useful, the agent won't reach for it.
|
|
10
|
+
|
|
11
|
+
One nuance: agents typically only consult skills for tasks requiring knowledge or capabilities beyond what they handle alone. A simple "read this PDF" may not trigger a PDF skill even with a perfect description, because the agent can handle it with basic tools. Skills matter most where there's specialized knowledge — an unfamiliar API, a domain workflow, an uncommon format.
|
|
12
|
+
|
|
13
|
+
## Writing effective descriptions
|
|
14
|
+
|
|
15
|
+
- **Imperative phrasing.** "Use this skill when…" not "This skill does…". The agent is deciding whether to act; tell it when to act.
|
|
16
|
+
- **Focus on user intent, not implementation.** Describe what the user is trying to achieve, not the skill's internal mechanics.
|
|
17
|
+
- **Err on the side of being pushy.** List contexts where the skill applies, including cases where the user doesn't name the domain directly: "even if they don't explicitly mention 'CSV' or 'analysis.'"
|
|
18
|
+
- **Keep it concise.** A few sentences to a short paragraph. The spec enforces 1024 chars.
|
|
19
|
+
|
|
20
|
+
## Designing trigger eval queries
|
|
21
|
+
|
|
22
|
+
Build a set of realistic user prompts, each labeled with whether it should trigger the skill.
|
|
23
|
+
|
|
24
|
+
```json eval_queries.json
|
|
25
|
+
[
|
|
26
|
+
{ "query": "I've got a spreadsheet in ~/data/q4_results.xlsx with revenue in col C and expenses in col D — can you add a profit margin column and highlight anything under 10%?", "should_trigger": true },
|
|
27
|
+
{ "query": "whats the quickest way to convert this json file to yaml", "should_trigger": false }
|
|
28
|
+
]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Aim for ~20 queries: 8-10 should-trigger, 8-10 should-NOT-trigger.
|
|
32
|
+
|
|
33
|
+
### Should-trigger queries
|
|
34
|
+
|
|
35
|
+
Vary along several axes:
|
|
36
|
+
|
|
37
|
+
- **Phrasing:** formal, casual, typos, abbreviations.
|
|
38
|
+
- **Explicitness:** some name the domain ("analyze this CSV"); others describe the need without naming it ("my boss wants a chart from this data file").
|
|
39
|
+
- **Detail:** terse prompts alongside context-heavy ones with file paths, column names, backstory.
|
|
40
|
+
- **Complexity:** single-step tasks alongside multi-step workflows.
|
|
41
|
+
|
|
42
|
+
The most useful should-trigger queries are ones where the skill would help but the connection isn't obvious. If the query already asks for exactly what the skill does, any reasonable description would trigger.
|
|
43
|
+
|
|
44
|
+
### Should-not-trigger queries
|
|
45
|
+
|
|
46
|
+
The most valuable negative test cases are **near-misses** — queries that share keywords or concepts with the skill but actually need something different. These test whether the description is precise, not just broad.
|
|
47
|
+
|
|
48
|
+
Weak negatives (test nothing):
|
|
49
|
+
|
|
50
|
+
- "Write a fibonacci function" — obviously irrelevant.
|
|
51
|
+
- "What's the weather today?" — no keyword overlap.
|
|
52
|
+
|
|
53
|
+
Strong negatives:
|
|
54
|
+
|
|
55
|
+
- "I need to update the formulas in my Excel budget spreadsheet" — shares "spreadsheet" and "data" concepts, but needs Excel editing, not CSV analysis.
|
|
56
|
+
- "Can you write a python script that reads a csv and uploads each row to our postgres database" — involves CSV, but the task is database ETL, not analysis.
|
|
57
|
+
|
|
58
|
+
### Tips for realism
|
|
59
|
+
|
|
60
|
+
Real user prompts contain context generic test queries lack. Include:
|
|
61
|
+
|
|
62
|
+
- File paths (`~/Downloads/report_final_v2.xlsx`)
|
|
63
|
+
- Personal context (`"my manager asked me to..."`)
|
|
64
|
+
- Specific details (column names, company names, values)
|
|
65
|
+
- Casual language, abbreviations, occasional typos
|
|
66
|
+
|
|
67
|
+
## Testing whether a description triggers
|
|
68
|
+
|
|
69
|
+
The basic approach: run each query through your agent with the skill installed, observe whether the agent invokes it. Make sure the skill is registered and discoverable — how varies by client.
|
|
70
|
+
|
|
71
|
+
Most agents provide observability — execution logs, tool call histories, verbose output — so you can see which skills were consulted. The skill triggered if the agent loaded the SKILL.md; it didn't if the agent proceeded without consulting it.
|
|
72
|
+
|
|
73
|
+
A query passes if:
|
|
74
|
+
|
|
75
|
+
- `should_trigger: true` and the skill was invoked, or
|
|
76
|
+
- `should_trigger: false` and the skill was not invoked.
|
|
77
|
+
|
|
78
|
+
### Running multiple times
|
|
79
|
+
|
|
80
|
+
Model behavior is nondeterministic — the same query might trigger the skill on one run but not the next. Run each query multiple times (3 is a reasonable start) and compute a **trigger rate**: the fraction of runs where the skill was invoked.
|
|
81
|
+
|
|
82
|
+
A should-trigger query passes if its trigger rate is above a threshold (0.5 is a reasonable default). A should-not-trigger query passes if its trigger rate is below that threshold.
|
|
83
|
+
|
|
84
|
+
With 20 queries at 3 runs each, that's 60 invocations. Script it.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
#!/bin/bash
|
|
88
|
+
# Example: Claude Code with JSON output. Replace the `claude` invocation and
|
|
89
|
+
# detection logic with whatever your agent client provides.
|
|
90
|
+
QUERIES_FILE="${1:?Usage: $0 <queries.json>}"
|
|
91
|
+
SKILL_NAME="my-skill"
|
|
92
|
+
RUNS=3
|
|
93
|
+
|
|
94
|
+
check_triggered() {
|
|
95
|
+
local query="$1"
|
|
96
|
+
claude -p "$query" --output-format json 2>/dev/null \
|
|
97
|
+
| jq -e --arg skill "$SKILL_NAME" \
|
|
98
|
+
'any(.messages[].content[]; .type == "tool_use" and .name == "Skill" and .input.skill == $skill)' \
|
|
99
|
+
> /dev/null 2>&1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
count=$(jq length "$QUERIES_FILE")
|
|
103
|
+
for i in $(seq 0 $((count - 1))); do
|
|
104
|
+
query=$(jq -r ".[$i].query" "$QUERIES_FILE")
|
|
105
|
+
should_trigger=$(jq -r ".[$i].should_trigger" "$QUERIES_FILE")
|
|
106
|
+
triggers=0
|
|
107
|
+
|
|
108
|
+
for run in $(seq 1 $RUNS); do
|
|
109
|
+
check_triggered "$query" && triggers=$((triggers + 1))
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
jq -n \
|
|
113
|
+
--arg query "$query" \
|
|
114
|
+
--argjson should_trigger "$should_trigger" \
|
|
115
|
+
--argjson triggers "$triggers" \
|
|
116
|
+
--argjson runs "$RUNS" \
|
|
117
|
+
'{query: $query, should_trigger: $should_trigger, triggers: $triggers, runs: $runs, trigger_rate: ($triggers / $runs)}'
|
|
118
|
+
done | jq -s '.'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
If your client supports it, stop a run early once the outcome is clear — the agent either consulted the skill or started working without it.
|
|
122
|
+
|
|
123
|
+
## Avoiding overfitting with train/validation splits
|
|
124
|
+
|
|
125
|
+
If you optimize the description against all queries, you risk overfitting — a description that works for these phrasings but fails on new ones.
|
|
126
|
+
|
|
127
|
+
Split the query set:
|
|
128
|
+
|
|
129
|
+
- **Train set (~60%):** queries you use to identify failures and guide improvements.
|
|
130
|
+
- **Validation set (~40%):** queries set aside, used only to check whether improvements generalize.
|
|
131
|
+
|
|
132
|
+
Both sets need a proportional mix of should-trigger and should-NOT-trigger. Shuffle randomly, keep the split fixed across iterations so you're comparing apples to apples.
|
|
133
|
+
|
|
134
|
+
## The optimization loop
|
|
135
|
+
|
|
136
|
+
1. **Evaluate** the current description on both train and validation sets. Train results guide changes; validation results tell you whether they generalize.
|
|
137
|
+
2. **Identify failures** in the *train* set: which should-trigger queries didn't trigger? Which should-NOT-trigger did? Use only train failures to guide changes.
|
|
138
|
+
3. **Revise the description.** Focus on generalizing:
|
|
139
|
+
- If should-trigger failures → description may be too narrow. Broaden scope or add context.
|
|
140
|
+
- If should-NOT-trigger false-positives → too broad. Add specificity about what the skill does NOT do.
|
|
141
|
+
- Avoid adding specific keywords from failed queries — that's overfitting. Find the general category those queries represent.
|
|
142
|
+
- If stuck after several iterations, try a structurally different framing rather than incremental tweaks.
|
|
143
|
+
- Keep description under 1024 chars (descriptions tend to grow).
|
|
144
|
+
4. **Repeat** steps 1-3 until all train queries pass or you stop seeing improvement.
|
|
145
|
+
5. **Select the best iteration** by its validation pass rate. The best description may not be the last — an earlier iteration might generalize better.
|
|
146
|
+
|
|
147
|
+
Five iterations is usually enough. If performance isn't improving, the issue may be the queries (too easy, too hard, or poorly labeled).
|
|
148
|
+
|
|
149
|
+
## Applying the result
|
|
150
|
+
|
|
151
|
+
Once you've selected the best description:
|
|
152
|
+
|
|
153
|
+
1. Update the `description` field in `SKILL.md` frontmatter.
|
|
154
|
+
2. Verify it's under 1024 chars.
|
|
155
|
+
3. Verify triggering as expected with manual sanity checks. For a rigorous test, write 5-10 fresh queries (mix of should/shouldn't) and run them — these were never in the optimization, so they give an honest generalization check.
|
|
156
|
+
|
|
157
|
+
Before/after:
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
# Before
|
|
161
|
+
description: Process CSV files.
|
|
162
|
+
|
|
163
|
+
# After
|
|
164
|
+
description: >
|
|
165
|
+
Analyze CSV and tabular data files — compute summary statistics, add derived columns,
|
|
166
|
+
generate charts, and clean messy data. Use this skill when the user has a CSV, TSV,
|
|
167
|
+
or Excel file and wants to explore, transform, or visualize the data, even if they
|
|
168
|
+
don't explicitly mention "CSV" or "analysis."
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The improved description is more specific about what the skill does (summary stats, derived columns, charts, cleaning) and broader about when it applies (CSV, TSV, Excel; even without explicit keywords).
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Output Quality Evaluation
|
|
2
|
+
|
|
3
|
+
> Read this in Phase 5 (OPTIMIZE) when you need to verify that a skill actually improves output quality, not just that it triggers. Workflow skills especially benefit from this loop.
|
|
4
|
+
|
|
5
|
+
You wrote a skill, tried it on a prompt, and it seemed to work. But does it work reliably — across varied prompts, in edge cases, better than no skill at all? Structured evaluations (evals) answer these and give you a feedback loop for systematic improvement.
|
|
6
|
+
|
|
7
|
+
## Designing test cases
|
|
8
|
+
|
|
9
|
+
A test case has three parts:
|
|
10
|
+
|
|
11
|
+
- **Prompt:** a realistic user message.
|
|
12
|
+
- **Expected output:** a human-readable description of what success looks like.
|
|
13
|
+
- **Input files** (optional): files the skill needs to work with.
|
|
14
|
+
|
|
15
|
+
Store test cases in `evals/evals.json` inside the skill directory:
|
|
16
|
+
|
|
17
|
+
```json evals/evals.json
|
|
18
|
+
{
|
|
19
|
+
"skill_name": "csv-analyzer",
|
|
20
|
+
"evals": [
|
|
21
|
+
{
|
|
22
|
+
"id": 1,
|
|
23
|
+
"prompt": "I have a CSV of monthly sales data in data/sales_2025.csv. Can you find the top 3 months by revenue and make a bar chart?",
|
|
24
|
+
"expected_output": "A bar chart image showing the top 3 months by revenue, with labeled axes and values.",
|
|
25
|
+
"files": ["evals/files/sales_2025.csv"]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": 2,
|
|
29
|
+
"prompt": "there's a csv in my downloads called customers.csv, some rows have missing emails — can you clean it up and tell me how many were missing?",
|
|
30
|
+
"expected_output": "A cleaned CSV with missing emails handled, plus a count of how many were missing.",
|
|
31
|
+
"files": ["evals/files/customers.csv"]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Tips for good test prompts:
|
|
38
|
+
|
|
39
|
+
- Start with 2-3. Don't over-invest before seeing the first round of results.
|
|
40
|
+
- Vary the prompts: different phrasings, detail levels, formality.
|
|
41
|
+
- Cover edge cases. Include at least one boundary condition — malformed input, unusual request, or a case where the skill's instructions might be ambiguous.
|
|
42
|
+
- Use realistic context. Real users mention file paths, column names, personal context.
|
|
43
|
+
|
|
44
|
+
Don't define specific pass/fail checks yet. Add detailed assertions after you see what the first run produces.
|
|
45
|
+
|
|
46
|
+
## Running evals
|
|
47
|
+
|
|
48
|
+
The core pattern: run each test case twice — once **with the skill**, once **without it** (or with a previous version). This gives a baseline to compare against.
|
|
49
|
+
|
|
50
|
+
### Workspace structure
|
|
51
|
+
|
|
52
|
+
Organize eval results in a workspace directory alongside the skill. Each pass through the full eval loop gets its own `iteration-N/` directory. Within that, each test case gets an eval directory with `with_skill/` and `without_skill/` subdirectories:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
csv-analyzer/
|
|
56
|
+
├── SKILL.md
|
|
57
|
+
└── evals/
|
|
58
|
+
└── evals.json
|
|
59
|
+
csv-analyzer-workspace/
|
|
60
|
+
└── iteration-1/
|
|
61
|
+
├── eval-top-months-chart/
|
|
62
|
+
│ ├── with_skill/
|
|
63
|
+
│ │ ├── outputs/ # Files produced by the run
|
|
64
|
+
│ │ ├── timing.json # Tokens and duration
|
|
65
|
+
│ │ └── grading.json # Assertion results
|
|
66
|
+
│ └── without_skill/
|
|
67
|
+
│ ├── outputs/
|
|
68
|
+
│ ├── timing.json
|
|
69
|
+
│ └── grading.json
|
|
70
|
+
├── eval-clean-missing-emails/
|
|
71
|
+
│ ├── with_skill/
|
|
72
|
+
│ │ └── ...
|
|
73
|
+
│ └── without_skill/
|
|
74
|
+
│ └── ...
|
|
75
|
+
└── benchmark.json # Aggregated statistics
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The main file you author is `evals/evals.json`. The rest (`grading.json`, `timing.json`, `benchmark.json`) are produced during the eval process.
|
|
79
|
+
|
|
80
|
+
### Spawning runs
|
|
81
|
+
|
|
82
|
+
Each run should start with a clean context — no leftover state from previous runs or skill development. In environments with subagents (Claude Code, etc.) this isolation comes naturally; without subagents, use a separate session per run.
|
|
83
|
+
|
|
84
|
+
For each run, provide:
|
|
85
|
+
|
|
86
|
+
- The skill path (or no skill for the baseline)
|
|
87
|
+
- The test prompt
|
|
88
|
+
- Any input files
|
|
89
|
+
- The output directory
|
|
90
|
+
|
|
91
|
+
Example instructions for a single with-skill run:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
Execute this task:
|
|
95
|
+
- Skill path: /path/to/csv-analyzer
|
|
96
|
+
- Task: I have a CSV of monthly sales data in data/sales_2025.csv. Can you find the top 3 months by revenue and make a bar chart?
|
|
97
|
+
- Input files: evals/files/sales_2025.csv
|
|
98
|
+
- Save outputs to: csv-analyzer-workspace/iteration-1/eval-top-months-chart/with_skill/outputs/
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For the baseline, same prompt but no skill path, saving to `without_skill/outputs/`.
|
|
102
|
+
|
|
103
|
+
When improving an existing skill, use the previous version as baseline. Snapshot before editing (`cp -r <skill-path> <workspace>/skill-snapshot/`) and point the baseline run at the snapshot.
|
|
104
|
+
|
|
105
|
+
### Capturing timing data
|
|
106
|
+
|
|
107
|
+
Record the token count and duration per run:
|
|
108
|
+
|
|
109
|
+
```json timing.json
|
|
110
|
+
{
|
|
111
|
+
"total_tokens": 84852,
|
|
112
|
+
"duration_ms": 23332
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
A skill that dramatically improves output but triples token usage is a different tradeoff than one that's both better and cheaper.
|
|
117
|
+
|
|
118
|
+
## Writing assertions
|
|
119
|
+
|
|
120
|
+
Assertions are verifiable statements about what the output should contain. Add them after you see your first round of outputs — you often don't know what "good" looks like until the skill has run.
|
|
121
|
+
|
|
122
|
+
Good assertions:
|
|
123
|
+
|
|
124
|
+
- "The output file is valid JSON" — programmatically verifiable.
|
|
125
|
+
- "The bar chart has labeled axes" — specific and observable.
|
|
126
|
+
- "The report includes at least 3 recommendations" — countable.
|
|
127
|
+
|
|
128
|
+
Weak assertions:
|
|
129
|
+
|
|
130
|
+
- "The output is good" — too vague.
|
|
131
|
+
- "The output uses exactly the phrase 'Total Revenue: $X'" — too brittle; correct output with different wording would fail.
|
|
132
|
+
|
|
133
|
+
Not everything needs an assertion. Style, visual design, "feels right" — those are better caught in human review. Reserve assertions for things checkable objectively.
|
|
134
|
+
|
|
135
|
+
Add to each test case in `evals/evals.json`:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"id": 1,
|
|
140
|
+
"prompt": "...",
|
|
141
|
+
"expected_output": "...",
|
|
142
|
+
"files": ["evals/files/sales_2025.csv"],
|
|
143
|
+
"assertions": [
|
|
144
|
+
"The output includes a bar chart image file",
|
|
145
|
+
"The chart shows exactly 3 months",
|
|
146
|
+
"Both axes are labeled",
|
|
147
|
+
"The chart title or caption mentions revenue"
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Grading outputs
|
|
153
|
+
|
|
154
|
+
Evaluate each assertion against the actual outputs and record **PASS** or **FAIL** with specific evidence. The evidence should quote or reference the output, not just state an opinion.
|
|
155
|
+
|
|
156
|
+
Simplest approach: give outputs and assertions to an LLM and ask it to evaluate each one. For code-checkable assertions (valid JSON, correct row count, file exists with expected dimensions), use a verification script — more reliable than LLM judgment for mechanical checks, and reusable across iterations.
|
|
157
|
+
|
|
158
|
+
```json grading.json
|
|
159
|
+
{
|
|
160
|
+
"assertion_results": [
|
|
161
|
+
{
|
|
162
|
+
"text": "The output includes a bar chart image file",
|
|
163
|
+
"passed": true,
|
|
164
|
+
"evidence": "Found chart.png (45KB) in outputs directory"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"text": "The chart shows exactly 3 months",
|
|
168
|
+
"passed": true,
|
|
169
|
+
"evidence": "Chart displays bars for March, July, November"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"text": "Both axes are labeled",
|
|
173
|
+
"passed": false,
|
|
174
|
+
"evidence": "Y-axis labeled 'Revenue ($)' but X-axis has no label"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"text": "The chart title or caption mentions revenue",
|
|
178
|
+
"passed": true,
|
|
179
|
+
"evidence": "Chart title reads 'Top 3 Months by Revenue'"
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"summary": {
|
|
183
|
+
"passed": 3,
|
|
184
|
+
"failed": 1,
|
|
185
|
+
"total": 4,
|
|
186
|
+
"pass_rate": 0.75
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Grading principles
|
|
192
|
+
|
|
193
|
+
- **Require concrete evidence for a PASS.** Don't give the benefit of the doubt. If "includes a summary" and the output has a section titled "Summary" with one vague sentence, that's a FAIL.
|
|
194
|
+
- **Review the assertions themselves, not just results.** While grading, notice when assertions are too easy (always pass), too hard (always fail), or unverifiable.
|
|
195
|
+
|
|
196
|
+
For comparing two skill versions, try **blind comparison**: present both outputs to an LLM judge without revealing which is which. Judge scores holistic qualities — organization, formatting, polish — free from bias.
|
|
197
|
+
|
|
198
|
+
## Aggregating results
|
|
199
|
+
|
|
200
|
+
Once every run in the iteration is graded, compute summary statistics per configuration and save to `benchmark.json`:
|
|
201
|
+
|
|
202
|
+
```json benchmark.json
|
|
203
|
+
{
|
|
204
|
+
"run_summary": {
|
|
205
|
+
"with_skill": {
|
|
206
|
+
"pass_rate": { "mean": 0.83, "stddev": 0.06 },
|
|
207
|
+
"time_seconds": { "mean": 45.0, "stddev": 12.0 },
|
|
208
|
+
"tokens": { "mean": 3800, "stddev": 400 }
|
|
209
|
+
},
|
|
210
|
+
"without_skill": {
|
|
211
|
+
"pass_rate": { "mean": 0.33, "stddev": 0.10 },
|
|
212
|
+
"time_seconds": { "mean": 32.0, "stddev": 8.0 },
|
|
213
|
+
"tokens": { "mean": 2100, "stddev": 300 }
|
|
214
|
+
},
|
|
215
|
+
"delta": {
|
|
216
|
+
"pass_rate": 0.50,
|
|
217
|
+
"time_seconds": 13.0,
|
|
218
|
+
"tokens": 1700
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`delta` tells you what the skill costs (more time, more tokens) and what it buys (higher pass rate). A skill that adds 13 seconds for a 50-point pass-rate jump is probably worth it. A skill that doubles tokens for 2 points might not be.
|
|
225
|
+
|
|
226
|
+
Standard deviation is meaningful only with multiple runs per eval. In early iterations with 2-3 cases and single runs, focus on raw pass counts and delta.
|
|
227
|
+
|
|
228
|
+
## Analyzing patterns
|
|
229
|
+
|
|
230
|
+
Aggregate statistics can hide important patterns. After computing benchmarks:
|
|
231
|
+
|
|
232
|
+
- **Remove or replace assertions that always pass in both configurations.** They don't tell you anything.
|
|
233
|
+
- **Investigate assertions that always fail in both.** Either the assertion is broken, the test case is too hard, or the assertion checks the wrong thing.
|
|
234
|
+
- **Study assertions that pass with-skill but fail without.** That's where the skill is clearly adding value. Understand *why* — which instructions or scripts made the difference?
|
|
235
|
+
- **Tighten instructions when results are inconsistent.** High stddev means flaky eval or ambiguous skill instructions. Add examples or more specific guidance.
|
|
236
|
+
- **Check time and token outliers.** If one eval takes 3x longer, read its execution transcript to find the bottleneck.
|
|
237
|
+
|
|
238
|
+
## Reviewing results with a human
|
|
239
|
+
|
|
240
|
+
Assertion grading catches a lot, but only what you thought to check for. A human reviewer catches issues you didn't anticipate. For each test case, review the actual outputs alongside the grades.
|
|
241
|
+
|
|
242
|
+
Record feedback per test case in `feedback.json` next to the eval directories:
|
|
243
|
+
|
|
244
|
+
```json feedback.json
|
|
245
|
+
{
|
|
246
|
+
"eval-top-months-chart": "The chart is missing axis labels and the months are in alphabetical order instead of chronological.",
|
|
247
|
+
"eval-clean-missing-emails": ""
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Empty feedback means the output looked fine. Actionable feedback ("missing axis labels") beats vague ("looks bad").
|
|
252
|
+
|
|
253
|
+
## Iterating on the skill
|
|
254
|
+
|
|
255
|
+
After grading and reviewing, three sources of signal:
|
|
256
|
+
|
|
257
|
+
- **Failed assertions** point to specific gaps.
|
|
258
|
+
- **Human feedback** points to broader quality issues.
|
|
259
|
+
- **Execution transcripts** reveal *why* things went wrong.
|
|
260
|
+
|
|
261
|
+
The most effective way to turn these into improvements: give all three — along with the current `SKILL.md` — to an LLM and ask it to propose changes. When prompting the LLM, include these guidelines:
|
|
262
|
+
|
|
263
|
+
- **Generalize from feedback.** Fixes should address underlying issues broadly, not narrow patches for specific examples.
|
|
264
|
+
- **Keep the skill lean.** Fewer, better instructions often outperform exhaustive rules. If pass rates plateau despite adding rules, the skill may be over-constrained — try removing instructions.
|
|
265
|
+
- **Explain the why.** Reasoning-based instructions ("Do X because Y tends to cause Z") work better than rigid directives.
|
|
266
|
+
- **Bundle repeated work.** If every test run independently wrote a similar helper script, that's the signal to bundle it.
|
|
267
|
+
|
|
268
|
+
### The loop
|
|
269
|
+
|
|
270
|
+
1. Give the eval signals and current `SKILL.md` to an LLM; ask it to propose improvements.
|
|
271
|
+
2. Review and apply changes.
|
|
272
|
+
3. Rerun all test cases in a new `iteration-<N+1>/` directory.
|
|
273
|
+
4. Grade and aggregate.
|
|
274
|
+
5. Review with a human. Repeat.
|
|
275
|
+
|
|
276
|
+
Stop when you're satisfied, feedback is consistently empty, or you're not seeing meaningful improvement between iterations.
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Scripts Guide
|
|
2
|
+
|
|
3
|
+
> Read this when designing or bundling scripts in the `scripts/` directory of a skill. The agent runs your scripts and reads stdout/stderr to decide what to do next — design choices here have outsized impact on reliability.
|
|
4
|
+
|
|
5
|
+
## One-off commands
|
|
6
|
+
|
|
7
|
+
When an existing package already does what you need, reference it directly in `SKILL.md` without a `scripts/` directory. Many ecosystems provide tools that auto-resolve dependencies at runtime.
|
|
8
|
+
|
|
9
|
+
| Runner | Install | Use when |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `uvx` | Ships with `uv` | Python tools, fast, caches aggressively |
|
|
12
|
+
| `pipx` | OS package manager | Python tools, mature, broad OS availability |
|
|
13
|
+
| `npx` | Ships with npm | Node tools, no extra install |
|
|
14
|
+
| `bunx` | Ships with Bun | Node tools, Bun environment |
|
|
15
|
+
| `deno run` | Ships with Deno | TS/JS with permission flags |
|
|
16
|
+
| `go run` | Built into Go | Go tools, pinned versions |
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
uvx ruff@0.8.0 check .
|
|
22
|
+
npx eslint@9 --fix .
|
|
23
|
+
deno run --allow-read npm:eslint@9 -- --fix .
|
|
24
|
+
go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 run
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Tips for one-off commands in skills:
|
|
28
|
+
|
|
29
|
+
- **Pin versions** (`npx eslint@9.0.0`) so the command behaves the same over time.
|
|
30
|
+
- **State prerequisites** in `SKILL.md` ("Requires Node.js 18+"). For runtime-level requirements, use the `compatibility` frontmatter field.
|
|
31
|
+
- **Move complex commands into scripts.** When a command grows complex enough that it's hard to get right on the first try, bundle a tested script.
|
|
32
|
+
|
|
33
|
+
## Referencing scripts from `SKILL.md`
|
|
34
|
+
|
|
35
|
+
Use **relative paths from the skill directory root** to reference bundled files. The agent resolves these automatically.
|
|
36
|
+
|
|
37
|
+
List available scripts in your `SKILL.md` so the agent knows they exist:
|
|
38
|
+
|
|
39
|
+
```markdown
|
|
40
|
+
## Available scripts
|
|
41
|
+
|
|
42
|
+
- **`scripts/validate.sh`** — Validates configuration files
|
|
43
|
+
- **`scripts/process.py`** — Processes input data
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then instruct the agent to run them:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
## Workflow
|
|
50
|
+
|
|
51
|
+
1. Run the validation script:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
bash scripts/validate.sh "$INPUT_FILE"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. Process the results:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python3 scripts/process.py --input results.json
|
|
61
|
+
```
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The same relative-path convention works in support files like `references/*.md` — script execution paths are relative to the **skill directory root**.
|
|
65
|
+
|
|
66
|
+
## Self-contained scripts
|
|
67
|
+
|
|
68
|
+
When you need reusable logic, bundle a script in `scripts/` that declares its own dependencies inline. The agent can run it with a single command — no separate manifest or install step.
|
|
69
|
+
|
|
70
|
+
### Python (PEP 723)
|
|
71
|
+
|
|
72
|
+
Declare dependencies in a TOML block inside `# ///` markers:
|
|
73
|
+
|
|
74
|
+
```python scripts/extract.py
|
|
75
|
+
# /// script
|
|
76
|
+
# dependencies = [
|
|
77
|
+
# "beautifulsoup4",
|
|
78
|
+
# ]
|
|
79
|
+
# requires-python = ">=3.11"
|
|
80
|
+
# ///
|
|
81
|
+
|
|
82
|
+
from bs4 import BeautifulSoup
|
|
83
|
+
|
|
84
|
+
html = '<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>'
|
|
85
|
+
print(BeautifulSoup(html, "html.parser").select_one("p.info").get_text())
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Run with `uv` (recommended):
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
uv run scripts/extract.py
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`uv run` creates an isolated environment, installs declared dependencies, and runs the script. Pin with PEP 508 specifiers: `"beautifulsoup4>=4.12,<5"`. Use `uv lock --script` to create a lockfile for full reproducibility.
|
|
95
|
+
|
|
96
|
+
### Deno
|
|
97
|
+
|
|
98
|
+
`npm:` and `jsr:` import specifiers make every script self-contained:
|
|
99
|
+
|
|
100
|
+
```typescript scripts/extract.ts
|
|
101
|
+
#!/usr/bin/env -S deno run
|
|
102
|
+
|
|
103
|
+
import * as cheerio from "npm:cheerio@1.0.0";
|
|
104
|
+
|
|
105
|
+
const html = `<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>`;
|
|
106
|
+
const $ = cheerio.load(html);
|
|
107
|
+
console.log($("p.info").text());
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
deno run scripts/extract.ts
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use `npm:` for npm packages, `jsr:` for Deno-native. Pin with semver: `@1.0.0` exact, `@^1.0.0` compatible. Packages with native addons (node-gyp) may not work; pre-built binaries work best.
|
|
115
|
+
|
|
116
|
+
### Bun
|
|
117
|
+
|
|
118
|
+
Bun auto-installs missing packages at runtime when no `node_modules/` exists. Pin versions in the import path:
|
|
119
|
+
|
|
120
|
+
```typescript scripts/extract.ts
|
|
121
|
+
#!/usr/bin/env bun
|
|
122
|
+
|
|
123
|
+
import * as cheerio from "cheerio@1.0.0";
|
|
124
|
+
|
|
125
|
+
const html = `<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>`;
|
|
126
|
+
const $ = cheerio.load(html);
|
|
127
|
+
console.log($("p.info").text());
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
bun run scripts/extract.ts
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
No `package.json` or `node_modules` needed; TypeScript works natively. If a `node_modules` exists anywhere up the tree, auto-install is disabled and Bun falls back to standard Node resolution.
|
|
135
|
+
|
|
136
|
+
### Ruby
|
|
137
|
+
|
|
138
|
+
Bundler ships with Ruby since 2.6. Use `bundler/inline` to declare gems in the script:
|
|
139
|
+
|
|
140
|
+
```ruby scripts/extract.rb
|
|
141
|
+
require 'bundler/inline'
|
|
142
|
+
|
|
143
|
+
gemfile do
|
|
144
|
+
source 'https://rubygems.org'
|
|
145
|
+
gem 'nokogiri'
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
html = '<html><body><h1>Welcome</h1><p class="info">This is a test.</p></body></html>'
|
|
149
|
+
doc = Nokogiri::HTML(html)
|
|
150
|
+
puts doc.at_css('p.info').text
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
ruby scripts/extract.rb
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Pin versions explicitly (`gem 'nokogiri', '~> 1.16'`) — there's no lockfile. An existing `Gemfile` or `BUNDLE_GEMFILE` env var in the working directory can interfere.
|
|
158
|
+
|
|
159
|
+
## Designing scripts for agentic use
|
|
160
|
+
|
|
161
|
+
When the agent runs your script, it reads stdout and stderr to decide what to do next. A few design choices make scripts dramatically easier to use.
|
|
162
|
+
|
|
163
|
+
### Avoid interactive prompts
|
|
164
|
+
|
|
165
|
+
Hard requirement of the agent environment. Agents operate in non-interactive shells — they cannot respond to TTY prompts, password dialogs, or confirmation menus. A script that blocks on interactive input will hang indefinitely.
|
|
166
|
+
|
|
167
|
+
Accept all input via command-line flags, environment variables, or stdin:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
# Bad: hangs waiting for input
|
|
171
|
+
$ python scripts/deploy.py
|
|
172
|
+
Target environment: _
|
|
173
|
+
|
|
174
|
+
# Good: clear error with guidance
|
|
175
|
+
$ python scripts/deploy.py
|
|
176
|
+
Error: --env is required. Options: development, staging, production.
|
|
177
|
+
Usage: python scripts/deploy.py --env staging --tag v1.2.3
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Document usage with `--help`
|
|
181
|
+
|
|
182
|
+
`--help` output is the primary way an agent learns your script's interface. Include a brief description, available flags, and usage examples:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
Usage: scripts/process.py [OPTIONS] INPUT_FILE
|
|
186
|
+
|
|
187
|
+
Process input data and produce a summary report.
|
|
188
|
+
|
|
189
|
+
Options:
|
|
190
|
+
--format FORMAT Output format: json, csv, table (default: json)
|
|
191
|
+
--output FILE Write output to FILE instead of stdout
|
|
192
|
+
--verbose Print progress to stderr
|
|
193
|
+
|
|
194
|
+
Examples:
|
|
195
|
+
scripts/process.py data.csv
|
|
196
|
+
scripts/process.py --format csv --output report.csv data.csv
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Keep it concise — the output enters the agent's context window alongside everything else.
|
|
200
|
+
|
|
201
|
+
### Write helpful error messages
|
|
202
|
+
|
|
203
|
+
When an agent gets an error, the message directly shapes its next attempt. Opaque "Error: invalid input" wastes a turn. Say what went wrong, what was expected, and what to try:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
Error: --format must be one of: json, csv, table.
|
|
207
|
+
Received: "xml"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Use structured output
|
|
211
|
+
|
|
212
|
+
Prefer structured formats — JSON, CSV, TSV — over free-form text. Structured formats can be consumed by both the agent and standard tools (`jq`, `cut`, `awk`):
|
|
213
|
+
|
|
214
|
+
```text
|
|
215
|
+
# Whitespace-aligned — hard to parse
|
|
216
|
+
NAME STATUS CREATED
|
|
217
|
+
my-service running 2025-01-15
|
|
218
|
+
|
|
219
|
+
# Delimited — unambiguous
|
|
220
|
+
{"name": "my-service", "status": "running", "created": "2025-01-15"}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Separate data from diagnostics:** send structured data to stdout and progress messages, warnings, and other diagnostics to stderr. The agent can capture clean output while keeping access to diagnostic info.
|
|
224
|
+
|
|
225
|
+
### Further considerations
|
|
226
|
+
|
|
227
|
+
- **Idempotency.** Agents may retry. "Create if not exists" is safer than "create and fail on duplicate."
|
|
228
|
+
- **Input constraints.** Reject ambiguous input with a clear error rather than guessing. Use enums and closed sets where possible.
|
|
229
|
+
- **Dry-run support.** For destructive or stateful operations, a `--dry-run` flag lets the agent preview what will happen.
|
|
230
|
+
- **Meaningful exit codes.** Use distinct exit codes for different failure types (not found, invalid arguments, auth failure) and document them in `--help` so the agent knows what each code means.
|
|
231
|
+
- **Safe defaults.** Consider whether destructive operations should require explicit confirmation (`--confirm`, `--force`) or other safeguards appropriate to the risk level.
|
|
232
|
+
- **Predictable output size.** Many harnesses automatically truncate tool output beyond a threshold (e.g. 10-30K characters), potentially losing critical information. If your script may produce large output, default to a summary and support flags like `--offset` for pagination, or require an explicit `--output` flag.
|