From 2e1301363364fbf9d53800caee4785f123da6fbe Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:28:09 -0700 Subject: [PATCH 01/43] Use VS Code handoffs --- templates/commands/constitution.md | 5 ++++- templates/commands/plan.md | 5 +++++ templates/commands/specify.md | 4 ++++ templates/commands/tasks.md | 5 +++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index f557dd17c4..36182a2fe9 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -1,5 +1,8 @@ --- -description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync +description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync. +handoffs: + - label: Build Specification + agent: speckit.spec --- ## User Input diff --git a/templates/commands/plan.md b/templates/commands/plan.md index 7dfe63a2fc..f05085e002 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -1,5 +1,10 @@ --- description: Execute the implementation planning workflow using the plan template to generate design artifacts. +handoffs: + - label: Create Tasks + agent: speckit.tasks + prompt: Break the plan into tasks + send: true scripts: sh: scripts/bash/setup-plan.sh --json ps: scripts/powershell/setup-plan.ps1 -Json diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 03f681e573..12a9ea326d 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -1,5 +1,9 @@ --- description: Create or update the feature specification from a natural language feature description. +handoffs: + - label: Build Technical Plan + agent: speckit.plan + prompt: Create a plan for the spec scripts: sh: scripts/bash/create-new-feature.sh --json "{ARGS}" ps: scripts/powershell/create-new-feature.ps1 -Json "{ARGS}" diff --git a/templates/commands/tasks.md b/templates/commands/tasks.md index 4663c1b678..f63c4b9ff7 100644 --- a/templates/commands/tasks.md +++ b/templates/commands/tasks.md @@ -1,5 +1,10 @@ --- description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. +handoffs: + - label: Implement Project + agent: speckit.implement + prompt: Start the implementation in phases + send: true scripts: sh: scripts/bash/check-prerequisites.sh --json ps: scripts/powershell/check-prerequisites.ps1 -Json From ffa657c3cc8418b32e2ff29af8347d2cba551af2 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:35:46 -0700 Subject: [PATCH 02/43] Testing hand-offs --- .github/workflows/scripts/create-release-packages.sh | 6 +++--- AGENTS.md | 12 ++++++++++-- scripts/bash/update-agent-context.sh | 2 +- scripts/powershell/update-agent-context.ps1 | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index f9d3b1ae18..412c52e7dc 100644 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -95,7 +95,7 @@ generate_commands() { { echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;; md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; - prompt.md) + chatmode.md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; esac done @@ -146,8 +146,8 @@ build_variant() { generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script" [[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;; copilot) - mkdir -p "$base_dir/.github/prompts" - generate_commands copilot prompt.md "\$ARGUMENTS" "$base_dir/.github/prompts" "$script" + mkdir -p "$base_dir/.github/chatmodes" + generate_commands copilot chatmode.md "\$ARGUMENTS" "$base_dir/.github/chatmodes" "$script" # Create VS Code workspace settings mkdir -p "$base_dir/.vscode" [[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json" diff --git a/AGENTS.md b/AGENTS.md index d34efb673a..b9e3f9f7b3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Specify supports multiple AI agents by generating agent-specific command files a |-------|-----------|---------|----------|-------------| | **Claude Code** | `.claude/commands/` | Markdown | `claude` | Anthropic's Claude Code CLI | | **Gemini CLI** | `.gemini/commands/` | TOML | `gemini` | Google's Gemini CLI | -| **GitHub Copilot** | `.github/prompts/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | +| **GitHub Copilot** | `.github/chatmodes/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | | **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI | | **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI | | **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI | @@ -325,6 +325,7 @@ Work within integrated development environments: Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp +**Standard format:** ```markdown --- description: "Command description" @@ -333,6 +334,13 @@ description: "Command description" Command content with {SCRIPT} and $ARGUMENTS placeholders. ``` +**GitHub Copilot Chat Mode format:** +```markdown +# Command Name + +Command content with {SCRIPT} and $ARGUMENTS placeholders. +``` + ### TOML Format Used by: Gemini, Qwen @@ -349,7 +357,7 @@ Command content with {SCRIPT} and {{args}} placeholders. - **CLI agents**: Usually `./commands/` - **IDE agents**: Follow IDE-specific patterns: - - Copilot: `.github/prompts/` + - Copilot: `.github/chatmodes/` - Cursor: `.cursor/commands/` - Windsurf: `.windsurf/workflows/` diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index 2a44c68a10..e327869d8f 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -61,7 +61,7 @@ AGENT_TYPE="${1:-}" # Agent-specific file paths CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" -COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md" +COPILOT_FILE="$REPO_ROOT/.github/chatmodes/copilot-instructions.md" CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" QWEN_FILE="$REPO_ROOT/QWEN.md" AGENTS_FILE="$REPO_ROOT/AGENTS.md" diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index 695e28b8db..d8fe34bf13 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -46,7 +46,7 @@ $NEW_PLAN = $IMPL_PLAN # Agent file paths $CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' -$COPILOT_FILE = Join-Path $REPO_ROOT '.github/copilot-instructions.md' +$COPILOT_FILE = Join-Path $REPO_ROOT '.github/chatmodes/copilot-instructions.md' $CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' $QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' From 785f10abc72a593704100c9e074492e65cd767a8 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:39:11 -0700 Subject: [PATCH 03/43] Update with prompt --- templates/commands/constitution.md | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index 36182a2fe9..d7cc37873b 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -3,6 +3,7 @@ description: Create or update the project constitution from interactive or provi handoffs: - label: Build Specification agent: speckit.spec + prompt: Implement the feature specification based on the updated constitution. I want to build... --- ## User Input From 3654c307eaa079d5a9b4ee3b791a0e9b9b06a153 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:48:59 -0700 Subject: [PATCH 04/43] Update prompts --- templates/commands/constitution.md | 2 +- templates/commands/plan.md | 4 +++- templates/commands/specify.md | 3 +++ templates/commands/tasks.md | 4 ++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index d7cc37873b..cf81f08c2f 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -2,7 +2,7 @@ description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync. handoffs: - label: Build Specification - agent: speckit.spec + agent: speckit.specify prompt: Implement the feature specification based on the updated constitution. I want to build... --- diff --git a/templates/commands/plan.md b/templates/commands/plan.md index f05085e002..f030c5119e 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -4,7 +4,9 @@ handoffs: - label: Create Tasks agent: speckit.tasks prompt: Break the plan into tasks - send: true + - label: Create Checklist + agent: speckit.checklist + prompt: Create a checklist for the following domain... scripts: sh: scripts/bash/setup-plan.sh --json ps: scripts/powershell/setup-plan.ps1 -Json diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 12a9ea326d..c69532666c 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -4,6 +4,9 @@ handoffs: - label: Build Technical Plan agent: speckit.plan prompt: Create a plan for the spec + - label: Clarify Spec Requirements + agent: speckit.clarify + prompt: Clarify specification requirements scripts: sh: scripts/bash/create-new-feature.sh --json "{ARGS}" ps: scripts/powershell/create-new-feature.ps1 -Json "{ARGS}" diff --git a/templates/commands/tasks.md b/templates/commands/tasks.md index f63c4b9ff7..adcb8b3a9a 100644 --- a/templates/commands/tasks.md +++ b/templates/commands/tasks.md @@ -1,6 +1,10 @@ --- description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. handoffs: + - label: Analyze For Consistency + agent: speckit.analyze + prompt: Start the implementation in phases + send: true - label: Implement Project agent: speckit.implement prompt: Start the implementation in phases From 67e814426da71b2c47ff9504d903814b873a1efb Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:17:48 -0700 Subject: [PATCH 05/43] Let's switch to proper prompts --- .github/workflows/scripts/create-release-packages.sh | 6 +++--- AGENTS.md | 9 ++++++--- scripts/bash/update-agent-context.sh | 2 +- scripts/powershell/update-agent-context.ps1 | 2 +- templates/commands/analyze.md | 1 + templates/commands/checklist.md | 1 + templates/commands/clarify.md | 1 + templates/commands/constitution.md | 1 + templates/commands/implement.md | 1 + templates/commands/plan.md | 1 + templates/commands/specify.md | 1 + templates/commands/tasks.md | 3 ++- 12 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 412c52e7dc..f9d3b1ae18 100644 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -95,7 +95,7 @@ generate_commands() { { echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;; md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; - chatmode.md) + prompt.md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; esac done @@ -146,8 +146,8 @@ build_variant() { generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script" [[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;; copilot) - mkdir -p "$base_dir/.github/chatmodes" - generate_commands copilot chatmode.md "\$ARGUMENTS" "$base_dir/.github/chatmodes" "$script" + mkdir -p "$base_dir/.github/prompts" + generate_commands copilot prompt.md "\$ARGUMENTS" "$base_dir/.github/prompts" "$script" # Create VS Code workspace settings mkdir -p "$base_dir/.vscode" [[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json" diff --git a/AGENTS.md b/AGENTS.md index b9e3f9f7b3..3f1abddf19 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Specify supports multiple AI agents by generating agent-specific command files a |-------|-----------|---------|----------|-------------| | **Claude Code** | `.claude/commands/` | Markdown | `claude` | Anthropic's Claude Code CLI | | **Gemini CLI** | `.gemini/commands/` | TOML | `gemini` | Google's Gemini CLI | -| **GitHub Copilot** | `.github/chatmodes/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | +| **GitHub Copilot** | `.github/prompts/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | | **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI | | **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI | | **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI | @@ -336,7 +336,10 @@ Command content with {SCRIPT} and $ARGUMENTS placeholders. **GitHub Copilot Chat Mode format:** ```markdown -# Command Name +--- +description: "Command description" +mode: speckit.command-name +--- Command content with {SCRIPT} and $ARGUMENTS placeholders. ``` @@ -357,7 +360,7 @@ Command content with {SCRIPT} and {{args}} placeholders. - **CLI agents**: Usually `./commands/` - **IDE agents**: Follow IDE-specific patterns: - - Copilot: `.github/chatmodes/` + - Copilot: `.github/prompts/` - Cursor: `.cursor/commands/` - Windsurf: `.windsurf/workflows/` diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index e327869d8f..3782beb6ba 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -61,7 +61,7 @@ AGENT_TYPE="${1:-}" # Agent-specific file paths CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" -COPILOT_FILE="$REPO_ROOT/.github/chatmodes/copilot-instructions.md" +COPILOT_FILE="$REPO_ROOT/.github/prompts/copilot-instructions.md" CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" QWEN_FILE="$REPO_ROOT/QWEN.md" AGENTS_FILE="$REPO_ROOT/AGENTS.md" diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index d8fe34bf13..b4413c6346 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -46,7 +46,7 @@ $NEW_PLAN = $IMPL_PLAN # Agent file paths $CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' -$COPILOT_FILE = Join-Path $REPO_ROOT '.github/chatmodes/copilot-instructions.md' +$COPILOT_FILE = Join-Path $REPO_ROOT '.github/prompts/copilot-instructions.md' $CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' $QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' diff --git a/templates/commands/analyze.md b/templates/commands/analyze.md index 827d4e4caf..c95b3881a8 100644 --- a/templates/commands/analyze.md +++ b/templates/commands/analyze.md @@ -1,5 +1,6 @@ --- description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation. +mode: speckit.analyze scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks diff --git a/templates/commands/checklist.md b/templates/commands/checklist.md index e32a2c843b..ead1d08896 100644 --- a/templates/commands/checklist.md +++ b/templates/commands/checklist.md @@ -1,5 +1,6 @@ --- description: Generate a custom checklist for the current feature based on user requirements. +mode: speckit.checklist scripts: sh: scripts/bash/check-prerequisites.sh --json ps: scripts/powershell/check-prerequisites.ps1 -Json diff --git a/templates/commands/clarify.md b/templates/commands/clarify.md index 9a62dfa74c..6ccfced855 100644 --- a/templates/commands/clarify.md +++ b/templates/commands/clarify.md @@ -1,5 +1,6 @@ --- description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec. +mode: speckit.clarify scripts: sh: scripts/bash/check-prerequisites.sh --json --paths-only ps: scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index cf81f08c2f..04e78a24ad 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -1,5 +1,6 @@ --- description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync. +mode: speckit.constitution handoffs: - label: Build Specification agent: speckit.specify diff --git a/templates/commands/implement.md b/templates/commands/implement.md index 38601920d5..3a7c31ef9b 100644 --- a/templates/commands/implement.md +++ b/templates/commands/implement.md @@ -1,5 +1,6 @@ --- description: Execute the implementation plan by processing and executing all tasks defined in tasks.md +mode: speckit.implement scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks diff --git a/templates/commands/plan.md b/templates/commands/plan.md index f030c5119e..65552171a4 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -1,5 +1,6 @@ --- description: Execute the implementation planning workflow using the plan template to generate design artifacts. +mode: speckit.plan handoffs: - label: Create Tasks agent: speckit.tasks diff --git a/templates/commands/specify.md b/templates/commands/specify.md index c69532666c..4a6243f0c7 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -1,5 +1,6 @@ --- description: Create or update the feature specification from a natural language feature description. +mode: speckit.specify handoffs: - label: Build Technical Plan agent: speckit.plan diff --git a/templates/commands/tasks.md b/templates/commands/tasks.md index adcb8b3a9a..0cea57bc5e 100644 --- a/templates/commands/tasks.md +++ b/templates/commands/tasks.md @@ -1,9 +1,10 @@ --- description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. +mode: speckit.tasks handoffs: - label: Analyze For Consistency agent: speckit.analyze - prompt: Start the implementation in phases + prompt: Run a project analysis for consistency send: true - label: Implement Project agent: speckit.implement From e2bbb49cba375ddf3bb21fb7324cf49f60e51c7b Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:29:45 -0700 Subject: [PATCH 06/43] Chatmodes are back in vogue --- .github/workflows/scripts/create-release-packages.sh | 6 +++--- AGENTS.md | 4 ++-- scripts/bash/update-agent-context.sh | 2 +- scripts/powershell/update-agent-context.ps1 | 2 +- templates/commands/analyze.md | 1 - templates/commands/checklist.md | 1 - templates/commands/clarify.md | 1 - templates/commands/constitution.md | 1 - templates/commands/implement.md | 1 - templates/commands/plan.md | 1 - templates/commands/specify.md | 1 - templates/commands/tasks.md | 1 - 12 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index f9d3b1ae18..412c52e7dc 100644 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -95,7 +95,7 @@ generate_commands() { { echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;; md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; - prompt.md) + chatmode.md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; esac done @@ -146,8 +146,8 @@ build_variant() { generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script" [[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;; copilot) - mkdir -p "$base_dir/.github/prompts" - generate_commands copilot prompt.md "\$ARGUMENTS" "$base_dir/.github/prompts" "$script" + mkdir -p "$base_dir/.github/chatmodes" + generate_commands copilot chatmode.md "\$ARGUMENTS" "$base_dir/.github/chatmodes" "$script" # Create VS Code workspace settings mkdir -p "$base_dir/.vscode" [[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json" diff --git a/AGENTS.md b/AGENTS.md index 3f1abddf19..862dc99131 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Specify supports multiple AI agents by generating agent-specific command files a |-------|-----------|---------|----------|-------------| | **Claude Code** | `.claude/commands/` | Markdown | `claude` | Anthropic's Claude Code CLI | | **Gemini CLI** | `.gemini/commands/` | TOML | `gemini` | Google's Gemini CLI | -| **GitHub Copilot** | `.github/prompts/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | +| **GitHub Copilot** | `.github/chatmodes/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | | **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI | | **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI | | **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI | @@ -360,7 +360,7 @@ Command content with {SCRIPT} and {{args}} placeholders. - **CLI agents**: Usually `./commands/` - **IDE agents**: Follow IDE-specific patterns: - - Copilot: `.github/prompts/` + - Copilot: `.github/chatmodes/` - Cursor: `.cursor/commands/` - Windsurf: `.windsurf/workflows/` diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index 3782beb6ba..e327869d8f 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -61,7 +61,7 @@ AGENT_TYPE="${1:-}" # Agent-specific file paths CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" -COPILOT_FILE="$REPO_ROOT/.github/prompts/copilot-instructions.md" +COPILOT_FILE="$REPO_ROOT/.github/chatmodes/copilot-instructions.md" CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" QWEN_FILE="$REPO_ROOT/QWEN.md" AGENTS_FILE="$REPO_ROOT/AGENTS.md" diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index b4413c6346..d8fe34bf13 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -46,7 +46,7 @@ $NEW_PLAN = $IMPL_PLAN # Agent file paths $CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' -$COPILOT_FILE = Join-Path $REPO_ROOT '.github/prompts/copilot-instructions.md' +$COPILOT_FILE = Join-Path $REPO_ROOT '.github/chatmodes/copilot-instructions.md' $CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' $QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' diff --git a/templates/commands/analyze.md b/templates/commands/analyze.md index c95b3881a8..827d4e4caf 100644 --- a/templates/commands/analyze.md +++ b/templates/commands/analyze.md @@ -1,6 +1,5 @@ --- description: Perform a non-destructive cross-artifact consistency and quality analysis across spec.md, plan.md, and tasks.md after task generation. -mode: speckit.analyze scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks diff --git a/templates/commands/checklist.md b/templates/commands/checklist.md index ead1d08896..e32a2c843b 100644 --- a/templates/commands/checklist.md +++ b/templates/commands/checklist.md @@ -1,6 +1,5 @@ --- description: Generate a custom checklist for the current feature based on user requirements. -mode: speckit.checklist scripts: sh: scripts/bash/check-prerequisites.sh --json ps: scripts/powershell/check-prerequisites.ps1 -Json diff --git a/templates/commands/clarify.md b/templates/commands/clarify.md index 6ccfced855..9a62dfa74c 100644 --- a/templates/commands/clarify.md +++ b/templates/commands/clarify.md @@ -1,6 +1,5 @@ --- description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec. -mode: speckit.clarify scripts: sh: scripts/bash/check-prerequisites.sh --json --paths-only ps: scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index 04e78a24ad..cf81f08c2f 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -1,6 +1,5 @@ --- description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync. -mode: speckit.constitution handoffs: - label: Build Specification agent: speckit.specify diff --git a/templates/commands/implement.md b/templates/commands/implement.md index 3a7c31ef9b..38601920d5 100644 --- a/templates/commands/implement.md +++ b/templates/commands/implement.md @@ -1,6 +1,5 @@ --- description: Execute the implementation plan by processing and executing all tasks defined in tasks.md -mode: speckit.implement scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks diff --git a/templates/commands/plan.md b/templates/commands/plan.md index 65552171a4..f030c5119e 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -1,6 +1,5 @@ --- description: Execute the implementation planning workflow using the plan template to generate design artifacts. -mode: speckit.plan handoffs: - label: Create Tasks agent: speckit.tasks diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 4a6243f0c7..c69532666c 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -1,6 +1,5 @@ --- description: Create or update the feature specification from a natural language feature description. -mode: speckit.specify handoffs: - label: Build Technical Plan agent: speckit.plan diff --git a/templates/commands/tasks.md b/templates/commands/tasks.md index 0cea57bc5e..86a766829f 100644 --- a/templates/commands/tasks.md +++ b/templates/commands/tasks.md @@ -1,6 +1,5 @@ --- description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. -mode: speckit.tasks handoffs: - label: Analyze For Consistency agent: speckit.analyze From 283a698d91bcf6a0ecf7956a4b7324494ffe52ee Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:34:19 -0700 Subject: [PATCH 07/43] Hand offs with prompts --- .../scripts/create-release-packages.sh | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 412c52e7dc..49f2ddad3f 100644 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -101,6 +101,26 @@ generate_commands() { done } +generate_copilot_prompts() { + local chatmodes_dir=$1 prompts_dir=$2 + mkdir -p "$prompts_dir" + + # Generate a .prompt.md file for each .chatmode.md file + for chatmode_file in "$chatmodes_dir"/speckit.*.chatmode.md; do + [[ -f "$chatmode_file" ]] || continue + + local basename=$(basename "$chatmode_file" .chatmode.md) + local prompt_file="$prompts_dir/${basename}.prompt.md" + + # Create prompt file with agent frontmatter + cat > "$prompt_file" < Date: Tue, 21 Oct 2025 14:44:17 -0700 Subject: [PATCH 08/43] Prompt updates --- templates/commands/clarify.md | 4 ++++ templates/commands/specify.md | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/templates/commands/clarify.md b/templates/commands/clarify.md index 9a62dfa74c..4de842aa60 100644 --- a/templates/commands/clarify.md +++ b/templates/commands/clarify.md @@ -1,5 +1,9 @@ --- description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec. +handoffs: + - label: Build Technical Plan + agent: speckit.plan + prompt: Create a plan for the spec. I am building with... scripts: sh: scripts/bash/check-prerequisites.sh --json --paths-only ps: scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly diff --git a/templates/commands/specify.md b/templates/commands/specify.md index c69532666c..61a6ff994f 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -3,10 +3,11 @@ description: Create or update the feature specification from a natural language handoffs: - label: Build Technical Plan agent: speckit.plan - prompt: Create a plan for the spec + prompt: Create a plan for the spec. I am building with... - label: Clarify Spec Requirements agent: speckit.clarify prompt: Clarify specification requirements + send: true scripts: sh: scripts/bash/create-new-feature.sh --json "{ARGS}" ps: scripts/powershell/create-new-feature.ps1 -Json "{ARGS}" From b2e9eb80d1cfb76560f2b478abc496eab2b5955b Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:12:33 -0700 Subject: [PATCH 09/43] Lint fixes --- AGENTS.md | 2 ++ SECURITY.md | 14 +++++++------- templates/agent-file-template.md | 2 +- templates/commands/clarify.md | 10 +++++----- templates/commands/implement.md | 3 +-- templates/commands/plan.md | 3 ++- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 862dc99131..55fd83e285 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -326,6 +326,7 @@ Work within integrated development environments: Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp **Standard format:** + ```markdown --- description: "Command description" @@ -335,6 +336,7 @@ Command content with {SCRIPT} and $ARGUMENTS placeholders. ``` **GitHub Copilot Chat Mode format:** + ```markdown --- description: "Command description" diff --git a/SECURITY.md b/SECURITY.md index 4c1e92da01..68b6f3fce2 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,13 +16,13 @@ Instead, please send an email to opensource-security[@]github.com. Please include as much of the information listed below as you can to help us better understand and resolve the issue: -- The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) -- Full paths of source file(s) related to the manifestation of the issue -- The location of the affected source code (tag/branch/commit or direct URL) -- Any special configuration required to reproduce the issue -- Step-by-step instructions to reproduce the issue -- Proof-of-concept or exploit code (if possible) -- Impact of the issue, including how an attacker might exploit the issue +* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) +* Full paths of source file(s) related to the manifestation of the issue +* The location of the affected source code (tag/branch/commit or direct URL) +* Any special configuration required to reproduce the issue +* Step-by-step instructions to reproduce the issue +* Proof-of-concept or exploit code (if possible) +* Impact of the issue, including how an attacker might exploit the issue This information will help us triage your report more quickly. diff --git a/templates/agent-file-template.md b/templates/agent-file-template.md index 4cc7fd6678..27961a8b1d 100644 --- a/templates/agent-file-template.md +++ b/templates/agent-file-template.md @@ -8,7 +8,7 @@ Auto-generated from all feature plans. Last updated: [DATE] ## Project Structure -```text +``` [ACTUAL STRUCTURE FROM PLANS] ``` diff --git a/templates/commands/clarify.md b/templates/commands/clarify.md index 4de842aa60..daffc8b8a3 100644 --- a/templates/commands/clarify.md +++ b/templates/commands/clarify.md @@ -93,11 +93,11 @@ Execution steps: - Each question must be answerable with EITHER: - A short multiple‑choice selection (2–5 distinct, mutually exclusive options), OR - A one-word / short‑phrase answer (explicitly constrain: "Answer in <=5 words"). - - Only include questions whose answers materially impact architecture, data modeling, task decomposition, test design, UX behavior, operational readiness, or compliance validation. - - Ensure category coverage balance: attempt to cover the highest impact unresolved categories first; avoid asking two low-impact questions when a single high-impact area (e.g., security posture) is unresolved. - - Exclude questions already answered, trivial stylistic preferences, or plan-level execution details (unless blocking correctness). - - Favor clarifications that reduce downstream rework risk or prevent misaligned acceptance tests. - - If more than 5 categories remain unresolved, select the top 5 by (Impact * Uncertainty) heuristic. + - Only include questions whose answers materially impact architecture, data modeling, task decomposition, test design, UX behavior, operational readiness, or compliance validation. + - Ensure category coverage balance: attempt to cover the highest impact unresolved categories first; avoid asking two low-impact questions when a single high-impact area (e.g., security posture) is unresolved. + - Exclude questions already answered, trivial stylistic preferences, or plan-level execution details (unless blocking correctness). + - Favor clarifications that reduce downstream rework risk or prevent misaligned acceptance tests. + - If more than 5 categories remain unresolved, select the top 5 by (Impact * Uncertainty) heuristic. 4. Sequential questioning loop (interactive): - Present EXACTLY ONE question at a time. diff --git a/templates/commands/implement.md b/templates/commands/implement.md index 38601920d5..072b546b55 100644 --- a/templates/commands/implement.md +++ b/templates/commands/implement.md @@ -25,7 +25,7 @@ You **MUST** consider the user input before proceeding (if not empty). - Incomplete items: Lines matching `- [ ]` - Create a status table: - ```text + ``` | Checklist | Total | Completed | Incomplete | Status | |-----------|-------|-----------|------------|--------| | ux.md | 12 | 12 | 0 | ✓ PASS | @@ -135,4 +135,3 @@ 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. - diff --git a/templates/commands/plan.md b/templates/commands/plan.md index f030c5119e..d3ec02f241 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -4,6 +4,7 @@ handoffs: - label: Create Tasks agent: speckit.tasks prompt: Break the plan into tasks + send: true - label: Create Checklist agent: speckit.checklist prompt: Create a checklist for the following domain... @@ -51,7 +52,7 @@ You **MUST** consider the user input before proceeding (if not empty). 2. **Generate and dispatch research agents**: - ```text + ``` For each unknown in Technical Context: Task: "Research {unknown} for {feature context}" For each technology choice: From 867f92321fb2d183c29a17baa0368dbffb9c7d70 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:21:30 -0700 Subject: [PATCH 10/43] Exclude generated releases --- .markdownlint-cli2.jsonc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc index a96fd3e6d9..d6db02777c 100644 --- a/.markdownlint-cli2.jsonc +++ b/.markdownlint-cli2.jsonc @@ -20,5 +20,8 @@ "MD050": { "style": "asterisk" } - } + }, + "ignores": [ + ".genreleases/" + ] } \ No newline at end of file From 3b622cac0b466dda993ceabb31edfc8a24ce5fc4 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:54:10 -0700 Subject: [PATCH 11/43] Support for version command --- pyproject.toml | 2 +- src/specify_cli/__init__.py | 80 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 567d48cd49..e4d2791bdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "specify-cli" -version = "0.0.20" +version = "0.0.21" description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)." requires-python = ">=3.11" dependencies = [ diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index a33a1c61ac..1af32bec73 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1202,6 +1202,86 @@ def check(): if not any(agent_results.values()): console.print("[dim]Tip: Install an AI assistant for the best experience[/dim]") +@app.command() +def version(): + """Display version and system information.""" + import platform + import importlib.metadata + + show_banner() + + # Get CLI version from package metadata + cli_version = "unknown" + try: + cli_version = importlib.metadata.version("specify-cli") + except Exception: + # Fallback: try reading from pyproject.toml if running from source + try: + import tomllib + pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml" + if pyproject_path.exists(): + with open(pyproject_path, "rb") as f: + data = tomllib.load(f) + cli_version = data.get("project", {}).get("version", "unknown") + except Exception: + pass + + # Fetch latest template release version + repo_owner = "github" + repo_name = "spec-kit" + api_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/latest" + + template_version = "unknown" + release_date = "unknown" + + try: + response = client.get( + api_url, + timeout=10, + follow_redirects=True, + headers=_github_auth_headers(), + ) + if response.status_code == 200: + release_data = response.json() + template_version = release_data.get("tag_name", "unknown") + # Remove 'v' prefix if present + if template_version != "unknown" and template_version.startswith("v"): + template_version = template_version[1:] + release_date = release_data.get("published_at", "unknown") + if release_date != "unknown": + # Format the date nicely + from datetime import datetime + try: + dt = datetime.fromisoformat(release_date.replace('Z', '+00:00')) + release_date = dt.strftime("%Y-%m-%d") + except Exception: + pass + except Exception: + pass + + info_table = Table(show_header=False, box=None, padding=(0, 2)) + info_table.add_column("Key", style="cyan", justify="right") + info_table.add_column("Value", style="white") + + info_table.add_row("CLI Version", cli_version) + info_table.add_row("Template Version", template_version) + info_table.add_row("Released", release_date) + info_table.add_row("", "") + info_table.add_row("Python", f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") + info_table.add_row("Platform", platform.system()) + info_table.add_row("Architecture", platform.machine()) + info_table.add_row("OS Version", platform.version()) + + panel = Panel( + info_table, + title="[bold cyan]Specify CLI Information[/bold cyan]", + border_style="cyan", + padding=(1, 2) + ) + + console.print(panel) + console.print() + def main(): app() From 496accb2330f31947173393db9c04eb4e07a834b Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:11:03 -0700 Subject: [PATCH 12/43] Fixes #975 --- scripts/bash/create-new-feature.sh | 32 +++++++++++++++++++++-- scripts/powershell/create-new-feature.ps1 | 29 ++++++++++++++++++-- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index 53adbcef11..353acccb85 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -87,17 +87,45 @@ cd "$REPO_ROOT" SPECS_DIR="$REPO_ROOT/specs" mkdir -p "$SPECS_DIR" -HIGHEST=0 +# Get highest number from specs directory +HIGHEST_FROM_SPECS=0 if [ -d "$SPECS_DIR" ]; then for dir in "$SPECS_DIR"/*; do [ -d "$dir" ] || continue dirname=$(basename "$dir") number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") number=$((10#$number)) - if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi + if [ "$number" -gt "$HIGHEST_FROM_SPECS" ]; then HIGHEST_FROM_SPECS=$number; fi done fi +# Get highest number from branch names (both local and remote) +HIGHEST_FROM_BRANCHES=0 +if [ "$HAS_GIT" = true ]; then + # Get all branches (local and remote) + branches=$(git branch -a 2>/dev/null || echo "") + + if [ -n "$branches" ]; then + while IFS= read -r branch; do + # Clean branch name: remove leading markers and remote prefixes + clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||') + + # Extract feature number if branch matches pattern ###-* + if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then + number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0") + number=$((10#$number)) + if [ "$number" -gt "$HIGHEST_FROM_BRANCHES" ]; then HIGHEST_FROM_BRANCHES=$number; fi + fi + done <<< "$branches" + fi +fi + +# Use the highest number from either source +HIGHEST=$HIGHEST_FROM_SPECS +if [ "$HIGHEST_FROM_BRANCHES" -gt "$HIGHEST" ]; then + HIGHEST=$HIGHEST_FROM_BRANCHES +fi + NEXT=$((HIGHEST + 1)) FEATURE_NUM=$(printf "%03d" "$NEXT") diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index 83e286aca2..f267377d45 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -79,15 +79,40 @@ Set-Location $repoRoot $specsDir = Join-Path $repoRoot 'specs' New-Item -ItemType Directory -Path $specsDir -Force | Out-Null -$highest = 0 +# Get highest number from specs directory +$highestFromSpecs = 0 if (Test-Path $specsDir) { Get-ChildItem -Path $specsDir -Directory | ForEach-Object { if ($_.Name -match '^(\d{3})') { $num = [int]$matches[1] - if ($num -gt $highest) { $highest = $num } + if ($num -gt $highestFromSpecs) { $highestFromSpecs = $num } } } } + +# Get highest number from branch names (both local and remote) +$highestFromBranches = 0 +try { + $branches = git branch -a 2>$null + if ($LASTEXITCODE -eq 0) { + foreach ($branch in $branches) { + # Clean branch name: remove leading markers and remote prefixes + $cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', '' + + # Extract feature number if branch matches pattern ###-* + if ($cleanBranch -match '^(\d{3})-') { + $num = [int]$matches[1] + if ($num -gt $highestFromBranches) { $highestFromBranches = $num } + } + } + } +} catch { + # If git command fails, just continue with specs-only check + Write-Verbose "Could not check Git branches: $_" +} + +# Use the highest number from either source +$highest = [Math]::Max($highestFromSpecs, $highestFromBranches) $next = $highest + 1 $featureNum = ('{0:000}' -f $next) From 9ff8cdca26f4227920d56708c18264ac772afe23 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:21:15 -0700 Subject: [PATCH 13/43] Fixes #970 --- CHANGELOG.md | 8 +++++ src/specify_cli/__init__.py | 72 ++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea6729145d..b84db71f90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ All notable changes to the Specify CLI and templates are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.21] - 2025-10-21 + +- Fixes [#975](https://github.com/github/spec-kit/issues/975) (thank you [@fgalarraga](https://github.com/fgalarraga)). +- Adds support for Amp CLI. +- Adds support for VS Code hand-offs and moves prompts to be full-fledged chat modes. +- Adds support for `version` command (addresses [#811](https://github.com/github/spec-kit/issues/811) and [#486](https://github.com/github/spec-kit/issues/486), thank you [@mcasalaina](https://github.com/github/spec-kit/issues/811) and [@dentity007](https://github.com/dentity007)). +- Adds support for rendering the rate limit errors from the CLI when encountered ([#970](https://github.com/github/spec-kit/issues/970), thank you [@psmman](https://github.com/psmman)). + ## [0.0.20] - 2025-10-14 ### Added diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 1af32bec73..b50904a172 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -51,6 +51,7 @@ import readchar import ssl import truststore +from datetime import datetime, timezone ssl_context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT) client = httpx.Client(verify=ssl_context) @@ -64,6 +65,63 @@ def _github_auth_headers(cli_token: str | None = None) -> dict: token = _github_token(cli_token) return {"Authorization": f"Bearer {token}"} if token else {} +def _parse_rate_limit_headers(headers: httpx.Headers) -> dict: + """Extract and parse GitHub rate-limit headers.""" + info = {} + + # Standard GitHub rate-limit headers + if "X-RateLimit-Limit" in headers: + info["limit"] = headers.get("X-RateLimit-Limit") + if "X-RateLimit-Remaining" in headers: + info["remaining"] = headers.get("X-RateLimit-Remaining") + if "X-RateLimit-Reset" in headers: + reset_epoch = int(headers.get("X-RateLimit-Reset", "0")) + if reset_epoch: + reset_time = datetime.fromtimestamp(reset_epoch, tz=timezone.utc) + info["reset_epoch"] = reset_epoch + info["reset_time"] = reset_time + info["reset_local"] = reset_time.astimezone() + + # Retry-After header (seconds or HTTP-date) + if "Retry-After" in headers: + retry_after = headers.get("Retry-After") + try: + info["retry_after_seconds"] = int(retry_after) + except ValueError: + # HTTP-date format - not implemented, just store as string + info["retry_after"] = retry_after + + return info + +def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) -> str: + """Format a user-friendly error message with rate-limit information.""" + rate_info = _parse_rate_limit_headers(headers) + + lines = [f"GitHub API returned status {status_code} for {url}"] + lines.append("") + + if rate_info: + lines.append("[bold]Rate Limit Information:[/bold]") + if "limit" in rate_info: + lines.append(f" • Rate Limit: {rate_info['limit']} requests/hour") + if "remaining" in rate_info: + lines.append(f" • Remaining: {rate_info['remaining']}") + if "reset_local" in rate_info: + reset_str = rate_info["reset_local"].strftime("%Y-%m-%d %H:%M:%S %Z") + lines.append(f" • Resets at: {reset_str}") + if "retry_after_seconds" in rate_info: + lines.append(f" • Retry after: {rate_info['retry_after_seconds']} seconds") + lines.append("") + + # Add troubleshooting guidance + lines.append("[bold]Troubleshooting Tips:[/bold]") + lines.append(" • If you're on a shared CI or corporate environment, you may be rate-limited.") + lines.append(" • Consider using a GitHub token via --github-token or the GH_TOKEN/GITHUB_TOKEN") + lines.append(" environment variable to increase rate limits.") + lines.append(" • Authenticated requests have a limit of 5,000/hour vs 60/hour for unauthenticated.") + + return "\n".join(lines) + # Agent configuration with name, folder, install URL, and CLI tool requirement AGENT_CONFIG = { "copilot": { @@ -577,10 +635,11 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri ) status = response.status_code if status != 200: - msg = f"GitHub API returned {status} for {api_url}" + # Format detailed error message with rate-limit info + error_msg = _format_rate_limit_error(status, response.headers, api_url) if debug: - msg += f"\nResponse headers: {response.headers}\nBody (truncated 500): {response.text[:500]}" - raise RuntimeError(msg) + error_msg += f"\n\n[dim]Response body (truncated 500):[/dim]\n{response.text[:500]}" + raise RuntimeError(error_msg) try: release_data = response.json() except ValueError as je: @@ -627,8 +686,11 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri headers=_github_auth_headers(github_token), ) as response: if response.status_code != 200: - body_sample = response.text[:400] - raise RuntimeError(f"Download failed with {response.status_code}\nHeaders: {response.headers}\nBody (truncated): {body_sample}") + # Handle rate-limiting on download as well + error_msg = _format_rate_limit_error(response.status_code, response.headers, download_url) + if debug: + error_msg += f"\n\n[dim]Response body (truncated 400):[/dim]\n{response.text[:400]}" + raise RuntimeError(error_msg) total_size = int(response.headers.get('content-length', 0)) with open(zip_path, 'wb') as f: if total_size == 0: From a7e0ad18fc07eddd602a7c2a7100daec39aefb44 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:22:40 -0700 Subject: [PATCH 14/43] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b84db71f90..a467feacf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixes [#975](https://github.com/github/spec-kit/issues/975) (thank you [@fgalarraga](https://github.com/fgalarraga)). - Adds support for Amp CLI. - Adds support for VS Code hand-offs and moves prompts to be full-fledged chat modes. -- Adds support for `version` command (addresses [#811](https://github.com/github/spec-kit/issues/811) and [#486](https://github.com/github/spec-kit/issues/486), thank you [@mcasalaina](https://github.com/github/spec-kit/issues/811) and [@dentity007](https://github.com/dentity007)). +- Adds support for `version` command (addresses [#811](https://github.com/github/spec-kit/issues/811) and [#486](https://github.com/github/spec-kit/issues/486), thank you [@mcasalaina](https://github.com/mcasalaina) and [@dentity007](https://github.com/dentity007)). - Adds support for rendering the rate limit errors from the CLI when encountered ([#970](https://github.com/github/spec-kit/issues/970), thank you [@psmman](https://github.com/psmman)). ## [0.0.20] - 2025-10-14 From 26eb75a02c749dce1652cf53c909338c236ee878 Mon Sep 17 00:00:00 2001 From: Den Delimarsky <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:32:29 -0700 Subject: [PATCH 15/43] Update src/specify_cli/__init__.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/specify_cli/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index b50904a172..c45d3086d2 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1312,7 +1312,6 @@ def version(): release_date = release_data.get("published_at", "unknown") if release_date != "unknown": # Format the date nicely - from datetime import datetime try: dt = datetime.fromisoformat(release_date.replace('Z', '+00:00')) release_date = dt.strftime("%Y-%m-%d") From 701c8095d145c7efc2774ca3253fd129a9137822 Mon Sep 17 00:00:00 2001 From: Den Delimarsky <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:56:34 -0700 Subject: [PATCH 16/43] Potential fix for code scanning alert no. 3: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/lint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fa20c809dd..5b37ed0be6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,6 @@ name: Lint +permissions: + contents: read on: push: From c2e6d8feebf6f104b1deb337bc282515a19f0049 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 19:37:50 -0700 Subject: [PATCH 17/43] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e5897b3835..c413dd0184 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -70,6 +70,7 @@ To test your templates, commands, and other changes locally, follow these steps: 1. **Create release packages** Run the following command to generate the local packages: + ``` ./.github/workflows/scripts/create-release-packages.sh v1.0.0 ``` From 84ec3b7a4e02153567efbe8f9f3937dced5492db Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 20:09:45 -0700 Subject: [PATCH 18/43] Create taskstoissues.md --- templates/commands/taskstoissues.md | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 templates/commands/taskstoissues.md diff --git a/templates/commands/taskstoissues.md b/templates/commands/taskstoissues.md new file mode 100644 index 0000000000..7f741f407d --- /dev/null +++ b/templates/commands/taskstoissues.md @@ -0,0 +1,31 @@ +--- +description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. +tools: ['github/github-mcp-server/create_issue'] +scripts: + sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks + ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks +--- + +## User Input + +```text +$ARGUMENTS +``` + +You **MUST** consider the user input before proceeding (if not empty). + +## 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"). +1. From the executed script, extract the path to **tasks**. +1. Get the Git remote by running: + +```bash +git config --get remote.origin.url +``` + +**ONLY PROCEED TO NEXT STEPS IF THE REMOTE IS A GITHUB URL** + +1. For each task in the list, use the GitHub MCP server to create a new issue in the repository that is representative of the Git remote. + +**UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL** \ No newline at end of file From 77470a748b91998d7c992731c7525291927f9ab0 Mon Sep 17 00:00:00 2001 From: Den Delimarsky <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 19:38:19 -0700 Subject: [PATCH 19/43] Update src/specify_cli/__init__.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/specify_cli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index c45d3086d2..3e1d41d563 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1307,7 +1307,7 @@ def version(): release_data = response.json() template_version = release_data.get("tag_name", "unknown") # Remove 'v' prefix if present - if template_version != "unknown" and template_version.startswith("v"): + if template_version.startswith("v"): template_version = template_version[1:] release_date = release_data.get("published_at", "unknown") if release_date != "unknown": From fab282aff3f5a2c3494fc749a7bd1ddd4f28ba19 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 20:10:21 -0700 Subject: [PATCH 20/43] Update taskstoissues.md --- templates/commands/taskstoissues.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/commands/taskstoissues.md b/templates/commands/taskstoissues.md index 7f741f407d..b381da952e 100644 --- a/templates/commands/taskstoissues.md +++ b/templates/commands/taskstoissues.md @@ -28,4 +28,4 @@ git config --get remote.origin.url 1. For each task in the list, use the GitHub MCP server to create a new issue in the repository that is representative of the Git remote. -**UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL** \ No newline at end of file +**UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL** From 2772bd7ec358282b4472c386469e8aad4ba59a60 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Tue, 21 Oct 2025 20:53:56 -0700 Subject: [PATCH 21/43] Script changes --- scripts/powershell/setup-plan.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/powershell/setup-plan.ps1 b/scripts/powershell/setup-plan.ps1 index db6e9f2d7f..d0ed582fa9 100644 --- a/scripts/powershell/setup-plan.ps1 +++ b/scripts/powershell/setup-plan.ps1 @@ -59,4 +59,3 @@ if ($Json) { Write-Output "BRANCH: $($paths.CURRENT_BRANCH)" Write-Output "HAS_GIT: $($paths.HAS_GIT)" } - From 2cf765cb7150ad17179bd189c311f8f9315de287 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Wed, 22 Oct 2025 13:17:14 -0700 Subject: [PATCH 22/43] Create create-release-packages.ps1 --- .../scripts/create-release-packages.ps1 | 416 ++++++++++++++++++ 1 file changed, 416 insertions(+) create mode 100644 .github/workflows/scripts/create-release-packages.ps1 diff --git a/.github/workflows/scripts/create-release-packages.ps1 b/.github/workflows/scripts/create-release-packages.ps1 new file mode 100644 index 0000000000..3bf74c92db --- /dev/null +++ b/.github/workflows/scripts/create-release-packages.ps1 @@ -0,0 +1,416 @@ +#!/usr/bin/env pwsh +#requires -Version 7.0 + +<# +.SYNOPSIS + Build Spec Kit template release archives for each supported AI assistant and script type. + +.DESCRIPTION + create-release-packages.ps1 (workflow-local) + Build Spec Kit template release archives for each supported AI assistant and script type. + +.PARAMETER Version + Version string with leading 'v' (e.g., v0.2.0) + +.PARAMETER Agents + Comma or space separated subset of agents to build (default: all) + Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, q + +.PARAMETER Scripts + Comma or space separated subset of script types to build (default: both) + Valid scripts: sh, ps + +.EXAMPLE + .\create-release-packages.ps1 -Version v0.2.0 + +.EXAMPLE + .\create-release-packages.ps1 -Version v0.2.0 -Agents claude,copilot -Scripts sh + +.EXAMPLE + .\create-release-packages.ps1 -Version v0.2.0 -Agents claude -Scripts ps +#> + +param( + [Parameter(Mandatory=$true, Position=0)] + [string]$Version, + + [Parameter(Mandatory=$false)] + [string]$Agents = "", + + [Parameter(Mandatory=$false)] + [string]$Scripts = "" +) + +$ErrorActionPreference = "Stop" + +# Validate version format +if ($Version -notmatch '^v\d+\.\d+\.\d+$') { + Write-Error "Version must look like v0.0.0" + exit 1 +} + +Write-Host "Building release packages for $Version" + +# Create and use .genreleases directory for all build artifacts +$GenReleasesDir = ".genreleases" +if (Test-Path $GenReleasesDir) { + Remove-Item -Path $GenReleasesDir -Recurse -Force -ErrorAction SilentlyContinue +} +New-Item -ItemType Directory -Path $GenReleasesDir -Force | Out-Null + +function Rewrite-Paths { + param([string]$Content) + + $Content = $Content -replace '(/?)\bmemory/', '.specify/memory/' + $Content = $Content -replace '(/?)\bscripts/', '.specify/scripts/' + $Content = $Content -replace '(/?)\btemplates/', '.specify/templates/' + return $Content +} + +function Generate-Commands { + param( + [string]$Agent, + [string]$Extension, + [string]$ArgFormat, + [string]$OutputDir, + [string]$ScriptVariant + ) + + New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null + + $templates = Get-ChildItem -Path "templates/commands/*.md" -File -ErrorAction SilentlyContinue + + foreach ($template in $templates) { + $name = [System.IO.Path]::GetFileNameWithoutExtension($template.Name) + + # Read file content and normalize line endings + $fileContent = (Get-Content -Path $template.FullName -Raw) -replace "`r`n", "`n" + + # Extract description from YAML frontmatter + $description = "" + if ($fileContent -match '(?m)^description:\s*(.+)$') { + $description = $matches[1] + } + + # Extract script command from YAML frontmatter + $scriptCommand = "" + if ($fileContent -match "(?m)^\s*${ScriptVariant}:\s*(.+)$") { + $scriptCommand = $matches[1] + } + + if ([string]::IsNullOrEmpty($scriptCommand)) { + Write-Warning "No script command found for $ScriptVariant in $($template.Name)" + $scriptCommand = "(Missing script command for $ScriptVariant)" + } + + # Extract agent_script command from YAML frontmatter if present + $agentScriptCommand = "" + if ($fileContent -match "(?ms)agent_scripts:.*?^\s*${ScriptVariant}:\s*(.+?)$") { + $agentScriptCommand = $matches[1].Trim() + } + + # Replace {SCRIPT} placeholder with the script command + $body = $fileContent -replace '\{SCRIPT\}', $scriptCommand + + # Replace {AGENT_SCRIPT} placeholder with the agent script command if found + if (-not [string]::IsNullOrEmpty($agentScriptCommand)) { + $body = $body -replace '\{AGENT_SCRIPT\}', $agentScriptCommand + } + + # Remove the scripts: and agent_scripts: sections from frontmatter + $lines = $body -split "`n" + $outputLines = @() + $inFrontmatter = $false + $skipScripts = $false + $dashCount = 0 + + foreach ($line in $lines) { + if ($line -match '^---$') { + $outputLines += $line + $dashCount++ + if ($dashCount -eq 1) { + $inFrontmatter = $true + } else { + $inFrontmatter = $false + } + continue + } + + if ($inFrontmatter) { + if ($line -match '^(scripts|agent_scripts):$') { + $skipScripts = $true + continue + } + if ($line -match '^[a-zA-Z].*:' -and $skipScripts) { + $skipScripts = $false + } + if ($skipScripts -and $line -match '^\s+') { + continue + } + } + + $outputLines += $line + } + + $body = $outputLines -join "`n" + + # Apply other substitutions + $body = $body -replace '\{ARGS\}', $ArgFormat + $body = $body -replace '__AGENT__', $Agent + $body = Rewrite-Paths -Content $body + + # Generate output file based on extension + $outputFile = Join-Path $OutputDir "speckit.$name.$Extension" + + switch ($Extension) { + 'toml' { + $body = $body -replace '\\', '\\' + $output = "description = `"$description`"`n`nprompt = `"`"`"`n$body`n`"`"`"" + Set-Content -Path $outputFile -Value $output -NoNewline + } + 'md' { + Set-Content -Path $outputFile -Value $body -NoNewline + } + 'chatmode.md' { + Set-Content -Path $outputFile -Value $body -NoNewline + } + } + } +} + +function Generate-CopilotPrompts { + param( + [string]$ChatmodesDir, + [string]$PromptsDir + ) + + New-Item -ItemType Directory -Path $PromptsDir -Force | Out-Null + + $chatmodeFiles = Get-ChildItem -Path "$ChatmodesDir/speckit.*.chatmode.md" -File -ErrorAction SilentlyContinue + + foreach ($chatmodeFile in $chatmodeFiles) { + $basename = $chatmodeFile.Name -replace '\.chatmode\.md$', '' + $promptFile = Join-Path $PromptsDir "$basename.prompt.md" + + $content = @" +--- +agent: $basename +--- +"@ + Set-Content -Path $promptFile -Value $content + } +} + +function Build-Variant { + param( + [string]$Agent, + [string]$Script + ) + + $baseDir = Join-Path $GenReleasesDir "sdd-${Agent}-package-${Script}" + Write-Host "Building $Agent ($Script) package..." + New-Item -ItemType Directory -Path $baseDir -Force | Out-Null + + # Copy base structure but filter scripts by variant + $specDir = Join-Path $baseDir ".specify" + New-Item -ItemType Directory -Path $specDir -Force | Out-Null + + # Copy memory directory + if (Test-Path "memory") { + Copy-Item -Path "memory" -Destination $specDir -Recurse -Force + Write-Host "Copied memory -> .specify" + } + + # Only copy the relevant script variant directory + if (Test-Path "scripts") { + $scriptsDestDir = Join-Path $specDir "scripts" + New-Item -ItemType Directory -Path $scriptsDestDir -Force | Out-Null + + switch ($Script) { + 'sh' { + if (Test-Path "scripts/bash") { + Copy-Item -Path "scripts/bash" -Destination $scriptsDestDir -Recurse -Force + Write-Host "Copied scripts/bash -> .specify/scripts" + } + } + 'ps' { + if (Test-Path "scripts/powershell") { + Copy-Item -Path "scripts/powershell" -Destination $scriptsDestDir -Recurse -Force + Write-Host "Copied scripts/powershell -> .specify/scripts" + } + } + } + + # Copy any script files that aren't in variant-specific directories + Get-ChildItem -Path "scripts" -File -ErrorAction SilentlyContinue | ForEach-Object { + Copy-Item -Path $_.FullName -Destination $scriptsDestDir -Force + } + } + + # Copy templates (excluding commands directory and vscode-settings.json) + if (Test-Path "templates") { + $templatesDestDir = Join-Path $specDir "templates" + New-Item -ItemType Directory -Path $templatesDestDir -Force | Out-Null + + Get-ChildItem -Path "templates" -Recurse -File | Where-Object { + $_.FullName -notmatch 'templates[/\\]commands[/\\]' -and $_.Name -ne 'vscode-settings.json' + } | ForEach-Object { + $relativePath = $_.FullName.Substring((Resolve-Path "templates").Path.Length + 1) + $destFile = Join-Path $templatesDestDir $relativePath + $destFileDir = Split-Path $destFile -Parent + New-Item -ItemType Directory -Path $destFileDir -Force | Out-Null + Copy-Item -Path $_.FullName -Destination $destFile -Force + } + Write-Host "Copied templates -> .specify/templates" + } + + # Generate agent-specific command files + switch ($Agent) { + 'claude' { + $cmdDir = Join-Path $baseDir ".claude/commands" + Generate-Commands -Agent 'claude' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'gemini' { + $cmdDir = Join-Path $baseDir ".gemini/commands" + Generate-Commands -Agent 'gemini' -Extension 'toml' -ArgFormat '{{args}}' -OutputDir $cmdDir -ScriptVariant $Script + if (Test-Path "agent_templates/gemini/GEMINI.md") { + Copy-Item -Path "agent_templates/gemini/GEMINI.md" -Destination (Join-Path $baseDir "GEMINI.md") + } + } + 'copilot' { + $chatmodesDir = Join-Path $baseDir ".github/chatmodes" + Generate-Commands -Agent 'copilot' -Extension 'chatmode.md' -ArgFormat '$ARGUMENTS' -OutputDir $chatmodesDir -ScriptVariant $Script + + # Generate companion prompt files + $promptsDir = Join-Path $baseDir ".github/prompts" + Generate-CopilotPrompts -ChatmodesDir $chatmodesDir -PromptsDir $promptsDir + + # Create VS Code workspace settings + $vscodeDir = Join-Path $baseDir ".vscode" + New-Item -ItemType Directory -Path $vscodeDir -Force | Out-Null + if (Test-Path "templates/vscode-settings.json") { + Copy-Item -Path "templates/vscode-settings.json" -Destination (Join-Path $vscodeDir "settings.json") + } + } + 'cursor-agent' { + $cmdDir = Join-Path $baseDir ".cursor/commands" + Generate-Commands -Agent 'cursor-agent' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'qwen' { + $cmdDir = Join-Path $baseDir ".qwen/commands" + Generate-Commands -Agent 'qwen' -Extension 'toml' -ArgFormat '{{args}}' -OutputDir $cmdDir -ScriptVariant $Script + if (Test-Path "agent_templates/qwen/QWEN.md") { + Copy-Item -Path "agent_templates/qwen/QWEN.md" -Destination (Join-Path $baseDir "QWEN.md") + } + } + 'opencode' { + $cmdDir = Join-Path $baseDir ".opencode/command" + Generate-Commands -Agent 'opencode' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'windsurf' { + $cmdDir = Join-Path $baseDir ".windsurf/workflows" + Generate-Commands -Agent 'windsurf' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'codex' { + $cmdDir = Join-Path $baseDir ".codex/prompts" + Generate-Commands -Agent 'codex' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'kilocode' { + $cmdDir = Join-Path $baseDir ".kilocode/workflows" + Generate-Commands -Agent 'kilocode' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'auggie' { + $cmdDir = Join-Path $baseDir ".augment/commands" + Generate-Commands -Agent 'auggie' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'roo' { + $cmdDir = Join-Path $baseDir ".roo/commands" + Generate-Commands -Agent 'roo' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'codebuddy' { + $cmdDir = Join-Path $baseDir ".codebuddy/commands" + Generate-Commands -Agent 'codebuddy' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'amp' { + $cmdDir = Join-Path $baseDir ".agents/commands" + Generate-Commands -Agent 'amp' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + 'q' { + $cmdDir = Join-Path $baseDir ".amazonq/prompts" + Generate-Commands -Agent 'q' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + } + } + + # Create zip archive + $zipFile = Join-Path $GenReleasesDir "spec-kit-template-${Agent}-${Script}-${Version}.zip" + Compress-Archive -Path "$baseDir/*" -DestinationPath $zipFile -Force + Write-Host "Created $zipFile" +} + +# Define all agents and scripts +$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'q') +$AllScripts = @('sh', 'ps') + +function Normalize-List { + param([string]$Input) + + if ([string]::IsNullOrEmpty($Input)) { + return @() + } + + # Split by comma or space and remove duplicates while preserving order + $items = $Input -split '[,\s]+' | Where-Object { $_ } | Select-Object -Unique + return $items +} + +function Validate-Subset { + param( + [string]$Type, + [string[]]$Allowed, + [string[]]$Items + ) + + $ok = $true + foreach ($item in $Items) { + if ($item -notin $Allowed) { + Write-Error "Unknown $Type '$item' (allowed: $($Allowed -join ', '))" + $ok = $false + } + } + return $ok +} + +# Determine agent list +if (-not [string]::IsNullOrEmpty($Agents)) { + $AgentList = Normalize-List -Input $Agents + if (-not (Validate-Subset -Type 'agent' -Allowed $AllAgents -Items $AgentList)) { + exit 1 + } +} else { + $AgentList = $AllAgents +} + +# Determine script list +if (-not [string]::IsNullOrEmpty($Scripts)) { + $ScriptList = Normalize-List -Input $Scripts + if (-not (Validate-Subset -Type 'script' -Allowed $AllScripts -Items $ScriptList)) { + exit 1 + } +} else { + $ScriptList = $AllScripts +} + +Write-Host "Agents: $($AgentList -join ', ')" +Write-Host "Scripts: $($ScriptList -join ', ')" + +# Build all variants +foreach ($agent in $AgentList) { + foreach ($script in $ScriptList) { + Build-Variant -Agent $agent -Script $script + } +} + +Write-Host "`nArchives in ${GenReleasesDir}:" +Get-ChildItem -Path $GenReleasesDir -Filter "spec-kit-template-*-${Version}.zip" | ForEach-Object { + Write-Host " $($_.Name)" +} From 555736431f5446d1d34a6ecc19cc4bd1c2066f3e Mon Sep 17 00:00:00 2001 From: Den Delimarsky <53200638+localden@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:21:57 -0800 Subject: [PATCH 23/43] Update src/specify_cli/__init__.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/specify_cli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 3e1d41d563..701b3bdca8 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1328,7 +1328,7 @@ def version(): info_table.add_row("Template Version", template_version) info_table.add_row("Released", release_date) info_table.add_row("", "") - info_table.add_row("Python", f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") + info_table.add_row("Python", platform.python_version()) info_table.add_row("Platform", platform.system()) info_table.add_row("Architecture", platform.machine()) info_table.add_row("OS Version", platform.version()) From dab572865905e2b8a6e345e8e325935cb96dbd2e Mon Sep 17 00:00:00 2001 From: Den Delimarsky <53200638+localden@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:22:10 -0800 Subject: [PATCH 24/43] Update scripts/powershell/create-new-feature.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/powershell/create-new-feature.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index f267377d45..b2b3bc8338 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -97,6 +97,9 @@ try { if ($LASTEXITCODE -eq 0) { foreach ($branch in $branches) { # Clean branch name: remove leading markers and remote prefixes + # The following regex removes: + # - Git's current branch marker ('*') and leading whitespace (e.g., '* main') + # - Remote prefixes (e.g., 'remotes/origin/') $cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', '' # Extract feature number if branch matches pattern ###-* From 6a6de598682f65c9d15934043306ab5ba41f661f Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:41:54 -0800 Subject: [PATCH 25/43] Update agent configuration --- .../scripts/create-release-packages.ps1 | 16 ++++++++-------- .../scripts/create-release-packages.sh | 18 +++++++++--------- AGENTS.md | 4 ++-- CHANGELOG.md | 5 +++++ pyproject.toml | 2 +- scripts/bash/update-agent-context.sh | 10 +++++++++- scripts/powershell/update-agent-context.ps1 | 10 ++++++++-- 7 files changed, 42 insertions(+), 23 deletions(-) diff --git a/.github/workflows/scripts/create-release-packages.ps1 b/.github/workflows/scripts/create-release-packages.ps1 index 3bf74c92db..f935dbe86d 100644 --- a/.github/workflows/scripts/create-release-packages.ps1 +++ b/.github/workflows/scripts/create-release-packages.ps1 @@ -171,7 +171,7 @@ function Generate-Commands { 'md' { Set-Content -Path $outputFile -Value $body -NoNewline } - 'chatmode.md' { + 'agent.md' { Set-Content -Path $outputFile -Value $body -NoNewline } } @@ -180,16 +180,16 @@ function Generate-Commands { function Generate-CopilotPrompts { param( - [string]$ChatmodesDir, + [string]$AgentsDir, [string]$PromptsDir ) New-Item -ItemType Directory -Path $PromptsDir -Force | Out-Null - $chatmodeFiles = Get-ChildItem -Path "$ChatmodesDir/speckit.*.chatmode.md" -File -ErrorAction SilentlyContinue + $agentFiles = Get-ChildItem -Path "$AgentsDir/speckit.*.agent.md" -File -ErrorAction SilentlyContinue - foreach ($chatmodeFile in $chatmodeFiles) { - $basename = $chatmodeFile.Name -replace '\.chatmode\.md$', '' + foreach ($agentFile in $agentFiles) { + $basename = $agentFile.Name -replace '\.agent\.md$', '' $promptFile = Join-Path $PromptsDir "$basename.prompt.md" $content = @" @@ -278,12 +278,12 @@ function Build-Variant { } } 'copilot' { - $chatmodesDir = Join-Path $baseDir ".github/chatmodes" - Generate-Commands -Agent 'copilot' -Extension 'chatmode.md' -ArgFormat '$ARGUMENTS' -OutputDir $chatmodesDir -ScriptVariant $Script + $agentsDir = Join-Path $baseDir ".github/agents" + Generate-Commands -Agent 'copilot' -Extension 'agent.md' -ArgFormat '$ARGUMENTS' -OutputDir $agentsDir -ScriptVariant $Script # Generate companion prompt files $promptsDir = Join-Path $baseDir ".github/prompts" - Generate-CopilotPrompts -ChatmodesDir $chatmodesDir -PromptsDir $promptsDir + Generate-CopilotPrompts -AgentsDir $agentsDir -PromptsDir $promptsDir # Create VS Code workspace settings $vscodeDir = Join-Path $baseDir ".vscode" diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 49f2ddad3f..1b2e532657 100644 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -95,21 +95,21 @@ generate_commands() { { echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;; md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; - chatmode.md) + agent.md) echo "$body" > "$output_dir/speckit.$name.$ext" ;; esac done } generate_copilot_prompts() { - local chatmodes_dir=$1 prompts_dir=$2 + local agents_dir=$1 prompts_dir=$2 mkdir -p "$prompts_dir" - # Generate a .prompt.md file for each .chatmode.md file - for chatmode_file in "$chatmodes_dir"/speckit.*.chatmode.md; do - [[ -f "$chatmode_file" ]] || continue + # Generate a .prompt.md file for each .agent.md file + for agent_file in "$agents_dir"/speckit.*.agent.md; do + [[ -f "$agent_file" ]] || continue - local basename=$(basename "$chatmode_file" .chatmode.md) + local basename=$(basename "$agent_file" .agent.md) local prompt_file="$prompts_dir/${basename}.prompt.md" # Create prompt file with agent frontmatter @@ -166,10 +166,10 @@ build_variant() { generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script" [[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;; copilot) - mkdir -p "$base_dir/.github/chatmodes" - generate_commands copilot chatmode.md "\$ARGUMENTS" "$base_dir/.github/chatmodes" "$script" + mkdir -p "$base_dir/.github/agents" + generate_commands copilot agent.md "\$ARGUMENTS" "$base_dir/.github/agents" "$script" # Generate companion prompt files - generate_copilot_prompts "$base_dir/.github/chatmodes" "$base_dir/.github/prompts" + generate_copilot_prompts "$base_dir/.github/agents" "$base_dir/.github/prompts" # Create VS Code workspace settings mkdir -p "$base_dir/.vscode" [[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json" diff --git a/AGENTS.md b/AGENTS.md index 55fd83e285..f7d956bd7b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Specify supports multiple AI agents by generating agent-specific command files a |-------|-----------|---------|----------|-------------| | **Claude Code** | `.claude/commands/` | Markdown | `claude` | Anthropic's Claude Code CLI | | **Gemini CLI** | `.gemini/commands/` | TOML | `gemini` | Google's Gemini CLI | -| **GitHub Copilot** | `.github/chatmodes/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | +| **GitHub Copilot** | `.github/agents/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code | | **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI | | **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI | | **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI | @@ -362,7 +362,7 @@ Command content with {SCRIPT} and {{args}} placeholders. - **CLI agents**: Usually `./commands/` - **IDE agents**: Follow IDE-specific patterns: - - Copilot: `.github/chatmodes/` + - Copilot: `.github/agents/` - Cursor: `.cursor/commands/` - Windsurf: `.windsurf/workflows/` diff --git a/CHANGELOG.md b/CHANGELOG.md index a467feacf9..7e7ee860be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ All notable changes to the Specify CLI and templates are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.22] - 2025-11-07 + +- Support for VS Code/Copilot agents, and moving away from prompts to proper agents with hand-offs. +- Move to use `AGENTS.md` for Copilot workloads, since it's already supported out-of-the-box. + ## [0.0.21] - 2025-10-21 - Fixes [#975](https://github.com/github/spec-kit/issues/975) (thank you [@fgalarraga](https://github.com/fgalarraga)). diff --git a/pyproject.toml b/pyproject.toml index e4d2791bdb..fb972adc7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "specify-cli" -version = "0.0.21" +version = "0.0.22" description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)." requires-python = ">=3.11" dependencies = [ diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index e327869d8f..fcb525ac0f 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -61,7 +61,8 @@ AGENT_TYPE="${1:-}" # Agent-specific file paths CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" -COPILOT_FILE="$REPO_ROOT/.github/chatmodes/copilot-instructions.md" +COPILOT_FILE="$REPO_ROOT/.github/agents/copilot-instructions.md" +COPILOT_AGENTS_FILE="$REPO_ROOT/AGENTS.md" CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" QWEN_FILE="$REPO_ROOT/QWEN.md" AGENTS_FILE="$REPO_ROOT/AGENTS.md" @@ -587,6 +588,7 @@ update_specific_agent() { ;; copilot) update_agent_file "$COPILOT_FILE" "GitHub Copilot" + update_agent_file "$COPILOT_AGENTS_FILE" "GitHub Copilot (AGENTS.md)" ;; cursor-agent) update_agent_file "$CURSOR_FILE" "Cursor IDE" @@ -648,6 +650,12 @@ update_all_existing_agents() { found_agent=true fi + # Also update AGENTS.md for Copilot if the Copilot directory exists + if [[ -d "$REPO_ROOT/.github/agents" ]]; then + update_agent_file "$COPILOT_AGENTS_FILE" "GitHub Copilot (AGENTS.md)" + found_agent=true + fi + if [[ -f "$CURSOR_FILE" ]]; then update_agent_file "$CURSOR_FILE" "Cursor IDE" found_agent=true diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index d8fe34bf13..a439cc4350 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -46,7 +46,8 @@ $NEW_PLAN = $IMPL_PLAN # Agent file paths $CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' -$COPILOT_FILE = Join-Path $REPO_ROOT '.github/chatmodes/copilot-instructions.md' +$COPILOT_FILE = Join-Path $REPO_ROOT '.github/agents/copilot-instructions.md' +$COPILOT_AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' $CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' $QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' @@ -370,7 +371,10 @@ function Update-SpecificAgent { switch ($Type) { 'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' } 'gemini' { Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI' } - 'copilot' { Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' } + 'copilot' { + Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' + Update-AgentFile -TargetFile $COPILOT_AGENTS_FILE -AgentName 'GitHub Copilot (AGENTS.md)' + } 'cursor-agent' { Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE' } 'qwen' { Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code' } 'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' } @@ -392,6 +396,8 @@ function Update-AllExistingAgents { if (Test-Path $CLAUDE_FILE) { if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }; $found = $true } if (Test-Path $GEMINI_FILE) { if (-not (Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI')) { $ok = $false }; $found = $true } if (Test-Path $COPILOT_FILE) { if (-not (Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot')) { $ok = $false }; $found = $true } + # Also update AGENTS.md for Copilot if the Copilot directory exists + if (Test-Path (Join-Path $REPO_ROOT '.github/agents')) { if (-not (Update-AgentFile -TargetFile $COPILOT_AGENTS_FILE -AgentName 'GitHub Copilot (AGENTS.md)')) { $ok = $false }; $found = $true } if (Test-Path $CURSOR_FILE) { if (-not (Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE')) { $ok = $false }; $found = $true } if (Test-Path $QWEN_FILE) { if (-not (Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code')) { $ok = $false }; $found = $true } if (Test-Path $AGENTS_FILE) { if (-not (Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex/opencode')) { $ok = $false }; $found = $true } From d4c70c8deffc86c29a16b33d72690f102557fe84 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:58:20 -0800 Subject: [PATCH 26/43] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e7ee860be..7e2ac3697f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for VS Code/Copilot agents, and moving away from prompts to proper agents with hand-offs. - Move to use `AGENTS.md` for Copilot workloads, since it's already supported out-of-the-box. +- Adds support for the version command. ([#486](https://github.com/github/spec-kit/issues/486)) +- Fixes potential bug with the `create-new-feature.ps1` script that ignores existing feature branches when determining next feature number ([#975](https://github.com/github/spec-kit/issues/975)) +- Add graceful fallback and logging for GitHub API rate-limiting during template fetch ([#970](https://github.com/github/spec-kit/issues/970)) ## [0.0.21] - 2025-10-21 From 33027ddb4f84cfc511f4decfc3edd2f9351c5442 Mon Sep 17 00:00:00 2001 From: Simon Gent Date: Thu, 23 Oct 2025 12:14:48 +0100 Subject: [PATCH 27/43] feat: check remote branches to prevent duplicate branch numbers - 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 --- scripts/bash/create-new-feature.sh | 107 +++++++++++++--------- scripts/powershell/create-new-feature.ps1 | 104 ++++++++++++--------- templates/commands/specify.md | 34 +++++-- 3 files changed, 151 insertions(+), 94 deletions(-) diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index 353acccb85..714927f2d4 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -4,6 +4,7 @@ set -e JSON_MODE=false SHORT_NAME="" +BRANCH_NUMBER="" ARGS=() i=1 while [ $i -le $# ]; do @@ -26,17 +27,31 @@ while [ $i -le $# ]; do fi SHORT_NAME="$next_arg" ;; + --number) + if [ $((i + 1)) -gt $# ]; then + echo 'Error: --number requires a value' >&2 + exit 1 + fi + i=$((i + 1)) + next_arg="${!i}" + if [[ "$next_arg" == --* ]]; then + echo 'Error: --number requires a value' >&2 + exit 1 + fi + BRANCH_NUMBER="$next_arg" + ;; --help|-h) - echo "Usage: $0 [--json] [--short-name ] " + echo "Usage: $0 [--json] [--short-name ] [--number N] " echo "" echo "Options:" echo " --json Output in JSON format" echo " --short-name Provide a custom short name (2-4 words) for the branch" + echo " --number N Specify branch number manually (overrides auto-detection)" echo " --help, -h Show this help message" echo "" echo "Examples:" echo " $0 'Add user authentication system' --short-name 'user-auth'" - echo " $0 'Implement OAuth2 integration for API'" + echo " $0 'Implement OAuth2 integration for API' --number 5" exit 0 ;; *) @@ -48,7 +63,7 @@ done FEATURE_DESCRIPTION="${ARGS[*]}" if [ -z "$FEATURE_DESCRIPTION" ]; then - echo "Usage: $0 [--json] [--short-name ] " >&2 + echo "Usage: $0 [--json] [--short-name ] [--number N] " >&2 exit 1 fi @@ -65,6 +80,28 @@ find_repo_root() { return 1 } +# Function to check existing branches (local and remote) and return next available number +check_existing_branches() { + local short_name="$1" + + # Fetch all remotes to get latest branch info (suppress errors if no remotes) + git fetch --all --prune 2>/dev/null || true + + # Find all branches matching the pattern (local and remote) + local branches=$(git branch -a 2>/dev/null | grep -E "feature/[0-9]+-${short_name}$" | sed 's/.*feature\///' | sed "s/-${short_name}$//" | sort -n) + + # Get the highest number + local max_num=0 + for num in $branches; do + if [ "$num" -gt "$max_num" ]; then + max_num=$num + fi + done + + # Return next number + echo $((max_num + 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 initialised with --no-git. @@ -87,48 +124,6 @@ cd "$REPO_ROOT" SPECS_DIR="$REPO_ROOT/specs" mkdir -p "$SPECS_DIR" -# Get highest number from specs directory -HIGHEST_FROM_SPECS=0 -if [ -d "$SPECS_DIR" ]; then - for dir in "$SPECS_DIR"/*; do - [ -d "$dir" ] || continue - dirname=$(basename "$dir") - number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") - number=$((10#$number)) - if [ "$number" -gt "$HIGHEST_FROM_SPECS" ]; then HIGHEST_FROM_SPECS=$number; fi - done -fi - -# Get highest number from branch names (both local and remote) -HIGHEST_FROM_BRANCHES=0 -if [ "$HAS_GIT" = true ]; then - # Get all branches (local and remote) - branches=$(git branch -a 2>/dev/null || echo "") - - if [ -n "$branches" ]; then - while IFS= read -r branch; do - # Clean branch name: remove leading markers and remote prefixes - clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||') - - # Extract feature number if branch matches pattern ###-* - if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then - number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0") - number=$((10#$number)) - if [ "$number" -gt "$HIGHEST_FROM_BRANCHES" ]; then HIGHEST_FROM_BRANCHES=$number; fi - fi - done <<< "$branches" - fi -fi - -# Use the highest number from either source -HIGHEST=$HIGHEST_FROM_SPECS -if [ "$HIGHEST_FROM_BRANCHES" -gt "$HIGHEST" ]; then - HIGHEST=$HIGHEST_FROM_BRANCHES -fi - -NEXT=$((HIGHEST + 1)) -FEATURE_NUM=$(printf "%03d" "$NEXT") - # Function to generate branch name with stop word filtering and length filtering generate_branch_name() { local description="$1" @@ -185,6 +180,28 @@ else BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION") fi +# Determine branch number +if [ -z "$BRANCH_NUMBER" ]; then + if [ "$HAS_GIT" = true ]; then + # Check existing branches on remotes + BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX") + else + # Fall back to local directory check + HIGHEST=0 + if [ -d "$SPECS_DIR" ]; then + for dir in "$SPECS_DIR"/*; do + [ -d "$dir" ] || continue + dirname=$(basename "$dir") + number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") + number=$((10#$number)) + if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi + done + fi + BRANCH_NUMBER=$((HIGHEST + 1)) + fi +fi + +FEATURE_NUM=$(printf "%03d" "$BRANCH_NUMBER") BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}" # GitHub enforces a 244-byte limit on branch names diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index b2b3bc8338..f3754725ef 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -4,6 +4,7 @@ param( [switch]$Json, [string]$ShortName, + [int]$Number = 0, [switch]$Help, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$FeatureDescription @@ -12,11 +13,12 @@ $ErrorActionPreference = 'Stop' # Show help if requested if ($Help) { - Write-Host "Usage: ./create-new-feature.ps1 [-Json] [-ShortName ] " + Write-Host "Usage: ./create-new-feature.ps1 [-Json] [-ShortName ] [-Number N] " Write-Host "" Write-Host "Options:" Write-Host " -Json Output in JSON format" Write-Host " -ShortName Provide a custom short name (2-4 words) for the branch" + Write-Host " -Number N Specify branch number manually (overrides auto-detection)" Write-Host " -Help Show this help message" Write-Host "" Write-Host "Examples:" @@ -56,6 +58,45 @@ function Find-RepositoryRoot { $current = $parent } } + +function Get-NextBranchNumber { + param( + [string]$ShortName + ) + + # Fetch all remotes to get latest branch info (suppress errors if no remotes) + try { + git fetch --all --prune 2>$null | Out-Null + } catch { + # Ignore fetch errors + } + + # Find all branches matching the pattern (local and remote) + $branches = @() + try { + $allBranches = git branch -a 2>$null + if ($allBranches) { + $branches = $allBranches | Where-Object { $_ -match "feature/(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object { + if ($_ -match "feature/(\d+)-") { + [int]$matches[1] + } + } + } + } catch { + # Ignore errors + } + + # Get the highest number + $maxNum = 0 + foreach ($num in $branches) { + if ($num -gt $maxNum) { + $maxNum = $num + } + } + + # Return next number + return $maxNum + 1 +} $fallbackRoot = (Find-RepositoryRoot -StartDir $PSScriptRoot) if (-not $fallbackRoot) { Write-Error "Error: Could not determine repository root. Please run this script from within the repository." @@ -79,46 +120,6 @@ Set-Location $repoRoot $specsDir = Join-Path $repoRoot 'specs' New-Item -ItemType Directory -Path $specsDir -Force | Out-Null -# Get highest number from specs directory -$highestFromSpecs = 0 -if (Test-Path $specsDir) { - Get-ChildItem -Path $specsDir -Directory | ForEach-Object { - if ($_.Name -match '^(\d{3})') { - $num = [int]$matches[1] - if ($num -gt $highestFromSpecs) { $highestFromSpecs = $num } - } - } -} - -# Get highest number from branch names (both local and remote) -$highestFromBranches = 0 -try { - $branches = git branch -a 2>$null - if ($LASTEXITCODE -eq 0) { - foreach ($branch in $branches) { - # Clean branch name: remove leading markers and remote prefixes - # The following regex removes: - # - Git's current branch marker ('*') and leading whitespace (e.g., '* main') - # - Remote prefixes (e.g., 'remotes/origin/') - $cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', '' - - # Extract feature number if branch matches pattern ###-* - if ($cleanBranch -match '^(\d{3})-') { - $num = [int]$matches[1] - if ($num -gt $highestFromBranches) { $highestFromBranches = $num } - } - } - } -} catch { - # If git command fails, just continue with specs-only check - Write-Verbose "Could not check Git branches: $_" -} - -# Use the highest number from either source -$highest = [Math]::Max($highestFromSpecs, $highestFromBranches) -$next = $highest + 1 -$featureNum = ('{0:000}' -f $next) - # Function to generate branch name with stop word filtering and length filtering function Get-BranchName { param([string]$Description) @@ -173,6 +174,27 @@ if ($ShortName) { $branchSuffix = Get-BranchName -Description $featureDesc } +# Determine branch number +if ($Number -eq 0) { + if ($hasGit) { + # Check existing branches on remotes + $Number = Get-NextBranchNumber -ShortName $branchSuffix + } else { + # Fall back to local directory check + $highest = 0 + if (Test-Path $specsDir) { + Get-ChildItem -Path $specsDir -Directory | ForEach-Object { + if ($_.Name -match '^(\d{3})') { + $num = [int]$matches[1] + if ($num -gt $highest) { $highest = $num } + } + } + } + $Number = $highest + 1 + } +} + +$featureNum = ('{0:000}' -f $Number) $branchName = "$featureNum-$branchSuffix" # GitHub enforces a 244-byte limit on branch names diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 61a6ff994f..fb4a53ba93 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -39,16 +39,34 @@ Given that feature description, do this: - "Create a dashboard for analytics" → "analytics-dashboard" - "Fix payment processing timeout bug" → "fix-payment-timeout" -2. Run the script `{SCRIPT}` from repo root **with the short-name argument** and parse its JSON output for BRANCH_NAME and SPEC_FILE. All file paths must be absolute. - +2. **Check for existing branches before creating new one**: + + a. First, fetch all remote branches to ensure we have the latest information: + ```bash + git fetch --all --prune + ``` + + b. List all branches (local and remote) that match the short-name pattern: + ```bash + git branch -a | grep -E "feature/[0-9]+-$" + ``` + + c. Determine the next available number: + - Extract all numbers from existing branches (both local and remote) + - Find the highest number N from branches that exist + - Use N+1 for the new branch number + + d. Run the script `{SCRIPT}` with the calculated number and short-name: + - Pass `--number N+1` and `--short-name "your-short-name"` along with the feature description + - Bash example: `{SCRIPT} --json --number 5 --short-name "user-auth" "Add user authentication"` + - PowerShell example: `{SCRIPT} -Json -Number 5 -ShortName "user-auth" "Add user authentication"` + **IMPORTANT**: - - - Append the short-name argument to the `{SCRIPT}` command with the 2-4 word short name you created in step 1. Keep the feature description as the final argument. - - Bash example: `--short-name "your-generated-short-name" "Feature description here"` - - PowerShell example: `-ShortName "your-generated-short-name" "Feature description here"` + - Only consider branches that still exist (local or remote) + - If no existing branches found with this short-name, start with number 1 + - The JSON output will contain BRANCH_NAME and SPEC_FILE paths + - You must only ever run this script once per feature - 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") - - You must only ever run this script once - - The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for 3. Load `templates/spec-template.md` to understand required sections. From 3c7b370403639d345484083d7934610faacb3348 Mon Sep 17 00:00:00 2001 From: Simon Gent Date: Thu, 23 Oct 2025 12:25:31 +0100 Subject: [PATCH 28/43] fix: improve branch number detection to check all sources - 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 --- scripts/bash/create-new-feature.sh | 17 ++++++-- scripts/powershell/create-new-feature.ps1 | 48 ++++++++++++++++++----- templates/commands/specify.md | 17 ++++---- 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index 714927f2d4..86d9ecf837 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -87,12 +87,21 @@ check_existing_branches() { # Fetch all remotes to get latest branch info (suppress errors if no remotes) git fetch --all --prune 2>/dev/null || true - # Find all branches matching the pattern (local and remote) - local branches=$(git branch -a 2>/dev/null | grep -E "feature/[0-9]+-${short_name}$" | sed 's/.*feature\///' | sed "s/-${short_name}$//" | sort -n) + # Find all branches matching the pattern using git ls-remote (more reliable) + local remote_branches=$(git ls-remote --heads origin 2>/dev/null | grep -E "refs/heads/[0-9]+-${short_name}$" | sed 's/.*\/\([0-9]*\)-.*/\1/' | sort -n) - # Get the highest number + # Also check local branches + local local_branches=$(git branch 2>/dev/null | grep -E "^[* ]*[0-9]+-${short_name}$" | sed 's/^[* ]*//' | sed 's/-.*//' | sort -n) + + # Check specs directory as well + local spec_dirs="" + if [ -d "$SPECS_DIR" ]; then + spec_dirs=$(find "$SPECS_DIR" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n) + fi + + # Combine all sources and get the highest number local max_num=0 - for num in $branches; do + for num in $remote_branches $local_branches $spec_dirs; do if [ "$num" -gt "$max_num" ]; then max_num=$num fi diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index f3754725ef..4daa6d2c06 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -61,7 +61,8 @@ function Find-RepositoryRoot { function Get-NextBranchNumber { param( - [string]$ShortName + [string]$ShortName, + [string]$SpecsDir ) # Fetch all remotes to get latest branch info (suppress errors if no remotes) @@ -71,13 +72,28 @@ function Get-NextBranchNumber { # Ignore fetch errors } - # Find all branches matching the pattern (local and remote) - $branches = @() + # Find remote branches matching the pattern using git ls-remote + $remoteBranches = @() try { - $allBranches = git branch -a 2>$null + $remoteRefs = git ls-remote --heads origin 2>$null + if ($remoteRefs) { + $remoteBranches = $remoteRefs | Where-Object { $_ -match "refs/heads/(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object { + if ($_ -match "refs/heads/(\d+)-") { + [int]$matches[1] + } + } + } + } catch { + # Ignore errors + } + + # Check local branches + $localBranches = @() + try { + $allBranches = git branch 2>$null if ($allBranches) { - $branches = $allBranches | Where-Object { $_ -match "feature/(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object { - if ($_ -match "feature/(\d+)-") { + $localBranches = $allBranches | Where-Object { $_ -match "^\*?\s*(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object { + if ($_ -match "(\d+)-") { [int]$matches[1] } } @@ -86,9 +102,23 @@ function Get-NextBranchNumber { # Ignore errors } - # Get the highest number + # Check specs directory + $specDirs = @() + if (Test-Path $SpecsDir) { + try { + $specDirs = Get-ChildItem -Path $SpecsDir -Directory | Where-Object { $_.Name -match "^(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object { + if ($_.Name -match "^(\d+)-") { + [int]$matches[1] + } + } + } catch { + # Ignore errors + } + } + + # Combine all sources and get the highest number $maxNum = 0 - foreach ($num in $branches) { + foreach ($num in ($remoteBranches + $localBranches + $specDirs)) { if ($num -gt $maxNum) { $maxNum = $num } @@ -178,7 +208,7 @@ if ($ShortName) { if ($Number -eq 0) { if ($hasGit) { # Check existing branches on remotes - $Number = Get-NextBranchNumber -ShortName $branchSuffix + $Number = Get-NextBranchNumber -ShortName $branchSuffix -SpecsDir $specsDir } else { # Fall back to local directory check $highest = 0 diff --git a/templates/commands/specify.md b/templates/commands/specify.md index fb4a53ba93..79fa046930 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -46,14 +46,14 @@ Given that feature description, do this: git fetch --all --prune ``` - b. List all branches (local and remote) that match the short-name pattern: - ```bash - git branch -a | grep -E "feature/[0-9]+-$" - ``` + b. Find the highest feature number across all sources for the short-name: + - Remote branches: `git ls-remote --heads origin | grep -E 'refs/heads/[0-9]+-$'` + - Local branches: `git branch | grep -E '^[* ]*[0-9]+-$'` + - Specs directories: Check for directories matching `specs/[0-9]+-` c. Determine the next available number: - - Extract all numbers from existing branches (both local and remote) - - Find the highest number N from branches that exist + - Extract all numbers from all three sources + - Find the highest number N - Use N+1 for the new branch number d. Run the script `{SCRIPT}` with the calculated number and short-name: @@ -62,8 +62,9 @@ Given that feature description, do this: - PowerShell example: `{SCRIPT} -Json -Number 5 -ShortName "user-auth" "Add user authentication"` **IMPORTANT**: - - Only consider branches that still exist (local or remote) - - If no existing branches found with this short-name, start with number 1 + - Check all three sources (remote branches, local branches, specs directories) to find the highest number + - Only match branches/directories with the exact short-name pattern + - If no existing branches/directories found with this short-name, start with number 1 - The JSON output will contain BRANCH_NAME and SPEC_FILE paths - You must only ever run this script once per feature - 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") From 5b3f685c3f5137e6d0585086e51f0430944c9447 Mon Sep 17 00:00:00 2001 From: Simon Gent Date: Thu, 23 Oct 2025 12:29:53 +0100 Subject: [PATCH 29/43] docs: restore important note about JSON output in specify command --- templates/commands/specify.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 79fa046930..3f0ddb78b1 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -65,8 +65,9 @@ Given that feature description, do this: - Check all three sources (remote branches, local branches, specs directories) to find the highest number - Only match branches/directories with the exact short-name pattern - If no existing branches/directories found with this short-name, start with number 1 - - The JSON output will contain BRANCH_NAME and SPEC_FILE paths - You must only ever run this script once per feature + - The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for + - The JSON output will contain BRANCH_NAME and SPEC_FILE paths - 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") 3. Load `templates/spec-template.md` to understand required sections. From 3cde2167628247c0abaec7359a1471c555fa2cd8 Mon Sep 17 00:00:00 2001 From: "den (work)" <53200638+localden@users.noreply.github.com> Date: Fri, 7 Nov 2025 13:17:35 -0800 Subject: [PATCH 30/43] Refactor feature script logic and update agent context scripts Refactored both Bash and PowerShell create-new-feature scripts to modularize and deduplicate logic for determining the next feature number, including new helper functions for extracting the highest number from specs and branches. Improved branch name cleaning and generation. In update-agent-context scripts, removed redundant updates to AGENTS.md for Copilot, streamlining agent update logic. --- scripts/bash/create-new-feature.sh | 75 ++++++++++++++++----- scripts/bash/update-agent-context.sh | 8 --- scripts/powershell/create-new-feature.ps1 | 61 +++++++++++++---- scripts/powershell/update-agent-context.ps1 | 8 +-- 4 files changed, 110 insertions(+), 42 deletions(-) diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index 86d9ecf837..8e8bcf6c35 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -80,9 +80,56 @@ find_repo_root() { return 1 } +# Function to get highest number from specs directory +get_highest_from_specs() { + local specs_dir="$1" + local highest=0 + + if [ -d "$specs_dir" ]; then + for dir in "$specs_dir"/*; do + [ -d "$dir" ] || continue + dirname=$(basename "$dir") + number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") + number=$((10#$number)) + if [ "$number" -gt "$highest" ]; then + highest=$number + fi + done + fi + + echo "$highest" +} + +# Function to get highest number from git branches +get_highest_from_branches() { + local highest=0 + + # Get all branches (local and remote) + branches=$(git branch -a 2>/dev/null || echo "") + + if [ -n "$branches" ]; then + while IFS= read -r branch; do + # Clean branch name: remove leading markers and remote prefixes + clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||') + + # Extract feature number if branch matches pattern ###-* + if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then + number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0") + number=$((10#$number)) + if [ "$number" -gt "$highest" ]; then + highest=$number + fi + fi + done <<< "$branches" + fi + + echo "$highest" +} + # Function to check existing branches (local and remote) and return next available number check_existing_branches() { local short_name="$1" + local specs_dir="$2" # Fetch all remotes to get latest branch info (suppress errors if no remotes) git fetch --all --prune 2>/dev/null || true @@ -95,8 +142,8 @@ check_existing_branches() { # Check specs directory as well local spec_dirs="" - if [ -d "$SPECS_DIR" ]; then - spec_dirs=$(find "$SPECS_DIR" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n) + if [ -d "$specs_dir" ]; then + spec_dirs=$(find "$specs_dir" -maxdepth 1 -type d -name "[0-9]*-${short_name}" 2>/dev/null | xargs -n1 basename 2>/dev/null | sed 's/-.*//' | sort -n) fi # Combine all sources and get the highest number @@ -111,6 +158,12 @@ check_existing_branches() { echo $((max_num + 1)) } +# Function to clean and format a branch name +clean_branch_name() { + local name="$1" + 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. @@ -176,14 +229,15 @@ generate_branch_name() { echo "$result" else # Fallback to original logic if no meaningful words found - echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//' | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//' + local cleaned=$(clean_branch_name "$description") + echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//' fi } # Generate branch name if [ -n "$SHORT_NAME" ]; then # Use provided short name, just clean it up - BRANCH_SUFFIX=$(echo "$SHORT_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//') + BRANCH_SUFFIX=$(clean_branch_name "$SHORT_NAME") else # Generate from description with smart filtering BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION") @@ -193,19 +247,10 @@ fi if [ -z "$BRANCH_NUMBER" ]; then if [ "$HAS_GIT" = true ]; then # Check existing branches on remotes - BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX") + BRANCH_NUMBER=$(check_existing_branches "$BRANCH_SUFFIX" "$SPECS_DIR") else # Fall back to local directory check - HIGHEST=0 - if [ -d "$SPECS_DIR" ]; then - for dir in "$SPECS_DIR"/*; do - [ -d "$dir" ] || continue - dirname=$(basename "$dir") - number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0") - number=$((10#$number)) - if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi - done - fi + HIGHEST=$(get_highest_from_specs "$SPECS_DIR") BRANCH_NUMBER=$((HIGHEST + 1)) fi fi diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index fcb525ac0f..a375bdc994 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -62,7 +62,6 @@ AGENT_TYPE="${1:-}" CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" GEMINI_FILE="$REPO_ROOT/GEMINI.md" COPILOT_FILE="$REPO_ROOT/.github/agents/copilot-instructions.md" -COPILOT_AGENTS_FILE="$REPO_ROOT/AGENTS.md" CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" QWEN_FILE="$REPO_ROOT/QWEN.md" AGENTS_FILE="$REPO_ROOT/AGENTS.md" @@ -588,7 +587,6 @@ update_specific_agent() { ;; copilot) update_agent_file "$COPILOT_FILE" "GitHub Copilot" - update_agent_file "$COPILOT_AGENTS_FILE" "GitHub Copilot (AGENTS.md)" ;; cursor-agent) update_agent_file "$CURSOR_FILE" "Cursor IDE" @@ -650,12 +648,6 @@ update_all_existing_agents() { found_agent=true fi - # Also update AGENTS.md for Copilot if the Copilot directory exists - if [[ -d "$REPO_ROOT/.github/agents" ]]; then - update_agent_file "$COPILOT_AGENTS_FILE" "GitHub Copilot (AGENTS.md)" - found_agent=true - fi - if [[ -f "$CURSOR_FILE" ]]; then update_agent_file "$CURSOR_FILE" "Cursor IDE" found_agent=true diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index 4daa6d2c06..351f4e9e7e 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -59,6 +59,46 @@ function Find-RepositoryRoot { } } +function Get-HighestNumberFromSpecs { + param([string]$SpecsDir) + + $highest = 0 + if (Test-Path $SpecsDir) { + Get-ChildItem -Path $SpecsDir -Directory | ForEach-Object { + if ($_.Name -match '^(\d+)') { + $num = [int]$matches[1] + if ($num -gt $highest) { $highest = $num } + } + } + } + return $highest +} + +function Get-HighestNumberFromBranches { + param() + + $highest = 0 + try { + $branches = git branch -a 2>$null + if ($LASTEXITCODE -eq 0) { + foreach ($branch in $branches) { + # Clean branch name: remove leading markers and remote prefixes + $cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', '' + + # Extract feature number if branch matches pattern ###-* + if ($cleanBranch -match '^(\d+)-') { + $num = [int]$matches[1] + if ($num -gt $highest) { $highest = $num } + } + } + } + } catch { + # If git command fails, return 0 + Write-Verbose "Could not check Git branches: $_" + } + return $highest +} + function Get-NextBranchNumber { param( [string]$ShortName, @@ -127,6 +167,12 @@ function Get-NextBranchNumber { # Return next number return $maxNum + 1 } + +function ConvertTo-CleanBranchName { + param([string]$Name) + + 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." @@ -189,7 +235,7 @@ function Get-BranchName { return $result } else { # Fallback to original logic if no meaningful words found - $result = $Description.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', '' + $result = ConvertTo-CleanBranchName -Name $Description $fallbackWords = ($result -split '-') | Where-Object { $_ } | Select-Object -First 3 return [string]::Join('-', $fallbackWords) } @@ -198,7 +244,7 @@ function Get-BranchName { # Generate branch name if ($ShortName) { # Use provided short name, just clean it up - $branchSuffix = $ShortName.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', '' + $branchSuffix = ConvertTo-CleanBranchName -Name $ShortName } else { # Generate from description with smart filtering $branchSuffix = Get-BranchName -Description $featureDesc @@ -211,16 +257,7 @@ if ($Number -eq 0) { $Number = Get-NextBranchNumber -ShortName $branchSuffix -SpecsDir $specsDir } else { # Fall back to local directory check - $highest = 0 - if (Test-Path $specsDir) { - Get-ChildItem -Path $specsDir -Directory | ForEach-Object { - if ($_.Name -match '^(\d{3})') { - $num = [int]$matches[1] - if ($num -gt $highest) { $highest = $num } - } - } - } - $Number = $highest + 1 + $Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1 } } diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index a439cc4350..741a55a638 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -47,7 +47,6 @@ $NEW_PLAN = $IMPL_PLAN $CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' $COPILOT_FILE = Join-Path $REPO_ROOT '.github/agents/copilot-instructions.md' -$COPILOT_AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' $CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' $QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' @@ -371,10 +370,7 @@ function Update-SpecificAgent { switch ($Type) { 'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' } 'gemini' { Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI' } - 'copilot' { - Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' - Update-AgentFile -TargetFile $COPILOT_AGENTS_FILE -AgentName 'GitHub Copilot (AGENTS.md)' - } + 'copilot' { Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' } 'cursor-agent' { Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE' } 'qwen' { Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code' } 'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' } @@ -396,8 +392,6 @@ function Update-AllExistingAgents { if (Test-Path $CLAUDE_FILE) { if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }; $found = $true } if (Test-Path $GEMINI_FILE) { if (-not (Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI')) { $ok = $false }; $found = $true } if (Test-Path $COPILOT_FILE) { if (-not (Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot')) { $ok = $false }; $found = $true } - # Also update AGENTS.md for Copilot if the Copilot directory exists - if (Test-Path (Join-Path $REPO_ROOT '.github/agents')) { if (-not (Update-AgentFile -TargetFile $COPILOT_AGENTS_FILE -AgentName 'GitHub Copilot (AGENTS.md)')) { $ok = $false }; $found = $true } if (Test-Path $CURSOR_FILE) { if (-not (Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE')) { $ok = $false }; $found = $true } if (Test-Path $QWEN_FILE) { if (-not (Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code')) { $ok = $false }; $found = $true } if (Test-Path $AGENTS_FILE) { if (-not (Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex/opencode')) { $ok = $false }; $found = $true } From f9db18bf37c4100301b5f37bb53744f7bb248aac Mon Sep 17 00:00:00 2001 From: Den Delimarsky <53200638+localden@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:59:07 -0800 Subject: [PATCH 31/43] Update templates/commands/taskstoissues.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- templates/commands/taskstoissues.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/commands/taskstoissues.md b/templates/commands/taskstoissues.md index b381da952e..e0f3663728 100644 --- a/templates/commands/taskstoissues.md +++ b/templates/commands/taskstoissues.md @@ -1,5 +1,5 @@ --- -description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts. +description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts. tools: ['github/github-mcp-server/create_issue'] scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks From 099b69ee771f16d862e987453807ccd355065129 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Fri, 14 Nov 2025 22:01:43 +0100 Subject: [PATCH 32/43] Fix tasktoissues.md to use the 'github/github-mcp-server/issue_write' tool --- templates/commands/taskstoissues.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/commands/taskstoissues.md b/templates/commands/taskstoissues.md index e0f3663728..fb6acc1791 100644 --- a/templates/commands/taskstoissues.md +++ b/templates/commands/taskstoissues.md @@ -1,6 +1,6 @@ --- description: Convert existing tasks into actionable, dependency-ordered GitHub issues for the feature based on available design artifacts. -tools: ['github/github-mcp-server/create_issue'] +tools: ['github/github-mcp-server/issue_write'] scripts: sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks From d9dba1862192f865103842bed8bbcbf70e19a370 Mon Sep 17 00:00:00 2001 From: hua Date: Fri, 7 Nov 2025 11:45:02 +0800 Subject: [PATCH 33/43] fix: incorrect logic to create release packages with subset AGENTS or SCRIPTS --- .github/workflows/scripts/create-release-packages.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) mode change 100644 => 100755 .github/workflows/scripts/create-release-packages.sh diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh old mode 100644 new mode 100755 index 1b2e532657..0cd13ce48f --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -218,22 +218,22 @@ ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilo ALL_SCRIPTS=(sh ps) norm_list() { - # convert comma+space separated -> space separated unique while preserving order of first occurrence - tr ',\n' ' ' | awk '{for(i=1;i<=NF;i++){if(!seen[$i]++){printf((out?" ":"") $i)}}}END{printf("\n")}' + # convert comma+space separated -> line separated unique while preserving order of first occurrence + tr ',\n' ' ' | awk '{for(i=1;i<=NF;i++){if(!seen[$i]++){printf((out?"\n":"") $i);out=1}}}END{printf("\n")}' } validate_subset() { local type=$1; shift; local -n allowed=$1; shift; local items=("$@") - local ok=1 + local invalid=0 for it in "${items[@]}"; do local found=0 for a in "${allowed[@]}"; do [[ $it == "$a" ]] && { found=1; break; }; done if [[ $found -eq 0 ]]; then echo "Error: unknown $type '$it' (allowed: ${allowed[*]})" >&2 - ok=0 + invalid=1 fi done - return $ok + return $invalid } if [[ -n ${AGENTS:-} ]]; then From 35df2c6fcfbffdb66d915bc55ffa201dd60384ff Mon Sep 17 00:00:00 2001 From: Elias TOURNEUX Date: Thu, 6 Nov 2025 13:55:17 -0500 Subject: [PATCH 34/43] feat: Add OVHcloud SHAI AI Agent --- .../workflows/scripts/create-github-release.sh | 2 ++ .../scripts/create-release-packages.sh | 7 +++++-- AGENTS.md | 4 +++- README.md | 8 ++++++-- scripts/bash/update-agent-context.sh | 17 +++++++++++++---- scripts/powershell/update-agent-context.ps1 | 11 +++++++---- src/specify_cli/__init__.py | 8 +++++++- 7 files changed, 43 insertions(+), 14 deletions(-) diff --git a/.github/workflows/scripts/create-github-release.sh b/.github/workflows/scripts/create-github-release.sh index 25d354ef2f..c09a255bac 100644 --- a/.github/workflows/scripts/create-github-release.sh +++ b/.github/workflows/scripts/create-github-release.sh @@ -42,6 +42,8 @@ gh release create "$VERSION" \ .genreleases/spec-kit-template-codebuddy-ps-"$VERSION".zip \ .genreleases/spec-kit-template-amp-sh-"$VERSION".zip \ .genreleases/spec-kit-template-amp-ps-"$VERSION".zip \ + .genreleases/spec-kit-template-shai-sh-"$VERSION".zip \ + .genreleases/spec-kit-template-shai-ps-"$VERSION".zip \ .genreleases/spec-kit-template-q-sh-"$VERSION".zip \ .genreleases/spec-kit-template-q-ps-"$VERSION".zip \ --title "Spec Kit Templates - $VERSION_NO_V" \ diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 0cd13ce48f..1f5c6e51b2 100755 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -6,7 +6,7 @@ set -euo pipefail # Usage: .github/workflows/scripts/create-release-packages.sh # Version argument should include leading 'v'. # Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built. -# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp (default: all) +# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp shai (default: all) # SCRIPTS : space or comma separated subset of: sh ps (default: both) # Examples: # AGENTS=claude SCRIPTS=sh $0 v0.2.0 @@ -205,6 +205,9 @@ build_variant() { amp) mkdir -p "$base_dir/.agents/commands" generate_commands amp md "\$ARGUMENTS" "$base_dir/.agents/commands" "$script" ;; + shai) + mkdir -p "$base_dir/.shai/commands" + generate_commands shai md "\$ARGUMENTS" "$base_dir/.shai/commands" "$script" ;; q) mkdir -p "$base_dir/.amazonq/prompts" generate_commands q md "\$ARGUMENTS" "$base_dir/.amazonq/prompts" "$script" ;; @@ -214,7 +217,7 @@ build_variant() { } # Determine agent list -ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp q) +ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai q) ALL_SCRIPTS=(sh ps) norm_list() { diff --git a/AGENTS.md b/AGENTS.md index f7d956bd7b..3016c3eda3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,6 +45,7 @@ Specify supports multiple AI agents by generating agent-specific command files a | **CodeBuddy CLI** | `.codebuddy/commands/` | Markdown | `codebuddy` | CodeBuddy CLI | | **Amazon Q Developer CLI** | `.amazonq/prompts/` | Markdown | `q` | Amazon Q Developer CLI | | **Amp** | `.agents/commands/` | Markdown | `amp` | Amp CLI | +| **SHAI** | `.shai/commands/` | Markdown | `shai` | SHAI CLI | ### Step-by-Step Integration Guide @@ -311,6 +312,7 @@ Require a command-line tool to be installed: - **Amazon Q Developer CLI**: `q` CLI - **CodeBuddy CLI**: `codebuddy` CLI - **Amp**: `amp` CLI +- **SHAI**: `shai` CLI ### IDE-Based Agents @@ -323,7 +325,7 @@ Work within integrated development environments: ### Markdown Format -Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp +Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp, SHAI **Standard format:** diff --git a/README.md b/README.md index 1c7dda2151..2b6064c89e 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,7 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c | [Codex CLI](https://github.com/openai/codex) | ✅ | | | [Amazon Q Developer CLI](https://aws.amazon.com/developer/learning/q-developer-cli/) | ⚠️ | Amazon Q Developer CLI [does not support](https://github.com/aws/amazon-q-developer-cli/issues/3064) custom arguments for slash commands. | | [Amp](https://ampcode.com/) | ✅ | | +| [SHAI (OVHcloud)](https://github.com/ovh/shai) | ✅ | | ## 🔧 Specify CLI Reference @@ -160,14 +161,14 @@ The `specify` command supports the following options: | Command | Description | |-------------|----------------------------------------------------------------| | `init` | Initialize a new Specify project from the latest template | -| `check` | Check for installed tools (`git`, `claude`, `gemini`, `code`/`code-insiders`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`) | +| `check` | Check for installed tools (`git`, `claude`, `gemini`, `code`/`code-insiders`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`, `shai`) | ### `specify init` Arguments & Options | Argument/Option | Type | Description | |------------------------|----------|------------------------------------------------------------------------------| | `` | Argument | Name for your new project directory (optional if using `--here`, or use `.` for current directory) | -| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, or `q` | +| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, `shai`, or `q` | | `--script` | Option | Script variant to use: `sh` (bash/zsh) or `ps` (PowerShell) | | `--ignore-agent-tools` | Flag | Skip checks for AI agent tools like Claude Code | | `--no-git` | Flag | Skip git repository initialization | @@ -195,6 +196,9 @@ specify init my-project --ai windsurf # Initialize with Amp support specify init my-project --ai amp +# Initialize with SHAI support +specify init my-project --ai shai + # Initialize with PowerShell scripts (Windows/cross-platform) specify init my-project --ai copilot --script ps diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index a375bdc994..5ba07ed6f2 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -30,12 +30,12 @@ # # 5. Multi-Agent Support # - Handles agent-specific file paths and naming conventions -# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Amp, or Amazon Q Developer CLI +# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Amp, SHAI, or Amazon Q Developer CLI # - Can update single agents or all existing agent files # - Creates default Claude file if no agent files exist # # Usage: ./update-agent-context.sh [agent_type] -# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|q +# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|shai|q # Leave empty to update all existing agent files set -e @@ -71,6 +71,7 @@ AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md" ROO_FILE="$REPO_ROOT/.roo/rules/specify-rules.md" CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md" AMP_FILE="$REPO_ROOT/AGENTS.md" +SHAI_FILE="$REPO_ROOT/SHAI.md" Q_FILE="$REPO_ROOT/AGENTS.md" # Template file @@ -618,12 +619,15 @@ update_specific_agent() { amp) update_agent_file "$AMP_FILE" "Amp" ;; + shai) + update_agent_file "$SHAI_FILE" "SHAI" + ;; q) update_agent_file "$Q_FILE" "Amazon Q Developer CLI" ;; *) log_error "Unknown agent type '$agent_type'" - log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|q" + log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|shai|q" exit 1 ;; esac @@ -688,6 +692,11 @@ update_all_existing_agents() { found_agent=true fi + if [[ -f "$SHAI_FILE" ]]; then + update_agent_file "$SHAI_FILE" "SHAI" + found_agent=true + fi + if [[ -f "$Q_FILE" ]]; then update_agent_file "$Q_FILE" "Amazon Q Developer CLI" found_agent=true @@ -717,7 +726,7 @@ print_summary() { echo - log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|codebuddy|q]" + log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|codebuddy|shai|q]" } #============================================================================== diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index 741a55a638..ea5654cce3 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -9,7 +9,7 @@ Mirrors the behavior of scripts/bash/update-agent-context.sh: 2. Plan Data Extraction 3. Agent File Management (create from template or update existing) 4. Content Generation (technology stack, recent changes, timestamp) - 5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, amp, q) + 5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, q) .PARAMETER AgentType Optional agent key to update a single agent. If omitted, updates all existing agent files (creating a default Claude file if none exist). @@ -25,7 +25,7 @@ Relies on common helper functions in common.ps1 #> param( [Parameter(Position=0)] - [ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','q')] + [ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','q')] [string]$AgentType ) @@ -56,6 +56,7 @@ $AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md' $ROO_FILE = Join-Path $REPO_ROOT '.roo/rules/specify-rules.md' $CODEBUDDY_FILE = Join-Path $REPO_ROOT 'CODEBUDDY.md' $AMP_FILE = Join-Path $REPO_ROOT 'AGENTS.md' +$SHAI_FILE = Join-Path $REPO_ROOT 'SHAI.md' $Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md' $TEMPLATE_FILE = Join-Path $REPO_ROOT '.specify/templates/agent-file-template.md' @@ -381,8 +382,9 @@ function Update-SpecificAgent { 'roo' { Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code' } 'codebuddy' { Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI' } 'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' } + 'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' } 'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' } - default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|q'; return $false } + default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q'; return $false } } } @@ -400,6 +402,7 @@ function Update-AllExistingAgents { if (Test-Path $AUGGIE_FILE) { if (-not (Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI')) { $ok = $false }; $found = $true } if (Test-Path $ROO_FILE) { if (-not (Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code')) { $ok = $false }; $found = $true } if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true } + if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true } if (Test-Path $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $ok = $false }; $found = $true } if (-not $found) { Write-Info 'No existing agent files found, creating default Claude file...' @@ -415,7 +418,7 @@ function Print-Summary { if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" } if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" } Write-Host '' - Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|q]' + Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q]' } function Main { diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 701b3bdca8..2fa6455a29 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -208,6 +208,12 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) "install_url": "https://ampcode.com/manual#install", "requires_cli": True, }, + "shai": { + "name": "SHAI", + "folder": ".shai/", + "install_url": "https://github.com/ovh/shai", + "requires_cli": True, + }, } SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"} @@ -927,7 +933,7 @@ def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None = @app.command() def init( project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"), - ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, or q"), + ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, shai, or q"), script_type: str = typer.Option(None, "--script", help="Script type to use: sh or ps"), ignore_agent_tools: bool = typer.Option(False, "--ignore-agent-tools", help="Skip checks for AI agent tools like Claude Code"), no_git: bool = typer.Option(False, "--no-git", help="Skip git repository initialization"), From cd3b0f45370157fa4adbc34a17c7885e910fcf7e Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Wed, 5 Nov 2025 18:46:48 -0500 Subject: [PATCH 35/43] docs: Add comprehensive upgrading guide for Spec Kit - Add upgrading-spec-kit.md with detailed upgrade instructions and troubleshooting - Update table of contents to include upgrading guide in Getting Started section - Update documentation index and README links - Address user questions about updating initialized projects from GitHub discussions Co-authored-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- .gitignore | 1 + README.md | 10 +- docs/index.md | 7 +- docs/toc.yml | 3 +- docs/upgrading-spec-kit.md | 445 +++++++++++++++++++++++++++++++++++++ 5 files changed, 459 insertions(+), 7 deletions(-) create mode 100644 docs/upgrading-spec-kit.md diff --git a/.gitignore b/.gitignore index 94bed859d4..1ed573622d 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ env/ *.swp *.swo .DS_Store +*.tmp # Project specific *.log diff --git a/README.md b/README.md index 2b6064c89e..fd174f5b4d 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ specify init specify check ``` -To upgrade specify run: +To upgrade Specify, see the [Upgrading Spec Kit guide](./docs/upgrading-spec-kit.md) for detailed instructions. Quick upgrade: ```bash uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git @@ -209,7 +209,7 @@ specify init --here --ai copilot # Force merge into current (non-empty) directory without confirmation specify init . --force --ai copilot -# or +# or specify init --here --force --ai copilot # Skip git initialization @@ -312,6 +312,10 @@ If you encounter issues with an agent, please open an issue so we can refine the ## 📖 Learn More +- **[Installation Guide](./docs/installation.md)** - First-time installation instructions +- **[Quick Start Guide](./docs/quickstart.md)** - Get started with a new project +- **[Existing Project Guide](./docs/existing-project-guide.md)** - Add Spec Kit to your current codebase +- **[Upgrading Spec Kit](./docs/upgrading-spec-kit.md)** - Update CLI and project files - **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process - **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide @@ -554,7 +558,7 @@ This helps refine the implementation plan and helps you avoid potential blind sp You can also ask Claude Code (if you have the [GitHub CLI](https://docs.github.com/en/github-cli/github-cli) installed) to go ahead and create a pull request from your current branch to `main` with a detailed description, to make sure that the effort is properly tracked. >[!NOTE] ->Before you have the agent implement it, it's also worth prompting Claude Code to cross-check the details to see if there are any over-engineered pieces (remember - it can be over-eager). If over-engineered components or decisions exist, you can ask Claude Code to resolve them. Ensure that Claude Code follows the [constitution](base/memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan. +>Before you have the agent implement it, it's also worth prompting Claude Code to cross-check the details to see if there are any over-engineered pieces (remember - it can be over-eager). If over-engineered components or decisions exist, you can ask Claude Code to resolve them. Ensure that Claude Code follows the [constitution](memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan. ### **STEP 6:** Generate task breakdown with /speckit.tasks diff --git a/docs/index.md b/docs/index.md index 38a6de34e1..5352dc655b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,9 +10,10 @@ Spec-Driven Development **flips the script** on traditional software development ## Getting Started -- [Installation Guide](installation.md) -- [Quick Start Guide](quickstart.md) -- [Local Development](local-development.md) +- [Installation Guide](installation.md) - First-time installation of Spec Kit +- [Quick Start Guide](quickstart.md) - Start a new project with Spec Kit +- [Upgrading Spec Kit](upgrading-spec-kit.md) - Update CLI and project files +- [Local Development](local-development.md) - Contribute to Spec Kit development ## Core Philosophy diff --git a/docs/toc.yml b/docs/toc.yml index 082bb8c868..fd8c3ca5ef 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -9,10 +9,11 @@ href: installation.md - name: Quick Start href: quickstart.md + - name: Upgrading Spec Kit + href: upgrading-spec-kit.md # Development workflows - name: Development items: - name: Local Development href: local-development.md - diff --git a/docs/upgrading-spec-kit.md b/docs/upgrading-spec-kit.md new file mode 100644 index 0000000000..e5d525d4a2 --- /dev/null +++ b/docs/upgrading-spec-kit.md @@ -0,0 +1,445 @@ +# Upgrading Spec Kit + +> You have Spec Kit installed and want to upgrade to the latest version to get new features, bug fixes, or updated slash commands. This guide covers both upgrading the CLI tool and updating your project files. + +--- + +## Quick Reference + +| What to Upgrade | Command | When to Use | +|----------------|---------|-------------| +| **CLI Tool Only** | `uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git` | Get latest CLI features without touching project files | +| **Project Files** | `specify init --here --force --ai ` | Update slash commands, templates, and scripts in your project | +| **Both** | Run CLI upgrade, then project update | Recommended for major version updates | + +--- + +## Part 1: Upgrading the CLI Tool + +The CLI tool (`specify`) is separate from your project files. Upgrade it to get the latest features and bug fixes. + +### If you installed with `uv tool install` + +```bash +uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git +``` + +### If you use one-shot `uvx` commands + +No upgrade needed—`uvx` always fetches the latest version. Just run your commands as normal: + +```bash +uvx --from git+https://github.com/github/spec-kit.git specify init --here --ai copilot +``` + +### Verify the upgrade + +```bash +specify check +``` + +This shows installed tools and confirms the CLI is working. + +--- + +## Part 2: Updating Project Files + +When Spec Kit releases new features (like new slash commands or updated templates), you need to refresh your project's Spec Kit files. + +### What gets updated? + +Running `specify init --here --force` will update: + +- ✅ **Slash command files** (`.claude/commands/`, `.github/prompts/`, etc.) +- ✅ **Script files** (`.specify/scripts/`) +- ✅ **Template files** (`.specify/templates/`) +- ✅ **Shared memory files** (`.specify/memory/`) - **⚠️ See warnings below** + +### What stays safe? + +These files are **never touched** by the upgrade—the template packages don't even contain them: + +- ✅ **Your specifications** (`specs/001-my-feature/spec.md`, etc.) - **CONFIRMED SAFE** +- ✅ **Your implementation plans** (`specs/001-my-feature/plan.md`, `tasks.md`, etc.) - **CONFIRMED SAFE** +- ✅ **Your source code** - **CONFIRMED SAFE** +- ✅ **Your git history** - **CONFIRMED SAFE** + +The `specs/` directory is completely excluded from template packages and will never be modified during upgrades. + +### Update command + +Run this inside your project directory: + +```bash +specify init --here --force --ai +``` + +Replace `` with your AI assistant: `claude`, `gemini`, `copilot`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`, `auggie`, `codebuddy`, `roo`, `kilocode`, or `q`. + +**Example:** + +```bash +specify init --here --force --ai copilot +``` + +### Understanding the `--force` flag + +Without `--force`, the CLI warns you and asks for confirmation: + +``` +Warning: Current directory is not empty (25 items) +Template files will be merged with existing content and may overwrite existing files +Proceed? [y/N] +``` + +With `--force`, it skips the confirmation and proceeds immediately. + +**Important: Your `specs/` directory is always safe.** The `--force` flag only affects template files (commands, scripts, templates, memory). Your feature specifications, plans, and tasks in `specs/` are never included in upgrade packages and cannot be overwritten. + +--- + +## ⚠️ Important Warnings + +### 1. Constitution file will be overwritten + +**Known issue:** `specify init --here --force` currently overwrites `.specify/memory/constitution.md` with the default template, erasing any customizations you made. + +**Workaround:** + +```bash +# 1. Back up your constitution before upgrading +cp .specify/memory/constitution.md .specify/memory/constitution-backup.md + +# 2. Run the upgrade +specify init --here --force --ai copilot + +# 3. Restore your customized constitution +mv .specify/memory/constitution-backup.md .specify/memory/constitution.md +``` + +Or use git to restore it: + +```bash +# After upgrade, restore from git history +git restore .specify/memory/constitution.md +``` + +### 2. Custom template modifications + +If you customized any templates in `.specify/templates/`, the upgrade will overwrite them. Back them up first: + +```bash +# Back up custom templates +cp -r .specify/templates .specify/templates-backup + +# After upgrade, merge your changes back manually +``` + +### 3. Duplicate slash commands (IDE-based agents) + +Some IDE-based agents (like Kilo Code, Windsurf) may show **duplicate slash commands** after upgrading—both old and new versions appear. + +**Solution:** Manually delete the old command files from your agent's folder. + +**Example for Kilo Code:** + +```bash +# Navigate to the agent's commands folder +cd .kilocode/rules/ + +# List files and identify duplicates +ls -la + +# Delete old versions (example filenames - yours may differ) +rm speckit.specify-old.md +rm speckit.plan-v1.md +``` + +Restart your IDE to refresh the command list. + +--- + +## Common Scenarios + +### Scenario 1: "I just want new slash commands" + +```bash +# Upgrade CLI (if using persistent install) +uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git + +# Update project files to get new commands +specify init --here --force --ai copilot + +# Restore your constitution if customized +git restore .specify/memory/constitution.md +``` + +### Scenario 2: "I customized templates and constitution" + +```bash +# 1. Back up customizations +cp .specify/memory/constitution.md /tmp/constitution-backup.md +cp -r .specify/templates /tmp/templates-backup + +# 2. Upgrade CLI +uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git + +# 3. Update project +specify init --here --force --ai copilot + +# 4. Restore customizations +mv /tmp/constitution-backup.md .specify/memory/constitution.md +# Manually merge template changes if needed +``` + +### Scenario 3: "I see duplicate slash commands in my IDE" + +This happens with IDE-based agents (Kilo Code, Windsurf, Roo Code, etc.). + +```bash +# Find the agent folder (example: .kilocode/rules/) +cd .kilocode/rules/ + +# List all files +ls -la + +# Delete old command files +rm speckit.old-command-name.md + +# Restart your IDE +``` + +### Scenario 4: "I'm working on a project without Git" + +If you initialized your project with `--no-git`, you can still upgrade: + +```bash +# Manually back up files you customized +cp .specify/memory/constitution.md /tmp/constitution-backup.md + +# Run upgrade +specify init --here --force --ai copilot --no-git + +# Restore customizations +mv /tmp/constitution-backup.md .specify/memory/constitution.md +``` + +The `--no-git` flag skips git initialization but doesn't affect file updates. + +--- + +## Using `--no-git` Flag + +The `--no-git` flag tells Spec Kit to **skip git repository initialization**. This is useful when: + +- You manage version control differently (Mercurial, SVN, etc.) +- Your project is part of a larger monorepo with existing git setup +- You're experimenting and don't want version control yet + +**During initial setup:** + +```bash +specify init my-project --ai copilot --no-git +``` + +**During upgrade:** + +```bash +specify init --here --force --ai copilot --no-git +``` + +### What `--no-git` does NOT do + +❌ Does NOT prevent file updates +❌ Does NOT skip slash command installation +❌ Does NOT affect template merging + +It **only** skips running `git init` and creating the initial commit. + +### Working without Git + +If you use `--no-git`, you'll need to manage feature directories manually: + +**Set the `SPECIFY_FEATURE` environment variable** before using planning commands: + +```bash +# Bash/Zsh +export SPECIFY_FEATURE="001-my-feature" + +# PowerShell +$env:SPECIFY_FEATURE = "001-my-feature" +``` + +This tells Spec Kit which feature directory to use when creating specs, plans, and tasks. + +**Why this matters:** Without git, Spec Kit can't detect your current branch name to determine the active feature. The environment variable provides that context manually. + +--- + +## Troubleshooting + +### "Slash commands not showing up after upgrade" + +**Cause:** Agent didn't reload the command files. + +**Fix:** + +1. **Restart your IDE/editor** completely (not just reload window) +2. **For CLI-based agents**, verify files exist: + ```bash + ls -la .claude/commands/ # Claude Code + ls -la .gemini/commands/ # Gemini + ls -la .cursor/commands/ # Cursor + ``` +3. **Check agent-specific setup:** + - Codex requires `CODEX_HOME` environment variable + - Some agents need workspace restart or cache clearing + +### "I lost my constitution customizations" + +**Fix:** Restore from git or backup: + +```bash +# If you committed before upgrading +git restore .specify/memory/constitution.md + +# If you backed up manually +cp /tmp/constitution-backup.md .specify/memory/constitution.md +``` + +**Prevention:** Always commit or back up `constitution.md` before upgrading. + +### "Warning: Current directory is not empty" + +**Full warning message:** +``` +Warning: Current directory is not empty (25 items) +Template files will be merged with existing content and may overwrite existing files +Do you want to continue? [y/N] +``` + +**What this means:** + +This warning appears when you run `specify init --here` (or `specify init .`) in a directory that already has files. It's telling you: + +1. **The directory has existing content** - In the example, 25 files/folders +2. **Files will be merged** - New template files will be added alongside your existing files +3. **Some files may be overwritten** - If you already have Spec Kit files (`.claude/`, `.specify/`, etc.), they'll be replaced with the new versions + +**What gets overwritten:** + +Only Spec Kit infrastructure files: +- Agent command files (`.claude/commands/`, `.github/prompts/`, etc.) +- Scripts in `.specify/scripts/` +- Templates in `.specify/templates/` +- Memory files in `.specify/memory/` (including constitution) + +**What stays untouched:** + +- Your `specs/` directory (specifications, plans, tasks) +- Your source code files +- Your `.git/` directory and git history +- Any other files not part of Spec Kit templates + +**How to respond:** + +- **Type `y` and press Enter** - Proceed with the merge (recommended if upgrading) +- **Type `n` and press Enter** - Cancel the operation +- **Use `--force` flag** - Skip this confirmation entirely: + ```bash + specify init --here --force --ai copilot + ``` + +**When you see this warning:** + +- ✅ **Expected** when upgrading an existing Spec Kit project +- ✅ **Expected** when adding Spec Kit to an existing codebase +- ⚠️ **Unexpected** if you thought you were creating a new project in an empty directory + +**Prevention tip:** Before upgrading, commit or back up your `.specify/memory/constitution.md` if you customized it. + +### "CLI upgrade doesn't seem to work" + +Verify the installation: + +```bash +# Check installed tools +uv tool list + +# Should show specify-cli + +# Verify path +which specify + +# Should point to the uv tool installation directory +``` + +If not found, reinstall: + +```bash +uv tool uninstall specify-cli +uv tool install specify-cli --from git+https://github.com/github/spec-kit.git +``` + +### "Do I need to run specify every time I open my project?" + +**Short answer:** No, you only run `specify init` once per project (or when upgrading). + +**Explanation:** + +The `specify` CLI tool is used for: +- **Initial setup:** `specify init` to bootstrap Spec Kit in your project +- **Upgrades:** `specify init --here --force` to update templates and commands +- **Diagnostics:** `specify check` to verify tool installation + +Once you've run `specify init`, the slash commands (like `/speckit.specify`, `/speckit.plan`, etc.) are **permanently installed** in your project's agent folder (`.claude/`, `.github/prompts/`, etc.). Your AI assistant reads these command files directly—no need to run `specify` again. + +**If your agent isn't recognizing slash commands:** + +1. **Verify command files exist:** + ```bash + # For GitHub Copilot + ls -la .github/prompts/ + + # For Claude + ls -la .claude/commands/ + ``` + +2. **Restart your IDE/editor completely** (not just reload window) + +3. **Check you're in the correct directory** where you ran `specify init` + +4. **For some agents**, you may need to reload the workspace or clear cache + +**Related issue:** If Copilot can't open local files or uses PowerShell commands unexpectedly, this is typically an IDE context issue, not related to `specify`. Try: +- Restarting VS Code +- Checking file permissions +- Ensuring the workspace folder is properly opened + +--- + +## Version Compatibility + +Spec Kit follows semantic versioning for major releases. The CLI and project files are designed to be compatible within the same major version. + +**Best practice:** Keep both CLI and project files in sync by upgrading both together during major version changes. + +--- + +## Next Steps + +After upgrading: + +- **Test new slash commands:** Run `/speckit.constitution` or another command to verify everything works +- **Review release notes:** Check [GitHub Releases](https://github.com/github/spec-kit/releases) for new features and breaking changes +- **Update workflows:** If new commands were added, update your team's development workflows +- **Check documentation:** Visit [github.io/spec-kit](https://github.github.io/spec-kit/) for updated guides + +--- + +## Related Documentation + +- [Installation Guide](installation.md) - First-time setup instructions +- [Existing Project Guide](existing-project-guide.md) - Adding Spec Kit to existing codebases +- [Quick Start](quickstart.md) - Getting started with new projects +- [Local Development](local-development.md) - Contributing to Spec Kit itself From 121019f60f68a6ae78b16bde6dcb38084ae1b62f Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Wed, 5 Nov 2025 20:54:39 -0500 Subject: [PATCH 36/43] fix: remove broken link to existing project guide - Remove link to non-existent existing project guide from README Commit-generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index fd174f5b4d..3059707864 100644 --- a/README.md +++ b/README.md @@ -314,7 +314,6 @@ If you encounter issues with an agent, please open an issue so we can refine the - **[Installation Guide](./docs/installation.md)** - First-time installation instructions - **[Quick Start Guide](./docs/quickstart.md)** - Get started with a new project -- **[Existing Project Guide](./docs/existing-project-guide.md)** - Add Spec Kit to your current codebase - **[Upgrading Spec Kit](./docs/upgrading-spec-kit.md)** - Update CLI and project files - **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process - **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide From b235936fe4beaf4ececfbba55d674604af496ca3 Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Thu, 6 Nov 2025 17:47:21 -0500 Subject: [PATCH 37/43] docs: remove related documentation section from upgrading guide - Remove outdated links section from docs/upgrading-spec-kit.md - Remove outdated section from README and docs/index Commit-generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- README.md | 3 --- docs/index.md | 7 ------- docs/upgrading-spec-kit.md | 9 --------- 3 files changed, 19 deletions(-) diff --git a/README.md b/README.md index 3059707864..48d5876ae7 100644 --- a/README.md +++ b/README.md @@ -312,9 +312,6 @@ If you encounter issues with an agent, please open an issue so we can refine the ## 📖 Learn More -- **[Installation Guide](./docs/installation.md)** - First-time installation instructions -- **[Quick Start Guide](./docs/quickstart.md)** - Get started with a new project -- **[Upgrading Spec Kit](./docs/upgrading-spec-kit.md)** - Update CLI and project files - **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process - **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide diff --git a/docs/index.md b/docs/index.md index 5352dc655b..4c73be352b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,13 +8,6 @@ Spec-Driven Development **flips the script** on traditional software development. For decades, code has been king — specifications were just scaffolding we built and discarded once the "real work" of coding began. Spec-Driven Development changes this: **specifications become executable**, directly generating working implementations rather than just guiding them. -## Getting Started - -- [Installation Guide](installation.md) - First-time installation of Spec Kit -- [Quick Start Guide](quickstart.md) - Start a new project with Spec Kit -- [Upgrading Spec Kit](upgrading-spec-kit.md) - Update CLI and project files -- [Local Development](local-development.md) - Contribute to Spec Kit development - ## Core Philosophy Spec-Driven Development is a structured process that emphasizes: diff --git a/docs/upgrading-spec-kit.md b/docs/upgrading-spec-kit.md index e5d525d4a2..34db38bc52 100644 --- a/docs/upgrading-spec-kit.md +++ b/docs/upgrading-spec-kit.md @@ -434,12 +434,3 @@ After upgrading: - **Review release notes:** Check [GitHub Releases](https://github.com/github/spec-kit/releases) for new features and breaking changes - **Update workflows:** If new commands were added, update your team's development workflows - **Check documentation:** Visit [github.io/spec-kit](https://github.github.io/spec-kit/) for updated guides - ---- - -## Related Documentation - -- [Installation Guide](installation.md) - First-time setup instructions -- [Existing Project Guide](existing-project-guide.md) - Adding Spec Kit to existing codebases -- [Quick Start](quickstart.md) - Getting started with new projects -- [Local Development](local-development.md) - Contributing to Spec Kit itself From e2123357cd57ad5072e10450c251c3d241c2e944 Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Thu, 6 Nov 2025 18:01:16 -0500 Subject: [PATCH 38/43] docs: reorganize upgrade documentation structure - Rename docs/upgrading-spec-kit.md to docs/upgrade.md for brevity - Update README and documentation index links to point to new upgrade guide - Update table of contents to use shorter "Upgrade" title - Simplify section headers in upgrade guide - Add Getting Started section back to docs/index.md with upgrade guide link Commit-generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- README.md | 2 +- docs/index.md | 7 +++++++ docs/toc.yml | 4 ++-- docs/{upgrading-spec-kit.md => upgrade.md} | 4 ++-- 4 files changed, 12 insertions(+), 5 deletions(-) rename docs/{upgrading-spec-kit.md => upgrade.md} (99%) diff --git a/README.md b/README.md index 48d5876ae7..c6b40d836a 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ specify init specify check ``` -To upgrade Specify, see the [Upgrading Spec Kit guide](./docs/upgrading-spec-kit.md) for detailed instructions. Quick upgrade: +To upgrade Specify, see the [Upgrade Guide](./docs/upgrade.md) for detailed instructions. Quick upgrade: ```bash uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git diff --git a/docs/index.md b/docs/index.md index 4c73be352b..a56fcc1761 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,6 +8,13 @@ Spec-Driven Development **flips the script** on traditional software development. For decades, code has been king — specifications were just scaffolding we built and discarded once the "real work" of coding began. Spec-Driven Development changes this: **specifications become executable**, directly generating working implementations rather than just guiding them. +## Getting Started + +- [Installation Guide](installation.md) +- [Quick Start Guide](quickstart.md) +- [Upgrade Guide](upgrade.md) +- [Local Development](local-development.md) + ## Core Philosophy Spec-Driven Development is a structured process that emphasizes: diff --git a/docs/toc.yml b/docs/toc.yml index fd8c3ca5ef..18650cb571 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -9,8 +9,8 @@ href: installation.md - name: Quick Start href: quickstart.md - - name: Upgrading Spec Kit - href: upgrading-spec-kit.md + - name: Upgrade + href: upgrade.md # Development workflows - name: Development diff --git a/docs/upgrading-spec-kit.md b/docs/upgrade.md similarity index 99% rename from docs/upgrading-spec-kit.md rename to docs/upgrade.md index 34db38bc52..9748f6e76c 100644 --- a/docs/upgrading-spec-kit.md +++ b/docs/upgrade.md @@ -1,4 +1,4 @@ -# Upgrading Spec Kit +# Upgrade Guide > You have Spec Kit installed and want to upgrade to the latest version to get new features, bug fixes, or updated slash commands. This guide covers both upgrading the CLI tool and updating your project files. @@ -14,7 +14,7 @@ --- -## Part 1: Upgrading the CLI Tool +## Part 1: Upgrade the CLI Tool The CLI tool (`specify`) is separate from your project files. Upgrade it to get the latest features and bug fixes. From 03277bdb6d37307e626da4cad40592cd996d673b Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Thu, 6 Nov 2025 23:43:16 -0500 Subject: [PATCH 39/43] docs: fix broken link and improve agent reference - Fix broken constitution.md link in detailed process section - Add reference to supported AI agents list in upgrade guide Commit-generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- README.md | 2 +- docs/upgrade.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c6b40d836a..c3dcdf269c 100644 --- a/README.md +++ b/README.md @@ -554,7 +554,7 @@ This helps refine the implementation plan and helps you avoid potential blind sp You can also ask Claude Code (if you have the [GitHub CLI](https://docs.github.com/en/github-cli/github-cli) installed) to go ahead and create a pull request from your current branch to `main` with a detailed description, to make sure that the effort is properly tracked. >[!NOTE] ->Before you have the agent implement it, it's also worth prompting Claude Code to cross-check the details to see if there are any over-engineered pieces (remember - it can be over-eager). If over-engineered components or decisions exist, you can ask Claude Code to resolve them. Ensure that Claude Code follows the [constitution](memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan. +>Before you have the agent implement it, it's also worth prompting Claude Code to cross-check the details to see if there are any over-engineered pieces (remember - it can be over-eager). If over-engineered components or decisions exist, you can ask Claude Code to resolve them. Ensure that Claude Code follows the [constitution](base/memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan. ### **STEP 6:** Generate task breakdown with /speckit.tasks diff --git a/docs/upgrade.md b/docs/upgrade.md index 9748f6e76c..035706eb88 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -74,7 +74,7 @@ Run this inside your project directory: specify init --here --force --ai ``` -Replace `` with your AI assistant: `claude`, `gemini`, `copilot`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`, `auggie`, `codebuddy`, `roo`, `kilocode`, or `q`. +Replace `` with your AI assistant. Refer to this list of [Supported AI Agents](../README.md#-supported-ai-agents) **Example:** From 1b834cd1d7db54ba1ba4e5e84b7413d194694a56 Mon Sep 17 00:00:00 2001 From: Dan Washusen Date: Tue, 28 Oct 2025 09:47:52 +1100 Subject: [PATCH 40/43] Refactor ESLint configuration checks in implement.md to address deprecation --- templates/commands/implement.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/commands/implement.md b/templates/commands/implement.md index 072b546b55..d34d5d6b76 100644 --- a/templates/commands/implement.md +++ b/templates/commands/implement.md @@ -67,7 +67,8 @@ You **MUST** consider the user input before proceeding (if not empty). ``` - Check if Dockerfile* exists or Docker in plan.md → create/verify .dockerignore - - Check if .eslintrc*or eslint.config.* exists → create/verify .eslintignore + - Check if .eslintrc* exists → create/verify .eslintignore + - Check if eslint.config.* exists → ensure the config's `ignores` entries cover required patterns - Check if .prettierrc* exists → create/verify .prettierignore - Check if .npmrc or package.json exists → create/verify .npmignore (if publishing) - Check if terraform files (*.tf) exist → create/verify .terraformignore From fcfe6590f7ff4066fcba54f981ef6c6b91998834 Mon Sep 17 00:00:00 2001 From: San Gillis Date: Sat, 25 Oct 2025 11:34:26 +0200 Subject: [PATCH 41/43] Unset CDPATH while getting SCRIPT_DIR --- scripts/bash/check-prerequisites.sh | 2 +- scripts/bash/common.sh | 2 +- scripts/bash/create-new-feature.sh | 2 +- scripts/bash/setup-plan.sh | 2 +- scripts/bash/update-agent-context.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/bash/check-prerequisites.sh b/scripts/bash/check-prerequisites.sh index 54f32ec36a..98e387c271 100644 --- a/scripts/bash/check-prerequisites.sh +++ b/scripts/bash/check-prerequisites.sh @@ -75,7 +75,7 @@ EOF done # Source common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/common.sh" # Get feature paths and validate branch diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 6931eccc80..2c3165e41d 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -7,7 +7,7 @@ get_repo_root() { git rev-parse --show-toplevel else # Fall back to script location for non-git repos - local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local script_dir="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" (cd "$script_dir/../../.." && pwd) fi } diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index 8e8bcf6c35..592dab2ea3 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -167,7 +167,7 @@ clean_branch_name() { # 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. -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if git rev-parse --show-toplevel >/dev/null 2>&1; then REPO_ROOT=$(git rev-parse --show-toplevel) diff --git a/scripts/bash/setup-plan.sh b/scripts/bash/setup-plan.sh index 740a1438cd..d01c6d6cb5 100644 --- a/scripts/bash/setup-plan.sh +++ b/scripts/bash/setup-plan.sh @@ -24,7 +24,7 @@ for arg in "$@"; do done # Get script directory and load common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/common.sh" # Get all paths and variables from common functions diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index 5ba07ed6f2..e0aa1de402 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -49,7 +49,7 @@ set -o pipefail #============================================================================== # Get script directory and load common functions -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/common.sh" # Get all paths and variables from common functions From f057d6cc74146eb0a4fe75b4cd9a9e2443ba889e Mon Sep 17 00:00:00 2001 From: Simon Gent Date: Tue, 18 Nov 2025 16:29:12 +0000 Subject: [PATCH 42/43] Add Kiro CLI support Kiro CLI (https://kiro.dev) is an upgrade replacement for Amazon Q Developer CLI with full custom prompt support. Changes: - Added 'kiro' to AGENT_CONFIG with .kiro/ folder structure - Updated CLI help text to include kiro option - Added Kiro CLI to README supported agents table - Updated release script to generate Kiro packages - Kiro uses .kiro/prompts/ directory (markdown format) Kiro CLI provides the same functionality as Q Developer CLI but with proper support for custom arguments in slash commands. --- .github/workflows/scripts/create-release-packages.sh | 5 ++++- README.md | 3 ++- src/specify_cli/__init__.py | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 1f5c6e51b2..a16def6532 100755 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -205,6 +205,9 @@ build_variant() { amp) mkdir -p "$base_dir/.agents/commands" generate_commands amp md "\$ARGUMENTS" "$base_dir/.agents/commands" "$script" ;; + kiro) + mkdir -p "$base_dir/.kiro/prompts" + generate_commands kiro md "\$ARGUMENTS" "$base_dir/.kiro/prompts" "$script" ;; shai) mkdir -p "$base_dir/.shai/commands" generate_commands shai md "\$ARGUMENTS" "$base_dir/.shai/commands" "$script" ;; @@ -217,7 +220,7 @@ build_variant() { } # Determine agent list -ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai q) +ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp kiro shai q) ALL_SCRIPTS=(sh ps) norm_list() { diff --git a/README.md b/README.md index c3dcdf269c..bd9c6b8f39 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c | [Roo Code](https://roocode.com/) | ✅ | | | [Codex CLI](https://github.com/openai/codex) | ✅ | | | [Amazon Q Developer CLI](https://aws.amazon.com/developer/learning/q-developer-cli/) | ⚠️ | Amazon Q Developer CLI [does not support](https://github.com/aws/amazon-q-developer-cli/issues/3064) custom arguments for slash commands. | +| [Kiro CLI](https://kiro.dev/) | ✅ | Upgrade replacement for Amazon Q Developer CLI with full custom prompt support | | [Amp](https://ampcode.com/) | ✅ | | | [SHAI (OVHcloud)](https://github.com/ovh/shai) | ✅ | | @@ -364,7 +365,7 @@ specify init . --force --ai claude specify init --here --force --ai claude ``` -The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, or Amazon Q Developer CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command: +The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, Kiro CLI, or Amazon Q Developer CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command: ```bash specify init --ai claude --ignore-agent-tools diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 2fa6455a29..08f9f6ab76 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -208,6 +208,12 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) "install_url": "https://ampcode.com/manual#install", "requires_cli": True, }, + "kiro": { + "name": "Kiro CLI", + "folder": ".kiro/", + "install_url": "https://kiro.dev/docs/cli/getting-started/", + "requires_cli": True, + }, "shai": { "name": "SHAI", "folder": ".shai/", @@ -933,7 +939,7 @@ def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None = @app.command() def init( project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"), - ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, shai, or q"), + ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, kiro, shai, or q"), script_type: str = typer.Option(None, "--script", help="Script type to use: sh or ps"), ignore_agent_tools: bool = typer.Option(False, "--ignore-agent-tools", help="Skip checks for AI agent tools like Claude Code"), no_git: bool = typer.Option(False, "--no-git", help="Skip git repository initialization"), From a1df4aa88537b932de9e0f2db5d457dbfe5fb9bb Mon Sep 17 00:00:00 2001 From: Simon Gent Date: Wed, 19 Nov 2025 09:49:02 +0000 Subject: [PATCH 43/43] Add Kiro CLI to release script and agent context update scripts --- .github/workflows/scripts/create-github-release.sh | 2 ++ AGENTS.md | 2 ++ scripts/bash/update-agent-context.sh | 9 +++++++++ scripts/powershell/update-agent-context.ps1 | 5 ++++- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scripts/create-github-release.sh b/.github/workflows/scripts/create-github-release.sh index c09a255bac..bbd34e64d5 100644 --- a/.github/workflows/scripts/create-github-release.sh +++ b/.github/workflows/scripts/create-github-release.sh @@ -42,6 +42,8 @@ gh release create "$VERSION" \ .genreleases/spec-kit-template-codebuddy-ps-"$VERSION".zip \ .genreleases/spec-kit-template-amp-sh-"$VERSION".zip \ .genreleases/spec-kit-template-amp-ps-"$VERSION".zip \ + .genreleases/spec-kit-template-kiro-sh-"$VERSION".zip \ + .genreleases/spec-kit-template-kiro-ps-"$VERSION".zip \ .genreleases/spec-kit-template-shai-sh-"$VERSION".zip \ .genreleases/spec-kit-template-shai-ps-"$VERSION".zip \ .genreleases/spec-kit-template-q-sh-"$VERSION".zip \ diff --git a/AGENTS.md b/AGENTS.md index 3016c3eda3..8c80cc6867 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,6 +44,7 @@ Specify supports multiple AI agents by generating agent-specific command files a | **Roo Code** | `.roo/rules/` | Markdown | N/A (IDE-based) | Roo Code IDE | | **CodeBuddy CLI** | `.codebuddy/commands/` | Markdown | `codebuddy` | CodeBuddy CLI | | **Amazon Q Developer CLI** | `.amazonq/prompts/` | Markdown | `q` | Amazon Q Developer CLI | +| **Kiro CLI** | `.kiro/prompts/` | Markdown | `kiro` | Kiro CLI | | **Amp** | `.agents/commands/` | Markdown | `amp` | Amp CLI | | **SHAI** | `.shai/commands/` | Markdown | `shai` | SHAI CLI | @@ -310,6 +311,7 @@ Require a command-line tool to be installed: - **Qwen Code**: `qwen` CLI - **opencode**: `opencode` CLI - **Amazon Q Developer CLI**: `q` CLI +- **Kiro CLI**: `kiro` CLI - **CodeBuddy CLI**: `codebuddy` CLI - **Amp**: `amp` CLI - **SHAI**: `shai` CLI diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index e0aa1de402..b1773f5600 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -71,6 +71,7 @@ AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md" ROO_FILE="$REPO_ROOT/.roo/rules/specify-rules.md" CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md" AMP_FILE="$REPO_ROOT/AGENTS.md" +KIRO_FILE="$REPO_ROOT/.kiro/prompts/specify-prompts.md" SHAI_FILE="$REPO_ROOT/SHAI.md" Q_FILE="$REPO_ROOT/AGENTS.md" @@ -619,6 +620,9 @@ update_specific_agent() { amp) update_agent_file "$AMP_FILE" "Amp" ;; + kiro) + update_agent_file "$KIRO_FILE" "Kiro CLI" + ;; shai) update_agent_file "$SHAI_FILE" "SHAI" ;; @@ -692,6 +696,11 @@ update_all_existing_agents() { found_agent=true fi + if [[ -f "$KIRO_FILE" ]]; then + update_agent_file "$KIRO_FILE" "Kiro CLI" + found_agent=true + fi + if [[ -f "$SHAI_FILE" ]]; then update_agent_file "$SHAI_FILE" "SHAI" found_agent=true diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index ea5654cce3..670af2a1a0 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -56,6 +56,7 @@ $AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md' $ROO_FILE = Join-Path $REPO_ROOT '.roo/rules/specify-rules.md' $CODEBUDDY_FILE = Join-Path $REPO_ROOT 'CODEBUDDY.md' $AMP_FILE = Join-Path $REPO_ROOT 'AGENTS.md' +$KIRO_FILE = Join-Path $REPO_ROOT '.kiro/prompts/specify-prompts.md' $SHAI_FILE = Join-Path $REPO_ROOT 'SHAI.md' $Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md' @@ -382,9 +383,10 @@ function Update-SpecificAgent { 'roo' { Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code' } 'codebuddy' { Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI' } 'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' } + 'kiro' { Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI' } 'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' } 'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' } - default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q'; return $false } + default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|kiro|shai|q'; return $false } } } @@ -402,6 +404,7 @@ function Update-AllExistingAgents { if (Test-Path $AUGGIE_FILE) { if (-not (Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI')) { $ok = $false }; $found = $true } if (Test-Path $ROO_FILE) { if (-not (Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code')) { $ok = $false }; $found = $true } if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true } + if (Test-Path $KIRO_FILE) { if (-not (Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI')) { $ok = $false }; $found = $true } if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true } if (Test-Path $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $ok = $false }; $found = $true } if (-not $found) {