anthropics / anthropics/claude-plugins-official

`run_eval.py` always reports 0% recall: it probes a `.claude/commands/` slash-command proxy instead of the real installed skill

Open
#3,174 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
36.3k
Forks
4.1k
Avg merge
2d 14h
Merged PRs (30d)
539

Description

**Plugin:** `skill-creator` (this repo, `plugins/skill-creator/.../scripts/run_eval.py`)
**Claude Code:** 2.1.185
**Affects:** `run_eval.py` and therefore `run_loop.py` (the description-optimization loop)

## Summary

The description-optimization eval always reports **recall = 0% / precision = 100% / accuracy = 50%** for every skill and every description — i.e. the target skill is *never* detected as triggering. This makes the entire `run_loop` description optimizer unusable: it can never observe a should-trigger query firing, so it has no real signal to optimize against.

This has been reported before in anthropics/claude-code#36570 and anthropics/claude-code#32184, where it was attributed to *"`claude -p` can't auto-trigger skills in headless mode"* and closed **"not planned."** **That attribution is now incomplete/outdated** — see below. The remaining, still-present root cause lives in this plugin's harness.

## Root cause

`run_eval.py` does not test the real installed skill. For each query it:

1. Writes a throwaway **slash command** to `/.claude/commands/.md` (comment in source: *"Creates a command file in .claude/commands/ so it appears in Claude's available_skills list"*), then
2. runs `claude -p --output-format stream-json` and counts a "trigger" only if the model's first tool call is a `Skill` (or `Read`) tool whose argument contains that **temp command's** name.

Two problems make this structurally unable to detect a trigger:

- **Commands are not model-auto-invoked the way skills are.** A file in `.claude/commands/` is a user-typed slash command (`/name`), not an entry the model selects from `available_skills` and invokes via the `Skill` tool. So the probe artifact never fires.
- **Even when the model *does* auto-trigger a skill, the name won't match.** The model triggers the real installed skill (its own `name`), but the detector is looking for the temp command's randomized `clean_name`. During `run_loop`, the description being optimized is the temp command's — the real skill's description is never varied — so optimization can't affect triggering either.

## Evidence that this is the harness, not `claude -p`

On 2.1.185, `claude -p` **does** auto-trigger real installed skills. Minimal check:

```bash
# real skill installed at ~/.claude/skills//SKILL.md
env -u CLAUDECODE claude -p "" \
--output-format stream-json --include-partial-messages --verbose \
--model --max-turns 1 | grep -o '"skill":"[^"]*"'
# -> "skill":"" # i.e. it triggered
```

In the **same environment**, against the **same skill**:
- `run_eval.py` (command proxy) → **recall 0%**
- a one-file harness that checks the **real** skill name in the `Skill` tool call → **recall ~100%**, specificity high.

So `claude -p` headless triggering works now; the harness reports 0% purely because it inspects the wrong artifact. (This is distinct from the historical anthropics/claude-code#32184 / anthropics/claude-code#36570 reports, which described `claude -p` not triggering skills at all in early 2026 — that part appears to have improved since.)

## Suggested fix

Test the **real** skill instead of a command proxy:

- Stage the candidate description onto the actual skill (write `SKILL.md` into a temp `.claude/skills//`, or temporarily swap the description of the installed skill), and
- detect triggering by matching the **real skill name** in the `Skill` tool invocation (`tool_use.name == "Skill"` and `input.skill == `), not a `.claude/commands/` proxy name.

A ~60-line reference harness doing exactly this (per-query `claude -p`, regex on `"skill":""`, recall/specificity scoring) reproduces correct numbers and can be shared if useful.

## Repro

1. Install a skill at `~/.claude/skills//SKILL.md` with a clear description.
2. Create an eval set of should-trigger queries.
3. Run `python -m scripts.run_eval --eval-set .json --skill-path --model ` → recall 0% for all should-trigger queries, despite the skill triggering fine when `claude -p` is run directly.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with plugins/skill-creator/.../scripts/run_eval.py and trace how it creates the temporary .claude/commands/ proxy, invokes claude -p, and identifies triggers; then inspect the affected run_loop.py flow. Reproduce the reported eval command against an installed skill and compare its result with the real Skill invocation described in the issue. Done means the eval varies and detects the actual installed skill and produces meaningful recall and specificity results.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
cli, testing, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.