${CLAUDE_SKILL_DIR} not substituted in SKILL.md frontmatter hook commands
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The Available string substitutions docs list ${CLAUDE_SKILL_DIR} as available for skills:
${CLAUDE_SKILL_DIR}— The directory containing the skill'sSKILL.mdfile. Use this in bash injection commands to reference scripts or files bundled with the skill, regardless of the current working directory.
However, ${CLAUDE_SKILL_DIR} is not substituted when used in SKILL.md frontmatter hook commands. The literal ${CLAUDE_SKILL_DIR} string is passed to the shell, where it resolves to empty (since it's not a real env var), causing the command to fail.
What Should Happen?
${CLAUDE_SKILL_DIR} should be resolved to the skill's directory in hook commands defined in SKILL.md frontmatter, just like it is in the skill body. This is critical for portable/publishable skills that bundle scripts.
Steps to Reproduce
- Create a skill with a script and a frontmatter hook referencing it:
my-skill/
├── SKILL.md
└── scripts/
└── validate.py
---
name: my-skill
description: "Test skill with hook"
hooks:
PostToolUse:
- matcher: "Write|Edit|Bash"
hooks:
- type: command
command: "uv run ${CLAUDE_SKILL_DIR}/scripts/validate.py"
---
- Symlink the skill into a different project:
ln -s /path/to/my-skill .claude/skills/my-skill
- Invoke the skill and trigger a matching tool (e.g., Edit a file)
- The hook command fails because
${CLAUDE_SKILL_DIR}is not substituted — the shell receives the literal string, which expands to empty since there's no such env var.
Expected: The hook command resolves to uv run /path/to/my-skill/scripts/validate.py
Actual: The hook command resolves to uv run /scripts/validate.py (or similar), and fails
Why This Matters
Skills that bundle helper scripts (validators, analyzers, etc.) need a way to reference those scripts from hook commands. Without ${CLAUDE_SKILL_DIR} working in frontmatter hooks, there's no portable way to do this — hardcoded paths break when the skill is consumed from a different project.
This is distinct from:
- #17688 (skill hooks not triggering in plugins)
- #9354 (
${CLAUDE_PLUGIN_ROOT}in plugin command markdown)
Claude Code Version
2.1.79
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗