Skip to content

Why your Claude Code skill never triggers

By Randy Olson, Co-Founder & CTO, Goodeye

You installed a skill, the work came back as though it did not exist, and nothing anywhere told you why. No error. No log line. No "skill not found". The agent simply answered without it.

That silence is the real difficulty. Three unrelated failures produce exactly the same symptom, and they take three different fixes, so the first job is finding out which one you have. Rewriting a description that was never loaded is a wasted afternoon.

The three gates a skill has to clear

A skill changes nothing you can see until it passes all three of these.

It has to load. The harness reads skills off disk when a session starts. The file has to sit in the directory that harness reads, under the exact filename it expects, with front matter it can parse.

It has to win the match. Once loaded, your skill sits beside every other loaded skill, and the agent chooses one by reading descriptions. Yours can lose that comparison without anything being wrong with it.

It has to be current on the machine doing the work. Your copy and your teammate's copy are two different files on two different disks. Only one of them may have your fix.

Each gate fails with its own signature. Walk them in order, because each one is cheaper to rule out than the one after it.

Gate 1: confirm it loaded

Ask the agent what it can see:

What skills do you have access to?

If your skill is not in the list it returns, stop here. Nothing downstream matters yet. Three things keep a skill off that list, and all three are silent.

The file is in a directory the harness does not read. Claude Code reads ~/.claude/skills for personal skills and .claude/skills in the project root for project skills. Codex reads ~/.agents/skills. Cursor reads ~/.cursor/skills. A skill in the wrong one of those is not a broken skill, it is an absent one:

ls ~/.claude/skills/my-skill/SKILL.md

Unpacking an archive is the usual way this happens, because it leaves you with ~/.claude/skills/my-skill/my-skill/SKILL.md and the extra level is enough to hide it.

The filename is not exactly SKILL.md. Capitals on both words. skill.md and Skill.md are ignored rather than corrected.

The front matter does not parse. It has to open on the very first line with ---, close with --- on its own line, and hold valid YAML with at least name and description. A tab where spaces belong, a colon inside an unquoted value, or one blank line above the opening marker takes the whole skill out of play.

One more thing belongs at this gate, and it catches more people than the other three combined: skills load when a session starts. A skill installed into a session that is already running is invisible to that session. If you have been editing and re-asking in the same window, every one of those tests ran against the list loaded before your first edit. Open a new session, then test.

If you sync from goodeye, this gate mostly stops being something you check by hand. goodeye skills sync pull writes each skill to <target>/<slug>/SKILL.md under a target you registered once:

goodeye skills sync target add --preset claude
goodeye skills sync pull

The layout is then correct by construction, on every machine that pulls.

Gate 2: it loaded and still lost the match

The skill is in the list and stays idle anyway. This is a description problem almost every time.

Your agent reads your description next to every other loaded description at the same moment, then picks one. It has not opened your skill body, so anything you can do that is documented only in the body is invisible at the moment of the decision. A capability you never named in the description cannot be chosen.

Two patterns account for most of it. The first is a description written to explain what the skill is rather than the situation someone is in when they need it, which leaves the agent nothing to match a prompt against. The second is a neighboring skill claiming the same ground more specifically than you claimed it, which shows up as a skill that fires sometimes and not others. Both, and the measured evidence behind them, are covered in write a skill description your agent actually uses.

You will also see imperative phrasing recommended for this, along the lines of writing "this skill MUST be invoked when the user says X". It circulates because it does help some people. Treat it as a hypothesis about your own skill rather than a rule, because the thing that decides is how your description reads beside the specific set of skills you have installed, and no phrasing convention can tell you that from the outside. Test it the same way you would test any other edit.

To judge a description on its own terms in one command, run the hosted authoring check against it:

goodeye verifiers run system:skill-discovery-coherence \
  --inputs-json '{"body":"<your SKILL.md body>","description":"<your description>","outcome":"(none declared)"}' \
  --json

That tells you whether the description names the job and the trigger. It does not tell you whether the skill wins against the others on your disk. For that, route prompts at it:

goodeye skills optimize-description my-skill

The command hands your agent a procedure it runs locally: write prompts that should fire the skill and near-misses that should not, take the right answers from the skill body rather than from the description under test, judge each one blind, and report which skill actually loaded for each prompt. The rows that went the wrong way are your edit list. It changes the description only, draws no credits, and saves nothing until you approve it.

Gate 3: it fires for you and not for your teammate

This one gets misdiagnosed as gate 2 constantly, and the misdiagnosis is expensive: you rewrite a description that was working, and now it is worse for everybody.

The tell is that the skill behaves correctly on the machine you fixed it on. Nothing about the description explains a result that changes with whose laptop runs it. What changes is which copy of the file is on that disk.

Check what is actually there, on the machine that is quiet:

goodeye skills sync status

That reads only, and reports each skill as clean, edited locally, behind the registry, conflicted, deleted upstream, or untracked. Anything other than clean is your answer. "Behind the registry" means your fix has not landed there yet and a pull will bring it. "Edited locally" means somebody changed the file on disk instead of publishing, so their machine has quietly forked away from the version everyone else runs:

goodeye skills sync pull
goodeye skills sync pull --force

The second form overwrites local edits with the hosted copy, which is what you want once you know the local edit was not deliberate.

Then check the simplest explanation of all, which is that the teammate never had the skill:

goodeye skills grants my-skill

Access is granted per user or per team, and a person who was never granted anything has nothing to sync. That listing shows who has access today, at what role, and who granted it.

Where to start

Do this before you change a line of the description. Open a fresh session, ask the agent what skills it can see, and note whether yours is in the list. That one answer sends you to gate 1 or gate 2 and costs you thirty seconds.

If the skill only misbehaves for other people, skip both and run goodeye skills sync status on one of their machines instead.

Once the skill fires reliably, the next thing worth pinning down is what its output has to be right about, rather than whether it ran at all: run a rubric check on AI output from the CLI covers writing a check the work has to pass and deploying it so everyone runs that exact one.

Frequently asked questions

Why does my Claude Code skill never trigger?

One of three things has gone wrong, and they need different fixes. Either the harness never loaded the file, which is a path, filename, or front matter problem, or it loaded the skill and the description lost the match against another installed skill, or the machine doing the work holds an older copy than the one you fixed. Check them in that order, because each one is cheap to rule out and rewriting a description that was never loaded wastes an afternoon. Start by asking the agent what skills it can see: if yours is missing from the list, the problem is placement, and if it is present but idle, the problem is the description.

How do I know whether Claude Code loaded my skill at all?

Ask it directly. Send "what skills do you have access to?" and read the list it returns. A skill that is missing from that list was never loaded, so no amount of description tuning will help. Then confirm the file is where the harness looks: ls ~/.claude/skills/my-skill/SKILL.md for a personal Claude Code skill, or .claude/skills/ inside the project root for a project skill. Codex reads ~/.agents/skills and Cursor reads ~/.cursor/skills. The filename has to be exactly SKILL.md in capitals, and the front matter has to open on line 1 with --- and parse as YAML with at least name and description.

Why does a skill work on my machine but not my teammate's?

Because those are two different files, and only yours has the fix. This is the failure most often misdiagnosed as a description problem, and rewriting the description makes it worse for everyone. In Goodeye each machine mirrors one hosted skill rather than holding an independent copy, so goodeye skills sync status on the quiet machine tells you what is actually there: clean, edited locally, behind the registry, conflicted, deleted upstream, or untracked. Anything other than clean explains the symptom. Also check goodeye skills grants my-skill, because a teammate who was never granted access has nothing to sync in the first place.

Do I need to restart Claude Code after installing a skill?

Yes. Skills are read at session start, so a skill you install into a running session is invisible to that session no matter how well it is written. End the session and open a new one before you conclude anything is broken. This catches people mid-debug more than any other single cause, because the natural loop is to edit the description, ask again in the same window, see nothing change, and edit again. Every one of those edits is being tested against the skill list the session loaded before your first change. Restart first, then test.

How do I test whether a skill fires before I rely on it?

Route real prompts at it and watch where they land, because reading your own description tells you almost nothing about how it reads beside every other one installed. goodeye skills optimize-description my-skill returns a set of instructions your agent runs locally: it writes prompts that should fire the skill and near-misses that should not, judges each one blind, and shows you a row per prompt with the skill that actually loaded. It changes the description only, spends no credits, and saves nothing until you approve it. The wrong rows are your edit list.