Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ jobs:
- spec-kit-template-windsurf-ps-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-codex-sh-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-codex-ps-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-zed-sh-${{ steps.get_tag.outputs.new_version }}.zip
- spec-kit-template-zed-ps-${{ steps.get_tag.outputs.new_version }}.zip
EOF

echo "Generated release notes:"
Expand Down Expand Up @@ -130,6 +132,8 @@ jobs:
spec-kit-template-windsurf-ps-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-codex-sh-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-codex-ps-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-zed-sh-${{ steps.get_tag.outputs.new_version }}.zip \
spec-kit-template-zed-ps-${{ steps.get_tag.outputs.new_version }}.zip \
--title "Spec Kit Templates - $VERSION_NO_V" \
--notes-file release_notes.md
env:
Expand Down
72 changes: 70 additions & 2 deletions .github/workflows/scripts/create-release-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -euo pipefail
# Usage: .github/workflows/scripts/create-release-packages.sh <version>
# 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 qwen opencode windsurf codex (default: all)
# AGENTS : space or comma separated subset of: claude gemini copilot cursor qwen opencode windsurf codex zed (default: all)
# SCRIPTS : space or comma separated subset of: sh ps (default: both)
# Examples:
# AGENTS=claude SCRIPTS=sh $0 v0.2.0
Expand Down Expand Up @@ -37,6 +37,72 @@ rewrite_paths() {
generate_commands() {
local agent=$1 ext=$2 arg_format=$3 output_dir=$4 script_variant=$5
mkdir -p "$output_dir"

if [[ "$agent" == "zed" ]]; then
local rules_file="$output_dir/.rules"
# Define slash command handling rules
cat > "$rules_file" <<'EOF'
# Agent Commands
When prompted with a command, you should consume the definition below and execute accordingly.
If no definition is found, respond that the command is undefined or prompt the user for clarification.

# Template for defining new commands:
# <agent_command>
# name: <command_name>
# description: <short description>
# body: <instructions for execution, including placeholders {SCRIPT}, {ARGS}, etc.>
# </agent_command>

EOF

# Iterate over all templates and append rules
for template in templates/commands/*.md; do
[[ -f "$template" ]] || continue
local name description script_command body
name=$(basename "$template" .md)

# Normalize line endings
file_content=$(tr -d '\r' < "$template")

# Extract description and script command for this variant
description=$(printf '%s\n' "$file_content" | awk '/^description:/ {sub(/^description:[[:space:]]*/, ""); print; exit}')
script_command=$(printf '%s\n' "$file_content" | awk -v sv="$script_variant" '/^[[:space:]]*'"$script_variant"':[[:space:]]*/ {sub(/^[[:space:]]*'"$script_variant"':[[:space:]]*/, ""); print; exit}')

if [[ -z $script_command ]]; then
echo "Warning: no script command found for $script_variant in $template" >&2
script_command="(Missing script command for $script_variant)"
fi

# Replace placeholders
body=$(printf '%s\n' "$file_content" | sed "s|{SCRIPT}|${script_command}|g")

# Remove entire frontmatter
body=$(printf '%s\n' "$file_content" | awk '
BEGIN{skip=0}
/^---$/ {skip = !skip; next}
!skip {print}
')

# Apply other substitutions
body=$(printf '%s\n' "$body" | sed "s/{ARGS}/$arg_format/g" | sed "s/__AGENT__/$agent/g" | rewrite_paths)

# Append the command as a command block following the template
{
echo "<agent_command>"
echo "name: $name"
echo "description: $description"
echo "body: |"
# Indent body by two spaces for YAML-style multiline
printf '%s\n' "$body" | sed 's/^/ /'
echo "</agent_command>"
echo ""
} >> "$rules_file"
done

return 0
fi

# Normal agent behavior for all other agents
for template in templates/commands/*.md; do
[[ -f "$template" ]] || continue
local name description script_command body
Expand Down Expand Up @@ -160,13 +226,15 @@ build_variant() {
codex)
mkdir -p "$base_dir/.codex/commands"
generate_commands codex md "\$ARGUMENTS" "$base_dir/.codex/commands" "$script" ;;
zed)
generate_commands zed md "\$ARGUMENTS" "$base_dir/" "$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 windsurf codex)
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf codex zed)
ALL_SCRIPTS=(sh ps)


Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ The `specify` command supports the following options:
| Argument/Option | Type | Description |
|------------------------|----------|------------------------------------------------------------------------------|
| `<project-name>` | Argument | Name for your new project directory (optional if using `--here`) |
| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor`, `qwen`, `opencode`, or `windsurf` |
| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor`, `qwen`, `opencode`, `windsurf` or `zed` |
| `--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 |
Expand All @@ -132,6 +132,9 @@ specify init my-project --ai cursor
# Initialize with Windsurf support
specify init my-project --ai windsurf

# Initialize with Zed support
specify init my-project --ai zed

# Initialize with PowerShell scripts (Windows/cross-platform)
specify init my-project --ai copilot --script ps

Expand Down Expand Up @@ -163,6 +166,13 @@ After running `specify init`, your AI coding agent will have access to these sla
| `/tasks` | Generate actionable task lists for implementation |
| `/implement` | Execute all tasks to build the feature according to the plan |

> **Note for Zed users:** Zed does not currently support agent slash-commands. Instead, provide the command name along with your arguments in a single message.
> **Example:**
> ```
> specify A todo list CLI app
> ```
> This will trigger the `/specify` workflow for Zed with the provided feature description.

## 📚 Core philosophy

Spec-Driven Development is a structured process that emphasizes:
Expand Down Expand Up @@ -209,7 +219,7 @@ Our research and experimentation focus on:
## 🔧 Prerequisites

- **Linux/macOS** (or WSL2 on Windows)
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Cursor](https://cursor.sh/), [Qwen CLI](https://github.com/QwenLM/qwen-code), [opencode](https://opencode.ai/), [Codex CLI](https://github.com/openai/codex), or [Windsurf](https://windsurf.com/)
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Cursor](https://cursor.sh/), [Qwen CLI](https://github.com/QwenLM/qwen-code), [opencode](https://opencode.ai/), [Codex CLI](https://github.com/openai/codex), [Windsurf](https://windsurf.com/) or [Zed](https://zed.dev/)
- [uv](https://docs.astral.sh/uv/) for package management
- [Python 3.11+](https://www.python.org/downloads/)
- [Git](https://git-scm.com/downloads)
Expand Down Expand Up @@ -251,6 +261,7 @@ specify init <project_name> --ai qwen
specify init <project_name> --ai opencode
specify init <project_name> --ai codex
specify init <project_name> --ai windsurf
specify init <project_name> --ai zed
# Or in current directory:
specify init --here --ai claude
specify init --here --ai codex
Expand Down
17 changes: 13 additions & 4 deletions scripts/bash/update-agent-context.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Zed
# - 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|qwen|opencode|codex|windsurf
# Agent types: claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|zed
# Leave empty to update all existing agent files

set -e
Expand All @@ -62,6 +62,7 @@ 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"
ZED_FILE="$REPO_ROOT/.rules"

# Template file
TEMPLATE_FILE="$REPO_ROOT/.specify/templates/agent-file-template.md"
Expand Down Expand Up @@ -559,9 +560,12 @@ update_specific_agent() {
windsurf)
update_agent_file "$WINDSURF_FILE" "Windsurf"
;;
zed)
update_agent_file "$ZED_FILE" "Zed"
;;
*)
log_error "Unknown agent type '$agent_type'"
log_error "Expected: claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf"
log_error "Expected: claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|zed"
exit 1
;;
esac
Expand Down Expand Up @@ -606,6 +610,11 @@ update_all_existing_agents() {
found_agent=true
fi

if [[ -f "$ZED_FILE" ]]; then
update_agent_file "$ZED_FILE" "Zed"
found_agent=true
fi

# If no agent files exist, create a default Claude file
if [[ "$found_agent" == false ]]; then
log_info "No existing agent files found, creating default Claude file..."
Expand All @@ -629,7 +638,7 @@ print_summary() {
fi

echo
log_info "Usage: $0 [claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf]"
log_info "Usage: $0 [claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|zed]"
}

#==============================================================================
Expand Down
11 changes: 7 additions & 4 deletions scripts/powershell/update-agent-context.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $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'
$zedFile = Join-Path $repoRoot '.rules'

Write-Output "=== Updating agent context files for feature $currentBranch ==="

Expand Down Expand Up @@ -78,6 +79,7 @@ switch ($AgentType) {
'opencode' { Update-AgentFile $agentsFile 'opencode' }
'windsurf' { Update-AgentFile $windsurfFile 'Windsurf' }
'codex' { Update-AgentFile $agentsFile 'Codex CLI' }
'zed' { Update-AgentFile $zedFile 'Zed' }
'' {
foreach ($pair in @(
@{file=$claudeFile; name='Claude Code'},
Expand All @@ -87,16 +89,17 @@ switch ($AgentType) {
@{file=$qwenFile; name='Qwen Code'},
@{file=$agentsFile; name='opencode'},
@{file=$windsurfFile; name='Windsurf'},
@{file=$agentsFile; name='Codex CLI'}
@{file=$agentsFile; name='Codex CLI'},
@{file=$zedFile; name='Zed'}
)) {
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) -and -not (Test-Path $windsurfFile)) {
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) -and -not (Test-Path $zedFile)) {
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, windsurf, codex or leave empty for all."; exit 1 }
Default { Write-Error "ERROR: Unknown agent type '$AgentType'. Use: claude, gemini, copilot, cursor, qwen, opencode, windsurf, codex, zed or leave empty for all."; exit 1 }
}

Write-Output ''
Expand All @@ -106,4 +109,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|windsurf|codex]'
Write-Output 'Usage: ./update-agent-context.ps1 [claude|gemini|copilot|cursor|qwen|opencode|windsurf|codex|zed]'
6 changes: 4 additions & 2 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def _github_auth_headers(cli_token: str | None = None) -> dict:
"opencode": "opencode",
"codex": "Codex CLI",
"windsurf": "Windsurf",
"zed": "Zed",
}
# Add script type choices
SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"}
Expand Down Expand Up @@ -746,7 +747,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)"),
ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor, qwen, opencode, codex, or windsurf"),
ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor, qwen, opencode, codex, windsurf or zed"),
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"),
Expand All @@ -760,7 +761,7 @@ def init(

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, opencode, Codex CLI, or Windsurf)
2. Let you choose your AI assistant (Claude Code, Gemini CLI, GitHub Copilot, Cursor, Qwen Code, opencode, Codex CLI, Windsurf or Zed)
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)
Expand All @@ -776,6 +777,7 @@ def init(
specify init my-project --ai opencode
specify init my-project --ai codex
specify init my-project --ai windsurf
specify init my-project --ai zed
specify init --ignore-agent-tools my-project
specify init --here --ai claude
specify init --here --ai codex
Expand Down