Supporting Files and Scripts
- Structure a skill directory with supporting files that Claude loads on demand
- Bundle a script with a skill using <code>${CLAUDE_SKILL_DIR}</code> for portable path references
- Apply the visual output pattern to generate interactive HTML reports from inside a skill
When SKILL.md is not enough
A skill that helps Claude write database migrations needs to know your schema conventions, your down-migration format, your team's naming rules, and a dozen edge cases from past incidents. You could put all of that in SKILL.md, but a 2,000-line SKILL.md that loads into context every time someone asks about a migration is wasteful. Most of that content is only needed occasionally.
Skills support a full directory structure. SKILL.md is the required entrypoint — everything else is optional and loaded on demand.
The skill directory structure
my-skill/
├── SKILL.md # Main instructions (required, keep under 500 lines)
├── reference.md # Detailed reference — loaded when needed
├── examples/
│ └── sample-output.md # Example output showing expected format
└── scripts/
└── generate.py # Executable script Claude can run
Reference the supporting files from SKILL.md so Claude knows they exist and when to consult them:
---
name: db-migration
description: Write and review database migrations safely
allowed-tools: Bash(psql *) Read
---
## Instructions
Write migrations following the project's conventions. When you need schema details or past incident patterns:
- See [reference.md](reference.md) for complete naming and type conventions
- See [examples/sample-output.md](examples/sample-output.md) for the expected migration format
Keep each migration small and reversible. Always include a down migration.
Claude loads SKILL.md when the skill is invoked. It reads the supporting files when needed, not automatically. Large reference documents stay out of context until Claude encounters a question they answer.
Bundling executable scripts
Skills can include scripts in any language. Claude runs them via the Bash tool, and the ${CLAUDE_SKILL_DIR} variable ensures the path resolves correctly regardless of where the skill is installed — personal, project, or plugin level:
---
name: codebase-map
description: Generate an interactive visual map of the codebase structure
allowed-tools: Bash(python3 *) Bash(open *)
---
Generate a visual codebase map:
```bash
python3 ${CLAUDE_SKILL_DIR}/scripts/visualize.py .
```
This creates `codebase-map.html` in the current directory and opens it in your browser. The map shows file sizes, type distributions, and a collapsible directory tree.
The script at scripts/visualize.py lives inside the skill directory. Whether the skill is installed at ~/.claude/skills/codebase-map/ or committed to .claude/skills/codebase-map/, the path ${CLAUDE_SKILL_DIR}/scripts/visualize.py always resolves correctly. A hardcoded absolute path would break the moment the skill moved.
The visual output pattern
One of the most powerful uses of bundled scripts is generating HTML reports that open in the browser. This pattern works for any data Claude can collect:
- Dependency graphs: parse
package.json, generate an interactive node diagram - Test coverage reports: run tests with coverage flags, render a colored file tree
- API documentation: parse route definitions, generate a browsable endpoint reference
- Database schema visualization: query table definitions, render an entity-relationship diagram
- Performance profiles: collect timing data, generate a flame chart
The script does the heavy lifting. Claude handles orchestration — collecting the inputs, calling the script, opening the result. You get an interactive output without Claude needing to generate HTML in its response.
Using ${CLAUDE_PROJECT_DIR} for project-local references
When a skill needs to reference a script or config file that lives in the project itself (not in the skill directory), use ${CLAUDE_PROJECT_DIR}:
---
name: run-checks
description: Run the project's full check suite
allowed-tools: Bash(${CLAUDE_PROJECT_DIR}/scripts/check.sh *)
---
Run the full check suite:
```bash
${CLAUDE_PROJECT_DIR}/scripts/check.sh
```
Report any failures with file and line numbers.
The allowed-tools field also supports this substitution, so the permission rule and the instruction body reference the same path — the skill works correctly whether it is in a personal skills directory or checked into a different project.
Keep SKILL.md concise
The recommendation to keep SKILL.md under 500 lines is not arbitrary. Skill content stays in context for the entire session after invocation. Every line of a large SKILL.md is a recurring token cost across every turn. Move reference material that is only consulted occasionally — API specifications, edge case tables, historical incident context — to supporting files that Claude can read when they become relevant.
The ultrathink keyword in skill content is an exception to this pattern: it is a single word that instructs Claude to apply maximum reasoning depth to the task. Add it to skills where deep analysis matters more than speed — architecture reviews, security audits, complex refactoring decisions.
- Reference supporting files from SKILL.md so Claude knows they exist — they are loaded on demand, not automatically, keeping context lean
- Use <code>${CLAUDE_SKILL_DIR}</code> in all script path references — it resolves correctly whether the skill is personal, project-level, or inside a plugin
- <code>${CLAUDE_PROJECT_DIR}</code> references the project root from any skill location — use it in both the skill body and <code>allowed-tools</code> for consistent path resolution
- The visual output pattern — bundled script generates interactive HTML — works for dependency graphs, coverage reports, schema diagrams, and any structured data Claude can collect
- Keep SKILL.md under 500 lines — move reference material to supporting files; add <code>ultrathink</code> to skill body when you always want maximum reasoning depth