Skip to content

fix: wire after_tasks and after_implement hook events into command templates#1702

Open
mnriem wants to merge 1 commit intogithub:mainfrom
mnriem:fix/extension-hooks-not-triggered
Open

fix: wire after_tasks and after_implement hook events into command templates#1702
mnriem wants to merge 1 commit intogithub:mainfrom
mnriem:fix/extension-hooks-not-triggered

Conversation

@mnriem
Copy link
Collaborator

@mnriem mnriem commented Feb 26, 2026

Summary

Fixes #1701.

The HookExecutor class in extensions.py was fully implemented but check_hooks_for_event() was never invoked - the core command templates had no instructions to check .specify/extensions.yml. Hooks silently did nothing after every command run.

Changes

  • templates/commands/tasks.md: added step 6 - after_tasks hook check
  • templates/commands/implement.md: added step 10 - after_implement hook check
  • pyproject.toml: version bump 0.1.6 to 0.1.7
  • CHANGELOG.md: entry for [0.1.7]

Testing

  1. Create an extension with an after_tasks hook and install it
  2. Confirm hook is registered in .specify/extensions.yml
  3. Run /speckit.tasks - the hook message should now appear at the end of the output

…mplates (github#1701)

The HookExecutor backend in extensions.py was fully implemented but
check_hooks_for_event() was never called by anything — the core command
templates had no instructions to check .specify/extensions.yml.

Add a final step to templates/commands/tasks.md (step 6, after_tasks) and
templates/commands/implement.md (step 10, after_implement) that instructs
the AI agent to:

- Read .specify/extensions.yml if it exists
- Filter hooks.{event} to enabled: true entries
- Evaluate any condition fields and skip non-matching hooks
- Output the RFC-specified hook message format, including
  EXECUTE_COMMAND: markers for mandatory (optional: false) hooks

Bumps version to 0.1.7.
Copilot AI review requested due to automatic review settings February 26, 2026 16:39
Copy link
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 issue #1701 by wiring extension hooks into command templates. The HookExecutor class in extensions.py was fully implemented but never invoked - core command templates had no instructions to check .specify/extensions.yml. This meant hooks silently did nothing after command completion. The fix adds step-by-step instructions to tasks.md and implement.md templates to read the extensions config, filter enabled hooks, evaluate conditions, and output the appropriate hook messages (including EXECUTE_COMMAND: markers for mandatory hooks).

Changes:

  • Added hook checking instructions to tasks.md (step 6) and implement.md (step 10) templates
  • Version bump from 0.1.6 to 0.1.7 with corresponding changelog entry
  • Templates now parse .specify/extensions.yml and output formatted hook messages for AI agents to execute

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
templates/commands/tasks.md Added step 6 to check for after_tasks hooks after task generation completes
templates/commands/implement.md Added step 10 to check for after_implement hooks after implementation validation
pyproject.toml Version bump from 0.1.6 to 0.1.7
CHANGELOG.md Added entry for version 0.1.7 documenting the hook wiring fix

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

6. **Check for extension hooks**: After tasks.md is generated, check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.after_tasks` key
- Filter to only hooks where `enabled: true`
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The instruction to "evaluate any condition value" is ambiguous and lacks implementation details. The HookExecutor class supports complex condition expressions like "config.project.key is set" and "env.VAR_NAME == 'value'" (see extensions.py lines 1567-1640), but the template doesn't explain how AI agents should evaluate these conditions. Consider either:

  1. Adding a detailed explanation of the condition syntax and evaluation rules
  2. Simplifying to just state "skip hooks with non-null condition values for now" if condition evaluation is meant to be handled by HookExecutor
  3. Providing examples of common condition patterns
Suggested change
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
- Do not attempt to interpret or evaluate hook `condition` expressions; if a hook has a non-null `condition` value, skip it and assume the HookExecutor will handle condition evaluation

Copilot uses AI. Check for mistakes.
10. **Check for extension hooks**: After completion validation, check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.after_implement` key
- Filter to only hooks where `enabled: true`
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The instruction to "evaluate any condition value" is ambiguous and lacks implementation details. The HookExecutor class supports complex condition expressions like "config.project.key is set" and "env.VAR_NAME == 'value'" (see extensions.py lines 1567-1640), but the template doesn't explain how AI agents should evaluate these conditions. Consider either:

  1. Adding a detailed explanation of the condition syntax and evaluation rules
  2. Simplifying to just state "skip hooks with non-null condition values for now" if condition evaluation is meant to be handled by HookExecutor
  3. Providing examples of common condition patterns
Suggested change
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
- For each remaining hook, do **not** attempt to interpret complex `condition` expressions:
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
- If the hook defines a non-empty `condition`, skip the hook for now and leave condition evaluation to the HookExecutor implementation

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +71
- Filter to only hooks where `enabled: true`
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The template doesn't provide guidance for handling malformed YAML or parsing errors when reading .specify/extensions.yml. Consider adding a note about gracefully handling parse failures, for example: "If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally."

Suggested change
- Filter to only hooks where `enabled: true`
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
- Filter to only hooks where `enabled: true`
- For each remaining hook, evaluate any `condition` value; skip the hook if the condition is not met
- For each executable hook, output the following based on its `optional` flag:

Copilot uses AI. Check for mistakes.
Comment on lines +140 to +141
10. **Check for extension hooks**: After completion validation, check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.after_implement` key
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

The template doesn't provide guidance for handling malformed YAML or parsing errors when reading .specify/extensions.yml. Consider adding a note about gracefully handling parse failures, for example: "If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally."

Copilot uses AI. Check for mistakes.
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.

Extension hooks (after_tasks, after_implement) are never triggered

2 participants