Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ Recent changes to the Specify CLI and templates are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.7] - 2026-02-26

### Fixed

- **Extension hooks never triggered (#1701)**: Wired `after_tasks` and `after_implement` hook events into their respective command templates
- `templates/commands/tasks.md` now includes a final step that reads `.specify/extensions.yml`, evaluates registered `after_tasks` hooks (respecting `enabled` flag and `condition`), and outputs the correct hook message format — including `EXECUTE_COMMAND:` markers for mandatory hooks
- `templates/commands/implement.md` does the same for `after_implement` hooks
- The `HookExecutor` backend in `extensions.py` was already complete; only the template wiring was missing

## [0.1.6] - 2026-02-23

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "specify-cli"
version = "0.1.6"
version = "0.1.7"
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
requires-python = ">=3.11"
dependencies = [
Expand Down
26 changes: 26 additions & 0 deletions templates/commands/implement.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,29 @@ You **MUST** consider the user input before proceeding (if not empty).
- Report final status with summary of completed work

Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list.

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
Comment on lines +140 to +141
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.
- 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.
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
```
## Extension Hooks

**Optional Hook**: {extension}
Command: `/{command}`
Description: {description}

Prompt: {prompt}
To execute: `/{command}`
```
- **Mandatory hook** (`optional: false`):
```
## Extension Hooks

**Automatic Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
```
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
26 changes: 26 additions & 0 deletions templates/commands/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,32 @@ You **MUST** consider the user input before proceeding (if not empty).
- Suggested MVP scope (typically just User Story 1)
- Format validation: Confirm ALL tasks follow the checklist format (checkbox, ID, labels, file paths)

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.
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
Comment on lines +68 to +71
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.
```
## Extension Hooks

**Optional Hook**: {extension}
Command: `/{command}`
Description: {description}

Prompt: {prompt}
To execute: `/{command}`
```
- **Mandatory hook** (`optional: false`):
```
## Extension Hooks

**Automatic Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
```
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently

Context for task generation: {ARGS}

The tasks.md should be immediately executable - each task must be specific enough that an LLM can complete it without additional context.
Expand Down