[BUG] Skill and agent frontmatter hooks silently not firing (CLI, Windows)
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?
Hooks defined in YAML frontmatter of skills and agents (as documented in Hooks in skills and agents) are silently ignored. The same hook command works correctly when placed in the plugin's hooks/hooks.json.
What Should Happen?
Hooks defined in skill/agent frontmatter should be scoped to the component's lifecycle and fire when the component is active.
Error Messages/Logs
### Debug Log Evidence
Enabled debug logging (`/debug`) and reproduced. The logs show two distinct behaviors:
**Frontmatter hook (does NOT fire)** — skill with `PostToolUse` frontmatter hook is active, Edit tool is called:
Getting matching hook commands for PostToolUse with query: Edit
Found 6 hook matchers in settings <-- only settings-based hooks searched
Matched 2 unique hooks for query "Edit" <-- 0 from frontmatter
Hook PostToolUse:Edit (PostToolUse) success:
✓ Deploy parameters updated <-- only post-creation-reminder.js ran
Verify container_settings and keyvalue_pairs format
The matcher count (6) is **constant** throughout the session — it never increases when a skill with frontmatter hooks becomes active.
**Global hooks.json (DOES fire)** — after adding validate-azdp.js back to `hooks.json`, same Edit call:
Getting matching hook commands for PostToolUse with query: Edit
Found 7 hook matchers in settings <-- count increased from 6 to 7
Matched 3 unique hooks for query "Edit" <-- increased from 2 to 3
Hook PostToolUse:Edit (PostToolUse) error:
❌ azuredeployparameters.json must use correct schema, not Azure ARM schema
Hook PostToolUse:Edit (PostToolUse) success:
✓ Reminder hook ran successfully
The validate-azdp.js script correctly detected the schema violation and blocked the edit — but only when registered via `hooks.json`. The identical hook defined in skill frontmatter is never added to the matcher pool.
Steps to Reproduce
Minimal Reproduction
my-plugin/
├── .claude-plugin/
│ └── plugin.json
├── hooks/
│ ├── hooks.json # Global hooks — these DO fire
│ └── scripts/
│ └── validate.js # Validation script (exits 2 on failure)
├── skills/
│ └── my-skill/
│ └── SKILL.md # Frontmatter hook — does NOT fire
└── agents/
└── my-agent.md # Frontmatter hook — does NOT fire
What the Hook Validates
The validate-azdp.js script reads the tool input from stdin (file path, old/new strings for Edit, content for Write), reconstructs the resulting file content, then validates the JSON structure. It checks for required sections, naming conventions, and correct nesting — exiting with code 2 on any violation.
A simplified valid file looks like this:
{
"parameters": {
"container_settings": {
"value": {
"image": "myregistry.azurecr.io/my-app:latest",
"targetPort": 8080,
"cpu": 0.5,
"memory": "1.0Gi"
}
},
"app_settings": {
"value": {
"keyvalue_pairs": [
{ "name": "MY_SETTING", "value": "some-value", "isSecret": false }
]
}
}
}
}
The test file we used intentionally has multiple violations (wrong schema, missing required sections, invalid naming) so the script would exit 2 and block the edit if the hook actually fired.
Steps to Reproduce
Test 1: Skill frontmatter hook (PreToolUse)
---
name: azdp-test
description: "Test skill for modifying azuredeployparameters.json."
hooks:
PreToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/validate-azdp.js\""
timeout: 30
---
Add a test entry to azuredeployparameters.json.
- Invoke the skill:
/platform:azdp-test - Claude edits the file successfully — the hook never fires
Test 2: Skill frontmatter hook (PostToolUse)
Same skill, switched to PostToolUse. Same result — hook never fires.
Test 3: Agent frontmatter hook (PreToolUse)
---
name: azdp-test-agent
description: Test agent for modifying azuredeployparameters.json with hook validation.
tools: Read, Grep, Glob, Edit, Write
hooks:
PreToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/validate-azdp.js\""
timeout: 30
---
Add a test entry to azuredeployparameters.json.
- A skill launches this agent
- The agent edits the file successfully — the hook never fires
Control: Global hooks.json (both PreToolUse and PostToolUse work)
The exact same hook command fires correctly for both event types when defined in the plugin's hooks/hooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/validate-azdp.js\"",
"timeout": 30
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/validate-azdp.js\"",
"timeout": 30
}
]
}
]
}
}
Both fire on every Write/Edit call. The issue is specific to frontmatter-defined hooks.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.84
Platform
Google Vertex AI
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
Additional Context
- Plugin is installed from a local marketplace via
claude plugin install - Tested with and without
disable-model-invocation: trueon the skill - Tested skill-direct invocation and agent-spawned-from-skill invocation
- Tested both
PreToolUseandPostToolUseevent types in frontmatter - No errors or warnings in CLI output or debug log
- Related issue #30874 reports the opposite problem (skill hooks persisting after completion), confirming the feature works in some environments
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗