Evaluation framework for any OpenClaw skill. No claude CLI dependency — all agent execution runs through sessions_spawn + sessions_history.
Scope: Works with CLI tool skills, conversational skills, and API integration skills.
This skill performs the following actions during evaluation:
ActionPurposeWhenRead ~/.openclaw/openclaw.jsonFind skill directories (extraDirs)Path resolutionWrite to eval-workspace/Store evaluation resultsEvery eval runCall sessions_spawnRun test queries in isolated sessionsTrigger & quality testsCall sessions_historyCollect conversation data for analysisAfter each spawnPersist cleanup="keep" sessionsRequired for trigger detectionTrigger rate tests
NOT performed automatically: Gateway restart, config modification, skill installation. These require manual user action (see "Bundled Test Skill" section).
Just say:
text
evaluate weather
The agent will:
scripts/resolve_paths.py weather to find all pathseval-workspace/weather/iter-N/Options:
evaluate weather trigger — trigger rate onlyevaluate weather quality — quality compare onlyevaluate github --mode all — explicit modeWhat gets auto-detected:
evals/{skill-name}/ or fallback to evals/example-*.jsoniter-N directoryFirst step for agent: Run the resolver to get paths:
bash
python scripts/resolve_paths.py {skill-name} --mode {trigger|quality|all}
Use the JSON output to fill in paths for the workflows below.
A test skill ( test-skills/fake-tool/) is included for validating trigger rate detection. It simulates a fictional "Zephyr API" that models cannot know from training.
Manual setup required: The agent will NOT automatically install fake-tool or restart your gateway. If you want to test with fake-tool:
Copy fake-tool to your skills directory: bash
cp -r test-skills/fake-tool ~/.openclaw/workspace/skills/
Restart OpenClaw gateway (from terminal): bash
openclaw gateway restart
Verify registration: bash
python scripts/resolve_paths.py fake-tool
If step 3 returns a valid path, fake-tool is ready. If "not found", check that your ~/.openclaw/openclaw.json includes the skills directory in skills.load.extraDirs.
ScenarioWhat It TestsOutputTrigger RateDoes description trigger SKILL.md reads at the right times? Includes positive (should trigger) AND negative (should NOT trigger) cases.recall, specificity, precision, F1Quality CompareDoes skill improve output vs no-skill baseline?quality_score, assertion pass rateDescription DiagnosisWhy did triggers fail? Analyzes both false negatives AND false positives.gap analysis, recommendations
ScenarioWhat It TestsWhen to UseModel ComparisonQuality + speed across haiku/sonnet/opusBefore deployment: which model is enough?Efficiency ProfileResponse time + retry patternsWhen skill feels slow: is agent walking wrong paths?
ScenarioWhat It TestsStatusCross-skill ConflictTwo skills with overlapping descriptionsPlannedError RecoveryDoes agent recover when CLI fails?Planned
Two-layer architecture:
text
Layer 1: Agent (main OpenClaw session) — YOU ARE HERE
→ Reads evals.json
→ Calls sessions_spawn to run subagents
→ Calls sessions_history to collect results
→ Writes raw data to workspace/
Layer 2: Python analysis scripts (run via exec)
→ Read the raw data from workspace/
→ Compute statistics
→ Generate reports
Python scripts ( analyze_*.py) are data processors — they cannot call sessions_spawn. The agent drives the workflow.
Follow USAGE.md for all workflows.
Quick reference:
WorkflowWhat It TestsUSAGE.md SectionTrigger RateDoes description trigger SKILL.md reads at the right times?Workflow 1Quality CompareDoes skill improve output vs no-skill baseline?Workflow 2Model ComparisonQuality + Speed across haiku/sonnet/opusWorkflow 3Latency ProfileResponse time p50/p90Workflow 4
Each workflow follows the same pattern:
sessions_spawnsessions_historyworkspace/{skill}/iter-{n}/raw/execeval-workspace/<skill-name>/iteration-N/full_history.json (including tool_use + tool_result)FilePurposeWhen to Usegrader.mdCheck assertions, record behavior anomalies, give priority recommendationsRequired for every Quality Compare evalcomparator.mdBlind A/B comparison without assertionsWhen unbiased comparison is neededanalyzer.mdAnalyze cross-eval patterns after all evals completePost-analysis
text
eval-workspace/<skill-name>/
├── evals.json ← Eval definition (shared across iterations)
└── iteration-1/
├── raw/
│ ├── histories/ ← Trigger test session histories
│ └── transcripts/ ← Quality compare transcripts
├── trigger_results.json ← analyze_triggers output
├── quality_results.json ← analyze_quality output
└── diagnostics/
└── RECOMMENDATIONS.md
Quality Compare (prompt + assertions):
json
{
"skill_name": "my-skill",
"evals": [
{
"id": 1,
"name": "onboarding-fresh",
"prompt": "Check the weather in Tokyo",
"context": "Clean machine, no prior setup. For grader only.",
"expected_output": "Install → configure → verify profile",
"assertions": [
{
"id": "a1-1",
"description": "Install command executed",
"type": "output_contains",
"value": "pip install"
},
{
"id": "a1-2",
"description": "Profile verified after setup",
"type": "output_contains",
"value": "profile current",
"priority": true
}
]
}
]
}
Trigger Rate (query + expected):
json
{
"id": 1,
"name": "direct-weather",
"query": "What's the weather in Singapore?",
"expected": true,
"category": "positive"
}
TypeDetectionoutput_containsValue appears in conversation or tool outputoutput_not_containsValue does not appearoutput_count_maxOccurrences ≤ maxtool_calledSpecific tool called at least oncetool_not_calledSpecific tool not calledconversation_containsValue appears anywhere in conversationconversation_contains_anyAt least one value appears
Priority assertions ( "priority": true): any failure → overall=FAIL.
Gap assertions ( "note": "Best practice..."): failure = skill design gap.
text
🔴 P0 Critical — Core functionality broken
🟠 P1 High — Significantly impacts usability
🟡 P2 Medium — Room for improvement
🟢 P3 Low — Minor polish
Grader records these signals beyond assertions:
FieldTriggerpath_correctionsWrong path then self-correctedretry_countSame command executed multiple timesmissing_file_readsAttempted to read non-existent filesskipped_stepsSteps required by skill were not executedhallucinationsFabricated non-existent commands/APIs
sandbox="inherit" — subagents inherit skill registration environmentcleanup="keep" — history must be retained for trigger detectionskills.load.extraDirs (symlinks rejected)