Skip to content

fix: allow Claude to chain skills for hook execution#2227

Merged
mnriem merged 4 commits intogithub:mainfrom
mnriem:fix/claude-hook-chaining-2178
Apr 15, 2026
Merged

fix: allow Claude to chain skills for hook execution#2227
mnriem merged 4 commits intogithub:mainfrom
mnriem:fix/claude-hook-chaining-2178

Conversation

@mnriem
Copy link
Copy Markdown
Collaborator

@mnriem mnriem commented Apr 15, 2026

Summary

Fixes #2178 — Claude Code fails to execute speckit commands because:

  1. disable-model-invocation: true prevents Claude from invoking extension skills (e.g., speckit-git-feature) when chaining from workflow skills
  2. Hook sections reference dot-notation command names (speckit.git.commit) but Claude skills use hyphens (speckit-git-commit)
  3. Unicode in PowerShell auto-commit.ps1 causes parser errors on Windows

Changes

Core fix: disable-model-invocationfalse

  • Removed Claude-specific frontmatter from the shared build_skill_frontmatter() in agents.py
  • Added post_process_skill_content() hook to SkillsIntegration (identity default)
  • ClaudeIntegration overrides it to inject user-invocable: true and disable-model-invocation: false
  • Wired through presets.py and extensions.py so all skill-generation paths go through the integration

Hook command name normalization

  • ClaudeIntegration.post_process_skill_content() injects a dot-to-hyphen note into hook sections of generated SKILL.md files, so Claude maps speckit.git.commit/speckit-git-commit

PowerShell encoding fix

  • Replaced Unicode with ASCII [OK] in both auto-commit.ps1 and auto-commit.sh

Tests

  • 9 new tests for disable-model-invocation (positive: value is false, negative: true never appears, non-Claude agents unaffected)
  • 5 new tests for hook note injection (positive: present in hook skills, negative: absent without hooks, idempotent, preserves indentation)
  • 4 new tests for auto-commit scripts (positive: [OK] in output, negative: no Unicode )

All 1433 tests pass.

- Set disable-model-invocation to false so Claude can invoke extension
  skills (e.g. speckit-git-feature) from within workflow skills
- Inject dot-to-hyphen normalization note into Claude SKILL.md hook
  sections so the model maps extension.yml command names to skill names
- Replace Unicode checkmark with ASCII [OK] in auto-commit scripts to
  fix PowerShell encoding errors on Windows
- Move Claude-specific frontmatter injection to ClaudeIntegration via
  post_process_skill_content() hook on SkillsIntegration, wired through
  presets and extensions managers
- Add positive and negative tests for all changes

Fixes github#2178
Copilot AI review requested due to automatic review settings April 15, 2026 13:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Claude Code failing to execute chained speckit skills/hooks by ensuring generated skills are user-invocable, model-invocation is enabled (for skill chaining), and hook documentation clarifies dot-to-hyphen command normalization; also removes Unicode output that breaks PowerShell parsing on Windows.

Changes:

  • Moves Claude-specific SKILL.md frontmatter mutation into ClaudeIntegration.post_process_skill_content() and routes preset/extension skill generation through integration post-processing.
  • Injects a dot→hyphen normalization note into hook instruction sections in Claude-generated skills.
  • Replaces Unicode with ASCII [OK] in auto-commit scripts and adds/updates tests to lock in behavior.
Show a summary per file
File Description
src/specify_cli/agents.py Removes Claude-only SKILL frontmatter from shared builder to avoid affecting other skill-generation paths.
src/specify_cli/integrations/base.py Adds SkillsIntegration.post_process_skill_content() hook (default identity) for integration-specific skill post-processing.
src/specify_cli/integrations/claude/__init__.py Implements Claude-specific post-processing: injects user-invocable: true, disable-model-invocation: false, and a hook command normalization note.
src/specify_cli/presets.py Applies integration post-processing to preset-created/restored SKILL.md content.
src/specify_cli/extensions.py Applies integration post-processing to extension-created SKILL.md content.
extensions/git/scripts/bash/auto-commit.sh Replaces Unicode checkmark success output with [OK] for portability.
extensions/git/scripts/powershell/auto-commit.ps1 Replaces Unicode checkmark success output with [OK] to avoid Windows PowerShell parser/encoding issues.
tests/integrations/test_integration_claude.py Updates expectations for disable-model-invocation: false and adds coverage for Claude post-processing + hook note injection behavior.
tests/test_extension_skills.py Updates extension skill YAML expectations to match new Claude post-processing (disable-model-invocation: false).
tests/test_presets.py Updates preset skill assertions to expect disable-model-invocation: false.
tests/extensions/git/test_git_extension.py Adds tests ensuring [OK] is used and Unicode is absent in script outputs.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 11/11 changed files
  • Comments generated: 3

Comment thread src/specify_cli/integrations/claude/__init__.py Outdated
Comment thread src/specify_cli/presets.py Outdated
Comment thread src/specify_cli/extensions.py Outdated
@mnriem
Copy link
Copy Markdown
Collaborator Author

mnriem commented Apr 15, 2026

@copilot apply changes based on the comments in this thread

@mnriem mnriem self-assigned this Apr 15, 2026
mnriem added 2 commits April 15, 2026 09:29
- Preserve line-ending style (CRLF/LF) in _inject_hook_command_note
  instead of always inserting \n, matching the convention used by other
  injection helpers in the same module.

- Extract duplicated _post_process_skill() from extensions.py and
  presets.py into a shared post_process_skill() function in agents.py.
  Both modules now import and call the shared helper.
The regex in _inject_hook_command_note only matched lines ending
immediately after 'output the following', but the actual template
lines continue with 'based on its `optional` flag:'. Use [^\r\n]*
to capture the rest of the line before the EOL.
Copilot AI review requested due to automatic review settings April 15, 2026 14:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Claude Code hook execution for Speckit by ensuring Claude-generated skills are invocable/chained, normalizing hook command naming expectations, and removing a Unicode character that breaks PowerShell parsing on Windows.

Changes:

  • Move Claude-specific SKILL.md frontmatter behavior out of the shared build_skill_frontmatter() and into Claude’s integration post-processing (sets disable-model-invocation: false, user-invocable: true).
  • Post-process SKILL.md content during preset/extension skill generation so Claude flags (and hook note) apply consistently across generation paths.
  • Replace Unicode with ASCII [OK] in auto-commit scripts and add tests to prevent regressions.
Show a summary per file
File Description
src/specify_cli/agents.py Adds post_process_skill() helper to route skill content through the selected integration’s post-processor.
src/specify_cli/integrations/base.py Introduces post_process_skill_content() hook (default no-op) for skills integrations.
src/specify_cli/integrations/claude/__init__.py Implements Claude-specific post-processing: injects user-invocable: true, disable-model-invocation: false, and a dot→hyphen hook command note.
src/specify_cli/presets.py Applies integration post-processing to generated/restored preset SKILL.md files.
src/specify_cli/extensions.py Applies integration post-processing to generated extension SKILL.md files.
extensions/git/scripts/bash/auto-commit.sh Replaces Unicode checkmark with [OK] in success output.
extensions/git/scripts/powershell/auto-commit.ps1 Replaces Unicode checkmark with [OK] in success output (avoids Windows PowerShell parsing issues).
tests/integrations/test_integration_claude.py Expands tests for Claude frontmatter flags and hook-note injection behavior.
tests/test_extension_skills.py Updates expectation for Claude-generated extension SKILL.md to have disable-model-invocation: false.
tests/test_presets.py Updates expectations for preset SKILL.md to have disable-model-invocation: false.
tests/extensions/git/test_git_extension.py Adds tests asserting [OK] output and absence of Unicode checkmark for both bash and PowerShell scripts.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new

Instead of a free function in agents.py that re-resolves the
integration by key, callers in extensions.py and presets.py now
resolve the integration once via get_integration() and call
integration.post_process_skill_content() directly. The base
identity method lives on SkillsIntegration.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts Claude Code skill generation so Claude can invoke extension skills during hook execution, while also normalizing hook command naming guidance and fixing Windows PowerShell parsing issues caused by Unicode output.

Changes:

  • Moves Claude-specific SKILL.md frontmatter injection (user-invocable, disable-model-invocation: false) into ClaudeIntegration.post_process_skill_content() and routes preset/extension skill generation through it.
  • Injects a dot-to-hyphen normalization note into hook instruction sections in Claude-generated skills to map speckit.git.commit/speckit-git-commit.
  • Replaces Unicode checkmarks in auto-commit scripts with ASCII [OK] and adds/updates tests accordingly.
Show a summary per file
File Description
src/specify_cli/agents.py Removes Claude-only frontmatter from shared build_skill_frontmatter() to avoid cross-agent coupling.
src/specify_cli/integrations/base.py Adds post_process_skill_content() hook (default identity) for skill-content post-processing.
src/specify_cli/integrations/claude/__init__.py Implements Claude post-processing to inject required frontmatter flags and hook dot→hyphen note.
src/specify_cli/presets.py Applies integration post-processing to preset skill generation and restore paths.
src/specify_cli/extensions.py Applies integration post-processing to extension skill generation.
extensions/git/scripts/bash/auto-commit.sh Switches success output from to [OK] (stderr).
extensions/git/scripts/powershell/auto-commit.ps1 Switches success output from to [OK] (stdout).
tests/integrations/test_integration_claude.py Updates expectations for disable-model-invocation: false and adds coverage for hook note injection + non-Claude behavior.
tests/test_extension_skills.py Updates YAML expectations for Claude-generated extension skills to include disable-model-invocation: false.
tests/test_presets.py Updates preset skill assertions to require disable-model-invocation: false for Claude.
tests/extensions/git/test_git_extension.py Adds tests ensuring [OK] is used and Unicode checkmarks are absent in both bash and PowerShell outputs.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new

@mnriem mnriem merged commit 8fc2bd3 into github:main Apr 15, 2026
12 checks passed
@mnriem mnriem deleted the fix/claude-hook-chaining-2178 branch April 15, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Claude dont execute speckit commands

2 participants