skill-evals
Validate skill outputs against assertions, diff vs prior eval to flag regressions, file issues for new failures, and queue concrete fixes
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Validate skill outputs against assertions, diff vs prior eval to flag regressions, file issues for new failures, and queue concrete fixes
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Audit every enabled skill's upstream file dependencies for staleness — flags chained skills about to consume yesterday's article or a long-dead topic file
Compare current progress against goals with quantified status, velocity, trend, and a concrete next action per goal
First-touch review of newly opened PRs on [REPLACE: WATCHED_REPO] — verdict + welcoming comment + label
Summary of the [REPLACE: CHANNEL_PLATFORM] channel [REPLACE: CHANNEL_NAME] — top [REPLACE: TOP_N_THREADS] threads + open questions
Price and volume tracker for [REPLACE: TOKEN_SYMBOL] with anomaly alerts above [REPLACE: ALERT_THRESHOLD_PCT]% movement
Watch Vercel deploys for [REPLACE: VERCEL_PROJECT] — alert on [REPLACE: ALERT_ON] in the last [REPLACE: LOOKBACK_HOURS] hours
| name | Skill Evals |
| description | Validate skill outputs against assertions, diff vs prior eval to flag regressions, file issues for new failures, and queue concrete fixes |
| var | |
| tags | ["meta"] |
${var} — Skill name to evaluate. If empty, evaluates all skills in
evals.json.
Today is ${today}. Read memory/MEMORY.md for context.
This skill exists to catch quality regressions between runs — not just to re-state a snapshot of the latest output. The lede is what changed since last eval and what to do about it, not a flat pass/fail table.
skills/skill-evals/evals.json — assertion manifest (read with jq; if parse fails, retry once after 5s, then exit SKILL_EVALS_ERROR).aeon.yml — registered skills, enabled flags, cron schedules.memory/cron-state.json — total_runs, success_rate, last_quality_score, last_failed, last_success per skill.memory/issues/INDEX.md — currently open issues (used to dedupe issue filing in step 5b).articles/skill-evals-*.md (sorted descending, excluding today's). If none exist, mark prior_run as BOOTSTRAP — every result is NEW_*.If evals.json is missing or has zero skills keys, run ./scripts/eval-audit --stubs to scaffold a starter spec and exit SKILL_EVALS_BOOTSTRAP with a notify telling the operator to commit the stub.
Call ./scripts/eval-audit --json and parse:
summary.coverage_pct, summary.covered, summary.uncovered_enabled, summary.uncovered_disableduncovered_enabled[].skill and .inferred_pattern — these are the spec-gap candidates surfaced in the Action Queue.Do not re-implement coverage detection in prose. If the script fails, fall back to the in-memory check (compare evals.json keys to aeon.yml enabled skills) and mark eval-audit=fail in the source-status footer.
${var} is set → evaluate only that one skill (skip if not in evals.json and notify "skill-evals: ${var} has no spec — add an entry to evals.json").evals.json.a. Find latest output: glob output_pattern, sort descending by filename. If empty → status NO_OUTPUT, root_cause no_file_match, skip remaining checks.
b. Empty/stale: if file size is 0 bytes → FAIL, root_cause empty_file. If file mtime is older than 2× expected_cadence (derived from the skill's cron in aeon.yml; fall back to 14 days if cron is workflow_dispatch or unparseable) → STALE, root_cause stale_file. Stale outputs still run their assertions but are reported as STALE so dashboard noise is correct.
c. Word count: count words; fail if < min_words → root_cause word_count (record actual vs threshold).
d. Required patterns: for each pattern (pipe-separated alternatives), grep with -E. Missing → root_cause missing_pattern:<pattern>.
e. Forbidden patterns: any match → root_cause forbidden_pattern:<pattern>.
f. Numeric checks: for each entry, extract first regex match. Outside [min, max] → root_cause numeric_oob:<label>. If no match found and entry has skip_if_not_found: true, skip; otherwise WARN with root_cause numeric_missing:<label>.
g. Quality cross-check: read memory/skill-health/{skill}.json. If avg_score < 2.5 → status QUALITY_DEGRADED, root_cause quality_score:<avg>. If 2.5 ≤ avg_score < 3.5, record as note (no status change). If file missing, record quality=unknown.
Final status precedence: NO_OUTPUT > FAIL > STALE > QUALITY_DEGRADED > WARN > PASS.
Parse the prior eval article's results table. For each skill produce one of:
NEW_FAIL — was PASS/STALE/WARN, now FAIL/QUALITY_DEGRADED/NO_OUTPUT
FIXED — was failing, now PASS
STILL_FAIL — was failing, still failing (carry the issue ID forward)
NEW_PASS — wasn't in prior (newly added to evals.json)
NEW_NO_COVERAGE — covered prior, no eval entry now (rare; usually means evals.json edit)
STABLE — same status both runs
a. Issue filing. For every NEW_FAIL and NEW_QUALITY_DEGRADED:
memory/issues/INDEX.md — if an open issue already names this skill in the title, skip (avoid duplicates).memory/issues/ISS-{NNN}.md with frontmatter:
---
id: ISS-{NNN}
title: {skill}: {root_cause_short}
status: open
severity: {high if NEW_FAIL, medium if QUALITY_DEGRADED}
category: {map root_cause: missing_pattern→prompt-bug, forbidden_pattern→prompt-bug, numeric_oob→quality-regression, word_count→quality-regression, stale_file→missing-secret-or-cron, empty_file→quality-regression, quality_score→quality-regression, no_file_match→missing-secret-or-cron}
detected_by: skill-evals
detected_at: {ISO timestamp}
affected_skills: [{skill}]
root_cause: {full root_cause string}
---
{one-paragraph context with file path, expected vs actual, link to article}
{NNN} = next free 3-digit ID (scan memory/issues/ISS-*.md, take max + 1, zero-pad).memory/issues/INDEX.md Open table.b. Issue closing. For every FIXED: scan memory/issues/ISS-*.md for an open issue whose affected_skills contains this skill and detected_by: skill-evals; flip status: resolved, set resolved_at, move row from Open → Resolved table in INDEX.md. (Don't touch issues filed by other detectors.)
One-line verdict, picked by precedence:
SKILL_EVALS_REGRESSED — any NEW_FAIL existsSKILL_EVALS_QUALITY_DROP — any NEW_QUALITY_DEGRADED (no NEW_FAIL)SKILL_EVALS_RECOVERED — FIXED ≥ 1 and zero new failuresSKILL_EVALS_COVERAGE_CLIFF — coverage_pct dropped ≥ 10 points vs last run, or absolute coverage_pct < 25 and last run was ≥ 25SKILL_EVALS_OK — all stable, all greenA short, ordered, concrete checklist at the top of the article. Cap at 8 items. Each item is one line, naming a specific skill and a specific next step:
Patch evals.json:{skill} — {root_cause}Investigate {skill} — {root_cause} (ISS-{NNN})Dispatch {skill} — no output in {N} daysAdd evals.json entry for {skill} — pattern: {inferred_pattern} (one line per uncovered enabled skill, max 5; if more, summarize "+N more — see Coverage Gaps")If the queue is empty, write Action Queue: none — all green.
Path: articles/skill-evals-${today}.md. Skeleton:
# Skill Evals — ${today}
**Verdict:** {VERDICT}
**Coverage:** {covered}/{enabled_total} ({coverage_pct}%) {↑↓ vs prior or "(first run)"}
**Diff:** {N_NEW_FAIL} new fail · {N_FIXED} fixed · {N_STILL_FAIL} still failing · {N_STABLE} stable
## Action Queue
1. ...
2. ...
## Regressions (NEW_FAIL + NEW_QUALITY_DEGRADED)
| Skill | Status | Root cause | Issue |
|-------|--------|------------|-------|
| ... | NEW_FAIL | missing_pattern:stars | ISS-014 |
## Recovered (FIXED)
| Skill | Was | Now |
|-------|-----|-----|
## Still Failing
| Skill | Status | Root cause | Issue | Failing since |
|-------|--------|------------|-------|---------------|
## Full Results
| Skill | Status | Diff | Root cause | Quality | Words | Last output |
|-------|--------|------|------------|---------|-------|-------------|
## Coverage Gaps (enabled in aeon.yml, missing from evals.json)
- {skill} — inferred pattern: `{inferred_pattern}`
## Sources
- evals.json={ok|fail} · cron-state={ok|fail} · skill-health={ok|empty|fail} · eval-audit={ok|fail} · prior-article={ok|none}
Omit empty sections (no Recovered section if zero FIXED, etc.). Keep the Coverage Gaps section bounded to 10 lines max — overflow into a +N more summary.
Only call ./notify when one of the following holds:
SKILL_EVALS_REGRESSED, SKILL_EVALS_QUALITY_DROP, or SKILL_EVALS_COVERAGE_CLIFFSKILL_EVALS_RECOVERED (good news worth a ping)Stay silent on SKILL_EVALS_OK (still write the article + log entry; just don't ping). This trains the operator that a notification means action is needed.
Notify body (concise, soul-voice):
*Skill Evals — {VERDICT}*
{N_NEW_FAIL} new fail · {N_FIXED} fixed · coverage {coverage_pct}%
Top action: {action_queue[0]}
Article: articles/skill-evals-${today}.md
If N_NEW_FAIL > 0, append the first 3 regressions as {skill}: {root_cause} lines.
Append to memory/logs/${today}.md:
### skill-evals
- Verdict: {VERDICT}
- Diff: {N_NEW_FAIL} new fail / {N_FIXED} fixed / {N_STILL_FAIL} still failing / {N_STABLE} stable
- Coverage: {covered}/{enabled_total} ({coverage_pct}%)
- Issues filed: [list ISS-IDs]
- Issues closed: [list ISS-IDs]
- Action queue head: {action_queue[0] or "none"}
All inputs are local files (evals.json, aeon.yml, memory/*, articles/*, scripts/eval-audit). No outbound HTTP — no fallback needed. ./scripts/eval-audit is a local bash script and uses jq; if jq is missing (rare on GH Actions ubuntu runners), the script will exit non-zero — mark eval-audit=fail in the source-status footer and continue with the in-memory coverage check.
ISS-{NNN} number.detected_by: skill-evals issues are closeable here).SKILL_EVALS_OK — silence is the correct signal on a green week.output_pattern, min_words, required_patterns, forbidden_patterns, numeric_checks) — additions allowed (skip_if_not_found, expected_cadence), removals are breaking.