You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: wire after_tasks and after_implement hook events into command templates (github#1702)
* fix: wire after_tasks and after_implement hook events into command templates (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.
* fix: clarify hook condition handling and add YAML error guidance in templates
- Replace ambiguous "evaluate any condition value" instruction with explicit
guidance to skip hooks with non-empty conditions, deferring evaluation to
HookExecutor
- Add instruction to skip hook checking silently if extensions.yml cannot
be parsed or is invalid
* Fix/extension hooks not triggered (#1)
* feat(templates): implement before-hooks check as pre-execution phase
* test(hooks): create scenario for LLMs/Agents on hooks
---------
Co-authored-by: Dhilip <s.dhilipkumar@gmail.com>
Copy file name to clipboardExpand all lines: templates/commands/implement.md
+64Lines changed: 64 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,6 +35,40 @@ $ARGUMENTS
35
35
36
36
You **MUST** consider the user input before proceeding (if not empty).
37
37
38
+
## Pre-Execution Checks
39
+
40
+
**Check for extension hooks (before implementation)**:
41
+
- Check if `.specify/extensions.yml` exists in the project root.
42
+
- If it exists, read it and look for entries under the `hooks.before_implement` key
43
+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
44
+
- Filter to only hooks where `enabled: true`
45
+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
46
+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
47
+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
48
+
- For each executable hook, output the following based on its `optional` flag:
49
+
-**Optional hook** (`optional: true`):
50
+
```
51
+
## Extension Hooks
52
+
53
+
**Optional Pre-Hook**: {extension}
54
+
Command: `/{command}`
55
+
Description: {description}
56
+
57
+
Prompt: {prompt}
58
+
To execute: `/{command}`
59
+
```
60
+
- **Mandatory hook** (`optional: false`):
61
+
```
62
+
## Extension Hooks
63
+
64
+
**Automatic Pre-Hook**: {extension}
65
+
Executing: `/{command}`
66
+
EXECUTE_COMMAND: {command}
67
+
68
+
Wait for the result of the hook command before proceeding to the Outline.
69
+
```
70
+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
71
+
38
72
## Multi-Repository Workspace Detection
39
73
40
74
**Before executing any tasks:**
@@ -51,6 +85,7 @@ You **MUST** consider the user input before proceeding (if not empty).
51
85
- **Single-repo**: Work continues on the current branch in the active repository
52
86
- **Multi-repo**: Create matching feature branches in all affected repositories using the same branch name as the `*-document` repository
53
87
88
+
54
89
## Outline
55
90
56
91
0. **Multi-Repository Branch Setup**:
@@ -239,3 +274,32 @@ You **MUST** consider the user input before proceeding (if not empty).
239
274
**IMPORTANT**: Do NOT commit any changes. All changes must remain uncommitted (staged or unstaged) for user review before committing. This applies to both single-repository and multi-repository implementations.
240
275
241
276
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.
277
+
278
+
10. **Check for extension hooks**: After completion validation, check if `.specify/extensions.yml` exists in the project root.
279
+
- If it exists, read it and look for entries under the `hooks.after_implement` key
280
+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
281
+
- Filter to only hooks where `enabled: true`
282
+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
283
+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
284
+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
285
+
- For each executable hook, output the following based on its `optional` flag:
286
+
- **Optional hook** (`optional: true`):
287
+
```
288
+
## Extension Hooks
289
+
290
+
**Optional Hook**: {extension}
291
+
Command: `/{command}`
292
+
Description: {description}
293
+
294
+
Prompt: {prompt}
295
+
To execute: `/{command}`
296
+
```
297
+
- **Mandatory hook** (`optional: false`):
298
+
```
299
+
## Extension Hooks
300
+
301
+
**Automatic Hook**: {extension}
302
+
Executing: `/{command}`
303
+
EXECUTE_COMMAND: {command}
304
+
```
305
+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
Copy file name to clipboardExpand all lines: templates/commands/tasks.md
+63Lines changed: 63 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,6 +68,40 @@ $ARGUMENTS
68
68
69
69
You **MUST** consider the user input before proceeding (if not empty).
70
70
71
+
## Pre-Execution Checks
72
+
73
+
**Check for extension hooks (before tasks generation)**:
74
+
- Check if `.specify/extensions.yml` exists in the project root.
75
+
- If it exists, read it and look for entries under the `hooks.before_tasks` key
76
+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
77
+
- Filter to only hooks where `enabled: true`
78
+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
79
+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
80
+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
81
+
- For each executable hook, output the following based on its `optional` flag:
82
+
-**Optional hook** (`optional: true`):
83
+
```
84
+
## Extension Hooks
85
+
86
+
**Optional Pre-Hook**: {extension}
87
+
Command: `/{command}`
88
+
Description: {description}
89
+
90
+
Prompt: {prompt}
91
+
To execute: `/{command}`
92
+
```
93
+
- **Mandatory hook** (`optional: false`):
94
+
```
95
+
## Extension Hooks
96
+
97
+
**Automatic Pre-Hook**: {extension}
98
+
Executing: `/{command}`
99
+
EXECUTE_COMMAND: {command}
100
+
101
+
Wait for the result of the hook command before proceeding to the Outline.
102
+
```
103
+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
104
+
71
105
## Outline
72
106
73
107
1. **Setup**: Run `{SCRIPT}` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
@@ -146,6 +180,35 @@ You **MUST** consider the user input before proceeding (if not empty).
146
180
- Document contract compatibility tasks
147
181
- Recommend coordination points between repositories during implementation
148
182
183
+
6. **Check for extension hooks**: After tasks.md is generated, check if `.specify/extensions.yml` exists in the project root.
184
+
- If it exists, read it and look for entries under the `hooks.after_tasks` key
185
+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
186
+
- Filter to only hooks where `enabled: true`
187
+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
188
+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
189
+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
190
+
- For each executable hook, output the following based on its `optional` flag:
191
+
- **Optional hook** (`optional: true`):
192
+
```
193
+
## Extension Hooks
194
+
195
+
**Optional Hook**: {extension}
196
+
Command: `/{command}`
197
+
Description: {description}
198
+
199
+
Prompt: {prompt}
200
+
To execute: `/{command}`
201
+
```
202
+
- **Mandatory hook** (`optional: false`):
203
+
```
204
+
## Extension Hooks
205
+
206
+
**Automatic Hook**: {extension}
207
+
Executing: `/{command}`
208
+
EXECUTE_COMMAND: {command}
209
+
```
210
+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
211
+
149
212
Context for task generation: {ARGS}
150
213
151
214
The tasks.md should be immediately executable - each task must be specific enough that an LLM can complete it without additional context.
This directory contains a mock project to verify that LLM agents correctly identify and execute hook commands defined in `.specify/extensions.yml`.
4
+
5
+
## Test 1: Testing `before_tasks` and `after_tasks`
6
+
7
+
1. Open a chat with an LLM (like GitHub Copilot) in this project.
8
+
2. Ask it to generate tasks for the current directory:
9
+
> "Please follow `/speckit.tasks` for the `./tests/hooks` directory."
10
+
3.**Expected Behavior**:
11
+
- Before doing any generation, the LLM should notice the `AUTOMATIC Pre-Hook` in `.specify/extensions.yml` under `before_tasks`.
12
+
- It should state it is executing `EXECUTE_COMMAND: pre_tasks_test`.
13
+
- It should then proceed to read the `.md` docs and produce a `tasks.md`.
14
+
- After generation, it should output the optional `after_tasks` hook (`post_tasks_test`) block, asking if you want to run it.
15
+
16
+
## Test 2: Testing `before_implement` and `after_implement`
17
+
18
+
*(Requires `tasks.md` from Test 1 to exist)*
19
+
20
+
1. In the same (or new) chat, ask the LLM to implement the tasks:
21
+
> "Please follow `/speckit.implement` for the `./tests/hooks` directory."
22
+
2.**Expected Behavior**:
23
+
- The LLM should first check for `before_implement` hooks.
24
+
- It should state it is executing `EXECUTE_COMMAND: pre_implement_test` BEFORE doing any actual task execution.
25
+
- It should evaluate the checklists and execute the code writing tasks.
26
+
- Upon completion, it should output the optional `after_implement` hook (`post_implement_test`) block.
27
+
28
+
## How it works
29
+
30
+
The templates for these commands in `templates/commands/tasks.md` and `templates/commands/implement.md` contains strict ordered lists. The new `before_*` hooks are explicitly formulated in a **Pre-Execution Checks** section prior to the outline to ensure they're evaluated first without breaking template step numbers.
0 commit comments