Skip to content

Commit 4b6983f

Browse files
committed
feat(preset): add extension hooks to all ADLC preset commands
Added before_* and after_* extension hooks to: - adlc.spec.analyze (before_analyze, after_analyze) - adlc.spec.checklist (before_checklist, after_checklist) - adlc.spec.clarify (before_clarify, after_clarify) - adlc.spec.constitution (before_constitution, after_constitution) Fixed hook enabled logic in: - adlc.spec.implement - adlc.spec.plan - adlc.spec.tasks Changed from 'Filter to only hooks where enabled: true' to 'Filter out hooks where enabled is explicitly false. Treat hooks without an enabled field as enabled by default.' This matches the upstream hook pattern and allows extensions to register hooks that work by default without requiring explicit enabled: true in extension.yml.
1 parent 6a9f2fa commit 4b6983f

7 files changed

Lines changed: 266 additions & 6 deletions

File tree

presets/agentic-sdlc/commands/adlc.spec.analyze.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,40 @@ $ARGUMENTS
1313

1414
You **MUST** consider the user input before proceeding (if not empty).
1515

16+
## Pre-Execution Checks
17+
18+
**Check for extension hooks (before analysis)**:
19+
- Check if `.specify/extensions.yml` exists in the project root.
20+
- If it exists, read it and look for entries under the `hooks.before_analyze` key
21+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
22+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
23+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
24+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
25+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
26+
- For each executable hook, output the following based on its `optional` flag:
27+
- **Optional hook** (`optional: true`):
28+
```
29+
## Extension Hooks
30+
31+
**Optional Pre-Hook**: {extension}
32+
Command: `/{command}`
33+
Description: {description}
34+
35+
Prompt: {prompt}
36+
To execute: `/{command}`
37+
```
38+
- **Mandatory hook** (`optional: false`):
39+
```
40+
## Extension Hooks
41+
42+
**Automatic Pre-Hook**: {extension}
43+
Executing: `/{command}`
44+
EXECUTE_COMMAND: {command}
45+
46+
Wait for the result of the hook command before proceeding to the Goal.
47+
```
48+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
49+
1650
## Goal
1751
1852
Perform consistency and quality analysis across artifacts and implementation with automatic context detection:
@@ -433,6 +467,37 @@ If post-implementation analysis identifies critical problems requiring rollback:
433467
3. **Clean Revert**: Remove problematic implementation while maintaining good changes
434468
4. **Regenerate Tasks**: Create new tasks for corrected implementation approach
435469
470+
### 11. Check for extension hooks
471+
472+
After reporting, check if `.specify/extensions.yml` exists in the project root.
473+
- If it exists, read it and look for entries under the `hooks.after_analyze` key
474+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
475+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
476+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
477+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
478+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
479+
- For each executable hook, output the following based on its `optional` flag:
480+
- **Optional hook** (`optional: true`):
481+
```
482+
## Extension Hooks
483+
484+
**Optional Hook**: {extension}
485+
Command: `/{command}`
486+
Description: {description}
487+
488+
Prompt: {prompt}
489+
To execute: `/{command}`
490+
```
491+
- **Mandatory hook** (`optional: false`):
492+
```
493+
## Extension Hooks
494+
495+
**Automatic Hook**: {extension}
496+
Executing: `/{command}`
497+
EXECUTE_COMMAND: {command}
498+
```
499+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
500+
436501
## Operating Principles
437502
438503
### Context Efficiency

presets/agentic-sdlc/commands/adlc.spec.checklist.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,40 @@ $ARGUMENTS
3434

3535
You **MUST** consider the user input before proceeding (if not empty).
3636

37+
## Pre-Execution Checks
38+
39+
**Check for extension hooks (before checklist)**:
40+
- Check if `.specify/extensions.yml` exists in the project root.
41+
- If it exists, read it and look for entries under the `hooks.before_checklist` key
42+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
43+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
44+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
45+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
46+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
47+
- For each executable hook, output the following based on its `optional` flag:
48+
- **Optional hook** (`optional: true`):
49+
```
50+
## Extension Hooks
51+
52+
**Optional Pre-Hook**: {extension}
53+
Command: `/{command}`
54+
Description: {description}
55+
56+
Prompt: {prompt}
57+
To execute: `/{command}`
58+
```
59+
- **Mandatory hook** (`optional: false`):
60+
```
61+
## Extension Hooks
62+
63+
**Automatic Pre-Hook**: {extension}
64+
Executing: `/{command}`
65+
EXECUTE_COMMAND: {command}
66+
67+
Wait for the result of the hook command before proceeding to Execution Steps.
68+
```
69+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
70+
3771
## Execution Steps
3872
3973
1. **Setup**: Run `{SCRIPT}` from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS.
@@ -251,6 +285,37 @@ If working in a non-git repository:
251285
252286
To avoid clutter, use descriptive types and clean up obsolete checklists when done.
253287
288+
8. **Check for extension hooks**
289+
290+
After reporting, check if `.specify/extensions.yml` exists in the project root.
291+
- If it exists, read it and look for entries under the `hooks.after_checklist` key
292+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
293+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
294+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
295+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
296+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
297+
- For each executable hook, output the following based on its `optional` flag:
298+
- **Optional hook** (`optional: true`):
299+
```
300+
## Extension Hooks
301+
302+
**Optional Hook**: {extension}
303+
Command: `/{command}`
304+
Description: {description}
305+
306+
Prompt: {prompt}
307+
To execute: `/{command}`
308+
```
309+
- **Mandatory hook** (`optional: false`):
310+
```
311+
## Extension Hooks
312+
313+
**Automatic Hook**: {extension}
314+
Executing: `/{command}`
315+
EXECUTE_COMMAND: {command}
316+
```
317+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
318+
254319
## Example Checklist Types & Sample Items
255320
256321
**UX Requirements Quality:** `ux.md`

presets/agentic-sdlc/commands/adlc.spec.clarify.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,40 @@ $ARGUMENTS
1717

1818
You **MUST** consider the user input before proceeding (if not empty).
1919

20+
## Pre-Execution Checks
21+
22+
**Check for extension hooks (before clarify)**:
23+
- Check if `.specify/extensions.yml` exists in the project root.
24+
- If it exists, read it and look for entries under the `hooks.before_clarify` key
25+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
26+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
27+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
28+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
29+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
30+
- For each executable hook, output the following based on its `optional` flag:
31+
- **Optional hook** (`optional: true`):
32+
```
33+
## Extension Hooks
34+
35+
**Optional Pre-Hook**: {extension}
36+
Command: `/{command}`
37+
Description: {description}
38+
39+
Prompt: {prompt}
40+
To execute: `/{command}`
41+
```
42+
- **Mandatory hook** (`optional: false`):
43+
```
44+
## Extension Hooks
45+
46+
**Automatic Pre-Hook**: {extension}
47+
Executing: `/{command}`
48+
EXECUTE_COMMAND: {command}
49+
50+
Wait for the result of the hook command before proceeding to Outline.
51+
```
52+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
53+
2054
## Outline
2155
2256
Goal: Detect and reduce ambiguity or missing decision points in the active feature specification. Validate spec against project constitution and architecture (three-pillar validation). Record clarifications directly in the spec file.
@@ -434,4 +468,35 @@ Behavior rules:
434468
435469
- If quota reached with unresolved high-impact categories remaining, explicitly flag them under Deferred with rationale.
436470
471+
9. **Check for extension hooks**
472+
473+
After reporting, check if `.specify/extensions.yml` exists in the project root.
474+
- If it exists, read it and look for entries under the `hooks.after_clarify` key
475+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
476+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
477+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
478+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
479+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
480+
- For each executable hook, output the following based on its `optional` flag:
481+
- **Optional hook** (`optional: true`):
482+
```
483+
## Extension Hooks
484+
485+
**Optional Hook**: {extension}
486+
Command: `/{command}`
487+
Description: {description}
488+
489+
Prompt: {prompt}
490+
To execute: `/{command}`
491+
```
492+
- **Mandatory hook** (`optional: false`):
493+
```
494+
## Extension Hooks
495+
496+
**Automatic Hook**: {extension}
497+
Executing: `/{command}`
498+
EXECUTE_COMMAND: {command}
499+
```
500+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
501+
437502
Context for prioritization: {ARGS}

presets/agentic-sdlc/commands/adlc.spec.constitution.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,40 @@ $ARGUMENTS
1717

1818
You **MUST** consider the user input before proceeding (if not empty).
1919

20+
## Pre-Execution Checks
21+
22+
**Check for extension hooks (before constitution)**:
23+
- Check if `.specify/extensions.yml` exists in the project root.
24+
- If it exists, read it and look for entries under the `hooks.before_constitution` key
25+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
26+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
27+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
28+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
29+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
30+
- For each executable hook, output the following based on its `optional` flag:
31+
- **Optional hook** (`optional: true`):
32+
```
33+
## Extension Hooks
34+
35+
**Optional Pre-Hook**: {extension}
36+
Command: `/{command}`
37+
Description: {description}
38+
39+
Prompt: {prompt}
40+
To execute: `/{command}`
41+
```
42+
- **Mandatory hook** (`optional: false`):
43+
```
44+
## Extension Hooks
45+
46+
**Automatic Pre-Hook**: {extension}
47+
Executing: `/{command}`
48+
EXECUTE_COMMAND: {command}
49+
50+
Wait for the result of the hook command before proceeding to Outline.
51+
```
52+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
53+
2054
## Outline
2155
2256
You are updating the project constitution at `{REPO_ROOT}/.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
@@ -77,6 +111,37 @@ Follow this execution flow:
77111
- Files flagged for manual follow-up
78112
- Suggested commit message (e.g., `docs: amend constitution to vX.Y.Z`)
79113
114+
10. **Check for extension hooks**
115+
116+
After reporting, check if `.specify/extensions.yml` exists in the project root.
117+
- If it exists, read it and look for entries under the `hooks.after_constitution` key
118+
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
119+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
120+
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
121+
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
122+
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
123+
- For each executable hook, output the following based on its `optional` flag:
124+
- **Optional hook** (`optional: true`):
125+
```
126+
## Extension Hooks
127+
128+
**Optional Hook**: {extension}
129+
Command: `/{command}`
130+
Description: {description}
131+
132+
Prompt: {prompt}
133+
To execute: `/{command}`
134+
```
135+
- **Mandatory hook** (`optional: false`):
136+
```
137+
## Extension Hooks
138+
139+
**Automatic Hook**: {extension}
140+
Executing: `/{command}`
141+
EXECUTE_COMMAND: {command}
142+
```
143+
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
144+
80145
## Formatting Requirements
81146
82147
- Use Markdown headings exactly as in template (do not change levels)

presets/agentic-sdlc/commands/adlc.spec.implement.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ You **MUST** consider the user input before proceeding (if not empty).
1919
- Check if `{REPO_ROOT}/.specify/extensions.yml` exists in the project root.
2020
- If it exists, read it and look for entries under the `hooks.before_implement` key
2121
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
22-
- Filter to only hooks where `enabled: true`
22+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
2323
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
2424
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
2525
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
@@ -197,7 +197,7 @@ If working in a non-git repository:
197197
9. **Check for extension hooks**: After completion validation, check if `{REPO_ROOT}/.specify/extensions.yml` exists in the project root.
198198
- If it exists, read it and look for entries under the `hooks.after_implement` key
199199
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
200-
- Filter to only hooks where `enabled: true`
200+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
201201
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
202202
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
203203
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation

presets/agentic-sdlc/commands/adlc.spec.plan.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Parse the following parameters from `$ARGUMENTS`:
3434
- Check if `{REPO_ROOT}/.specify/extensions.yml` exists in the project root
3535
- If it exists, read it and look for entries under the `hooks.before_plan` key
3636
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
37-
- Filter to only hooks where `enabled: true`
37+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
3838
- For hooks with conditions, skip condition evaluation (leave to HookExecutor)
3939
- For hooks without conditions, treat as executable
4040

@@ -259,7 +259,7 @@ Document each task with: Classification ([SYNC]/[ASYNC]), Primary Criteria, Risk
259259
- After plan is generated, check if `{REPO_ROOT}/.specify/extensions.yml` exists in the project root
260260
- If it exists, read it and look for entries under the `hooks.after_plan` key
261261
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
262-
- Filter to only hooks where `enabled: true`
262+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
263263

264264
**For each executable hook**:
265265
- **Optional hook** (`optional: true`):

presets/agentic-sdlc/commands/adlc.spec.tasks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ You **MUST** consider the user input before proceeding (if not empty).
2828
- Check if `{REPO_ROOT}/.specify/extensions.yml` exists in the project root.
2929
- If it exists, read it and look for entries under the `hooks.before_tasks` key
3030
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
31-
- Filter to only hooks where `enabled: true`
31+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
3232
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
3333
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
3434
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation
@@ -147,7 +147,7 @@ If working in a non-git repository:
147147
8. **Check for extension hooks**: After tasks.md is generated, check if `{REPO_ROOT}/.specify/extensions.yml` exists in the project root.
148148
- If it exists, read it and look for entries under the `hooks.after_tasks` key
149149
- If the YAML cannot be parsed or is invalid, skip hook checking silently and continue normally
150-
- Filter to only hooks where `enabled: true`
150+
- Filter out hooks where `enabled` is explicitly `false`. Treat hooks without an `enabled` field as enabled by default.
151151
- For each remaining hook, do **not** attempt to interpret or evaluate hook `condition` expressions:
152152
- If the hook has no `condition` field, or it is null/empty, treat the hook as executable
153153
- If the hook defines a non-empty `condition`, skip the hook and leave condition evaluation to the HookExecutor implementation

0 commit comments

Comments
 (0)