Skip to the content.

Quality rules

Every finding the suite can emit, all 106 of them, rendered from scripts/rules.py.

sqs.py explain <CODE> prints the same reasoning at the terminal, and sqs.py rules --module security lists one module.

Each rule carries two gradings that are about the check, not about the skill:

--min-confidence high keeps the facts and drops the heuristics, which is the gate you can leave switched on in CI.

capabilities (CBxxx)

Code Severity Confidence False positives Autofix What it is
CB001 info medium medium no Bundled script can reach the network
CB002 info high low no Bundled script can spawn a process
CB003 info high low no Bundled script can read the environment
CB004 info high low no Commands run when the skill loads
CB005 warning high low no Bundled script’s capabilities cannot be read
CB006 warning high low no Bundled script needs a package the skill never names

CB001 - Bundled script can reach the network

Why it matters. An import or a command a bundled script carries - requests, socket, curl - gives it the ability to reach the network, independent of whether the specific call looks dangerous. security flags a call that is dangerous on its own; this names the capability so an installer can decide before reading every line.

Fix. Not a defect - confirm the destination matches what the skill claims to do.

CB002 - Bundled script can spawn a process

Why it matters. An import of subprocess/multiprocessing, or a call to os.system/os.popen/os.exec*, gives the script the ability to run another program with the permissions the agent has.

Fix. Not a defect - confirm the process it spawns matches what the skill claims to do.

CB003 - Bundled script can read the environment

Why it matters. os.environ/os.getenv gives a script access to whatever the process’s environment carries, which commonly includes API keys and tokens set for other tools.

Fix. Not a defect - confirm the script only reads the variables it names needing.

CB004 - Commands run when the skill loads

Why it matters. !commandin the body, and every line of a block opened with!, runs on the machine before the model is sent the skill - the output replaces the placeholder. It never prompts: a permission rule or the skill's own allowed-tools` lets it through, or the invocation aborts. A skill that pre-approves its own injected commands runs them silently on every load, before anything in it has been read. A plain code block does not stop it: watched, an injection inside one ran like any other.

Fix. Read each command as you would a hook. If the skill pre-approves them in allowed-tools, that approval is the author’s, not yours.

CB005 - Bundled script’s capabilities cannot be read

Why it matters. The script imports a module by a name it computes, reaches into os, subprocess or builtins by a computed attribute name, or passes code built at run time to exec/eval. Whatever that line does is decided by data, not by the file, so the other capability rules stay silent about it - and a silent manifest reads as “can do nothing”. The same indirection written with constants is followed and reported as the capability it spells.

Fix. Write the import or the call out plainly. If the name really has to come from data, check it against a fixed list first, and say in the skill what the list is.

CB006 - Bundled script needs a package the skill never names

Why it matters. A script imports a package outside the standard library, outside try: ... except ImportError, and neither the skill’s text, a requirements file nor the script’s inline PEP 723 block names it. The agent finds out halfway through the task, as a traceback, on every machine that does not happen to have it - and the author’s machine always does.

Fix. Name the package where the agent reads before running the script - a line in SKILL.md (“needs pymupdf: pip install pymupdf”), a requirements file, or a PEP 723 block the script runs under with uv run. If the script can do without it, import it inside try/except ImportError.

cases (CSxxx)

Code Severity Confidence False positives Autofix What it is
CS001 warning medium medium no Promise with no instruction behind it
CS002 info low medium no Expectation the description never claimed
CS003 info low high no Capability the skill never announces
CS004 info medium medium no Numbered steps no case checks

CS001 - Promise with no instruction behind it

Why it matters. The description commits to leaving something behind - a file, a note, a report - and no step in the body writes, saves or files anything. This skill passes --trigger, passes a hand-written --runtime set, and still does not deliver what it advertised, which is the failure nothing else here catches because nothing about it looks broken.

Fix. Either the body is missing the step that produces it, or the description is promising work the skill does not do. QL004 reports the same gap as a statistic; this names the clause.

CS002 - Expectation the description never claimed

Why it matters. A sentence in evals/expectations.md shares no wording with the description. The top row of the disagreement table: not a broken skill, the wrong skill for what you wrote beside it.

Fix. Not a defect. Either you are adopting the wrong skill, or the expectation belongs beside a different one - the finding names the closer skill when the tree holds one.

CS003 - Capability the skill never announces

Why it matters. A bundled script reaches the network (CB001) or spawns a process (CB002) and no wording anywhere in the skill says so. The bottom row of the disagreement table: it does Z and never mentioned it. capabilities says what a skill CAN do to the machine; this says you were not told. Reading the environment (CB003) is out of scope on purpose - the words an author would announce it with are ordinary prose in the same breath, so the test cannot tell an announcement from the subject matter.

Fix. Not a defect - say so in the body, in the sentence that sends the agent to the script.

CS004 - Numbered steps no case checks

Why it matters. The body prescribes a procedure - three or more numbered steps - and evals/evals.json exists, but no case in it carries process. Every case grades what the run left behind; none grades how it got there, so a run that skips a step or does them out of order passes as long as the answer comes out right. SkillForgeBench (arXiv 2610.14918) separates the two and finds strict process scores far below loose ones: following most steps and following every step are different measurements.

Fix. Add a process item to the case that exercises the procedure: order for the steps that must come in sequence, after/then for a check that must follow the last change. sqs.py cases <skill> --generate --format json drafts one with a TODO matcher per step. A numbered list of options rather than steps reads the same to this check - suppress it there.

compat (CPxxx)

Whether the skill will work on somebody else’s harness. UNKNOWN is never NOT_SUPPORTED: where a project’s documentation is silent, the answer is unknown rather than an invented incompatibility.

Code Severity Confidence False positives Autofix What it is
CP001 warning high low no Field value the runtime cannot read
CP002 warning high low no Field rejected by the strict reference validator
CP006 warning medium medium no Feature that does not travel
CP007 info high low no Undocumented on a target harness
CP008 error high low no Target harness refuses the skill
CP009 warning high low no No adapter for the named harness

CP001 - Field value the runtime cannot read

Why it matters. The field is read; the value is not one of the ones it accepts, so the runtime falls back to its default and says nothing.

Fix. Use one of the accepted values.

CP002 - Field rejected by the strict reference validator

Why it matters. skills-ref refuses unknown top-level fields. Real clients warn and load anyway, so the breakage only shows on publication.

Fix. Nest it under metadata:, which is the spec’s escape hatch.

CP006 - Feature that does not travel

Why it matters. The feature is real on one harness and inert or absent on another target. Nothing fails loudly: the instruction simply has no effect there.

Fix. Keep it if that harness is the only target; otherwise state the behaviour in the instructions, where every harness reads it.

CP007 - Undocumented on a target harness

Why it matters. The harness’s official documentation does not say what it does with this. That is a gap in the documentation, not a defect in the skill, and it is reported as unknown rather than as an incompatibility.

Fix. Try it once on that harness and record what happened, or avoid relying on it.

CP008 - Target harness refuses the skill

Why it matters. A rule the harness publishes is broken - a required field missing, a documented ceiling exceeded, a name that has to match its folder and does not.

Fix. Fix the field, or drop the harness from the targets.

CP009 - No adapter for the named harness

Why it matters. The target is not in the registry, so nothing about it was checked. Silence here would read as a pass.

Fix. Use a name from sqs.py harnesses, or add an adapter under scripts/harnesses/.

evals (EVxxx)

Whether anything would notice the skill breaking: the eval files, the routing invariants, and the agent runs behind sqs.py eval.

Code Severity Confidence False positives Autofix What it is
EV001 error high low no Routing invariant broken
EV002 info high low no Skill has no routing cases
EV003 error high low no Live routing run below threshold
EV004 warning high low no Malformed evals
EV005 info high low no Thin trigger set
EV006 info high low no Routing runner in the tree was not executed
EV007 warning low high no Semantic overlap between two skills
EV008 warning high low no Eval case cannot pass or fail
EV009 error high low no Eval case cannot run as written
EV010 info high medium no Trigger cases repeat the description
EV011 warning high low no Eval case uses files for an output

EV001 - Routing invariant broken

Why it matters. Two skills claim the same wording and only one can win, or a skill claims wording its own instructions do not serve.

Fix. Run run_evals.py for the detail; the fix is in the descriptions, not here.

EV002 - Skill has no routing cases

Why it matters. Nothing verifies that this skill fires on the wording a human would actually use, so every description edit moves it blind.

Fix. Add cases to evals/cases/.

EV003 - Live routing run below threshold

Why it matters. The judge sent wording to the wrong skill.

Fix. Read the failing cases: usually one description is claiming a neighbour’s branch.

EV004 - Malformed evals

Why it matters. An evals/ directory that does not parse is worse than none: it looks like the skill is tested.

Fix. evals/evals.json is {skill_name, evals: [{id, prompt, expected_output, assertions}]}; evals/eval_queries.json is [{query, should_trigger}].

EV005 - Thin trigger set

Why it matters. A trigger set with few cases on one side measures almost nothing. The negatives matter most, and the useful ones are near-misses: queries sharing keywords with the skill that need something else.

Fix. Aim for about twenty queries, eight to ten on each side.

EV006 - Routing runner in the tree was not executed

Why it matters. The routing report comes from a script that lives in the tree being checked. Running it would mean executing code out of the directory the suite was handed to read, which is the thing reading it was meant to avoid.

Fix. If the tree is yours, pass --trust-target. If it is not, a missing routing report is the correct outcome.

EV007 - Semantic overlap between two skills

Why it matters. Two skills’ trigger branches cover the same wording, so only one of them can win a request that names it - this is EV001’s claim made without executing the tree’s own run_evals.py, so it works on any skill tree, not only one that ships its own routing runner.

Fix. Read the two descriptions named in the finding; usually one needs to name the other and defer, the way QL008 and QL013 already ask for.

EV008 - Eval case cannot pass or fail

Why it matters. A case in evals/evals.json carries no assertions, outputs or judge, so nothing decides whether a run of it passed. eval --runtime would run it on both arms, spend the money, and report it as ungraded. skill-creator’s expectations do not count: a model grades them there, and nothing reads them here.

Fix. Add one checkable assertion - a literal the answer must contain, a re: pattern, an output the run has to create, with contains for what has to be in it, or a judge program whose exit code decides.

EV009 - Eval case cannot run as written

Why it matters. A case is still a draft (a field opens with TODO), names a fixture that is not in the skill, carries a re: assertion that does not compile, or has an output that is malformed, outside the run’s directory, or a binary format checked with contains, or a judge that is not an argv list or names a script the skill does not have. The first measures nothing, the second hands the agent a task about a file it never receives, and the rest crash the grader or fail every run on both arms. eval --runtime refuses the whole set until it is fixed.

Fix. Fill the draft, add the fixture under the skill or drop it, fix the pattern; check a binary output by existence, or have the task also write a text summary and check that.

EV010 - Trigger cases repeat the description

Why it matters. A should-trigger case that contains, word for word, a wording the description quotes as a trigger can pass by string match alone. It shows the listed words are there; it says nothing about the phrasings a person uses that the author did not think to list, which is what a trigger set is for. Measured on a real routing set of 105 positives: 37 were this.

Fix. Keep one such case per branch as a sanity check if you like, and write the rest the way the requests actually arrive - with context, in other words, without the listed phrase.

EV011 - Eval case uses files for an output

Why it matters. In skill-creator’s evals.json, which this set is read as, files are input paths inside the skill. This suite used to read them as outputs, so an entry that is not a file in the skill is still graded that way - the case runs - but the same file means something else to every other tool that reads it, and a missing input looks exactly like an old-style output.

Fix. Move outputs to outputs. If the entry was an input, put the file under the skill at that path.

publish (PBxxx)

What has to be true before the skill leaves the machine it was written on. Half of these are correct-and-intended for a skill that stays home.

Code Severity Confidence False positives Autofix What it is
PB001 warning high low no No license
PB002 info high low no No README
PB003 error high low no Personal path in a skill about to be published
PB004 warning high medium no Text not in the declared publication language
PB005 warning high low no Version drift
PB006 info medium medium no Private material in a skill about to be published
PB007 info high low no Package wires hooks beside this skill
PB008 warning medium medium no Skill points at a package sibling
PB009 info high low no Package installed from an unreviewed checkout
PB010 warning high medium no Instructions changed, the version did not
PB011 warning medium medium no Call surface changed, the version moved by a patch
PB012 warning medium medium no Update reaches further than the version before it
PB013 warning high low no Version went backwards
PB014 warning medium medium no README installs from somewhere this does not ship
PB015 warning high low no Repository material ships inside the skill

PB001 - No license

Why it matters. Without one, nobody may legally reuse the skill.

Fix. Add a license: field, or a LICENSE file beside the skill.

PB002 - No README

Why it matters. The SKILL.md talks to the agent. A human deciding whether to install needs a page that talks to them.

Fix. Add README.md next to the skill folder.

PB003 - Personal path in a skill about to be published

Why it matters. It leaks your directory layout and breaks on every other machine.

Fix. Replace with ~, or with a path the reader supplies.

PB004 - Text not in the declared publication language

Why it matters. A published skill documented in another language than its repository is read by nobody it was published for.

Fix. Translate, or drop --lang.

PB005 - Version drift

Why it matters. The version in the plugin or marketplace manifest disagrees with the skill’s own.

Fix. Make them agree; the manifest is usually the one that went stale.

PB006 - Private material in a skill about to be published

Why it matters. A path into a personal vault, a private repository name, an email address.

Fix. Strip it, or keep the skill unpublished.

PB007 - Package wires hooks beside this skill

Why it matters. hooks/hooks.json runs a command on its event whether or not the model ever routes to this skill. A clean verdict on SKILL.md next to an unread hooks/ directory is the most convincing wrong answer the suite can give.

Fix. Not a defect - read hooks/hooks.json before trusting the package, the way you would read a script this skill calls.

PB008 - Skill points at a package sibling

Why it matters. A command, agent or script one directory above skills/<name>/, or a path through ${CLAUDE_PLUGIN_ROOT}. The structure rules only resolve pointers inside the skill, so this one is invisible to them and breaks in silence the moment the skill is copied out of the plugin.

Fix. Declare the dependency in prose, or bring what it needs inside the skill.

PB009 - Package installed from an unreviewed checkout

Why it matters. The marketplace entry’s source names a remote repository, archive or command - the files under review may be a checkout nobody has looked at.

Fix. Not a defect - a fact about where the package came from.

PB010 - Instructions changed, the version did not

Why it matters. A skill that was improved and still carries its old version is a skill nobody can tell apart from the one they installed. PB005 catches two files contradicting each other; this catches a number that contradicts nothing and describes nothing, which is why it goes unnoticed for months.

Fix. Bump the patch, 0.0.1 at a time. Nothing rewrites it for you - the version is your claim about your own work.

PB011 - Call surface changed, the version moved by a patch

Why it matters. name, the invocation mode and allowed-tools decide how a skill is called. Moving one of them and bumping only the patch tells every reader the upgrade is safe to take without reading it.

Fix. Bump the minor or the major, whichever the break deserves.

PB012 - Update reaches further than the version before it

Why it matters. A skill keeps the trust it earned when somebody read it and installed it, while its content moves underneath. This update pre-approves a tool or a scope the earlier copy did not, or a bundled script gained network access or started spawning processes. Either one is a decision the person who installed the earlier copy never made.

Fix. Read the new reach before taking the update. If it is yours and intended, say so in the changelog and bump the minor - the reader deciding whether to update is the one who needs to know.

PB013 - Version went backwards

Why it matters. The declared version is lower than the one at --since. Replacing a patched release with an older one that still looks correctly published is how a fixed hole comes back without anybody editing anything.

Fix. If the rollback is deliberate, ship it as a new, higher version that carries the old content. A number that only ever rises is what lets a reader trust it.

PB014 - README installs from somewhere this does not ship

Why it matters. An install command in the README names this project under an owner its own git remotes and marketplace entry do not know, or installs this plugin from a marketplace other than the one listing it. A project that moved while its instructions did not sends every new user to an account that is no longer the author’s, and whoever takes that name next receives the installs.

Fix. Point the command at where the project lives now. If this is a fork telling people to install upstream, add upstream as a git remote and the finding goes away on its own.

PB015 - Repository material ships inside the skill

Why it matters. SKILL.md sits at the root of its git repository, beside tests, docs, examples or CI. An installer copies the skill’s folder, which here is the whole repository: the test corpus and the documentation land in every user’s skills directory, and every marketplace scanner reads them as the skill. A fixture of an attack that tests a scanner reads, to the next scanner, as an attack.

Fix. Move the skill into skills/<name>/ and keep the repository’s own material beside it. .sqsignore does not help: it hides a directory from this suite, not from the installer or anybody else’s scanner.

quality (QLxxx)

Whether the instructions read like instructions. The module with the most room to lie, so every rule here names a file and a line.

Code Severity Confidence False positives Autofix What it is
QL001 warning high low no Description too short to carry triggers
QL002 warning medium medium no Description states what, never when
QL003 warning low high no One branch written twice
QL004 info low high no Description and body barely overlap
QL005 warning medium high no Steering by prohibition
QL006 info medium medium no Unverifiable instruction
QL007 warning high low no TODO or placeholder left in the text
QL008 info medium medium no Disclaimer naming a neighbouring skill’s topic
QL009 info high medium no Description repeats the skill’s own name
QL010 warning medium low no Description talks about itself
QL011 error medium medium no Bundled script waits for input
QL012 info high low no Unpinned one-off command
QL013 info medium medium no Description rules out a topic
QL014 warning medium medium no Fuzzy boundary between fire and do-not-fire
QL015 warning medium low no User-invoked skill’s description is written for the router
QL016 info medium medium no Procedure written as one block of prose
QL017 info medium medium no No example anywhere in the skill
QL018 info low medium no Output produced, never checked
QL019 info medium low no Output format required, no template shown

QL001 - Description too short to carry triggers

Why it matters. Trigger conditions are the only thing the agent uses to decide whether to open the skill. Two words hold none.

Fix. State what the skill is and list the distinct branches that should reach it.

QL002 - Description states what, never when

Why it matters. A pointer does two jobs: name the material and list the branches that trigger reaching it. This one does the first only, so firing is left to chance.

Fix. Add the trigger conditions: Use when ..., Trigger on ....

QL003 - One branch written twice

Why it matters. Two trigger phrases that name the same branch cost context on every turn and sharpen nothing. The rule prints the pair, so you can judge it.

Fix. Collapse the pair into one trigger. Deliberately high-precision and therefore low-recall: it catches word-level repetition only, and the judgement-level pass over a description lives in references/writing-rubric.md.

QL004 - Description and body barely overlap

Why it matters. The skill fires on wording that its own instructions never mention, which usually means the description drifted from what the skill grew into.

Fix. Re-read the body and rewrite the description from it.

QL005 - Steering by prohibition

Why it matters. A ban drags the forbidden behaviour into context and makes it more available, not less. The negation is a weak modifier that the strongly-activated concept overruns, so the ban half-reads as an instruction to do the thing.

Fix. State the target behaviour positively, so the banned one is never spoken. Keep a prohibition only as a hard guardrail you cannot phrase positively - and pair it with the positive target.

QL006 - Unverifiable instruction

Why it matters. be thorough, write clearly, as needed: the agent cannot tell done from not-done, and neither can you.

Fix. Replace with a checkable bound, or with a bad -> good pair the reader can compare.

QL007 - TODO or placeholder left in the text

Why it matters. The agent reads it as instruction, not as a note to self.

Fix. Finish the sentence or cut it.

QL008 - Disclaimer naming a neighbouring skill’s topic

Why it matters. A description is a shop window, not a fence. Naming a neighbour’s topic makes this skill a candidate for it; negation does not reliably reverse that.

Fix. Move the boundary into the body, which is read after activation and does not affect the choice. Keep it in the description only when the neighbour can fire on its own.

QL009 - Description repeats the skill’s own name

Why it matters. Identity the body already carries, paid for on every turn.

Fix. Cut the restatement and spend the room on a trigger.

QL010 - Description talks about itself

Why it matters. The description is an instruction to the agent about when to act, not a paragraph about the skill. Use when the user ... outperforms This skill does ..., and first or second person (I can help you ...) is injected into a system prompt where the point of view does not fit.

Fix. Rewrite in the imperative, third person: what it does, then the situations that should reach it.

QL011 - Bundled script waits for input

Why it matters. Agents run in non-interactive shells. A script that blocks on a prompt does not fail - it hangs until something kills it, and the skill looks broken for reasons nothing explains.

Fix. Take every input from flags, environment variables or stdin, and fail with a message naming the missing one.

QL012 - Unpinned one-off command

Why it matters. npx eslint resolves to whatever is newest today. The skill’s behaviour then changes without the skill changing, which is the hardest kind of drift to trace.

Fix. Pin the version: npx eslint@9.0.0.

QL013 - Description rules out a topic

Why it matters. A description is matched on topic, and a negation does not reverse a match. Spelling out the work the skill will not take puts that work’s vocabulary in the one place the router reads, so the clause meant as a fence reads as one more reason to fire. QL008 is this same trap when a neighbouring skill is named; this is the version with only a topic in it, which is the common one.

Fix. Move the boundary into the body, which is read after the skill has already been chosen. Keep it in the description only when a model-invoked neighbour would otherwise take the work, and then name that neighbour rather than its topic.

QL014 - Fuzzy boundary between fire and do-not-fire

Why it matters. An exclusion clause in the description shares its topic words with a clause that claims the work. A description can separate its branches well on average and still be misrouted by one pair like this, because the router matches wording and a negation does not reverse a match. QL003 compares two clauses that agree and calls the second redundant; this compares two that disagree, where the second reads as a reason to fire rather than a reason to stay quiet.

Fix. Make the two sides differ in topic words, not only in the negation - or move the exclusion into the body, which is read after the skill has been chosen.

QL015 - User-invoked skill’s description is written for the router

Why it matters. With disable-model-invocation: true the description is not in the model’s context at all. Trigger wordings, orders to fire or not to fire, and the user spoken of in the third person are addressed to a reader who never sees them - and they take the place of the one thing the remaining reader needs: what the command does when you run it.

Fix. Rewrite the description as a one-line menu entry for a person. Keep the routing boundary, if it matters, in the body.

QL016 - Procedure written as one block of prose

Why it matters. The body has no steps - no numbered item, no step heading - and one paragraph of 200 words or more carries an order (first, then, finally). An agent reading a procedure that way has to find the step boundaries itself, and a step buried mid-sentence is the one it skips. The Stepless Workflow smell of arXiv 2607.01456, which found it in 32% of 238 marketplace skills with a model; this check sees only the extreme shape.

Fix. Split the paragraph at its steps, each one saying what it is for. Numbered or bulleted both work. Keep each step a goal, not a fixed command line: the same paper counts a rigid series of commands as a smell of its own (62%), so the fix is structure, not a script.

QL017 - No example anywhere in the skill

Why it matters. Neither SKILL.md nor any reference gives an example: no for example, no fenced block, no bad / good pair, no quoted wording. The agent works from the description of a thing alone, and fills what it has not seen with a guess. Missing Example in arXiv 2607.01456 (34% of 238 skills by a model).

Fix. Add one worked example of the input and what the skill makes of it - in SKILL.md if it is short, in a reference the body links if it is long.

QL018 - Output produced, never checked

Why it matters. The body tells the agent to write, create, render or build something, and no text in the skill mentions checking the result in any form - verify, test, compare, review, a checklist. The output is treated as done the moment it exists. No Validation Step in arXiv 2607.01456 (69% of 238 skills by a model); this check fires only where checking is never mentioned at all.

Fix. Add the check that would catch this output being wrong - run it, render it and look, compare it with the source - and what to do when it fails.

QL019 - Output format required, no template shown

Why it matters. A section is headed as the output or report format, or a sentence promises “the following format:”, and what follows is prose: no fenced block, table, list of parts, sample or linked file. The agent invents a layout each run, and two runs disagree. Missing Template in arXiv 2607.01456 (25% of 238 skills by a model).

Fix. Put the template under the heading - a fenced skeleton with the parts filled by placeholders - or link the file that holds it.

security (SExxx)

What an installed skill can do to the machine that loads it. A skill is executable text, and an installed skill is a supply chain.

Code Severity Confidence False positives Autofix What it is
SE001 error high medium no Secret in the skill text
SE002 warning medium medium no Destructive command in an instruction
SE003 error medium medium no Instruction-override text
SE004 error high low yes Hidden or bidirectional Unicode
SE005 warning medium medium no Outbound network call carrying local data
SE006 info high medium no Absolute path naming a user account
SE007 info medium low no Skill vouches for itself
SE008 error medium low no Code decoded before it runs

SE001 - Secret in the skill text

Why it matters. An API key, token or private key committed into a skill travels with every copy of it.

Fix. Revoke the credential, then remove it and read it from the environment.

SE002 - Destructive command in an instruction

Why it matters. A recursive delete, a download piped into a shell, world-writable permissions, a force push: the agent runs what the skill tells it to run.

Fix. Narrow the command, or make the step ask the human first.

SE003 - Instruction-override text

Why it matters. An instruction to disregard what came before, a claimed change of role, an order to keep something from the user. In a skill you wrote it is a mistake; in a skill you installed it is the payload.

Fix. Remove it. If the skill came from elsewhere, read the whole file before using it.

SE004 - Hidden or bidirectional Unicode

Why it matters. Zero-width and bidi control characters make the rendered text differ from the text the model reads - the Trojan Source trick.

Fix. Strip the characters. sqs.py fix removes them.

SE005 - Outbound network call carrying local data

Why it matters. A step that posts file contents to a host is exfiltration whether or not it was meant as one.

Fix. Confirm the host is yours and that the human agreed to the send.

SE006 - Absolute path naming a user account

Why it matters. C:\Users\<name>, /home/<name>: the skill only works on one machine, and it publishes whose machine that is.

Fix. Use ~, or an environment variable.

SE007 - Skill vouches for itself

Why it matters. A guarantee of safety, an endorsement by a named vendor, a count of users who trust it, or an invitation to skip review. Nothing in a skill can certify the skill: whoever wrote the files wrote the badge too. It is aimed at the router choosing between skills and at the person deciding whether to install, and it asks both to take on faith what they should check. The router’s half is a description that ranks the skill above its neighbours (“the best tool”, “better than any other”): rewriting a tool’s description that way moved its selection rate from about 20% to 81% in one published attack.

Fix. Remove the claim, or replace it with something a reader can verify - a link to an audit, a test suite, a repository with history. In a description, say when the skill applies, not how it compares.

SE008 - Code decoded before it runs

Why it matters. A script or an instruction decodes text - base64, hex, a compressed or marshalled blob - and executes the result: a decoder piped into a shell, PowerShell’s encoded-command switch, eval over a decoded string, or Python’s exec/eval over a decoder’s output. Nothing on the page says what runs, which is the purpose of writing it that way; no instruction a person has to trust needs to be unreadable to them.

Fix. Put the code in the file in plain text. If it is a vendored binary or data, ship it as a file with its source named, not as a string that is executed.

spec (SPxxx)

Agent Skills specification conformance. Everything here is something a skill survives locally and fails on publication, which is why it is a separate pass: the author never sees it until it is too late.

Code Severity Confidence False positives Autofix What it is
SP001 error high low no No frontmatter
SP002 error high low yes Required field name missing
SP003 error high low no Required field description missing
SP004 error high low yes name does not match the folder
SP005 warning high low no name longer than 64 characters
SP006 warning high low yes name off-spec
SP007 error high low no description empty
SP008 warning high low no description over 1024 characters
SP009 warning high low no compatibility over 500 characters
SP010 warning high medium no Unknown frontmatter key
SP011 error high low no Unclosed code fence
SP012 info high medium no Directory outside the conventions
SP013 info high high no Extraneous file at the skill root
SP014 error high low no No body
SP015 info high low no Multiline description
SP016 warning high medium no Oversized or binary asset
SP017 warning high medium no Reference nested too deep
SP018 error high low no XML tag in name or description
SP019 error high low no Reserved word in name
SP020 warning high low no Bare angle bracket in description

SP001 - No frontmatter

Why it matters. Without a --- block the file is plain markdown and never loads as a skill.

Fix. Open the file with ---, put name and description inside, close with ---.

SP002 - Required field name missing

Why it matters. The loader keys the skill by name; without it there is nothing to invoke.

Fix. Add name: <folder-name>.

SP003 - Required field description missing

Why it matters. The description is the skill’s only context pointer. No description, no triggering.

Fix. Add a description stating what the skill does and when to reach for it.

SP004 - name does not match the folder

Why it matters. The specification requires them equal. What actually happens is split, and the client-implementation guide states both halves: a lenient client warns and loads the skill anyway, while skills-ref validate and publication reject it. So it works on your machine and fails the moment the skill leaves it.

Fix. Rename the folder or the field so the two agree.

SP005 - name longer than 64 characters

Why it matters. Over the spec limit. Claude Code tolerates it, skills-ref validate and publication do not.

Fix. Shorten the name.

SP006 - name off-spec

Why it matters. The spec allows lowercase latin letters, digits and single inner hyphens only.

Fix. Rewrite as lower-case-with-hyphens.

SP007 - description empty

Why it matters. An empty description is the same as none: the skill never triggers.

Fix. Write the description.

SP008 - description over 1024 characters

Why it matters. Over the spec limit. It works locally and is rejected on publication.

Fix. Cut restated identity and synonym triggers; keep one trigger per branch.

SP009 - compatibility over 500 characters

Why it matters. Over the spec limit.

Fix. Shorten it.

SP010 - Unknown frontmatter key

Why it matters. A typo in a key is not a syntax error: the field silently vanishes along with its meaning, and the skill keeps loading as if nothing happened.

Fix. Fix the spelling, or drop the key.

SP011 - Unclosed code fence

Why it matters. Everything after the unclosed fence reads as code, so the instructions that follow it stop being instructions.

Fix. Close the fence.

SP012 - Directory outside the conventions

Why it matters. The specification permits any directory beside SKILL.md and calls scripts/, references/ and assets/ recommendations, so this is not a violation. It is a portability note: tools that walk the conventional layout will not see the directory, and harnesses document different sets - Cline names docs/ and templates/, Antigravity names examples/ and resources/.

Fix. Leave it if the skill links it from SKILL.md; compat says what each harness makes of it. Add the name to allow_dirs to stop being told.

SP013 - Extraneous file at the skill root

Why it matters. README.md, CHANGELOG.md, Makefile and friends are repository furniture. Inside a published skill they ship as payload nobody reads.

Fix. Keep them outside the skill folder, or accept the cost knowingly.

SP014 - No body

Why it matters. Frontmatter present, instructions absent: the skill activates and says nothing.

Fix. Write the instructions.

SP015 - Multiline description

Why it matters. A folded or literal block scalar (>-, |) is valid YAML and Claude Code reads it. It is flagged as non-portable by the vendor-neutral validators, which is as far as the evidence goes: whether a given other runtime reads it has to be tried, not assumed.

Fix. Put the description on one line if the skill has to be portable; leave it if Claude Code is the only target.

SP016 - Oversized or binary asset

Why it matters. Every byte in the skill folder travels with it. A large binary is paid for by everyone who installs the skill and read by nobody.

Fix. Host it elsewhere and link, or shrink it.

SP017 - Reference nested too deep

Why it matters. Progressive disclosure is one hop: SKILL.md names the file. Three levels down, nothing reaches the file but a reader who already knew it was there.

Fix. Flatten to references/<file>.md, or link the intermediate level explicitly.

SP018 - XML tag in name or description

Why it matters. The Agent Skills validation rules forbid XML tags in either field. The description is injected into a system prompt, where a stray tag changes how the surrounding text is read.

Fix. Remove the angle brackets; name the tag in prose instead.

SP019 - Reserved word in name

Why it matters. anthropic and claude are reserved in a skill name by the validation rules, and the refusal comes at upload time, after the skill is finished.

Fix. Rename the skill after what it does.

SP020 - Bare angle bracket in description

Why it matters. Not a tag, so SP018 stays quiet - but the validator the reference skill-creation tooling ships refuses any < or > in a description, and its packager runs that validator before packaging. An arrow or a <10MB is enough for a skill that works locally to be refused there.

Fix. Write it out: “to” for an arrow, “under 10 MB” for a comparison.

structure (STxxx)

Links, orphans, budgets, section pointers, outbound paths. This is the class of defect that breaks today, in silence: a broken pointer into references/ crashes nothing, the agent just skips the step.

Code Severity Confidence False positives Autofix What it is
ST001 error high low no Link to a file that does not exist
ST002 error high low no Broken sibling link
ST003 error high low no Link to a skill that does not exist
ST004 error high low no Linked skill has no such file
ST005 warning high medium no Orphan file
ST006 warning high low no SKILL.md over budget
ST007 warning high low no Reference over budget
ST008 warning medium medium no Pointer to a section that is gone
ST009 warning medium medium no Path naming no folder in this skill
ST010 warning medium medium no Path with no skill name
ST011 error high low no Outbound path does not exist
ST012 warning medium high no Code as prose
ST013 warning high low no Body nearly empty
ST014 error high low no Duplicate name across skills
ST015 error high low no No SKILL.md
ST016 warning unrated unrated no External link unreachable
ST017 warning high medium no Path into a tool’s folder not on this machine

Why it matters. The agent does not crash on a broken pointer: it skips the step in silence, and the only symptom is that the work came out worse than usual.

Fix. Restore the file or correct the link.

Why it matters. Same silent skip, in the short [text](neighbour.md) form that a path-shaped check cannot see.

Fix. Restore the file or correct the link.

Why it matters. A rename elsewhere left this pointer aimed at nothing.

Fix. Point at the new name, or drop the link.

ST004 - Linked skill has no such file

Why it matters. The skill is there, the file inside it is not.

Fix. Correct the path, or restore the file in the other skill.

ST005 - Orphan file

Why it matters. Nothing links to it. Either it was never wired up, or it is no longer needed. An orphan is a pruning candidate, not a defect.

Fix. Link it from SKILL.md, or delete it.

ST006 - SKILL.md over budget

Why it matters. SKILL.md is loaded whole on every activation, so its length is a permanent tax on the context window.

Fix. Move what only some branches need into references/, and keep the routing - which reference to open when - in SKILL.md.

ST007 - Reference over budget

Why it matters. A reference is opened whole too, just later. A 30 KB file cancels the point of two-stage loading.

Fix. Split it by branch.

ST008 - Pointer to a section that is gone

Why it matters. The file is in place, so an ordinary link check stays quiet while the agent opens the reference and does not find what it came for. Renaming a heading is enough.

Fix. Restore the heading, or correct the pointer - copying the section name from the file verbatim, never from memory.

ST009 - Path naming no folder in this skill

Why it matters. Almost always an example path from somebody else’s repository rather than a route of your own.

Fix. Leave it if it is an example; fix it if it was meant to be a route.

ST010 - Path with no skill name

Why it matters. The file lives in a different skill, and the bare relative path resolves there only by accident.

Fix. Spell out ~/.claude/skills/<skill>/<path>.

ST011 - Outbound path does not exist

Why it matters. A skill that reads a note before working degrades silently when the note is renamed: the theory is gone and the work goes on anyway.

Fix. Update the path. Cyrillic is compared NFC/NFD-insensitively, so a hit here is a real miss, not a normalisation artefact.

ST012 - Code as prose

Why it matters. A long executable block sitting in the text is retyped by the model every run - probabilistically, and for tokens. It cannot be run, and it cannot be fixed once.

Fix. Move it into scripts/; leave the call and how to read its output in the text.

ST013 - Body nearly empty

Why it matters. Enough text to load, not enough to act on.

Fix. Write the instructions.

ST014 - Duplicate name across skills

Why it matters. One shadows the other and which one wins is not knowable in advance.

Fix. Rename one of them.

ST015 - No SKILL.md

Why it matters. The folder is in the skills tree and holds no skill.

Fix. Add SKILL.md, or move the folder out.

Why it matters. A dead URL in a reference sends the agent to fetch nothing.

Fix. Update or remove the link. 403 is reported separately: it usually means the site blocks bots, not that the page is gone.

ST017 - Path into a tool’s folder not on this machine

Why it matters. A path under ~/.claude, ~/.config/<tool>, a dot-folder or a platform config root exists only where that tool is installed. On a CI runner or a fresh machine it is missing, and a missing install cannot be told from a broken path.

Fix. Check it on a machine with the tool installed. If the file only describes install locations, waive it for the file with sqs-allow-file: ST017.