Compare commits

...

7 Commits

Author SHA1 Message Date
Den Delimarsky 🌺
0889635e66 Update with Windsurf support 2025-09-19 18:01:47 -07:00
Den Delimarsky
2825bb1247 Merge pull request #243 from zryfish/dev/add_authentication_when_download_template
add github auth headers if there are GITHUB_TOKEN/GH_TOKEN set
2025-09-19 17:29:59 -07:00
Den Delimarsky 🌺
919ba00198 Update specify.md 2025-09-18 23:21:26 -07:00
Den Delimarsky 🌺
4e869cb11a Update __init__.py 2025-09-18 23:13:38 -07:00
Den Delimarsky 🌺
32c933c960 Update with support for /implement 2025-09-18 23:03:01 -07:00
zhangrenyu
b1688b9633 expose token as an argument through cli --github-token 2025-09-17 17:05:49 +08:00
zryfish
70413f5214 add github auth headers if there are GITHUB_TOKEN/GH_TOKEN set 2025-09-15 00:06:08 +08:00
13 changed files with 489 additions and 81 deletions

View File

@@ -81,7 +81,7 @@ jobs:
cat > release_notes.md << EOF
Template release ${{ steps.get_tag.outputs.new_version }}
Updated specification-driven development templates for GitHub Copilot, Claude Code, Gemini CLI, Cursor, Qwen, and opencode.
Updated specification-driven development templates for GitHub Copilot, Claude Code, Gemini CLI, Cursor, Qwen, opencode, and Windsurf.
Now includes per-script variants for POSIX shell (sh) and PowerShell (ps).
@@ -98,6 +98,8 @@ jobs:
- spec-kit-template-opencode-ps-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-qwen-sh-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-qwen-ps-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-windsurf-sh-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-windsurf-ps-${{ steps.get_tag.outputs.new_version }}.zip
EOF
echo "Generated release notes:"
@@ -122,6 +124,8 @@ jobs:
spec-kit-template-opencode-ps-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-qwen-sh-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-qwen-ps-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-windsurf-sh-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-windsurf-ps-${{ steps.get_tag.outputs.new_version }}.zip \
--title "Spec Kit Templates - $VERSION_NO_V" \
--notes-file release_notes.md
env:

View File

@@ -154,13 +154,16 @@ build_variant() {
opencode)
mkdir -p "$base_dir/.opencode/command"
generate_commands opencode md "\$ARGUMENTS" "$base_dir/.opencode/command" "$script" ;;
windsurf)
mkdir -p "$base_dir/.windsurf/workflows"
generate_commands windsurf md "\$ARGUMENTS" "$base_dir/.windsurf/workflows" "$script" ;;
esac
( cd "$base_dir" && zip -r "../spec-kit-template-${agent}-${script}-${NEW_VERSION}.zip" . )
echo "Created spec-kit-template-${agent}-${script}-${NEW_VERSION}.zip"
}
# Determine agent list
ALL_AGENTS=(claude gemini copilot cursor qwen opencode)
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf)
ALL_SCRIPTS=(sh ps)

230
AGENTS.md Normal file
View File

@@ -0,0 +1,230 @@
# AGENTS.md
## About Spec Kit and Specify
**GitHub Spec Kit** is a comprehensive toolkit for implementing Spec-Driven Development (SDD) - a methodology that emphasizes creating clear specifications before implementation. The toolkit includes templates, scripts, and workflows that guide development teams through a structured approach to building software.
**Specify CLI** is the command-line interface that bootstraps projects with the Spec Kit framework. It sets up the necessary directory structures, templates, and AI agent integrations to support the Spec-Driven Development workflow.
The toolkit supports multiple AI coding assistants, allowing teams to use their preferred tools while maintaining consistent project structure and development practices.
---
## Adding New Agent Support
This section explains how to add support for new AI agents/assistants to the Specify CLI. Use this guide as a reference when integrating new AI tools into the Spec-Driven Development workflow.
### Overview
Specify supports multiple AI agents by generating agent-specific command files and directory structures when initializing projects. Each agent has its own conventions for:
- **Command file formats** (Markdown, TOML, etc.)
- **Directory structures** (`.claude/commands/`, `.windsurf/workflows/`, etc.)
- **Command invocation patterns** (slash commands, CLI tools, etc.)
- **Argument passing conventions** (`$ARGUMENTS`, `{{args}}`, etc.)
### Current Supported Agents
| Agent | Directory | Format | CLI Tool | Description |
|-------|-----------|---------|----------|-------------|
| **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 |
| **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 |
| **Windsurf** | `.windsurf/workflows/` | Markdown | N/A (IDE-based) | Windsurf IDE workflows |
### Step-by-Step Integration Guide
Follow these steps to add a new agent (using Windsurf as an example):
#### 1. Update AI_CHOICES Constant
Add the new agent to the `AI_CHOICES` dictionary in `src/specify_cli/__init__.py`:
```python
AI_CHOICES = {
"copilot": "GitHub Copilot",
"claude": "Claude Code",
"gemini": "Gemini CLI",
"cursor": "Cursor",
"qwen": "Qwen Code",
"opencode": "opencode",
"windsurf": "Windsurf" # Add new agent here
}
```
#### 2. Update CLI Help Text
Update all help text and examples to include the new agent:
- Command option help: `--ai` parameter description
- Function docstrings and examples
- Error messages with agent lists
#### 3. Update Release Package Script
Modify `.github/workflows/scripts/create-release-packages.sh`:
##### Add to ALL_AGENTS array:
```bash
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf)
```
##### Add case statement for directory structure:
```bash
case $agent in
# ... existing cases ...
windsurf)
mkdir -p "$base_dir/.windsurf/workflows"
generate_commands windsurf md "\$ARGUMENTS" "$base_dir/.windsurf/workflows" "$script" ;;
esac
```
#### 4. Update Agent Context Scripts
##### Bash script (`scripts/bash/update-agent-context.sh`):
Add file variable:
```bash
WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
```
Add to case statement:
```bash
case "$AGENT_TYPE" in
# ... existing cases ...
windsurf) update_agent_file "$WINDSURF_FILE" "Windsurf" ;;
"")
# ... existing checks ...
[ -f "$WINDSURF_FILE" ] && update_agent_file "$WINDSURF_FILE" "Windsurf";
# Update default creation condition
;;
esac
```
##### PowerShell script (`scripts/powershell/update-agent-context.ps1`):
Add file variable:
```powershell
$windsurfFile = Join-Path $repoRoot '.windsurf/rules/specify-rules.md'
```
Add to switch statement:
```powershell
switch ($AgentType) {
# ... existing cases ...
'windsurf' { Update-AgentFile $windsurfFile 'Windsurf' }
'' {
foreach ($pair in @(
# ... existing pairs ...
@{file=$windsurfFile; name='Windsurf'}
)) {
if (Test-Path $pair.file) { Update-AgentFile $pair.file $pair.name }
}
# Update default creation condition
}
}
```
#### 5. Update CLI Tool Checks (Optional)
For agents that require CLI tools, add checks in the `check()` command and agent validation:
```python
# In check() command
tracker.add("windsurf", "Windsurf IDE (optional)")
windsurf_ok = check_tool_for_tracker("windsurf", "https://windsurf.com/", tracker)
# In init validation (only if CLI tool required)
elif selected_ai == "windsurf":
if not check_tool("windsurf", "Install from: https://windsurf.com/"):
console.print("[red]Error:[/red] Windsurf CLI is required for Windsurf projects")
agent_tool_missing = True
```
**Note**: Skip CLI checks for IDE-based agents (Copilot, Windsurf).
## Agent Categories
### CLI-Based Agents
Require a command-line tool to be installed:
- **Claude Code**: `claude` CLI
- **Gemini CLI**: `gemini` CLI
- **Cursor**: `cursor-agent` CLI
- **Qwen Code**: `qwen` CLI
- **opencode**: `opencode` CLI
### IDE-Based Agents
Work within integrated development environments:
- **GitHub Copilot**: Built into VS Code/compatible editors
- **Windsurf**: Built into Windsurf IDE
## Command File Formats
### Markdown Format
Used by: Claude, Cursor, opencode, Windsurf
```markdown
---
description: "Command description"
---
Command content with {SCRIPT} and $ARGUMENTS placeholders.
```
### TOML Format
Used by: Gemini, Qwen
```toml
description = "Command description"
prompt = """
Command content with {SCRIPT} and {{args}} placeholders.
"""
```
## Directory Conventions
- **CLI agents**: Usually `.<agent-name>/commands/`
- **IDE agents**: Follow IDE-specific patterns:
- Copilot: `.github/prompts/`
- Cursor: `.cursor/commands/`
- Windsurf: `.windsurf/workflows/`
## Argument Patterns
Different agents use different argument placeholders:
- **Markdown/prompt-based**: `$ARGUMENTS`
- **TOML-based**: `{{args}}`
- **Script placeholders**: `{SCRIPT}` (replaced with actual script path)
- **Agent placeholders**: `__AGENT__` (replaced with agent name)
## Testing New Agent Integration
1. **Build test**: Run package creation script locally
2. **CLI test**: Test `specify init --ai <agent>` command
3. **File generation**: Verify correct directory structure and files
4. **Command validation**: Ensure generated commands work with the agent
5. **Context update**: Test agent context update scripts
## Common Pitfalls
1. **Forgetting update scripts**: Both bash and PowerShell scripts must be updated
2. **Missing CLI checks**: Only add for agents that actually have CLI tools
3. **Wrong argument format**: Use correct placeholder format for each agent type
4. **Directory naming**: Follow agent-specific conventions exactly
5. **Help text inconsistency**: Update all user-facing text consistently
## Future Considerations
When adding new agents:
- Consider the agent's native command/workflow patterns
- Ensure compatibility with the Spec-Driven Development process
- Document any special requirements or limitations
- Update this guide with lessons learned
---
*This documentation should be updated whenever new agents are added to maintain accuracy and completeness.*

View File

@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.0.7] - 2025-09-18
### Changed
- Updated command instructions in the CLI.
- Cleaned up the code to not render agent-specific information when it's generic.
## [0.0.6] - 2025-09-17
### Added

View File

@@ -44,7 +44,15 @@ Initialize your project depending on the coding agent you're using:
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME>
```
### 2. Create the spec
### 2. Establish project principles
Use the **`/constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
```bash
/constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements
```
### 3. Create the spec
Use the **`/specify`** command to describe what you want to build. Focus on the **what** and **why**, not the tech stack.
@@ -52,7 +60,7 @@ Use the **`/specify`** command to describe what you want to build. Focus on the
/specify Build an application that can help me organize my photos in separate photo albums. Albums are grouped by date and can be re-organized by dragging and dropping on the main page. Albums are never in other nested albums. Within each album, photos are previewed in a tile-like interface.
```
### 3. Create a technical implementation plan
### 4. Create a technical implementation plan
Use the **`/plan`** command to provide your tech stack and architecture choices.
@@ -60,9 +68,21 @@ Use the **`/plan`** command to provide your tech stack and architecture choices.
/plan The application uses Vite with minimal number of libraries. Use vanilla HTML, CSS, and JavaScript as much as possible. Images are not uploaded anywhere and metadata is stored in a local SQLite database.
```
### 4. Break down and implement
### 5. Break down into tasks
Use **`/tasks`** to create an actionable task list, then ask your agent to implement the feature.
Use **`/tasks`** to create an actionable task list from your implementation plan.
```bash
/tasks
```
### 6. Execute implementation
Use **`/implement`** to execute all tasks and build your feature according to the plan.
```bash
/implement
```
For detailed step-by-step instructions, see our [comprehensive guide](./spec-driven.md).
@@ -124,6 +144,18 @@ specify init my-project --ai claude --debug
specify check
```
### Available Slash Commands
After running `specify init`, your AI coding agent will have access to these slash commands for structured development:
| Command | Description |
|-----------------|-----------------------------------------------------------------------|
| `/constitution` | Create or update project governing principles and development guidelines |
| `/specify` | Define what you want to build (requirements and user stories) |
| `/plan` | Create technical implementation plans with your chosen tech stack |
| `/tasks` | Generate actionable task lists for implementation |
| `/implement` | Execute all tasks to build the feature according to the plan |
## 📚 Core philosophy
Spec-Driven Development is a structured process that emphasizes:
@@ -219,15 +251,25 @@ The CLI will check if you have Claude Code, Gemini CLI, Qwen CLI or opencode ins
specify init <project_name> --ai claude --ignore-agent-tools
```
### **STEP 1:** Bootstrap the project
### **STEP 1:** Establish project principles
Go to the project folder and run your AI agent. In our example, we're using `claude`.
![Bootstrapping Claude Code environment](./media/bootstrap-claude-code.gif)
You will know that things are configured correctly if you see the `/specify`, `/plan`, and `/tasks` commands available.
You will know that things are configured correctly if you see the `/constitution`, `/specify`, `/plan`, `/tasks`, and `/implement` commands available.
The first step should be creating a new project scaffolding. Use `/specify` command and then provide the concrete requirements for the project you want to develop.
The first step should be establishing your project's governing principles using the `/constitution` command. This helps ensure consistent decision-making throughout all subsequent development phases:
```text
/constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements. Include governance for how these principles should guide technical decisions and implementation choices.
```
This step creates or updates the `/memory/constitution.md` file with your project's foundational guidelines that the AI agent will reference during specification, planning, and implementation phases.
### **STEP 2:** Create project specifications
With your project principles established, you can now create the functional specifications. Use the `/specify` command and then provide the concrete requirements for the project you want to develop.
>[!IMPORTANT]
>Be as explicit as possible about _what_ you are trying to build and _why_. **Do not focus on the tech stack at this point**.
@@ -281,7 +323,7 @@ At this stage, your project folder contents should resemble the following:
└── tasks-template.md
```
### **STEP 2:** Functional specification clarification
### **STEP 3:** Functional specification clarification
With the baseline specification created, you can go ahead and clarify any of the requirements that were not captured properly within the first shot attempt. For example, you could use a prompt like this within the same Claude Code session:
@@ -299,7 +341,7 @@ Read the review and acceptance checklist, and check off each item in the checkli
It's important to use the interaction with Claude Code as an opportunity to clarify and ask questions around the specification - **do not treat its first attempt as final**.
### **STEP 3:** Generate a plan
### **STEP 4:** Generate a plan
You can now be specific about the tech stack and other technical requirements. You can use the `/plan` command that is built into the project template with a prompt like this:
@@ -368,7 +410,7 @@ That's way too untargeted research. The research needs to help you solve a speci
>[!NOTE]
>Claude Code might be over-eager and add components that you did not ask for. Ask it to clarify the rationale and the source of the change.
### **STEP 4:** Have Claude Code validate the plan
### **STEP 5:** Have Claude Code validate the plan
With the plan in place, you should have Claude Code run through it to make sure that there are no missing pieces. You can use a prompt like this:
@@ -387,20 +429,25 @@ You can also ask Claude Code (if you have the [GitHub CLI](https://docs.github.c
>[!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.
### STEP 5: Implementation
### STEP 6: Implementation
Once ready, instruct Claude Code to implement your solution (example path included):
Once ready, use the `/implement` command to execute your implementation plan:
```text
implement specs/002-create-taskify/plan.md
/implement
```
Claude Code will spring into action and will start creating the implementation.
The `/implement` command will:
- Validate that all prerequisites are in place (constitution, spec, plan, and tasks)
- Parse the task breakdown from `tasks.md`
- Execute tasks in the correct order, respecting dependencies and parallel execution markers
- Follow the TDD approach defined in your task plan
- Provide progress updates and handle errors appropriately
>[!IMPORTANT]
>Claude Code will execute local CLI commands (such as `dotnet`) - make sure you have them installed on your machine.
>The AI agent will execute local CLI commands (such as `dotnet`, `npm`, etc.) - make sure you have the required tools installed on your machine.
Once the implementation step is done, ask Claude Code to try to run the application and resolve any emerging build errors. If the application runs, but there are _runtime errors_ that are not directly available to Claude Code through CLI logs (e.g., errors rendered in browser logs), copy and paste the error in Claude Code and have it attempt to resolve it.
Once the implementation is complete, test the application and resolve any runtime errors that may not be visible in CLI logs (e.g., browser console errors). You can copy and paste such errors back to your AI agent for resolution.
</details>

View File

@@ -1,7 +1,7 @@
[project]
name = "specify-cli"
version = "0.0.6"
description = "Setup tool for Specify spec-driven development projects"
version = "0.0.7"
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
requires-python = ">=3.11"
dependencies = [
"typer",

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
JSON_MODE=false
for arg in "$@"; do case "$arg" in --json) JSON_MODE=true ;; --help|-h) echo "Usage: $0 [--json]"; exit 0 ;; esac; done
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"
eval $(get_feature_paths)
check_feature_branch "$CURRENT_BRANCH" || exit 1
if [[ ! -d "$FEATURE_DIR" ]]; then echo "ERROR: Feature directory not found: $FEATURE_DIR"; echo "Run /specify first."; exit 1; fi
if [[ ! -f "$IMPL_PLAN" ]]; then echo "ERROR: plan.md not found in $FEATURE_DIR"; echo "Run /plan first."; exit 1; fi
if [[ ! -f "$TASKS" ]]; then echo "ERROR: tasks.md not found in $FEATURE_DIR"; echo "Run /tasks first."; exit 1; fi
if $JSON_MODE; then
docs=(); [[ -f "$RESEARCH" ]] && docs+=("research.md"); [[ -f "$DATA_MODEL" ]] && docs+=("data-model.md"); ([[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]) && docs+=("contracts/"); [[ -f "$QUICKSTART" ]] && docs+=("quickstart.md"); [[ -f "$TASKS" ]] && docs+=("tasks.md");
json_docs=$(printf '"%s",' "${docs[@]}"); json_docs="[${json_docs%,}]"; printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$FEATURE_DIR" "$json_docs"
else
echo "FEATURE_DIR:$FEATURE_DIR"; echo "AVAILABLE_DOCS:"; check_file "$RESEARCH" "research.md"; check_file "$DATA_MODEL" "data-model.md"; check_dir "$CONTRACTS_DIR" "contracts/"; check_file "$QUICKSTART" "quickstart.md"; check_file "$TASKS" "tasks.md"; fi

View File

@@ -4,7 +4,7 @@ REPO_ROOT=$(git rev-parse --show-toplevel)
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
FEATURE_DIR="$REPO_ROOT/specs/$CURRENT_BRANCH"
NEW_PLAN="$FEATURE_DIR/plan.md"
CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"; GEMINI_FILE="$REPO_ROOT/GEMINI.md"; COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md"; CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc"; QWEN_FILE="$REPO_ROOT/QWEN.md"; AGENTS_FILE="$REPO_ROOT/AGENTS.md"
CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"; GEMINI_FILE="$REPO_ROOT/GEMINI.md"; COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md"; CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc"; QWEN_FILE="$REPO_ROOT/QWEN.md"; AGENTS_FILE="$REPO_ROOT/AGENTS.md"; WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
AGENT_TYPE="$1"
[ -f "$NEW_PLAN" ] || { echo "ERROR: No plan.md found at $NEW_PLAN"; exit 1; }
echo "=== Updating agent context files for feature $CURRENT_BRANCH ==="
@@ -54,13 +54,15 @@ case "$AGENT_TYPE" in
cursor) update_agent_file "$CURSOR_FILE" "Cursor IDE" ;;
qwen) update_agent_file "$QWEN_FILE" "Qwen Code" ;;
opencode) update_agent_file "$AGENTS_FILE" "opencode" ;;
windsurf) update_agent_file "$WINDSURF_FILE" "Windsurf" ;;
"") [ -f "$CLAUDE_FILE" ] && update_agent_file "$CLAUDE_FILE" "Claude Code"; \
[ -f "$GEMINI_FILE" ] && update_agent_file "$GEMINI_FILE" "Gemini CLI"; \
[ -f "$COPILOT_FILE" ] && update_agent_file "$COPILOT_FILE" "GitHub Copilot"; \
[ -f "$CURSOR_FILE" ] && update_agent_file "$CURSOR_FILE" "Cursor IDE"; \
[ -f "$QWEN_FILE" ] && update_agent_file "$QWEN_FILE" "Qwen Code"; \
[ -f "$AGENTS_FILE" ] && update_agent_file "$AGENTS_FILE" "opencode"; \
if [ ! -f "$CLAUDE_FILE" ] && [ ! -f "$GEMINI_FILE" ] && [ ! -f "$COPILOT_FILE" ] && [ ! -f "$CURSOR_FILE" ] && [ ! -f "$QWEN_FILE" ] && [ ! -f "$AGENTS_FILE" ]; then update_agent_file "$CLAUDE_FILE" "Claude Code"; fi ;;
*) echo "ERROR: Unknown agent type '$AGENT_TYPE' (expected claude|gemini|copilot|cursor|qwen|opencode)"; exit 1 ;;
[ -f "$WINDSURF_FILE" ] && update_agent_file "$WINDSURF_FILE" "Windsurf"; \
if [ ! -f "$CLAUDE_FILE" ] && [ ! -f "$GEMINI_FILE" ] && [ ! -f "$COPILOT_FILE" ] && [ ! -f "$CURSOR_FILE" ] && [ ! -f "$QWEN_FILE" ] && [ ! -f "$AGENTS_FILE" ] && [ ! -f "$WINDSURF_FILE" ]; then update_agent_file "$CLAUDE_FILE" "Claude Code"; fi ;;
*) echo "ERROR: Unknown agent type '$AGENT_TYPE' (expected claude|gemini|copilot|cursor|qwen|opencode|windsurf)"; exit 1 ;;
esac
echo; echo "Summary of changes:"; [ -n "$NEW_LANG" ] && echo "- Added language: $NEW_LANG"; [ -n "$NEW_FRAMEWORK" ] && echo "- Added framework: $NEW_FRAMEWORK"; [ -n "$NEW_DB" ] && [ "$NEW_DB" != "N/A" ] && echo "- Added database: $NEW_DB"; echo; echo "Usage: $0 [claude|gemini|copilot|cursor|qwen|opencode]"
echo; echo "Summary of changes:"; [ -n "$NEW_LANG" ] && echo "- Added language: $NEW_LANG"; [ -n "$NEW_FRAMEWORK" ] && echo "- Added framework: $NEW_FRAMEWORK"; [ -n "$NEW_DB" ] && [ "$NEW_DB" != "N/A" ] && echo "- Added database: $NEW_DB"; echo; echo "Usage: $0 [claude|gemini|copilot|cursor|qwen|opencode|windsurf]"

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env pwsh
[CmdletBinding()]
param([switch]$Json)
$ErrorActionPreference = 'Stop'
. "$PSScriptRoot/common.ps1"
$paths = Get-FeaturePathsEnv
if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH)) { exit 1 }
if (-not (Test-Path $paths.FEATURE_DIR -PathType Container)) {
Write-Output "ERROR: Feature directory not found: $($paths.FEATURE_DIR)"
Write-Output "Run /specify first to create the feature structure."
exit 1
}
if (-not (Test-Path $paths.IMPL_PLAN -PathType Leaf)) {
Write-Output "ERROR: plan.md not found in $($paths.FEATURE_DIR)"
Write-Output "Run /plan first to create the plan."
exit 1
}
if (-not (Test-Path $paths.TASKS -PathType Leaf)) {
Write-Output "ERROR: tasks.md not found in $($paths.FEATURE_DIR)"
Write-Output "Run /tasks first to create the task list."
exit 1
}
if ($Json) {
$docs = @()
if (Test-Path $paths.RESEARCH) { $docs += 'research.md' }
if (Test-Path $paths.DATA_MODEL) { $docs += 'data-model.md' }
if ((Test-Path $paths.CONTRACTS_DIR) -and (Get-ChildItem -Path $paths.CONTRACTS_DIR -ErrorAction SilentlyContinue | Select-Object -First 1)) { $docs += 'contracts/' }
if (Test-Path $paths.QUICKSTART) { $docs += 'quickstart.md' }
if (Test-Path $paths.TASKS) { $docs += 'tasks.md' }
[PSCustomObject]@{ FEATURE_DIR=$paths.FEATURE_DIR; AVAILABLE_DOCS=$docs } | ConvertTo-Json -Compress
} else {
Write-Output "FEATURE_DIR:$($paths.FEATURE_DIR)"
Write-Output "AVAILABLE_DOCS:"
Test-FileExists -Path $paths.RESEARCH -Description 'research.md' | Out-Null
Test-FileExists -Path $paths.DATA_MODEL -Description 'data-model.md' | Out-Null
Test-DirHasFiles -Path $paths.CONTRACTS_DIR -Description 'contracts/' | Out-Null
Test-FileExists -Path $paths.QUICKSTART -Description 'quickstart.md' | Out-Null
Test-FileExists -Path $paths.TASKS -Description 'tasks.md' | Out-Null
}

View File

@@ -15,6 +15,7 @@ $copilotFile = Join-Path $repoRoot '.github/copilot-instructions.md'
$cursorFile = Join-Path $repoRoot '.cursor/rules/specify-rules.mdc'
$qwenFile = Join-Path $repoRoot 'QWEN.md'
$agentsFile = Join-Path $repoRoot 'AGENTS.md'
$windsurfFile = Join-Path $repoRoot '.windsurf/rules/specify-rules.md'
Write-Output "=== Updating agent context files for feature $currentBranch ==="
@@ -75,6 +76,7 @@ switch ($AgentType) {
'cursor' { Update-AgentFile $cursorFile 'Cursor IDE' }
'qwen' { Update-AgentFile $qwenFile 'Qwen Code' }
'opencode' { Update-AgentFile $agentsFile 'opencode' }
'windsurf' { Update-AgentFile $windsurfFile 'Windsurf' }
'' {
foreach ($pair in @(
@{file=$claudeFile; name='Claude Code'},
@@ -82,16 +84,17 @@ switch ($AgentType) {
@{file=$copilotFile; name='GitHub Copilot'},
@{file=$cursorFile; name='Cursor IDE'},
@{file=$qwenFile; name='Qwen Code'},
@{file=$agentsFile; name='opencode'}
@{file=$agentsFile; name='opencode'},
@{file=$windsurfFile; name='Windsurf'}
)) {
if (Test-Path $pair.file) { Update-AgentFile $pair.file $pair.name }
}
if (-not (Test-Path $claudeFile) -and -not (Test-Path $geminiFile) -and -not (Test-Path $copilotFile) -and -not (Test-Path $cursorFile) -and -not (Test-Path $qwenFile) -and -not (Test-Path $agentsFile)) {
if (-not (Test-Path $claudeFile) -and -not (Test-Path $geminiFile) -and -not (Test-Path $copilotFile) -and -not (Test-Path $cursorFile) -and -not (Test-Path $qwenFile) -and -not (Test-Path $agentsFile) -and -not (Test-Path $windsurfFile)) {
Write-Output 'No agent context files found. Creating Claude Code context file by default.'
Update-AgentFile $claudeFile 'Claude Code'
}
}
Default { Write-Error "ERROR: Unknown agent type '$AgentType'. Use: claude, gemini, copilot, cursor, qwen, opencode or leave empty for all."; exit 1 }
Default { Write-Error "ERROR: Unknown agent type '$AgentType'. Use: claude, gemini, copilot, cursor, qwen, opencode, windsurf or leave empty for all."; exit 1 }
}
Write-Output ''
@@ -101,4 +104,4 @@ if ($newFramework) { Write-Output "- Added framework: $newFramework" }
if ($newDb -and $newDb -ne 'N/A') { Write-Output "- Added database: $newDb" }
Write-Output ''
Write-Output 'Usage: ./update-agent-context.ps1 [claude|gemini|copilot|cursor|qwen|opencode]'
Write-Output 'Usage: ./update-agent-context.ps1 [claude|gemini|copilot|cursor|qwen|opencode|windsurf]'

View File

@@ -52,6 +52,19 @@ import truststore
ssl_context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
client = httpx.Client(verify=ssl_context)
def _github_token(cli_token: str | None = None) -> str | None:
return cli_token or os.getenv("GH_TOKEN") or os.getenv("GITHUB_TOKEN")
def _github_auth_headers(cli_token: str | None = None) -> dict:
"""Headers for GitHub REST API requests.
- Uses Bearer auth if token present
"""
headers = {}
token = _github_token(cli_token)
if token:
headers["Authorization"] = f"Bearer {token}"
return headers
# Constants
AI_CHOICES = {
"copilot": "GitHub Copilot",
@@ -59,7 +72,8 @@ AI_CHOICES = {
"gemini": "Gemini CLI",
"cursor": "Cursor",
"qwen": "Qwen Code",
"opencode": "opencode"
"opencode": "opencode",
"windsurf": "Windsurf"
}
# Add script type choices
SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"}
@@ -77,7 +91,7 @@ BANNER = """
╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝
"""
TAGLINE = "Spec-Driven Development Toolkit"
TAGLINE = "GitHub Spec Kit - Spec-Driven Development Toolkit"
class StepTracker:
"""Track and render hierarchical steps without emojis, similar to Claude Code tree output.
Supports live auto-refresh via an attached refresh callback.
@@ -418,7 +432,7 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> bool:
os.chdir(original_cwd)
def download_template_from_github(ai_assistant: str, download_dir: Path, *, script_type: str = "sh", verbose: bool = True, show_progress: bool = True, client: httpx.Client = None, debug: bool = False) -> Tuple[Path, dict]:
def download_template_from_github(ai_assistant: str, download_dir: Path, *, script_type: str = "sh", verbose: bool = True, show_progress: bool = True, client: httpx.Client = None, debug: bool = False, github_token: str = None) -> Tuple[Path, dict]:
repo_owner = "github"
repo_name = "spec-kit"
if client is None:
@@ -429,7 +443,12 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
api_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/latest"
try:
response = client.get(api_url, timeout=30, follow_redirects=True)
response = client.get(
api_url,
timeout=30,
follow_redirects=True,
headers=_github_auth_headers(github_token) or None,
)
status = response.status_code
if status != 200:
msg = f"GitHub API returned {status} for {api_url}"
@@ -475,7 +494,14 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
console.print(f"[cyan]Downloading template...[/cyan]")
try:
with client.stream("GET", download_url, timeout=60, follow_redirects=True) as response:
# Include auth header for initial GitHub request; it won't leak across cross-origin redirects
with client.stream(
"GET",
download_url,
timeout=60,
follow_redirects=True,
headers=_github_auth_headers(github_token) or None,
) 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}")
@@ -519,7 +545,7 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
return zip_path, metadata
def download_and_extract_template(project_path: Path, ai_assistant: str, script_type: str, is_current_dir: bool = False, *, verbose: bool = True, tracker: StepTracker | None = None, client: httpx.Client = None, debug: bool = False) -> Path:
def download_and_extract_template(project_path: Path, ai_assistant: str, script_type: str, is_current_dir: bool = False, *, verbose: bool = True, tracker: StepTracker | None = None, client: httpx.Client = None, debug: bool = False, github_token: str = None) -> Path:
"""Download the latest release and extract it to create a new project.
Returns project_path. Uses tracker if provided (with keys: fetch, download, extract, cleanup)
"""
@@ -536,7 +562,8 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
verbose=verbose and tracker is None,
show_progress=(tracker is None),
client=client,
debug=debug
debug=debug,
github_token=github_token
)
if tracker:
tracker.complete("fetch", f"release {meta['release']} ({meta['size']:,} bytes)")
@@ -724,20 +751,21 @@ 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)"),
ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor, qwen or opencode"),
ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor, qwen, opencode or windsurf"),
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"),
here: bool = typer.Option(False, "--here", help="Initialize project in the current directory instead of creating a new one"),
skip_tls: bool = typer.Option(False, "--skip-tls", help="Skip SSL/TLS verification (not recommended)"),
debug: bool = typer.Option(False, "--debug", help="Show verbose diagnostic output for network and extraction failures"),
github_token: str = typer.Option(None, "--github-token", help="GitHub token to use for API requests (or set GH_TOKEN or GITHUB_TOKEN environment variable)"),
):
"""
Initialize a new Specify project from the latest template.
This command will:
1. Check that required tools are installed (git is optional)
2. Let you choose your AI assistant (Claude Code, Gemini CLI, GitHub Copilot, Cursor, Qwen Code or opencode)
2. Let you choose your AI assistant (Claude Code, Gemini CLI, GitHub Copilot, Cursor, Qwen Code, opencode or Windsurf)
3. Download the appropriate template from GitHub
4. Extract the template to a new project directory or current directory
5. Initialize a fresh git repository (if not --no-git and no existing repo)
@@ -750,7 +778,7 @@ def init(
specify init my-project --ai copilot --no-git
specify init my-project --ai cursor
specify init my-project --ai qwen
specify init my-project --ai opencode
specify init my-project --ai windsurf
specify init --ignore-agent-tools my-project
specify init --here --ai claude
specify init --here
@@ -897,7 +925,7 @@ def init(
local_ssl_context = ssl_context if verify else False
local_client = httpx.Client(verify=local_ssl_context)
download_and_extract_template(project_path, selected_ai, selected_script, here, verbose=False, tracker=tracker, client=local_client, debug=debug)
download_and_extract_template(project_path, selected_ai, selected_script, here, verbose=False, tracker=tracker, client=local_client, debug=debug, github_token=github_token)
# Ensure scripts are executable (POSIX)
ensure_executable_scripts(project_path, tracker=tracker)
@@ -950,42 +978,16 @@ def init(
steps_lines.append("1. You're already in the project directory!")
step_num = 2
if selected_ai == "claude":
steps_lines.append(f"{step_num}. Open in Visual Studio Code and start using / commands with Claude Code")
steps_lines.append(" - Type / in any file to see available commands")
steps_lines.append(" - Use /specify to create specifications")
steps_lines.append(" - Use /plan to create implementation plans")
steps_lines.append(" - Use /tasks to generate tasks")
elif selected_ai == "gemini":
steps_lines.append(f"{step_num}. Use / commands with Gemini CLI")
steps_lines.append(" - Run gemini /specify to create specifications")
steps_lines.append(" - Run gemini /plan to create implementation plans")
steps_lines.append(" - Run gemini /tasks to generate tasks")
steps_lines.append(" - See GEMINI.md for all available commands")
elif selected_ai == "copilot":
steps_lines.append(f"{step_num}. Open in Visual Studio Code and use [bold cyan]/specify[/], [bold cyan]/plan[/], [bold cyan]/tasks[/] commands with GitHub Copilot")
elif selected_ai == "qwen":
steps_lines.append(f"{step_num}. Use / commands with Qwen CLI")
steps_lines.append(" - Run qwen /specify to create specifications")
steps_lines.append(" - Run qwen /plan to create implementation plans")
steps_lines.append(" - Run qwen /tasks to generate tasks")
steps_lines.append(" - See QWEN.md for all available commands")
elif selected_ai == "opencode":
steps_lines.append(f"{step_num}. Use / commands with opencode")
steps_lines.append(" - Use /specify to create specifications")
steps_lines.append(" - Use /plan to create implementation plans")
steps_lines.append(" - Use /tasks to generate tasks")
# Removed script variant step (scripts are transparent to users)
step_num += 1
steps_lines.append(f"{step_num}. Update [bold magenta]CONSTITUTION.md[/bold magenta] with your project's non-negotiable principles")
steps_lines.append(f"{step_num}. Start using slash commands with your AI agent:")
steps_lines.append(" 2.1 [bold cyan]/constitution[/] - Establish project principles")
steps_lines.append(" 2.2 [bold cyan]/specify[/] - Create specifications")
steps_lines.append(" 2.3 [bold cyan]/plan[/] - Create implementation plans")
steps_lines.append(" 2.4 [bold cyan]/tasks[/] - Generate actionable tasks")
steps_lines.append(" 2.5 [bold cyan]/implement[/] - Execute implementation")
steps_panel = Panel("\n".join(steps_lines), title="Next steps", border_style="cyan", padding=(1,2))
console.print() # blank line
console.print()
console.print(steps_panel)
# Removed farewell line per user request
@app.command()
def check():
@@ -993,40 +995,35 @@ def check():
show_banner()
console.print("[bold]Checking for installed tools...[/bold]\n")
# Create tracker for checking tools
tracker = StepTracker("Check Available Tools")
# Add all tools we want to check
tracker.add("git", "Git version control")
tracker.add("claude", "Claude Code CLI")
tracker.add("gemini", "Gemini CLI")
tracker.add("qwen", "Qwen Code CLI")
tracker.add("code", "VS Code (for GitHub Copilot)")
tracker.add("cursor-agent", "Cursor IDE agent (optional)")
tracker.add("windsurf", "Windsurf IDE (optional)")
tracker.add("opencode", "opencode")
# Check each tool
git_ok = check_tool_for_tracker("git", "https://git-scm.com/downloads", tracker)
claude_ok = check_tool_for_tracker("claude", "https://docs.anthropic.com/en/docs/claude-code/setup", tracker)
gemini_ok = check_tool_for_tracker("gemini", "https://github.com/google-gemini/gemini-cli", tracker)
qwen_ok = check_tool_for_tracker("qwen", "https://github.com/QwenLM/qwen-code", tracker)
# Check for VS Code (code or code-insiders)
code_ok = check_tool_for_tracker("code", "https://code.visualstudio.com/", tracker)
if not code_ok:
code_ok = check_tool_for_tracker("code-insiders", "https://code.visualstudio.com/insiders/", tracker)
cursor_ok = check_tool_for_tracker("cursor-agent", "https://cursor.sh/", tracker)
windsurf_ok = check_tool_for_tracker("windsurf", "https://windsurf.com/", tracker)
opencode_ok = check_tool_for_tracker("opencode", "https://opencode.ai/", tracker)
# Render the final tree
console.print(tracker.render())
# Summary
console.print("\n[bold green]Specify CLI is ready to use![/bold green]")
# Recommendations
if not git_ok:
console.print("[dim]Tip: Install git for repository management[/dim]")
if not (claude_ok or gemini_ok or cursor_ok or qwen_ok or opencode_ok):
if not (claude_ok or gemini_ok or cursor_ok or qwen_ok or windsurf_ok or opencode_ok):
console.print("[dim]Tip: Install an AI assistant for the best experience[/dim]")

View File

@@ -0,0 +1,55 @@
---
description: Execute the implementation plan by processing and executing all tasks defined in tasks.md
scripts:
sh: scripts/bash/check-implementation-prerequisites.sh --json
ps: scripts/powershell/check-implementation-prerequisites.ps1 -Json
---
Given the current feature context, do this:
1. Run `{SCRIPT}` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute.
2. Load and analyze the implementation context:
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
- **IF EXISTS**: Read data-model.md for entities and relationships
- **IF EXISTS**: Read contracts/ for API specifications and test requirements
- **IF EXISTS**: Read research.md for technical decisions and constraints
- **IF EXISTS**: Read quickstart.md for integration scenarios
3. Parse tasks.md structure and extract:
- **Task phases**: Setup, Tests, Core, Integration, Polish
- **Task dependencies**: Sequential vs parallel execution rules
- **Task details**: ID, description, file paths, parallel markers [P]
- **Execution flow**: Order and dependency requirements
4. Execute implementation following the task plan:
- **Phase-by-phase execution**: Complete each phase before moving to the next
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
- **File-based coordination**: Tasks affecting the same files must run sequentially
- **Validation checkpoints**: Verify each phase completion before proceeding
5. Implementation execution rules:
- **Setup first**: Initialize project structure, dependencies, configuration
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
- **Core development**: Implement models, services, CLI commands, endpoints
- **Integration work**: Database connections, middleware, logging, external services
- **Polish and validation**: Unit tests, performance optimization, documentation
6. Progress tracking and error handling:
- Report progress after each completed task
- Halt execution if any non-parallel task fails
- For parallel tasks [P], continue with successful tasks, report failed ones
- Provide clear error messages with context for debugging
- Suggest next steps if implementation cannot proceed
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
7. Completion validation:
- Verify all required tasks are completed
- Check that implemented features match the original specification
- Validate that tests pass and coverage meets requirements
- Confirm the implementation follows the technical plan
- 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 `/tasks` first to regenerate the task list.

View File

@@ -8,6 +8,7 @@ scripts:
Given the feature description provided as an argument, do this:
1. Run the script `{SCRIPT}` from repo root and parse its JSON output for BRANCH_NAME and SPEC_FILE. All file paths must be absolute.
**IMPORTANT** 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.
2. Load `templates/spec-template.md` to understand required sections.
3. Write the specification to SPEC_FILE using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings.
4. Report completion with branch name, spec file path, and readiness for the next phase.