Compare commits

..

3 Commits

Author SHA1 Message Date
layla
13dec1de05 Fix docs: update Antigravity link and add initialization example (#1748)
* Fix docs: update Antigravity link and add initialization example

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-04 08:29:52 -06:00
Manfred Riem
d0a112c60f fix: wire after_tasks and after_implement hook events into command templates (#1702)
* fix: wire after_tasks and after_implement hook events into command templates (#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>
2026-03-04 08:16:31 -06:00
Dhilip
c84756b7f3 make c ignores consistent with c++ (#1747) 2026-03-04 08:08:04 -06:00
8 changed files with 200 additions and 2 deletions

View File

@@ -161,7 +161,7 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c
| [Roo Code](https://roocode.com/) | ✅ | |
| [SHAI (OVHcloud)](https://github.com/ovh/shai) | ✅ | |
| [Windsurf](https://windsurf.com/) | ✅ | |
| [Antigravity (agy)](https://agy.ai/) | ✅ | |
| [Antigravity (agy)](https://antigravity.google/) | ✅ | |
| Generic | ✅ | Bring your own agent — use `--ai generic --ai-commands-dir <path>` for unsupported agents |
## 🔧 Specify CLI Reference
@@ -222,6 +222,9 @@ specify init my-project --ai shai
# Initialize with IBM Bob support
specify init my-project --ai bob
# Initialize with Antigravity support
specify init my-project --ai agy
# Initialize with an unsupported agent (generic / bring your own agent)
specify init my-project --ai generic --ai-commands-dir .myagent/commands/

View File

@@ -13,6 +13,40 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Pre-Execution Checks
**Check for extension hooks (before implementation)**:
- Check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.before_implement` key
- 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, do **not** attempt to interpret or evaluate hook `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 and leave condition evaluation to the HookExecutor implementation
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
```
## Extension Hooks
**Optional Pre-Hook**: {extension}
Command: `/{command}`
Description: {description}
Prompt: {prompt}
To execute: `/{command}`
```
- **Mandatory hook** (`optional: false`):
```
## Extension Hooks
**Automatic Pre-Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
Wait for the result of the hook command before proceeding to the Outline.
```
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
## Outline
1. 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").
@@ -88,7 +122,7 @@ You **MUST** consider the user input before proceeding (if not empty).
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `autom4te.cache/`, `config.status`, `config.log`, `.idea/`, `*.log`, `.env*`
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `*.dll`, `autom4te.cache/`, `config.status`, `config.log`, `.idea/`, `*.log`, `.env*`
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
@@ -136,3 +170,32 @@ 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
- 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, do **not** attempt to interpret or evaluate hook `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 and leave condition evaluation to the HookExecutor implementation
- 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

View File

@@ -22,6 +22,40 @@ $ARGUMENTS
You **MUST** consider the user input before proceeding (if not empty).
## Pre-Execution Checks
**Check for extension hooks (before tasks generation)**:
- Check if `.specify/extensions.yml` exists in the project root.
- If it exists, read it and look for entries under the `hooks.before_tasks` key
- 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, do **not** attempt to interpret or evaluate hook `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 and leave condition evaluation to the HookExecutor implementation
- For each executable hook, output the following based on its `optional` flag:
- **Optional hook** (`optional: true`):
```
## Extension Hooks
**Optional Pre-Hook**: {extension}
Command: `/{command}`
Description: {description}
Prompt: {prompt}
To execute: `/{command}`
```
- **Mandatory hook** (`optional: false`):
```
## Extension Hooks
**Automatic Pre-Hook**: {extension}
Executing: `/{command}`
EXECUTE_COMMAND: {command}
Wait for the result of the hook command before proceeding to the Outline.
```
- If no hooks are registered or `.specify/extensions.yml` does not exist, skip silently
## Outline
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").
@@ -63,6 +97,35 @@ 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
- 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, do **not** attempt to interpret or evaluate hook `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 and leave condition evaluation to the HookExecutor implementation
- 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
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.

View File

@@ -0,0 +1,34 @@
hooks:
before_implement:
- id: pre_test
enabled: true
optional: false
extension: "test-extension"
command: "pre_implement_test"
description: "Test before implement hook execution"
after_implement:
- id: post_test
enabled: true
optional: true
extension: "test-extension"
command: "post_implement_test"
description: "Test after implement hook execution"
prompt: "Would you like to run the post-implement test?"
before_tasks:
- id: pre_tasks_test
enabled: true
optional: false
extension: "test-extension"
command: "pre_tasks_test"
description: "Test before tasks hook execution"
after_tasks:
- id: post_tasks_test
enabled: true
optional: true
extension: "test-extension"
command: "post_tasks_test"
description: "Test after tasks hook execution"
prompt: "Would you like to run the post-tasks test?"

30
tests/hooks/TESTING.md Normal file
View File

@@ -0,0 +1,30 @@
# Testing Extension Hooks
This directory contains a mock project to verify that LLM agents correctly identify and execute hook commands defined in `.specify/extensions.yml`.
## Test 1: Testing `before_tasks` and `after_tasks`
1. Open a chat with an LLM (like GitHub Copilot) in this project.
2. Ask it to generate tasks for the current directory:
> "Please follow `/speckit.tasks` for the `./tests/hooks` directory."
3. **Expected Behavior**:
- Before doing any generation, the LLM should notice the `AUTOMATIC Pre-Hook` in `.specify/extensions.yml` under `before_tasks`.
- It should state it is executing `EXECUTE_COMMAND: pre_tasks_test`.
- It should then proceed to read the `.md` docs and produce a `tasks.md`.
- After generation, it should output the optional `after_tasks` hook (`post_tasks_test`) block, asking if you want to run it.
## Test 2: Testing `before_implement` and `after_implement`
*(Requires `tasks.md` from Test 1 to exist)*
1. In the same (or new) chat, ask the LLM to implement the tasks:
> "Please follow `/speckit.implement` for the `./tests/hooks` directory."
2. **Expected Behavior**:
- The LLM should first check for `before_implement` hooks.
- It should state it is executing `EXECUTE_COMMAND: pre_implement_test` BEFORE doing any actual task execution.
- It should evaluate the checklists and execute the code writing tasks.
- Upon completion, it should output the optional `after_implement` hook (`post_implement_test`) block.
## How it works
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.

3
tests/hooks/plan.md Normal file
View File

@@ -0,0 +1,3 @@
# Test Setup for Hooks
This feature is designed to test if LLMs correctly invoke Spec Kit extensions hooks when generating tasks and implementing code.

1
tests/hooks/spec.md Normal file
View File

@@ -0,0 +1 @@
- **User Story 1:** I want a test script that prints "Hello hooks!".

1
tests/hooks/tasks.md Normal file
View File

@@ -0,0 +1 @@
- [ ] T001 [US1] Create script that prints 'Hello hooks!' in hello.py