Compare commits

...

7 Commits

Author SHA1 Message Date
Copilot
07fd90a4a1 fix(changelog): correct 0.4.1 section ordering and version reference (#1954)
* Initial plan

* fix(changelog): correct 0.4.1 section ordering and version reference

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/98bc10bc-f444-4833-bd3a-ab8ea0f5e192

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
2026-03-24 10:08:43 -05:00
github-actions[bot]
765b125a0f chore: bump version to 0.4.1 2026-03-24 14:24:01 +00:00
Aaron Sun
a01180955d Add checkpoint extension (#1947)
Co-authored-by: Aaron Sun <aaronsun@mac.lan>
2026-03-24 08:59:43 -05:00
Michal Bachorik
b1ba972978 fix(scripts): prioritize .specify over git for repo root detection (#1933)
* fix(scripts): prioritize .specify over git for repo root detection

When spec-kit is initialized in a subdirectory that doesn't have its
own .git, but a parent directory does, spec-kit was incorrectly using
the parent's git repository root. This caused specs to be created in
the wrong location.

The fix changes repo root detection to prioritize .specify directory
over git rev-parse, ensuring spec-kit respects its own initialization
boundary rather than inheriting a parent git repo.

Fixes #1932

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address code review feedback

- Normalize paths in find_specify_root to prevent infinite loop with relative paths
- Use -PathType Container in PowerShell to only match .specify directories
- Improve has_git/Test-HasGit to check git command availability and validate work tree
- Handle git worktrees/submodules where .git can be a file
- Remove dead fallback code in create-new-feature scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: check .specify before termination in find_specify_root

Fixes edge case where project root is at filesystem root (common in
containers). The loop now checks for .specify before checking the
termination condition.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: scope git operations to spec-kit root & remove unused helpers

- get_current_branch now uses has_git check and runs git with -C to
  prevent using parent git repo branch names in .specify-only projects
- Same fix applied to PowerShell Get-CurrentBranch
- Removed unused find_repo_root() from create-new-feature.sh
- Removed unused Find-RepositoryRoot from create-new-feature.ps1

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: use cd -- to handle paths starting with dash

Prevents cd from interpreting directory names like -P or -L as options.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: check git command exists before calling get_repo_root in has_git

Avoids unnecessary work when git isn't installed since get_repo_root
may internally call git rev-parse.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(powershell): use LiteralPath and check git before Get-RepoRoot

- Use -LiteralPath in Find-SpecifyRoot to handle paths with wildcard
  characters ([, ], *, ?)
- Check Get-Command git before calling Get-RepoRoot in Test-HasGit to
  avoid unnecessary work when git isn't installed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(powershell): use LiteralPath for .git check in Test-HasGit

Prevents Test-Path from treating wildcard characters in paths as globs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(powershell): use LiteralPath in Get-RepoRoot fallback

Prevents Resolve-Path from treating wildcard characters as patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: iamaeroplane <michal.bachorik@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-24 08:55:21 -05:00
Manfred Riem
24247c24c9 docs: add AIDE extension demo to community projects (#1943)
Add the AIDE extension demo to the community projects section,
showcasing a Spring Boot + React project that uses a custom
extension with an alternative spec-driven workflow featuring
a 7-step iterative lifecycle.
2026-03-23 18:14:29 -05:00
Ismael
dc7f09a711 fix(templates): add missing Assumptions section to spec template (#1939) 2026-03-23 16:30:39 -05:00
Manfred Riem
b72a5850fe chore: bump version to 0.4.0 (#1937)
* chore: bump version to 0.4.0

* fix: restore newest-first ordering in CHANGELOG.md for v0.4.0 (#1938)

* Initial plan

* fix: move 0.4.0 section above 0.3.2 to restore newest-first ordering in CHANGELOG.md

Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/spec-kit/sessions/1c1787ad-64df-4b8c-bd32-0bc5198f5029

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mnriem <15701806+mnriem@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
2026-03-23 09:53:19 -05:00
10 changed files with 205 additions and 96 deletions

View File

@@ -1,11 +1,33 @@
# Changelog
## [0.3.2] - 2026-03-19
## [0.4.1] - 2026-03-24
### Changes
- chore: bump version to 0.3.2
- Add conduct extension to community catalog (#1908)
- Add checkpoint extension (#1947)
- fix(scripts): prioritize .specify over git for repo root detection (#1933)
- docs: add AIDE extension demo to community projects (#1943)
- fix(templates): add missing Assumptions section to spec template (#1939)
- chore: bump version to 0.4.1 (#1937)
## [0.4.0] - 2026-03-23
### Changes
- fix(cli): add allow_unicode=True and encoding="utf-8" to YAML I/O (#1936)
- fix(codex): native skills fallback refresh + legacy prompt suppression (#1930)
- feat(cli): embed core pack in wheel for offline/air-gapped deployment (#1803)
- ci: increase stale workflow operations-per-run to 250 (#1922)
- docs: update publishing guide with Category and Effect columns (#1913)
- fix: Align native skills frontmatter with install_ai_skills (#1920)
- feat: add timestamp-based branch naming option for `specify init` (#1911)
- docs: add Extension Comparison Guide for community extensions (#1897)
- docs: update SUPPORT.md, fix issue templates, add preset submission template (#1910)
- Add support for Junie (#1831)
- feat: migrate Codex/agy init to native skills workflow (#1906)
- chore: bump version to 0.3.2 (#1909)
- feat(extensions): add verify-tasks extension to community catalog (#1871)
- feat(presets): add enable/disable toggle and update semantics (#1891)
- feat: add iFlow CLI support (#1875)
@@ -21,6 +43,13 @@
- Feature/spec kit add pi coding agent pullrequest (#1853)
- feat: register spec-kit-learn extension (#1883)
## [0.3.2] - 2026-03-19
### Changes
- chore: bump version to 0.3.2
- Add conduct extension to community catalog (#1908)
## [0.3.1] - 2026-03-17
### Changed

View File

@@ -171,6 +171,8 @@ See Spec-Driven Development in action across different scenarios with these comm
- **[Greenfield Spring Boot MVC with a custom preset](https://github.com/mnriem/spec-kit-pirate-speak-preset-demo)** — Builds a Spring Boot MVC application from scratch using a custom pirate-speak preset, demonstrating how presets can reshape the entire spec-kit experience: specifications become "Voyage Manifests," plans become "Battle Plans," and tasks become "Crew Assignments" — all generated in full pirate vernacular without changing any tooling.
- **[Greenfield Spring Boot + React with a custom extension](https://github.com/mnriem/spec-kit-aide-extension-demo)** — Walks through the **AIDE extension**, a community extension that adds an alternative spec-driven workflow to spec-kit with high-level specs (vision) and low-level specs (work items) organized in a 7-step iterative lifecycle: vision → roadmap → progress tracking → work queue → work items → execution → feedback loops. Uses a family trading platform (Spring Boot 4, React 19, PostgreSQL, Docker Compose) as the scenario to illustrate how the extension mechanism lets you plug in a different style of spec-driven development without changing any core tooling — truly utilizing the "Kit" in Spec Kit.
## 🤖 Supported AI Agents
| Agent | Support | Notes |

View File

@@ -78,6 +78,7 @@ The following community-contributed extensions are available in [`catalog.commun
|-----------|---------|----------|--------|-----|
| Archive Extension | Archive merged features into main project memory. | `docs` | Read+Write | [spec-kit-archive](https://github.com/stn1slv/spec-kit-archive) |
| Azure DevOps Integration | Sync user stories and tasks to Azure DevOps work items using OAuth authentication | `integration` | Read+Write | [spec-kit-azure-devops](https://github.com/pragya247/spec-kit-azure-devops) |
| Checkpoint Extension | Commit the changes made during the middle of the implementation, so you don't end up with just one very large commit at the end | `code` | Read+Write | [spec-kit-checkpoint](https://github.com/aaronrsun/spec-kit-checkpoint) |
| Cleanup Extension | Post-implementation quality gate that reviews changes, fixes small issues (scout rule), creates tasks for medium issues, and generates analysis for large issues | `code` | Read+Write | [spec-kit-cleanup](https://github.com/dsrednicki/spec-kit-cleanup) |
| Cognitive Squad | Multi-agent cognitive system with Triadic Model: understanding, internalization, application — with quality gates, backpropagation verification, and self-healing | `docs` | Read+Write | [cognitive-squad](https://github.com/Testimonial/cognitive-squad) |
| Conduct Extension | Orchestrates spec-kit phases via sub-agent delegation to reduce context pollution. | `process` | Read+Write | [spec-kit-conduct-ext](https://github.com/twbrandon7/spec-kit-conduct-ext) |

View File

@@ -73,6 +73,35 @@
"created_at": "2026-03-03T00:00:00Z",
"updated_at": "2026-03-03T00:00:00Z"
},
"checkpoint": {
"name": "Checkpoint Extension",
"id": "checkpoint",
"description": "An extension to commit the changes made during the middle of the implementation, so you don't end up with just one very large commit at the end.",
"author": "aaronrsun",
"version": "1.0.0",
"download_url": "https://github.com/aaronrsun/spec-kit-checkpoint/archive/refs/tags/v1.0.0.zip",
"repository": "https://github.com/aaronrsun/spec-kit-checkpoint",
"homepage": "https://github.com/aaronrsun/spec-kit-checkpoint",
"documentation": "https://github.com/aaronrsun/spec-kit-checkpoint/blob/main/README.md",
"changelog": "https://github.com/aaronrsun/spec-kit-checkpoint/blob/main/CHANGELOG.md",
"license": "MIT",
"requires": {
"speckit_version": ">=0.1.0"
},
"provides": {
"commands": 1,
"hooks": 0
},
"tags": [
"checkpoint",
"commit"
],
"verified": false,
"downloads": 0,
"stars": 0,
"created_at": "2026-03-22T00:00:00Z",
"updated_at": "2026-03-22T00:00:00Z"
},
"cleanup": {
"name": "Cleanup Extension",
"id": "cleanup",

View File

@@ -1,6 +1,6 @@
[project]
name = "specify-cli"
version = "0.3.2"
version = "0.4.1"
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
requires-python = ">=3.11"
dependencies = [

View File

@@ -1,15 +1,48 @@
#!/usr/bin/env bash
# Common functions and variables for all scripts
# Get repository root, with fallback for non-git repositories
# Find repository root by searching upward for .specify directory
# This is the primary marker for spec-kit projects
find_specify_root() {
local dir="${1:-$(pwd)}"
# Normalize to absolute path to prevent infinite loop with relative paths
# Use -- to handle paths starting with - (e.g., -P, -L)
dir="$(cd -- "$dir" 2>/dev/null && pwd)" || return 1
local prev_dir=""
while true; do
if [ -d "$dir/.specify" ]; then
echo "$dir"
return 0
fi
# Stop if we've reached filesystem root or dirname stops changing
if [ "$dir" = "/" ] || [ "$dir" = "$prev_dir" ]; then
break
fi
prev_dir="$dir"
dir="$(dirname "$dir")"
done
return 1
}
# Get repository root, prioritizing .specify directory over git
# This prevents using a parent git repo when spec-kit is initialized in a subdirectory
get_repo_root() {
# First, look for .specify directory (spec-kit's own marker)
local specify_root
if specify_root=$(find_specify_root); then
echo "$specify_root"
return
fi
# Fallback to git if no .specify found
if git rev-parse --show-toplevel >/dev/null 2>&1; then
git rev-parse --show-toplevel
else
# Fall back to script location for non-git repos
local script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
(cd "$script_dir/../../.." && pwd)
return
fi
# Final fallback to script location for non-git repos
local script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
(cd "$script_dir/../../.." && pwd)
}
# Get current branch, with fallback for non-git repositories
@@ -20,14 +53,14 @@ get_current_branch() {
return
fi
# Then check git if available
if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
git rev-parse --abbrev-ref HEAD
# Then check git if available at the spec-kit root (not parent)
local repo_root=$(get_repo_root)
if has_git; then
git -C "$repo_root" rev-parse --abbrev-ref HEAD
return
fi
# For non-git repos, try to find the latest feature directory
local repo_root=$(get_repo_root)
local specs_dir="$repo_root/specs"
if [[ -d "$specs_dir" ]]; then
@@ -68,9 +101,17 @@ get_current_branch() {
echo "main" # Final fallback
}
# Check if we have git available
# Check if we have git available at the spec-kit root level
# Returns true only if git is installed and the repo root is inside a git work tree
# Handles both regular repos (.git directory) and worktrees/submodules (.git file)
has_git() {
git rev-parse --show-toplevel >/dev/null 2>&1
# First check if git command is available (before calling get_repo_root which may use git)
command -v git >/dev/null 2>&1 || return 1
local repo_root=$(get_repo_root)
# Check if .git exists (directory or file for worktrees/submodules)
[ -e "$repo_root/.git" ] || return 1
# Verify it's actually a valid git work tree
git -C "$repo_root" rev-parse --is-inside-work-tree >/dev/null 2>&1
}
check_feature_branch() {

View File

@@ -80,19 +80,6 @@ if [ -z "$FEATURE_DESCRIPTION" ]; then
exit 1
fi
# Function to find the repository root by searching for existing project markers
find_repo_root() {
local dir="$1"
while [ "$dir" != "/" ]; do
if [ -d "$dir/.git" ] || [ -d "$dir/.specify" ]; then
echo "$dir"
return 0
fi
dir="$(dirname "$dir")"
done
return 1
}
# Function to get highest number from specs directory
get_highest_from_specs() {
local specs_dir="$1"
@@ -171,21 +158,16 @@ clean_branch_name() {
echo "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//'
}
# Resolve repository root. Prefer git information when available, but fall back
# to searching for repository markers so the workflow still functions in repositories that
# were initialised with --no-git.
# Resolve repository root using common.sh functions which prioritize .specify over git
SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
if git rev-parse --show-toplevel >/dev/null 2>&1; then
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_ROOT=$(get_repo_root)
# Check if git is available at this repo root (not a parent)
if has_git; then
HAS_GIT=true
else
REPO_ROOT="$(find_repo_root "$SCRIPT_DIR")"
if [ -z "$REPO_ROOT" ]; then
echo "Error: Could not determine repository root. Please run this script from within the repository." >&2
exit 1
fi
HAS_GIT=false
fi

View File

@@ -1,7 +1,38 @@
#!/usr/bin/env pwsh
# Common PowerShell functions analogous to common.sh
# Find repository root by searching upward for .specify directory
# This is the primary marker for spec-kit projects
function Find-SpecifyRoot {
param([string]$StartDir = (Get-Location).Path)
# Normalize to absolute path to prevent issues with relative paths
# Use -LiteralPath to handle paths with wildcard characters ([, ], *, ?)
$current = (Resolve-Path -LiteralPath $StartDir -ErrorAction SilentlyContinue)?.Path
if (-not $current) { return $null }
while ($true) {
if (Test-Path -LiteralPath (Join-Path $current ".specify") -PathType Container) {
return $current
}
$parent = Split-Path $current -Parent
if ([string]::IsNullOrEmpty($parent) -or $parent -eq $current) {
return $null
}
$current = $parent
}
}
# Get repository root, prioritizing .specify directory over git
# This prevents using a parent git repo when spec-kit is initialized in a subdirectory
function Get-RepoRoot {
# First, look for .specify directory (spec-kit's own marker)
$specifyRoot = Find-SpecifyRoot
if ($specifyRoot) {
return $specifyRoot
}
# Fallback to git if no .specify found
try {
$result = git rev-parse --show-toplevel 2>$null
if ($LASTEXITCODE -eq 0) {
@@ -10,9 +41,10 @@ function Get-RepoRoot {
} catch {
# Git command failed
}
# Fall back to script location for non-git repos
return (Resolve-Path (Join-Path $PSScriptRoot "../../..")).Path
# Final fallback to script location for non-git repos
# Use -LiteralPath to handle paths with wildcard characters
return (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "../../..")).Path
}
function Get-CurrentBranch {
@@ -20,19 +52,21 @@ function Get-CurrentBranch {
if ($env:SPECIFY_FEATURE) {
return $env:SPECIFY_FEATURE
}
# Then check git if available
try {
$result = git rev-parse --abbrev-ref HEAD 2>$null
if ($LASTEXITCODE -eq 0) {
return $result
}
} catch {
# Git command failed
}
# For non-git repos, try to find the latest feature directory
# Then check git if available at the spec-kit root (not parent)
$repoRoot = Get-RepoRoot
if (Test-HasGit) {
try {
$result = git -C $repoRoot rev-parse --abbrev-ref HEAD 2>$null
if ($LASTEXITCODE -eq 0) {
return $result
}
} catch {
# Git command failed
}
}
# For non-git repos, try to find the latest feature directory
$specsDir = Join-Path $repoRoot "specs"
if (Test-Path $specsDir) {
@@ -69,9 +103,23 @@ function Get-CurrentBranch {
return "main"
}
# Check if we have git available at the spec-kit root level
# Returns true only if git is installed and the repo root is inside a git work tree
# Handles both regular repos (.git directory) and worktrees/submodules (.git file)
function Test-HasGit {
# First check if git command is available (before calling Get-RepoRoot which may use git)
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
return $false
}
$repoRoot = Get-RepoRoot
# Check if .git exists (directory or file for worktrees/submodules)
# Use -LiteralPath to handle paths with wildcard characters
if (-not (Test-Path -LiteralPath (Join-Path $repoRoot ".git"))) {
return $false
}
# Verify it's actually a valid git work tree
try {
git rev-parse --show-toplevel 2>$null | Out-Null
$null = git -C $repoRoot rev-parse --is-inside-work-tree 2>$null
return ($LASTEXITCODE -eq 0)
} catch {
return $false

View File

@@ -45,30 +45,6 @@ if ([string]::IsNullOrWhiteSpace($featureDesc)) {
exit 1
}
# Resolve repository root. Prefer git information when available, but fall back
# to searching for repository markers so the workflow still functions in repositories that
# were initialized with --no-git.
function Find-RepositoryRoot {
param(
[string]$StartDir,
[string[]]$Markers = @('.git', '.specify')
)
$current = Resolve-Path $StartDir
while ($true) {
foreach ($marker in $Markers) {
if (Test-Path (Join-Path $current $marker)) {
return $current
}
}
$parent = Split-Path $current -Parent
if ($parent -eq $current) {
# Reached filesystem root without finding markers
return $null
}
$current = $parent
}
}
function Get-HighestNumberFromSpecs {
param([string]$SpecsDir)
@@ -139,26 +115,14 @@ function ConvertTo-CleanBranchName {
return $Name.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''
}
$fallbackRoot = (Find-RepositoryRoot -StartDir $PSScriptRoot)
if (-not $fallbackRoot) {
Write-Error "Error: Could not determine repository root. Please run this script from within the repository."
exit 1
}
# Load common functions (includes Resolve-Template)
# Load common functions (includes Get-RepoRoot, Test-HasGit, Resolve-Template)
. "$PSScriptRoot/common.ps1"
try {
$repoRoot = git rev-parse --show-toplevel 2>$null
if ($LASTEXITCODE -eq 0) {
$hasGit = $true
} else {
throw "Git not available"
}
} catch {
$repoRoot = $fallbackRoot
$hasGit = $false
}
# Use common.ps1 functions which prioritize .specify over git
$repoRoot = Get-RepoRoot
# Check if git is available at this repo root (not a parent)
$hasGit = Test-HasGit
Set-Location $repoRoot

View File

@@ -113,3 +113,16 @@
- **SC-002**: [Measurable metric, e.g., "System handles 1000 concurrent users without degradation"]
- **SC-003**: [User satisfaction metric, e.g., "90% of users successfully complete primary task on first attempt"]
- **SC-004**: [Business metric, e.g., "Reduce support tickets related to [X] by 50%"]
## Assumptions
<!--
ACTION REQUIRED: The content in this section represents placeholders.
Fill them out with the right assumptions based on reasonable defaults
chosen when the feature description did not specify certain details.
-->
- [Assumption about target users, e.g., "Users have stable internet connectivity"]
- [Assumption about scope boundaries, e.g., "Mobile support is out of scope for v1"]
- [Assumption about data/environment, e.g., "Existing authentication system will be reused"]
- [Dependency on existing system/service, e.g., "Requires access to the existing user profile API"]