# 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](agentskills.md) | ## 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.py` or `run.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: ```yaml rules: agentskill-unreferenced-files: exclude: - "assets/fonts/*" ``` 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 ```yaml rules: agentskill-unreferenced-files: enabled: auto # true | false | auto severity: warning ``` | 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.*