agentskill-unreferenced-files¶
Every bundled skill file should be referenced from SKILL.md, directly or transitively
| Severity | warning (auto) |
| Autofix | - |
| Since | v0.15.0 |
| Repo Types | agent-plugin, agentskills, antigravity-plugin, codex-marketplace, codex-plugin, dot-claude, grok-marketplace, grok-plugin, marketplace, single-plugin |
| Category | agentskills.io |
Why¶
Every file bundled in a skill directory should be reachable from SKILL.md. An unreferenced file is dead weight in the skill package — it ships to every consumer, inflates installs, and rots silently because nothing points at it.
It is also a security risk: unreferenced files can bundle hidden or untrusted functionality that reviewers skip because the skill instructions never ask an agent to open or run them.
What counts as a reference¶
A file is referenced when its path or filename is mentioned in SKILL.md or
transitively in any local file reachable from SKILL.md (e.g. SKILL.md →
references/a.md → references/b.md). A skill-root README.md and
agents/openai.yaml also count as reference roots.
Mentions are detected in markdown links, inline code spans, fenced code blocks, and plain prose:
- Relative paths and bare filenames (
scripts/run.pyorrun.py) - Case-insensitive filename matches
- Directory mentions covering their contents (
references/or./assets) - Directories loaded as a whole by a script — globbed (
schemas/*.xsd), joined to a base path (Path(__file__).parent / "schemas"), or enumerated (os.listdir('data'),fs.readdirSync("assets")) - Python imports resolved within the skill package
Path join operators and directory-reading calls indicate intentional directory loading; standalone words in configuration settings (like "workload_manager": "slurm") do not match directories.
Never flagged (all case-insensitive): SKILL.md itself, README and
CHANGELOG in any extension, LICENSE* and NOTICE* files (such as
LICENSE-MIT or license.txt), test files and scaffolding (evals/,
tests/, test_*.py, and testdata/), hidden files or directories,
and symlinks. You can add more patterns using the exclude option.
Consolidating findings for large directories¶
When a directory contains more unreferenced files than collapse_directory_threshold (default: 5), skillsaw groups them into a single friendly finding summarizing the contents:
⚠ [my-skill/data]: 12 unreferenced files under 'data/' (a.json, b.json,
c.json, and 9 more) — unreferenced files add unused bulk and might contain
unreviewed behavior; reference the directory from SKILL.md, or exclude it
This keeps your lint report clean and focused. To report every file individually, set collapse_directory_threshold: 0.
Files matched by a global or per-rule exclude never count toward the threshold. A baseline written before findings were consolidated lists the files one by one; it keeps suppressing the directory finding until the pile grows, and the next skillsaw baseline records the directory instead.
Examples¶
Bad:
my-skill/
SKILL.md # only mentions scripts/run.py
scripts/
run.py
cleanup.py # never mentioned anywhere — dead or hidden behavior
Good:
my-skill/
SKILL.md # "Run `python scripts/run.py`, then scripts/cleanup.py"
scripts/
run.py
cleanup.py
Also good — the script loads the directory, so its contents are not dead:
my-skill/
SKILL.md # "Run `python scripts/validate.py doc.docx`"
scripts/
validate.py # SCHEMAS = Path(__file__).parent / "schemas"
schemas/
wml.xsd
sml.xsd
How to fix¶
Delete the unreferenced file, or mention it from SKILL.md (or from a
markdown file SKILL.md references) so agents and reviewers know why it
is bundled. If the file is intentionally unlisted supporting data,
either mention its directory (assets/) from SKILL.md or add a glob
to the rule's exclude option:
A finding that names a directory rather than a file is asking the same question about the whole directory: reference it, delete it, or exclude it.
Configuration¶
| Parameter | Description | Default |
|---|---|---|
directory_mention_covers |
Treat a mention of a directory (e.g. references/, ./canvas-fonts, or assets/fonts when the directory exists) as referencing every file under it |
true |
exclude |
Additional glob patterns (matched against skill-relative paths and bare file names; a leading **/ also matches at the skill root) exempt from dead-file detection; extends the built-in exclusions (SKILL.md, README.md, CHANGELOG.md, LICENSE, NOTICE, evals/, tests/, test_*.py, testdata/, hidden files) |
[] |
collapse_directory_threshold |
Report one finding naming the directory when it holds more than this many unreferenced files, instead of one finding per file; 0 reports every file individually | 5 |
Run skillsaw explain agentskill-unreferenced-files to see this documentation and the rule's effective configuration in your terminal.