* feat: add git extension with hooks on all core commands
- Create extensions/git/ with 5 commands: initialize, feature,
validate, remote, commit
- 18 hooks covering before/after for all 9 core commands
- Scripts: create-new-feature, initialize-repo, auto-commit,
git-common (bash + powershell)
- Configurable: branch_numbering, init_commit_message,
per-command auto-commit with custom messages
- Add hooks to analyze, checklist, clarify, constitution,
taskstoissues command templates
- Allow hooks-only extensions (no commands required)
- Bundle extension in wheel via pyproject.toml force-include
- Resolve bundled extensions locally before catalog lookup
- Remove planned-but-unimplemented before/after_commit hook refs
- Update extension docs (API ref, dev guide, user guide)
- 37 new tests covering manifest, install, all scripts (bash+pwsh),
config reading, graceful degradation
Stage 1: opt-in via 'specify extension add git'. No auto-install,
no changes to specify.md or core git init code.
Refs: #841, #1382, #1066, #1791, #1191
* fix: set git identity env vars in extension tests for CI runners
* fix: address PR review comments
- Fix commands property KeyError for hooks-only extensions
- Fix has_git() operator precedence in git-common.sh
- Align default commit message to '[Spec Kit] Initial commit' across
config-template, extension.yml defaults, and both init scripts
- Update README to reflect all 5 commands and 18 hooks
* fix: address second round of PR review comments
- Add type validation for provides.commands (must be list) and hooks
(must be dict) in manifest _validate()
- Tighten malformed timestamp detection in git-common.sh to catch
7-digit dates without trailing slug (e.g. 2026031-143022)
- Pass REPO_ROOT to has_git/Test-HasGit in create-new-feature scripts
- Fix initialize command docs: surface errors on git failures, only
skip when git is not installed
- Fix commit command docs: 'skips with a warning' not 'silently'
- Add tests for commands:null and hooks:list rejection
* fix: address third round of PR review comments
- Remove scripts frontmatter from command files (CommandRegistrar
rewrites ../../scripts/ to .specify/scripts/ which points at core
scripts, not extension scripts)
- Update speckit.git.commit command to derive event name from hook
context rather than using a static example
- Clarify that hook argument passthrough works via AI agent context
(the agent carries conversation state including user's original
feature description)
* fix: address fourth round of PR review comments
- Validate extension_id against ^[a-z0-9-]+$ in _locate_bundled_extension
to prevent path traversal (security fix)
- Move defaults under config.defaults in extension.yml to match
ConfigManager._get_extension_defaults() schema
- Ship git-config.yml in extension directory so it's copied during
install (provides.config template isn't materialized by ExtensionManager)
- Condition handling in hook templates: intentionally matches existing
pattern from specify/plan/tasks/implement templates (not a new issue)
* fix: add --allow-empty to git commit in initialize-repo scripts
Ensures git init succeeds even on empty repos where nothing has been
staged yet.
* fix: resolve display names to bundled extensions before catalog download
When 'specify extension add "Git Branching Workflow"' is used with a
display name instead of the ID, the catalog resolver now runs first to
map the name to an ID, then checks bundled extensions again with the
resolved ID before falling back to network download.
Also noted: EXECUTE_COMMAND_INVOCATION and condition handling match the
existing pattern in specify/plan/tasks/implement templates (pre-existing,
not introduced by this PR).
* fix: handle before_/after_ prefixes in auto-commit message derivation
- Strip both before_ and after_ prefixes when deriving command name
(fixes misleading 'Auto-commit after before_plan' messages)
- Include phase (before/after) in default commit messages
- Clarify README config example is an override, not default behavior
* fix: use portable grep -qw for word boundary in create-new-feature.sh
BSD grep (macOS) doesn't support \b as a word boundary. Replace with
grep -qw which is POSIX-portable.
* fix: validate hook values, numeric --number, and PS warning routing
- Validate each hook value is a dict with a 'command' field during
manifest _validate() (prevents crash at install time)
- Validate --number is a non-negative integer in bash create-new-feature
(clear error instead of cryptic shell arithmetic failure)
- Route PowerShell no-git warning to stderr in JSON mode so stdout
stays valid JSON
---------
Co-authored-by: Manfred Riem <15701806+mnriem@users.noreply.github.com>
* fix(commands): rename NFR references to success criteria in analyze and clarify
* fix(analyze): align Success Criteria description and inventory keys with spec template
- Reword "non-functional targets" to "measurable outcomes" to match the spec template's broader scope (performance, user success, business impact)
- Use explicit FR-/SC- identifiers as primary stable keys in the requirements inventory instead of derived slugs alone
* feat(commands): wire before/after hook events into specify and plan templates
Replicates the hook evaluation pattern from tasks.md and implement.md
(introduced in PR #1702) into the specify and plan command templates.
This completes the hook lifecycle across all SDD phases.
Changes:
- specify.md: Add before_specify/after_specify hook blocks
- plan.md: Add before_plan/after_plan hook blocks
- EXTENSION-API-REFERENCE.md: Document new hook events
- EXTENSION-USER-GUIDE.md: List all available hook events
Fixes#1788
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Mark before_commit/after_commit as planned in extension docs
These hook events are defined in the API reference but not yet wired
into any core command template. Marking them as planned rather than
removing them, since the infrastructure supports them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix hook enablement to default true when field is absent
Matches HookExecutor.get_hooks_for_event() semantics where
hooks without an explicit enabled field are treated as enabled.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(docs): mark commit hooks as planned in user guide config example
The yaml config comment listed before_commit/after_commit as
"Available events" but they are not yet wired into core templates.
Moved them to a separate "Planned" line, consistent with the
API reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(commands): align enabled-filtering semantics across all hook templates
tasks.md and implement.md previously said "Filter to only hooks where
enabled: true", which would skip hooks that omit the enabled field.
Updated to match specify.md/plan.md and HookExecutor's h.get('enabled', True)
behavior: filter out only hooks where enabled is explicitly false.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove per-short-name number detection from specify prompt
The specify.md prompt instructed the AI to search for existing branches
filtered by the exact short-name, causing every new feature to start at
001 since no branches matched the new short-name. The underlying
create-new-feature.sh script already has correct global numbering logic
via check_existing_branches() that searches ALL branches and spec
directories.
The fix removes the AI's flawed number-detection steps and tells it to
NOT pass --number, letting the script auto-detect the next globally
available number.
Closes#1744Closes#1468🤖 Generated with [Claude Code](https://claude.com/code)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clarify --json flag requirement per Copilot review
- Rephrased step 2 to mention both --short-name and --json flags
- Added explicit note to always include the JSON flag for reliable output parsing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* 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>
* fix(implement): remove Makefile from C ignore patterns
Makefile is typically source-controlled and should not be in .gitignore.
Replaced with proper autotools-generated files (autom4te.cache/, config.status).
Co-authored-by: Augment Agent <noreply@augmentcode.com>
* fix(implement): restore config.log in C ignore patterns
---------
Co-authored-by: Augment Agent <noreply@augmentcode.com>
* fix(checklist): clarify file handling behavior for append vs create
Resolves contradictory instructions in checklist.md lines 97-99 where the
template stated both 'append to existing file' and 'creates a NEW file'.
Changes:
- Clarified that if file doesn't exist, create new with CHK001
- If file exists, append new items continuing from last CHK ID
- Emphasized preservation of existing content (never delete/replace)
Co-authored-by: Augment Agent <noreply@augmentcode.com>
* fix(checklist): align report language with append behavior
---------
Co-authored-by: Augment Agent <noreply@augmentcode.com>
Resolves inconsistency where line 92 stated 'Maximum of 10 total questions'
while all other references (lines 2, 91, 100, 134, 158, 178) consistently
specify a maximum of 5 questions.
Co-authored-by: Augment Agent <noreply@augmentcode.com>
Moves constitution template from memory/ to templates/ to prevent
overwrites when spec-kit is reinitialized with a different AI agent.
Changes:
- Move memory/constitution.md to templates/constitution-template.md
- Update CLI to copy template to memory/ only on first initialization
- Update constitution command to reference correct paths with .specify/ prefix
- Preserve existing constitution.md when reinitializing project
The CLI now checks if .specify/memory/constitution.md exists:
- If it exists: preserve it (no overwrite)
- If it doesn't exist: copy from .specify/templates/constitution-template.md
This allows users to customize their constitution without losing changes
when adding support for additional AI agents or reinitializing.
Fixes#1541
Co-authored-by: jjoung1128 <jinwoong.joung@gmail.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use git ls-remote for more reliable remote branch detection
- Check remote branches, local branches, AND specs directories
- Match exact short-name pattern to avoid false positives
- Ensures no duplicate numbers across all sources
- Add --number parameter to create-new-feature scripts (bash & PowerShell)
- Add check_existing_branches() function to fetch and scan remote branches
- Update branch numbering logic to check remotes before creating new branches
- Update /speckit.specify command to document remote branch checking workflow
- Prevents duplicate branch numbers when branches exist on remotes but not locally
- Maintains backward compatibility with existing workflows
- Falls back to local directory scanning when Git is not available
Update speckit.implement.md to correct the command for regenerating the task list from '/tasks' to '/speckit.tasks', ensuring accurate documentation for task breakdown requirements.
Update speckit.analyze.md to reflect changes in command references, ensuring consistency in the execution flow and clarity in the analysis process. The command now specifies `/speckit.tasks` and `/speckit.implement` for improved user guidance.
Add automated markdown linting to ensure consistent formatting across
all markdown files in the repository.
Changes:
- Add .markdownlint-cli2.jsonc configuration
- Create .github/workflows/lint.yml for CI/CD integration
- Fix all 908 existing markdown errors across 27 files
- Enforce ATX-style headings and asterisk emphasis
- Set consistent 2-space list indentation
This prevents markdown errors after project initialization and
maintains high documentation quality standards.