mirror of
https://github.com/github/spec-kit.git
synced 2026-01-31 13:03:36 +00:00
Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60bd9dc849 | ||
|
|
eb030dab19 | ||
|
|
be06a23fd7 | ||
|
|
79328aa38d | ||
|
|
f7903192a8 | ||
|
|
f3ada747cf | ||
|
|
cbc8ab020c | ||
|
|
e0e62f6757 | ||
|
|
6c22085214 | ||
|
|
02c1549f80 | ||
|
|
ab14090813 | ||
|
|
546e9d6617 | ||
|
|
33a07969c3 | ||
|
|
ea90d02c41 | ||
|
|
3e85f46465 | ||
|
|
015440838a | ||
|
|
7050a3151c | ||
|
|
9e84f46e56 | ||
|
|
5e32de1f3f | ||
|
|
5558b24475 | ||
|
|
f892b9e1cb | ||
|
|
a66af9b7f5 | ||
|
|
a5fdd53a3e | ||
|
|
ed0fa8fffe | ||
|
|
098380a46f | ||
|
|
74f7e508a4 | ||
|
|
8130d98bcc | ||
|
|
315269d9a8 | ||
|
|
71c2c63d55 | ||
|
|
b37a9516d0 | ||
|
|
b009773d5c | ||
|
|
a8514da3e8 | ||
|
|
9d4e8e9eb9 | ||
|
|
f3c77e2f4f | ||
|
|
ecec4bc5e0 | ||
|
|
900bc2ed68 | ||
|
|
03c7021270 | ||
|
|
a97374ded0 | ||
|
|
6b58824a39 | ||
|
|
b291a6efb0 | ||
|
|
3b000fce4d | ||
|
|
c59595d065 | ||
|
|
1c16a68df2 | ||
|
|
39bf3e4d9a | ||
|
|
045696641a | ||
|
|
41690cd1d4 | ||
|
|
e45c469709 | ||
|
|
8c9e586662 | ||
|
|
ce844c6259 | ||
|
|
84b46cd1b9 | ||
|
|
0cca67fcd2 | ||
|
|
66fc4c292d | ||
|
|
2baae57b26 | ||
|
|
514b0548fe | ||
|
|
be7db635cc | ||
|
|
a945077b8d | ||
|
|
7b55522213 | ||
|
|
7ca792509b | ||
|
|
4522fb4c44 | ||
|
|
36ff7e6505 | ||
|
|
defb1870da | ||
|
|
b61f04c898 | ||
|
|
64745162df | ||
|
|
97df98b9a0 | ||
|
|
36383b411f | ||
|
|
3e476c2ba6 | ||
|
|
654a00aac9 | ||
|
|
4690d13f88 | ||
|
|
e7bb98de42 | ||
|
|
d4f5c75519 | ||
|
|
09f57a87fa | ||
|
|
b702fcbbc0 | ||
|
|
2c1de4202e | ||
|
|
e65660ffc3 | ||
|
|
f7ae5781b7 | ||
|
|
d09552fc63 | ||
|
|
ed5dbf197f | ||
|
|
df4d7fa062 | ||
|
|
b4ecd14ffa | ||
|
|
26fde7cfda | ||
|
|
8abc812c57 | ||
|
|
940714df0a | ||
|
|
f393ae9825 | ||
|
|
97dee3e4bf | ||
|
|
aec568949c | ||
|
|
ed9044345b | ||
|
|
058ee510a7 | ||
|
|
e91aca54ee | ||
|
|
9c87fdd5bb | ||
|
|
301a556110 | ||
|
|
bb9ec8e638 | ||
|
|
e83d2c777d | ||
|
|
68809bdacb | ||
|
|
3cc545243b | ||
|
|
9ef389baba | ||
|
|
426ac8ab2e | ||
|
|
4de1b6b6c3 | ||
|
|
199c63901f | ||
|
|
369ed643d7 | ||
|
|
6c947cc8d8 | ||
|
|
07d506feb5 | ||
|
|
0124a0f32e | ||
|
|
e7936c3fd0 | ||
|
|
583d556677 | ||
|
|
72ed39d8a1 | ||
|
|
7c4c1edd85 | ||
|
|
5846a38c68 | ||
|
|
47e5f7c2e2 | ||
|
|
aa599b8af1 | ||
|
|
09cf4f6cc4 | ||
|
|
2b2f5a7c2a | ||
|
|
8b09559690 | ||
|
|
318b76de50 | ||
|
|
a85fdd4051 | ||
|
|
92621bca7d |
77
.devcontainer/devcontainer.json
Normal file
77
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
||||||
|
{
|
||||||
|
"name": "SpecKitDevContainer",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/python:3.13-trixie", // based on Debian "Trixie" (13)
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/common-utils:2": {
|
||||||
|
"installZsh": true,
|
||||||
|
"installOhMyZsh": true,
|
||||||
|
"installOhMyZshConfig": true,
|
||||||
|
"upgradePackages": true,
|
||||||
|
"username": "devcontainer",
|
||||||
|
"userUid": "automatic",
|
||||||
|
"userGid": "automatic"
|
||||||
|
},
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "lts"
|
||||||
|
},
|
||||||
|
"ghcr.io/devcontainers/features/git:1": {
|
||||||
|
"ppa": true,
|
||||||
|
"version": "latest"
|
||||||
|
},
|
||||||
|
"ghcr.io/devcontainers/features/node": {
|
||||||
|
"version": "lts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
"forwardPorts": [
|
||||||
|
8080 // for Spec-Kit documentation site
|
||||||
|
],
|
||||||
|
"containerUser": "devcontainer",
|
||||||
|
"updateRemoteUserUID": true,
|
||||||
|
"postCreateCommand": "chmod +x ./.devcontainer/post-create.sh && ./.devcontainer/post-create.sh",
|
||||||
|
"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"mhutchie.git-graph",
|
||||||
|
"eamodio.gitlens",
|
||||||
|
"anweber.reveal-button",
|
||||||
|
"chrisdias.promptboost",
|
||||||
|
// Github Copilot
|
||||||
|
"GitHub.copilot",
|
||||||
|
"GitHub.copilot-chat",
|
||||||
|
// Codex
|
||||||
|
"openai.chatgpt",
|
||||||
|
// Kilo Code
|
||||||
|
"kilocode.Kilo-Code",
|
||||||
|
// Roo Code
|
||||||
|
"RooVeterinaryInc.roo-cline",
|
||||||
|
// Amazon Developer Q
|
||||||
|
"AmazonWebServices.amazon-q-vscode",
|
||||||
|
// Claude Code
|
||||||
|
"anthropic.claude-code"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"debug.javascript.autoAttachFilter": "disabled", // fix running commands in integrated terminal
|
||||||
|
|
||||||
|
// Specify settings for Github Copilot
|
||||||
|
"git.autofetch": true,
|
||||||
|
"chat.promptFilesRecommendations": {
|
||||||
|
"speckit.constitution": true,
|
||||||
|
"speckit.specify": true,
|
||||||
|
"speckit.plan": true,
|
||||||
|
"speckit.tasks": true,
|
||||||
|
"speckit.implement": true
|
||||||
|
},
|
||||||
|
"chat.tools.terminal.autoApprove": {
|
||||||
|
".specify/scripts/bash/": true,
|
||||||
|
".specify/scripts/powershell/": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
.devcontainer/post-create.sh
Executable file
100
.devcontainer/post-create.sh
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit immediately on error, treat unset variables as an error, and fail if any command in a pipeline fails.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Function to run a command and show logs only on error
|
||||||
|
run_command() {
|
||||||
|
local command_to_run="$*"
|
||||||
|
local output
|
||||||
|
local exit_code
|
||||||
|
|
||||||
|
# Capture all output (stdout and stderr)
|
||||||
|
output=$(eval "$command_to_run" 2>&1) || exit_code=$?
|
||||||
|
exit_code=${exit_code:-0}
|
||||||
|
|
||||||
|
if [ $exit_code -ne 0 ]; then
|
||||||
|
echo -e "\033[0;31m[ERROR] Command failed (Exit Code $exit_code): $command_to_run\033[0m" >&2
|
||||||
|
echo -e "\033[0;31m$output\033[0m" >&2
|
||||||
|
|
||||||
|
exit $exit_code
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Installing CLI-based AI Agents
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Copilot CLI..."
|
||||||
|
run_command "npm install -g @github/copilot@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Claude CLI..."
|
||||||
|
run_command "npm install -g @anthropic-ai/claude-code@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Codex CLI..."
|
||||||
|
run_command "npm install -g @openai/codex@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Gemini CLI..."
|
||||||
|
run_command "npm install -g @google/gemini-cli@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Augie CLI..."
|
||||||
|
run_command "npm install -g @augmentcode/auggie@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Qwen Code CLI..."
|
||||||
|
run_command "npm install -g @qwen-code/qwen-code@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing OpenCode CLI..."
|
||||||
|
run_command "npm install -g opencode-ai@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing Amazon Q CLI..."
|
||||||
|
# 👉🏾 https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-verify-download.html
|
||||||
|
|
||||||
|
run_command "curl --proto '=https' --tlsv1.2 -sSf 'https://desktop-release.q.us-east-1.amazonaws.com/latest/q-x86_64-linux.zip' -o 'q.zip'"
|
||||||
|
run_command "curl --proto '=https' --tlsv1.2 -sSf 'https://desktop-release.q.us-east-1.amazonaws.com/latest/q-x86_64-linux.zip.sig' -o 'q.zip.sig'"
|
||||||
|
cat > amazonq-public-key.asc << 'EOF'
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mDMEZig60RYJKwYBBAHaRw8BAQdAy/+G05U5/EOA72WlcD4WkYn5SInri8pc4Z6D
|
||||||
|
BKNNGOm0JEFtYXpvbiBRIENMSSBUZWFtIDxxLWNsaUBhbWF6b24uY29tPoiZBBMW
|
||||||
|
CgBBFiEEmvYEF+gnQskUPgPsUNx6jcJMVmcFAmYoOtECGwMFCQPCZwAFCwkIBwIC
|
||||||
|
IgIGFQoJCAsCBBYCAwECHgcCF4AACgkQUNx6jcJMVmef5QD/QWWEGG/cOnbDnp68
|
||||||
|
SJXuFkwiNwlH2rPw9ZRIQMnfAS0A/0V6ZsGB4kOylBfc7CNfzRFGtovdBBgHqA6P
|
||||||
|
zQ/PNscGuDgEZig60RIKKwYBBAGXVQEFAQEHQC4qleONMBCq3+wJwbZSr0vbuRba
|
||||||
|
D1xr4wUPn4Avn4AnAwEIB4h+BBgWCgAmFiEEmvYEF+gnQskUPgPsUNx6jcJMVmcF
|
||||||
|
AmYoOtECGwwFCQPCZwAACgkQUNx6jcJMVmchMgEA6l3RveCM0YHAGQaSFMkguoAo
|
||||||
|
vK6FgOkDawgP0NPIP2oA/jIAO4gsAntuQgMOsPunEdDeji2t+AhV02+DQIsXZpoB
|
||||||
|
=f8yY
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
EOF
|
||||||
|
run_command "gpg --batch --import amazonq-public-key.asc"
|
||||||
|
run_command "gpg --verify q.zip.sig q.zip"
|
||||||
|
run_command "unzip -q q.zip"
|
||||||
|
run_command "chmod +x ./q/install.sh"
|
||||||
|
run_command "./q/install.sh --no-confirm"
|
||||||
|
run_command "rm -rf ./q q.zip q.zip.sig amazonq-public-key.asc"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing CodeBuddy CLI..."
|
||||||
|
run_command "npm install -g @tencent-ai/codebuddy-code@latest"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
# Installing UV (Python package manager)
|
||||||
|
echo -e "\n🐍 Installing UV - Python Package Manager..."
|
||||||
|
run_command "pipx install uv"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
# Installing DocFx (for documentation site)
|
||||||
|
echo -e "\n📚 Installing DocFx..."
|
||||||
|
run_command "dotnet tool update -g docfx"
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
echo -e "\n🧹 Cleaning cache..."
|
||||||
|
run_command "sudo apt-get autoclean"
|
||||||
|
run_command "sudo apt-get clean"
|
||||||
|
|
||||||
|
echo "✅ Setup completed. Happy coding! 🚀"
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1,2 +1,3 @@
|
|||||||
# Global code owner
|
# Global code owner
|
||||||
* @localden
|
* @localden
|
||||||
|
|
||||||
|
|||||||
1
.github/workflows/docs.yml
vendored
1
.github/workflows/docs.yml
vendored
@@ -65,3 +65,4 @@ jobs:
|
|||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v4
|
uses: actions/deploy-pages@v4
|
||||||
|
|
||||||
|
|||||||
18
.github/workflows/lint.yml
vendored
Normal file
18
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name: Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
markdownlint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run markdownlint-cli2
|
||||||
|
uses: DavidAnson/markdownlint-cli2-action@v19
|
||||||
|
with:
|
||||||
|
globs: '**/*.md'
|
||||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -57,3 +57,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
chmod +x .github/workflows/scripts/update-version.sh
|
chmod +x .github/workflows/scripts/update-version.sh
|
||||||
.github/workflows/scripts/update-version.sh ${{ steps.get_tag.outputs.new_version }}
|
.github/workflows/scripts/update-version.sh ${{ steps.get_tag.outputs.new_version }}
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ if gh release view "$VERSION" >/dev/null 2>&1; then
|
|||||||
else
|
else
|
||||||
echo "exists=false" >> $GITHUB_OUTPUT
|
echo "exists=false" >> $GITHUB_OUTPUT
|
||||||
echo "Release $VERSION does not exist, proceeding..."
|
echo "Release $VERSION does not exist, proceeding..."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ gh release create "$VERSION" \
|
|||||||
.genreleases/spec-kit-template-claude-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-claude-ps-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-gemini-sh-"$VERSION".zip \
|
.genreleases/spec-kit-template-gemini-sh-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-gemini-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-gemini-ps-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-cursor-sh-"$VERSION".zip \
|
.genreleases/spec-kit-template-cursor-agent-sh-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-cursor-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-cursor-agent-ps-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-opencode-sh-"$VERSION".zip \
|
.genreleases/spec-kit-template-opencode-sh-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-opencode-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-opencode-ps-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-qwen-sh-"$VERSION".zip \
|
.genreleases/spec-kit-template-qwen-sh-"$VERSION".zip \
|
||||||
@@ -38,7 +38,11 @@ gh release create "$VERSION" \
|
|||||||
.genreleases/spec-kit-template-auggie-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-auggie-ps-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-roo-sh-"$VERSION".zip \
|
.genreleases/spec-kit-template-roo-sh-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-roo-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-roo-ps-"$VERSION".zip \
|
||||||
|
.genreleases/spec-kit-template-codebuddy-sh-"$VERSION".zip \
|
||||||
|
.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-q-sh-"$VERSION".zip \
|
.genreleases/spec-kit-template-q-sh-"$VERSION".zip \
|
||||||
.genreleases/spec-kit-template-q-ps-"$VERSION".zip \
|
.genreleases/spec-kit-template-q-ps-"$VERSION".zip \
|
||||||
--title "Spec Kit Templates - $VERSION_NO_V" \
|
--title "Spec Kit Templates - $VERSION_NO_V" \
|
||||||
--notes-file release_notes.md
|
--notes-file release_notes.md
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ set -euo pipefail
|
|||||||
# Usage: .github/workflows/scripts/create-release-packages.sh <version>
|
# Usage: .github/workflows/scripts/create-release-packages.sh <version>
|
||||||
# Version argument should include leading 'v'.
|
# Version argument should include leading 'v'.
|
||||||
# Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built.
|
# 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-agent qwen opencode windsurf codex amp (default: all)
|
||||||
# SCRIPTS : space or comma separated subset of: sh ps (default: both)
|
# SCRIPTS : space or comma separated subset of: sh ps (default: both)
|
||||||
# Examples:
|
# Examples:
|
||||||
# AGENTS=claude SCRIPTS=sh $0 v0.2.0
|
# AGENTS=claude SCRIPTS=sh $0 v0.2.0
|
||||||
@@ -91,6 +91,7 @@ generate_commands() {
|
|||||||
|
|
||||||
case $ext in
|
case $ext in
|
||||||
toml)
|
toml)
|
||||||
|
body=$(printf '%s\n' "$body" | sed 's/\\/\\\\/g')
|
||||||
{ echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;;
|
{ echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;;
|
||||||
md)
|
md)
|
||||||
echo "$body" > "$output_dir/speckit.$name.$ext" ;;
|
echo "$body" > "$output_dir/speckit.$name.$ext" ;;
|
||||||
@@ -132,7 +133,7 @@ build_variant() {
|
|||||||
[[ -d templates ]] && { mkdir -p "$SPEC_DIR/templates"; find templates -type f -not -path "templates/commands/*" -not -name "vscode-settings.json" -exec cp --parents {} "$SPEC_DIR"/ \; ; echo "Copied templates -> .specify/templates"; }
|
[[ -d templates ]] && { mkdir -p "$SPEC_DIR/templates"; find templates -type f -not -path "templates/commands/*" -not -name "vscode-settings.json" -exec cp --parents {} "$SPEC_DIR"/ \; ; echo "Copied templates -> .specify/templates"; }
|
||||||
|
|
||||||
# NOTE: We substitute {ARGS} internally. Outward tokens differ intentionally:
|
# NOTE: We substitute {ARGS} internally. Outward tokens differ intentionally:
|
||||||
# * Markdown/prompt (claude, copilot, cursor, opencode): $ARGUMENTS
|
# * Markdown/prompt (claude, copilot, cursor-agent, opencode): $ARGUMENTS
|
||||||
# * TOML (gemini, qwen): {{args}}
|
# * TOML (gemini, qwen): {{args}}
|
||||||
# This keeps formats readable without extra abstraction.
|
# This keeps formats readable without extra abstraction.
|
||||||
|
|
||||||
@@ -151,9 +152,9 @@ build_variant() {
|
|||||||
mkdir -p "$base_dir/.vscode"
|
mkdir -p "$base_dir/.vscode"
|
||||||
[[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json"
|
[[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json"
|
||||||
;;
|
;;
|
||||||
cursor)
|
cursor-agent)
|
||||||
mkdir -p "$base_dir/.cursor/commands"
|
mkdir -p "$base_dir/.cursor/commands"
|
||||||
generate_commands cursor md "\$ARGUMENTS" "$base_dir/.cursor/commands" "$script" ;;
|
generate_commands cursor-agent md "\$ARGUMENTS" "$base_dir/.cursor/commands" "$script" ;;
|
||||||
qwen)
|
qwen)
|
||||||
mkdir -p "$base_dir/.qwen/commands"
|
mkdir -p "$base_dir/.qwen/commands"
|
||||||
generate_commands qwen toml "{{args}}" "$base_dir/.qwen/commands" "$script"
|
generate_commands qwen toml "{{args}}" "$base_dir/.qwen/commands" "$script"
|
||||||
@@ -176,6 +177,12 @@ build_variant() {
|
|||||||
roo)
|
roo)
|
||||||
mkdir -p "$base_dir/.roo/commands"
|
mkdir -p "$base_dir/.roo/commands"
|
||||||
generate_commands roo md "\$ARGUMENTS" "$base_dir/.roo/commands" "$script" ;;
|
generate_commands roo md "\$ARGUMENTS" "$base_dir/.roo/commands" "$script" ;;
|
||||||
|
codebuddy)
|
||||||
|
mkdir -p "$base_dir/.codebuddy/commands"
|
||||||
|
generate_commands codebuddy md "\$ARGUMENTS" "$base_dir/.codebuddy/commands" "$script" ;;
|
||||||
|
amp)
|
||||||
|
mkdir -p "$base_dir/.agents/commands"
|
||||||
|
generate_commands amp md "\$ARGUMENTS" "$base_dir/.agents/commands" "$script" ;;
|
||||||
q)
|
q)
|
||||||
mkdir -p "$base_dir/.amazonq/prompts"
|
mkdir -p "$base_dir/.amazonq/prompts"
|
||||||
generate_commands q md "\$ARGUMENTS" "$base_dir/.amazonq/prompts" "$script" ;;
|
generate_commands q md "\$ARGUMENTS" "$base_dir/.amazonq/prompts" "$script" ;;
|
||||||
@@ -185,10 +192,9 @@ build_variant() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Determine agent list
|
# Determine agent list
|
||||||
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf codex kilocode auggie roo q)
|
ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp q)
|
||||||
ALL_SCRIPTS=(sh ps)
|
ALL_SCRIPTS=(sh ps)
|
||||||
|
|
||||||
|
|
||||||
norm_list() {
|
norm_list() {
|
||||||
# convert comma+space separated -> space separated unique while preserving order of first occurrence
|
# 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")}'
|
tr ',\n' ' ' | awk '{for(i=1;i<=NF;i++){if(!seen[$i]++){printf((out?" ":"") $i)}}}END{printf("\n")}'
|
||||||
@@ -233,3 +239,4 @@ done
|
|||||||
|
|
||||||
echo "Archives in $GENRELEASES_DIR:"
|
echo "Archives in $GENRELEASES_DIR:"
|
||||||
ls -1 "$GENRELEASES_DIR"/spec-kit-template-*-"${NEW_VERSION}".zip
|
ls -1 "$GENRELEASES_DIR"/spec-kit-template-*-"${NEW_VERSION}".zip
|
||||||
|
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ This is the latest set of releases that you can use with your agent of choice. W
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "Generated release notes:"
|
echo "Generated release notes:"
|
||||||
cat release_notes.md
|
cat release_notes.md
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ PATCH=$((PATCH + 1))
|
|||||||
NEW_VERSION="v$MAJOR.$MINOR.$PATCH"
|
NEW_VERSION="v$MAJOR.$MINOR.$PATCH"
|
||||||
|
|
||||||
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||||
echo "New version will be: $NEW_VERSION"
|
echo "New version will be: $NEW_VERSION"
|
||||||
|
|||||||
2
.github/workflows/scripts/update-version.sh
vendored
2
.github/workflows/scripts/update-version.sh
vendored
@@ -20,4 +20,4 @@ if [ -f "pyproject.toml" ]; then
|
|||||||
echo "Updated pyproject.toml version to $PYTHON_VERSION (for release artifacts only)"
|
echo "Updated pyproject.toml version to $PYTHON_VERSION (for release artifacts only)"
|
||||||
else
|
else
|
||||||
echo "Warning: pyproject.toml not found, skipping version update"
|
echo "Warning: pyproject.toml not found, skipping version update"
|
||||||
fi
|
fi
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -42,4 +42,4 @@ env/
|
|||||||
# Spec Kit-specific files
|
# Spec Kit-specific files
|
||||||
.genreleases/
|
.genreleases/
|
||||||
*.zip
|
*.zip
|
||||||
sdd-*/
|
sdd-*/
|
||||||
|
|||||||
24
.markdownlint-cli2.jsonc
Normal file
24
.markdownlint-cli2.jsonc
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
// https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
|
||||||
|
"config": {
|
||||||
|
"default": true,
|
||||||
|
"MD003": {
|
||||||
|
"style": "atx"
|
||||||
|
},
|
||||||
|
"MD007": {
|
||||||
|
"indent": 2
|
||||||
|
},
|
||||||
|
"MD013": false,
|
||||||
|
"MD024": {
|
||||||
|
"siblings_only": true
|
||||||
|
},
|
||||||
|
"MD033": false,
|
||||||
|
"MD041": false,
|
||||||
|
"MD049": {
|
||||||
|
"style": "asterisk"
|
||||||
|
},
|
||||||
|
"MD050": {
|
||||||
|
"style": "asterisk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
210
AGENTS.md
210
AGENTS.md
@@ -37,56 +37,60 @@ Specify supports multiple AI agents by generating agent-specific command files a
|
|||||||
| **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI |
|
| **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI |
|
||||||
| **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI |
|
| **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI |
|
||||||
| **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI |
|
| **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI |
|
||||||
|
| **Codex CLI** | `.codex/commands/` | Markdown | `codex` | Codex CLI |
|
||||||
| **Windsurf** | `.windsurf/workflows/` | Markdown | N/A (IDE-based) | Windsurf IDE workflows |
|
| **Windsurf** | `.windsurf/workflows/` | Markdown | N/A (IDE-based) | Windsurf IDE workflows |
|
||||||
|
| **Kilo Code** | `.kilocode/rules/` | Markdown | N/A (IDE-based) | Kilo Code IDE |
|
||||||
|
| **Auggie CLI** | `.augment/rules/` | Markdown | `auggie` | Auggie CLI |
|
||||||
|
| **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 |
|
| **Amazon Q Developer CLI** | `.amazonq/prompts/` | Markdown | `q` | Amazon Q Developer CLI |
|
||||||
|
| **Amp** | `.agents/commands/` | Markdown | `amp` | Amp CLI |
|
||||||
|
|
||||||
### Step-by-Step Integration Guide
|
### Step-by-Step Integration Guide
|
||||||
|
|
||||||
Follow these steps to add a new agent (using Windsurf as an example):
|
Follow these steps to add a new agent (using a hypothetical new agent as an example):
|
||||||
|
|
||||||
#### 1. Update AI_CHOICES Constant
|
#### 1. Add to AGENT_CONFIG
|
||||||
|
|
||||||
Add the new agent to the `AI_CHOICES` dictionary in `src/specify_cli/__init__.py`:
|
**IMPORTANT**: Use the actual CLI tool name as the key, not a shortened version.
|
||||||
|
|
||||||
|
Add the new agent to the `AGENT_CONFIG` dictionary in `src/specify_cli/__init__.py`. This is the **single source of truth** for all agent metadata:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
AI_CHOICES = {
|
AGENT_CONFIG = {
|
||||||
"copilot": "GitHub Copilot",
|
# ... existing agents ...
|
||||||
"claude": "Claude Code",
|
"new-agent-cli": { # Use the ACTUAL CLI tool name (what users type in terminal)
|
||||||
"gemini": "Gemini CLI",
|
"name": "New Agent Display Name",
|
||||||
"cursor": "Cursor",
|
"folder": ".newagent/", # Directory for agent files
|
||||||
"qwen": "Qwen Code",
|
"install_url": "https://example.com/install", # URL for installation docs (or None if IDE-based)
|
||||||
"opencode": "opencode",
|
"requires_cli": True, # True if CLI tool required, False for IDE-based agents
|
||||||
"windsurf": "Windsurf",
|
},
|
||||||
"q": "Amazon Q Developer CLI" # Add new agent here
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Also update the `agent_folder_map` in the same file to include the new agent's folder for the security notice:
|
**Key Design Principle**: The dictionary key should match the actual executable name that users install. For example:
|
||||||
|
|
||||||
```python
|
- ✅ Use `"cursor-agent"` because the CLI tool is literally called `cursor-agent`
|
||||||
agent_folder_map = {
|
- ❌ Don't use `"cursor"` as a shortcut if the tool is `cursor-agent`
|
||||||
"claude": ".claude/",
|
|
||||||
"gemini": ".gemini/",
|
This eliminates the need for special-case mappings throughout the codebase.
|
||||||
"cursor": ".cursor/",
|
|
||||||
"qwen": ".qwen/",
|
**Field Explanations**:
|
||||||
"opencode": ".opencode/",
|
|
||||||
"codex": ".codex/",
|
- `name`: Human-readable display name shown to users
|
||||||
"windsurf": ".windsurf/",
|
- `folder`: Directory where agent-specific files are stored (relative to project root)
|
||||||
"kilocode": ".kilocode/",
|
- `install_url`: Installation documentation URL (set to `None` for IDE-based agents)
|
||||||
"auggie": ".auggie/",
|
- `requires_cli`: Whether the agent requires a CLI tool check during initialization
|
||||||
"copilot": ".github/",
|
|
||||||
"q": ".amazonq/" # Add new agent folder here
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Update CLI Help Text
|
#### 2. Update CLI Help Text
|
||||||
|
|
||||||
Update all help text and examples to include the new agent:
|
Update the `--ai` parameter help text in the `init()` command to include the new agent:
|
||||||
|
|
||||||
- Command option help: `--ai` parameter description
|
```python
|
||||||
- Function docstrings and examples
|
ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, new-agent-cli, or q"),
|
||||||
- Error messages with agent lists
|
```
|
||||||
|
|
||||||
|
Also update any function docstrings, examples, and error messages that list available agents.
|
||||||
|
|
||||||
#### 3. Update README Documentation
|
#### 3. Update README Documentation
|
||||||
|
|
||||||
@@ -101,12 +105,14 @@ Update the **Supported AI Agents** section in `README.md` to include the new age
|
|||||||
|
|
||||||
Modify `.github/workflows/scripts/create-release-packages.sh`:
|
Modify `.github/workflows/scripts/create-release-packages.sh`:
|
||||||
|
|
||||||
##### Add to ALL_AGENTS array:
|
##### Add to ALL_AGENTS array
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ALL_AGENTS=(claude gemini copilot cursor qwen opencode windsurf q)
|
ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf q)
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Add case statement for directory structure:
|
##### Add case statement for directory structure
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
case $agent in
|
case $agent in
|
||||||
# ... existing cases ...
|
# ... existing cases ...
|
||||||
@@ -130,14 +136,16 @@ gh release create "$VERSION" \
|
|||||||
|
|
||||||
#### 5. Update Agent Context Scripts
|
#### 5. Update Agent Context Scripts
|
||||||
|
|
||||||
##### Bash script (`scripts/bash/update-agent-context.sh`):
|
##### Bash script (`scripts/bash/update-agent-context.sh`)
|
||||||
|
|
||||||
Add file variable:
|
Add file variable:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
|
WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
|
||||||
```
|
```
|
||||||
|
|
||||||
Add to case statement:
|
Add to case statement:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
case "$AGENT_TYPE" in
|
case "$AGENT_TYPE" in
|
||||||
# ... existing cases ...
|
# ... existing cases ...
|
||||||
@@ -150,14 +158,16 @@ case "$AGENT_TYPE" in
|
|||||||
esac
|
esac
|
||||||
```
|
```
|
||||||
|
|
||||||
##### PowerShell script (`scripts/powershell/update-agent-context.ps1`):
|
##### PowerShell script (`scripts/powershell/update-agent-context.ps1`)
|
||||||
|
|
||||||
Add file variable:
|
Add file variable:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
$windsurfFile = Join-Path $repoRoot '.windsurf/rules/specify-rules.md'
|
$windsurfFile = Join-Path $repoRoot '.windsurf/rules/specify-rules.md'
|
||||||
```
|
```
|
||||||
|
|
||||||
Add to switch statement:
|
Add to switch statement:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
switch ($AgentType) {
|
switch ($AgentType) {
|
||||||
# ... existing cases ...
|
# ... existing cases ...
|
||||||
@@ -190,27 +200,130 @@ elif selected_ai == "windsurf":
|
|||||||
agent_tool_missing = True
|
agent_tool_missing = True
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Skip CLI checks for IDE-based agents (Copilot, Windsurf).
|
**Note**: CLI tool checks are now handled automatically based on the `requires_cli` field in AGENT_CONFIG. No additional code changes needed in the `check()` or `init()` commands - they automatically loop through AGENT_CONFIG and check tools as needed.
|
||||||
|
|
||||||
|
## Important Design Decisions
|
||||||
|
|
||||||
|
### Using Actual CLI Tool Names as Keys
|
||||||
|
|
||||||
|
**CRITICAL**: When adding a new agent to AGENT_CONFIG, always use the **actual executable name** as the dictionary key, not a shortened or convenient version.
|
||||||
|
|
||||||
|
**Why this matters:**
|
||||||
|
|
||||||
|
- The `check_tool()` function uses `shutil.which(tool)` to find executables in the system PATH
|
||||||
|
- If the key doesn't match the actual CLI tool name, you'll need special-case mappings throughout the codebase
|
||||||
|
- This creates unnecessary complexity and maintenance burden
|
||||||
|
|
||||||
|
**Example - The Cursor Lesson:**
|
||||||
|
|
||||||
|
❌ **Wrong approach** (requires special-case mapping):
|
||||||
|
|
||||||
|
```python
|
||||||
|
AGENT_CONFIG = {
|
||||||
|
"cursor": { # Shorthand that doesn't match the actual tool
|
||||||
|
"name": "Cursor",
|
||||||
|
# ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Then you need special cases everywhere:
|
||||||
|
cli_tool = agent_key
|
||||||
|
if agent_key == "cursor":
|
||||||
|
cli_tool = "cursor-agent" # Map to the real tool name
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Correct approach** (no mapping needed):
|
||||||
|
|
||||||
|
```python
|
||||||
|
AGENT_CONFIG = {
|
||||||
|
"cursor-agent": { # Matches the actual executable name
|
||||||
|
"name": "Cursor",
|
||||||
|
# ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# No special cases needed - just use agent_key directly!
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits of this approach:**
|
||||||
|
|
||||||
|
- Eliminates special-case logic scattered throughout the codebase
|
||||||
|
- Makes the code more maintainable and easier to understand
|
||||||
|
- Reduces the chance of bugs when adding new agents
|
||||||
|
- Tool checking "just works" without additional mappings
|
||||||
|
|
||||||
|
#### 7. Update Devcontainer files (Optional)
|
||||||
|
|
||||||
|
For agents that have VS Code extensions or require CLI installation, update the devcontainer configuration files:
|
||||||
|
|
||||||
|
##### VS Code Extension-based Agents
|
||||||
|
|
||||||
|
For agents available as VS Code extensions, add them to `.devcontainer/devcontainer.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
// ... existing extensions ...
|
||||||
|
// [New Agent Name]
|
||||||
|
"[New Agent Extension ID]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### CLI-based Agents
|
||||||
|
|
||||||
|
For agents that require CLI tools, add installation commands to `.devcontainer/post-create.sh`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Existing installations...
|
||||||
|
|
||||||
|
echo -e "\n🤖 Installing [New Agent Name] CLI..."
|
||||||
|
# run_command "npm install -g [agent-cli-package]@latest" # Example for node-based CLI
|
||||||
|
# or other installation instructions (must be non-interactive and compatible with Linux Debian "Trixie" or later)...
|
||||||
|
echo "✅ Done"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**Quick Tips:**
|
||||||
|
|
||||||
|
- **Extension-based agents**: Add to the `extensions` array in `devcontainer.json`
|
||||||
|
- **CLI-based agents**: Add installation scripts to `post-create.sh`
|
||||||
|
- **Hybrid agents**: May require both extension and CLI installation
|
||||||
|
- **Test thoroughly**: Ensure installations work in the devcontainer environment
|
||||||
|
|
||||||
## Agent Categories
|
## Agent Categories
|
||||||
|
|
||||||
### CLI-Based Agents
|
### CLI-Based Agents
|
||||||
|
|
||||||
Require a command-line tool to be installed:
|
Require a command-line tool to be installed:
|
||||||
|
|
||||||
- **Claude Code**: `claude` CLI
|
- **Claude Code**: `claude` CLI
|
||||||
- **Gemini CLI**: `gemini` CLI
|
- **Gemini CLI**: `gemini` CLI
|
||||||
- **Cursor**: `cursor-agent` CLI
|
- **Cursor**: `cursor-agent` CLI
|
||||||
- **Qwen Code**: `qwen` CLI
|
- **Qwen Code**: `qwen` CLI
|
||||||
- **opencode**: `opencode` CLI
|
- **opencode**: `opencode` CLI
|
||||||
|
- **Amazon Q Developer CLI**: `q` CLI
|
||||||
|
- **CodeBuddy CLI**: `codebuddy` CLI
|
||||||
|
- **Amp**: `amp` CLI
|
||||||
|
|
||||||
### IDE-Based Agents
|
### IDE-Based Agents
|
||||||
|
|
||||||
Work within integrated development environments:
|
Work within integrated development environments:
|
||||||
|
|
||||||
- **GitHub Copilot**: Built into VS Code/compatible editors
|
- **GitHub Copilot**: Built into VS Code/compatible editors
|
||||||
- **Windsurf**: Built into Windsurf IDE
|
- **Windsurf**: Built into Windsurf IDE
|
||||||
|
|
||||||
## Command File Formats
|
## Command File Formats
|
||||||
|
|
||||||
### Markdown Format
|
### Markdown Format
|
||||||
Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer
|
|
||||||
|
Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
---
|
---
|
||||||
@@ -221,6 +334,7 @@ Command content with {SCRIPT} and $ARGUMENTS placeholders.
|
|||||||
```
|
```
|
||||||
|
|
||||||
### TOML Format
|
### TOML Format
|
||||||
|
|
||||||
Used by: Gemini, Qwen
|
Used by: Gemini, Qwen
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
@@ -242,6 +356,7 @@ Command content with {SCRIPT} and {{args}} placeholders.
|
|||||||
## Argument Patterns
|
## Argument Patterns
|
||||||
|
|
||||||
Different agents use different argument placeholders:
|
Different agents use different argument placeholders:
|
||||||
|
|
||||||
- **Markdown/prompt-based**: `$ARGUMENTS`
|
- **Markdown/prompt-based**: `$ARGUMENTS`
|
||||||
- **TOML-based**: `{{args}}`
|
- **TOML-based**: `{{args}}`
|
||||||
- **Script placeholders**: `{SCRIPT}` (replaced with actual script path)
|
- **Script placeholders**: `{SCRIPT}` (replaced with actual script path)
|
||||||
@@ -257,20 +372,23 @@ Different agents use different argument placeholders:
|
|||||||
|
|
||||||
## Common Pitfalls
|
## Common Pitfalls
|
||||||
|
|
||||||
1. **Forgetting update scripts**: Both bash and PowerShell scripts must be updated
|
1. **Using shorthand keys instead of actual CLI tool names**: Always use the actual executable name as the AGENT_CONFIG key (e.g., `"cursor-agent"` not `"cursor"`). This prevents the need for special-case mappings throughout the codebase.
|
||||||
2. **Missing CLI checks**: Only add for agents that actually have CLI tools
|
2. **Forgetting update scripts**: Both bash and PowerShell scripts must be updated when adding new agents.
|
||||||
3. **Wrong argument format**: Use correct placeholder format for each agent type
|
3. **Incorrect `requires_cli` value**: Set to `True` only for agents that actually have CLI tools to check; set to `False` for IDE-based agents.
|
||||||
4. **Directory naming**: Follow agent-specific conventions exactly
|
4. **Wrong argument format**: Use correct placeholder format for each agent type (`$ARGUMENTS` for Markdown, `{{args}}` for TOML).
|
||||||
5. **Help text inconsistency**: Update all user-facing text consistently
|
5. **Directory naming**: Follow agent-specific conventions exactly (check existing agents for patterns).
|
||||||
|
6. **Help text inconsistency**: Update all user-facing text consistently (help strings, docstrings, README, error messages).
|
||||||
|
|
||||||
## Future Considerations
|
## Future Considerations
|
||||||
|
|
||||||
When adding new agents:
|
When adding new agents:
|
||||||
|
|
||||||
- Consider the agent's native command/workflow patterns
|
- Consider the agent's native command/workflow patterns
|
||||||
- Ensure compatibility with the Spec-Driven Development process
|
- Ensure compatibility with the Spec-Driven Development process
|
||||||
- Document any special requirements or limitations
|
- Document any special requirements or limitations
|
||||||
- Update this guide with lessons learned
|
- Update this guide with lessons learned
|
||||||
|
- Verify the actual CLI tool name before adding to AGENT_CONFIG
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*This documentation should be updated whenever new agents are added to maintain accuracy and completeness.*
|
*This documentation should be updated whenever new agents are added to maintain accuracy and completeness.*
|
||||||
|
|||||||
39
CHANGELOG.md
39
CHANGELOG.md
@@ -7,6 +7,42 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.0.20] - 2025-10-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Intelligent Branch Naming**: `create-new-feature` scripts now support `--short-name` parameter for custom branch names
|
||||||
|
- When `--short-name` provided: Uses the custom name directly (cleaned and formatted)
|
||||||
|
- When omitted: Automatically generates meaningful names using stop word filtering and length-based filtering
|
||||||
|
- Filters out common stop words (I, want, to, the, for, etc.)
|
||||||
|
- Removes words shorter than 3 characters (unless they're uppercase acronyms)
|
||||||
|
- Takes 3-4 most meaningful words from the description
|
||||||
|
- **Enforces GitHub's 244-byte branch name limit** with automatic truncation and warnings
|
||||||
|
- Examples:
|
||||||
|
- "I want to create user authentication" → `001-create-user-authentication`
|
||||||
|
- "Implement OAuth2 integration for API" → `001-implement-oauth2-integration-api`
|
||||||
|
- "Fix payment processing bug" → `001-fix-payment-processing`
|
||||||
|
- Very long descriptions are automatically truncated at word boundaries to stay within limits
|
||||||
|
- Designed for AI agents to provide semantic short names while maintaining standalone usability
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Enhanced help documentation for `create-new-feature.sh` and `create-new-feature.ps1` scripts with examples
|
||||||
|
- Branch names now validated against GitHub's 244-byte limit with automatic truncation if needed
|
||||||
|
|
||||||
|
## [0.0.19] - 2025-10-10
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support for CodeBuddy (thank you to [@lispking](https://github.com/lispking) for the contribution).
|
||||||
|
- You can now see Git-sourced errors in the Specify CLI.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Fixed the path to the constitution in `plan.md` (thank you to [@lyzno1](https://github.com/lyzno1) for spotting).
|
||||||
|
- Fixed backslash escapes in generated TOML files for Gemini (thank you to [@hsin19](https://github.com/hsin19) for the contribution).
|
||||||
|
- Implementation command now ensures that the correct ignore files are added (thank you to [@sigent-amazon](https://github.com/sigent-amazon) for the contribution).
|
||||||
|
|
||||||
## [0.0.18] - 2025-10-06
|
## [0.0.18] - 2025-10-06
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@@ -27,7 +63,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- New `/clarify` command template to surface up to 5 targeted clarification questions for an existing spec and persist answers into a Clarifications section in the spec.
|
- New `/clarify` command template to surface up to 5 targeted clarification questions for an existing spec and persist answers into a Clarifications section in the spec.
|
||||||
- New `/analyze` command template providing a non-destructive cross-artifact discrepancy and alignment report (spec, clarifications, plan, tasks, constitution) inserted after `/tasks` and before `/implement`.
|
- New `/analyze` command template providing a non-destructive cross-artifact discrepancy and alignment report (spec, clarifications, plan, tasks, constitution) inserted after `/tasks` and before `/implement`.
|
||||||
- Note: Constitution rules are explicitly treated as non-negotiable; any conflict is a CRITICAL finding requiring artifact remediation, not weakening of principles.
|
- Note: Constitution rules are explicitly treated as non-negotiable; any conflict is a CRITICAL finding requiring artifact remediation, not weakening of principles.
|
||||||
|
|
||||||
## [0.0.16] - 2025-09-22
|
## [0.0.16] - 2025-09-22
|
||||||
|
|
||||||
@@ -104,7 +140,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Updated command instructions in the CLI.
|
- Updated command instructions in the CLI.
|
||||||
- Cleaned up the code to not render agent-specific information when it's generic.
|
- Cleaned up the code to not render agent-specific information when it's generic.
|
||||||
|
|
||||||
|
|
||||||
## [0.0.6] - 2025-09-17
|
## [0.0.6] - 2025-09-17
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -14,21 +14,21 @@ orientation.
|
|||||||
Examples of behavior that contributes to creating a positive environment
|
Examples of behavior that contributes to creating a positive environment
|
||||||
include:
|
include:
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
- Using welcoming and inclusive language
|
||||||
* Being respectful of differing viewpoints and experiences
|
- Being respectful of differing viewpoints and experiences
|
||||||
* Gracefully accepting constructive criticism
|
- Gracefully accepting constructive criticism
|
||||||
* Focusing on what is best for the community
|
- Focusing on what is best for the community
|
||||||
* Showing empathy towards other community members
|
- Showing empathy towards other community members
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
advances
|
advances
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
* Public or private harassment
|
- Public or private harassment
|
||||||
* Publishing others' private information, such as a physical or electronic
|
- Publishing others' private information, such as a physical or electronic
|
||||||
address, without explicit permission
|
address, without explicit permission
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
- Other conduct which could reasonably be considered inappropriate in a
|
||||||
professional setting
|
professional setting
|
||||||
|
|
||||||
## Our Responsibilities
|
## Our Responsibilities
|
||||||
@@ -71,4 +71,4 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], versi
|
|||||||
available at [http://contributor-covenant.org/version/1/4][version]
|
available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
[homepage]: http://contributor-covenant.org
|
[homepage]: http://contributor-covenant.org
|
||||||
[version]: http://contributor-covenant.org/version/1/4/
|
[version]: http://contributor-covenant.org/version/1/4/
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
## Contributing to Spec Kit
|
# Contributing to Spec Kit
|
||||||
|
|
||||||
Hi there! We're thrilled that you'd like to contribute to Spec Kit. Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
Hi there! We're thrilled that you'd like to contribute to Spec Kit. Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
||||||
|
|
||||||
@@ -13,6 +13,23 @@ These are one time installations required to be able to test your changes locall
|
|||||||
1. Install [Git](https://git-scm.com/downloads)
|
1. Install [Git](https://git-scm.com/downloads)
|
||||||
1. Have an [AI coding agent available](README.md#-supported-ai-agents)
|
1. Have an [AI coding agent available](README.md#-supported-ai-agents)
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>💡 Hint if you are using <code>VSCode</code> or <code>GitHub Codespaces</code> as your IDE</b></summary>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
Provided you have [Docker](https://docker.com) installed on your machine, you can leverage [Dev Containers](https://containers.dev) through this [VSCode extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers), to easily set up your development environment, with aforementioned tools already installed and configured, thanks to the `.devcontainer/devcontainer.json` file (located at the root of the project).
|
||||||
|
|
||||||
|
To do so, simply:
|
||||||
|
|
||||||
|
- Checkout the repo
|
||||||
|
- Open it with VSCode
|
||||||
|
- Open the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) and select "Dev Containers: Open Folder in Container..."
|
||||||
|
|
||||||
|
On [GitHub Codespaces](https://github.com/features/codespaces) it's even simpler, as it leverages the `.devcontainer/devcontainer.json` automatically upon opening the codespace.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## Submitting a pull request
|
## Submitting a pull request
|
||||||
|
|
||||||
>[!NOTE]
|
>[!NOTE]
|
||||||
|
|||||||
1
LICENSE
1
LICENSE
@@ -19,3 +19,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
|||||||
124
README.md
124
README.md
@@ -1,11 +1,11 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="./media/logo_small.webp"/>
|
<img src="./media/logo_small.webp" alt="Spec Kit Logo"/>
|
||||||
<h1>🌱 Spec Kit</h1>
|
<h1>🌱 Spec Kit</h1>
|
||||||
<h3><em>Build high-quality software faster.</em></h3>
|
<h3><em>Build high-quality software faster.</em></h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<strong>An effort to allow organizations to focus on product scenarios rather than writing undifferentiated code with the help of Spec-Driven Development.</strong>
|
<strong>An open source toolkit that allows you to focus on product scenarios and predictable outcomes instead of vibe coding every piece from scratch.</strong>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -20,16 +20,16 @@
|
|||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [🤔 What is Spec-Driven Development?](#-what-is-spec-driven-development)
|
- [🤔 What is Spec-Driven Development?](#-what-is-spec-driven-development)
|
||||||
- [⚡ Get started](#-get-started)
|
- [⚡ Get Started](#-get-started)
|
||||||
- [📽️ Video Overview](#️-video-overview)
|
- [📽️ Video Overview](#️-video-overview)
|
||||||
- [🤖 Supported AI Agents](#-supported-ai-agents)
|
- [🤖 Supported AI Agents](#-supported-ai-agents)
|
||||||
- [🔧 Specify CLI Reference](#-specify-cli-reference)
|
- [🔧 Specify CLI Reference](#-specify-cli-reference)
|
||||||
- [📚 Core philosophy](#-core-philosophy)
|
- [📚 Core Philosophy](#-core-philosophy)
|
||||||
- [🌟 Development phases](#-development-phases)
|
- [🌟 Development Phases](#-development-phases)
|
||||||
- [🎯 Experimental goals](#-experimental-goals)
|
- [🎯 Experimental Goals](#-experimental-goals)
|
||||||
- [🔧 Prerequisites](#-prerequisites)
|
- [🔧 Prerequisites](#-prerequisites)
|
||||||
- [📖 Learn more](#-learn-more)
|
- [📖 Learn More](#-learn-more)
|
||||||
- [📋 Detailed process](#-detailed-process)
|
- [📋 Detailed Process](#-detailed-process)
|
||||||
- [🔍 Troubleshooting](#-troubleshooting)
|
- [🔍 Troubleshooting](#-troubleshooting)
|
||||||
- [👥 Maintainers](#-maintainers)
|
- [👥 Maintainers](#-maintainers)
|
||||||
- [💬 Support](#-support)
|
- [💬 Support](#-support)
|
||||||
@@ -40,9 +40,9 @@
|
|||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
## ⚡ Get started
|
## ⚡ Get Started
|
||||||
|
|
||||||
### 1. Install Specify
|
### 1. Install Specify CLI
|
||||||
|
|
||||||
Choose your preferred installation method:
|
Choose your preferred installation method:
|
||||||
|
|
||||||
@@ -61,6 +61,12 @@ specify init <PROJECT_NAME>
|
|||||||
specify check
|
specify check
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To upgrade specify run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv tool install specify-cli --force --from git+https://github.com/github/spec-kit.git
|
||||||
|
```
|
||||||
|
|
||||||
#### Option 2: One-time Usage
|
#### Option 2: One-time Usage
|
||||||
|
|
||||||
Run directly without installing:
|
Run directly without installing:
|
||||||
@@ -78,6 +84,8 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME
|
|||||||
|
|
||||||
### 2. Establish project principles
|
### 2. Establish project principles
|
||||||
|
|
||||||
|
Launch your AI assistant in the project directory. The `/speckit.*` commands are available in the assistant.
|
||||||
|
|
||||||
Use the **`/speckit.constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
|
Use the **`/speckit.constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -137,9 +145,11 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c
|
|||||||
| [Windsurf](https://windsurf.com/) | ✅ | |
|
| [Windsurf](https://windsurf.com/) | ✅ | |
|
||||||
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | |
|
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | |
|
||||||
| [Auggie CLI](https://docs.augmentcode.com/cli/overview) | ✅ | |
|
| [Auggie CLI](https://docs.augmentcode.com/cli/overview) | ✅ | |
|
||||||
|
| [CodeBuddy CLI](https://www.codebuddy.ai/cli) | ✅ | |
|
||||||
| [Roo Code](https://roocode.com/) | ✅ | |
|
| [Roo Code](https://roocode.com/) | ✅ | |
|
||||||
| [Codex CLI](https://github.com/openai/codex) | ✅ | |
|
| [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. |
|
| [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/) | ✅ | |
|
||||||
|
|
||||||
## 🔧 Specify CLI Reference
|
## 🔧 Specify CLI Reference
|
||||||
|
|
||||||
@@ -157,7 +167,7 @@ The `specify` command supports the following options:
|
|||||||
| Argument/Option | Type | Description |
|
| Argument/Option | Type | Description |
|
||||||
|------------------------|----------|------------------------------------------------------------------------------|
|
|------------------------|----------|------------------------------------------------------------------------------|
|
||||||
| `<project-name>` | Argument | Name for your new project directory (optional if using `--here`, or use `.` for current directory) |
|
| `<project-name>` | 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`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, or `q` |
|
| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, or `q` |
|
||||||
| `--script` | Option | Script variant to use: `sh` (bash/zsh) or `ps` (PowerShell) |
|
| `--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 |
|
| `--ignore-agent-tools` | Flag | Skip checks for AI agent tools like Claude Code |
|
||||||
| `--no-git` | Flag | Skip git repository initialization |
|
| `--no-git` | Flag | Skip git repository initialization |
|
||||||
@@ -177,11 +187,14 @@ specify init my-project
|
|||||||
specify init my-project --ai claude
|
specify init my-project --ai claude
|
||||||
|
|
||||||
# Initialize with Cursor support
|
# Initialize with Cursor support
|
||||||
specify init my-project --ai cursor
|
specify init my-project --ai cursor-agent
|
||||||
|
|
||||||
# Initialize with Windsurf support
|
# Initialize with Windsurf support
|
||||||
specify init my-project --ai windsurf
|
specify init my-project --ai windsurf
|
||||||
|
|
||||||
|
# Initialize with Amp support
|
||||||
|
specify init my-project --ai amp
|
||||||
|
|
||||||
# Initialize with PowerShell scripts (Windows/cross-platform)
|
# Initialize with PowerShell scripts (Windows/cross-platform)
|
||||||
specify init my-project --ai copilot --script ps
|
specify init my-project --ai copilot --script ps
|
||||||
|
|
||||||
@@ -240,16 +253,16 @@ Additional commands for enhanced quality and validation:
|
|||||||
|------------------|------------------------------------------------------------------------------------------------|
|
|------------------|------------------------------------------------------------------------------------------------|
|
||||||
| `SPECIFY_FEATURE` | Override feature detection for non-Git repositories. Set to the feature directory name (e.g., `001-photo-albums`) to work on a specific feature when not using Git branches.<br/>**Must be set in the context of the agent you're working with prior to using `/speckit.plan` or follow-up commands. |
|
| `SPECIFY_FEATURE` | Override feature detection for non-Git repositories. Set to the feature directory name (e.g., `001-photo-albums`) to work on a specific feature when not using Git branches.<br/>**Must be set in the context of the agent you're working with prior to using `/speckit.plan` or follow-up commands. |
|
||||||
|
|
||||||
## 📚 Core philosophy
|
## 📚 Core Philosophy
|
||||||
|
|
||||||
Spec-Driven Development is a structured process that emphasizes:
|
Spec-Driven Development is a structured process that emphasizes:
|
||||||
|
|
||||||
- **Intent-driven development** where specifications define the "_what_" before the "_how_"
|
- **Intent-driven development** where specifications define the "*what*" before the "*how*"
|
||||||
- **Rich specification creation** using guardrails and organizational principles
|
- **Rich specification creation** using guardrails and organizational principles
|
||||||
- **Multi-step refinement** rather than one-shot code generation from prompts
|
- **Multi-step refinement** rather than one-shot code generation from prompts
|
||||||
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
||||||
|
|
||||||
## 🌟 Development phases
|
## 🌟 Development Phases
|
||||||
|
|
||||||
| Phase | Focus | Key Activities |
|
| Phase | Focus | Key Activities |
|
||||||
|-------|-------|----------------|
|
|-------|-------|----------------|
|
||||||
@@ -257,7 +270,7 @@ Spec-Driven Development is a structured process that emphasizes:
|
|||||||
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
|
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
|
||||||
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
|
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
|
||||||
|
|
||||||
## 🎯 Experimental goals
|
## 🎯 Experimental Goals
|
||||||
|
|
||||||
Our research and experimentation focus on:
|
Our research and experimentation focus on:
|
||||||
|
|
||||||
@@ -285,22 +298,22 @@ Our research and experimentation focus on:
|
|||||||
|
|
||||||
## 🔧 Prerequisites
|
## 🔧 Prerequisites
|
||||||
|
|
||||||
- **Linux/macOS** (or WSL2 on Windows)
|
- **Linux/macOS/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), [Windsurf](https://windsurf.com/), or [Amazon Q Developer CLI](https://aws.amazon.com/developer/learning/q-developer-cli/)
|
- [Supported](#-supported-ai-agents) AI coding agent.
|
||||||
- [uv](https://docs.astral.sh/uv/) for package management
|
- [uv](https://docs.astral.sh/uv/) for package management
|
||||||
- [Python 3.11+](https://www.python.org/downloads/)
|
- [Python 3.11+](https://www.python.org/downloads/)
|
||||||
- [Git](https://git-scm.com/downloads)
|
- [Git](https://git-scm.com/downloads)
|
||||||
|
|
||||||
If you encounter issues with an agent, please open an issue so we can refine the integration.
|
If you encounter issues with an agent, please open an issue so we can refine the integration.
|
||||||
|
|
||||||
## 📖 Learn more
|
## 📖 Learn More
|
||||||
|
|
||||||
- **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process
|
- **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process
|
||||||
- **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide
|
- **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Detailed process
|
## 📋 Detailed Process
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>Click to expand the detailed step-by-step walkthrough</summary>
|
<summary>Click to expand the detailed step-by-step walkthrough</summary>
|
||||||
@@ -374,7 +387,7 @@ This step creates or updates the `.specify/memory/constitution.md` file with you
|
|||||||
With your project principles established, you can now create the functional specifications. Use the `/speckit.specify` command and then provide the concrete requirements for the project you want to develop.
|
With your project principles established, you can now create the functional specifications. Use the `/speckit.specify` command and then provide the concrete requirements for the project you want to develop.
|
||||||
|
|
||||||
>[!IMPORTANT]
|
>[!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**.
|
>Be as explicit as possible about *what* you are trying to build and *why*. **Do not focus on the tech stack at this point**.
|
||||||
|
|
||||||
An example prompt:
|
An example prompt:
|
||||||
|
|
||||||
@@ -408,16 +421,16 @@ At this stage, your project folder contents should resemble the following:
|
|||||||
```text
|
```text
|
||||||
└── .specify
|
└── .specify
|
||||||
├── memory
|
├── memory
|
||||||
│ └── constitution.md
|
│ └── constitution.md
|
||||||
├── scripts
|
├── scripts
|
||||||
│ ├── check-prerequisites.sh
|
│ ├── check-prerequisites.sh
|
||||||
│ ├── common.sh
|
│ ├── common.sh
|
||||||
│ ├── create-new-feature.sh
|
│ ├── create-new-feature.sh
|
||||||
│ ├── setup-plan.sh
|
│ ├── setup-plan.sh
|
||||||
│ └── update-claude-md.sh
|
│ └── update-claude-md.sh
|
||||||
├── specs
|
├── specs
|
||||||
│ └── 001-create-taskify
|
│ └── 001-create-taskify
|
||||||
│ └── spec.md
|
│ └── spec.md
|
||||||
└── templates
|
└── templates
|
||||||
├── plan-template.md
|
├── plan-template.md
|
||||||
├── spec-template.md
|
├── spec-template.md
|
||||||
@@ -431,6 +444,7 @@ With the baseline specification created, you can go ahead and clarify any of the
|
|||||||
You should run the structured clarification workflow **before** creating a technical plan to reduce rework downstream.
|
You should run the structured clarification workflow **before** creating a technical plan to reduce rework downstream.
|
||||||
|
|
||||||
Preferred order:
|
Preferred order:
|
||||||
|
|
||||||
1. Use `/speckit.clarify` (structured) – sequential, coverage-based questioning that records answers in a Clarifications section.
|
1. Use `/speckit.clarify` (structured) – sequential, coverage-based questioning that records answers in a Clarifications section.
|
||||||
2. Optionally follow up with ad-hoc free-form refinement if something still feels vague.
|
2. Optionally follow up with ad-hoc free-form refinement if something still feels vague.
|
||||||
|
|
||||||
@@ -468,23 +482,23 @@ The output of this step will include a number of implementation detail documents
|
|||||||
.
|
.
|
||||||
├── CLAUDE.md
|
├── CLAUDE.md
|
||||||
├── memory
|
├── memory
|
||||||
│ └── constitution.md
|
│ └── constitution.md
|
||||||
├── scripts
|
├── scripts
|
||||||
│ ├── check-prerequisites.sh
|
│ ├── check-prerequisites.sh
|
||||||
│ ├── common.sh
|
│ ├── common.sh
|
||||||
│ ├── create-new-feature.sh
|
│ ├── create-new-feature.sh
|
||||||
│ ├── setup-plan.sh
|
│ ├── setup-plan.sh
|
||||||
│ └── update-claude-md.sh
|
│ └── update-claude-md.sh
|
||||||
├── specs
|
├── specs
|
||||||
│ └── 001-create-taskify
|
│ └── 001-create-taskify
|
||||||
│ ├── contracts
|
│ ├── contracts
|
||||||
│ │ ├── api-spec.json
|
│ │ ├── api-spec.json
|
||||||
│ │ └── signalr-spec.md
|
│ │ └── signalr-spec.md
|
||||||
│ ├── data-model.md
|
│ ├── data-model.md
|
||||||
│ ├── plan.md
|
│ ├── plan.md
|
||||||
│ ├── quickstart.md
|
│ ├── quickstart.md
|
||||||
│ ├── research.md
|
│ ├── research.md
|
||||||
│ └── spec.md
|
│ └── spec.md
|
||||||
└── templates
|
└── templates
|
||||||
├── CLAUDE-template.md
|
├── CLAUDE-template.md
|
||||||
├── plan-template.md
|
├── plan-template.md
|
||||||
@@ -538,7 +552,26 @@ You can also ask Claude Code (if you have the [GitHub CLI](https://docs.github.c
|
|||||||
>[!NOTE]
|
>[!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](base/memory/constitution.md) as the foundational piece that it must adhere to when establishing the plan.
|
||||||
|
|
||||||
### STEP 6: Implementation
|
### **STEP 6:** Generate task breakdown with /speckit.tasks
|
||||||
|
|
||||||
|
With the implementation plan validated, you can now break down the plan into specific, actionable tasks that can be executed in the correct order. Use the `/speckit.tasks` command to automatically generate a detailed task breakdown from your implementation plan:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/speckit.tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
This step creates a `tasks.md` file in your feature specification directory that contains:
|
||||||
|
|
||||||
|
- **Task breakdown organized by user story** - Each user story becomes a separate implementation phase with its own set of tasks
|
||||||
|
- **Dependency management** - Tasks are ordered to respect dependencies between components (e.g., models before services, services before endpoints)
|
||||||
|
- **Parallel execution markers** - Tasks that can run in parallel are marked with `[P]` to optimize development workflow
|
||||||
|
- **File path specifications** - Each task includes the exact file paths where implementation should occur
|
||||||
|
- **Test-driven development structure** - If tests are requested, test tasks are included and ordered to be written before implementation
|
||||||
|
- **Checkpoint validation** - Each user story phase includes checkpoints to validate independent functionality
|
||||||
|
|
||||||
|
The generated tasks.md provides a clear roadmap for the `/speckit.implement` command, ensuring systematic implementation that maintains code quality and allows for incremental delivery of user stories.
|
||||||
|
|
||||||
|
### **STEP 7:** Implementation
|
||||||
|
|
||||||
Once ready, use the `/speckit.implement` command to execute your implementation plan:
|
Once ready, use the `/speckit.implement` command to execute your implementation plan:
|
||||||
|
|
||||||
@@ -547,6 +580,7 @@ Once ready, use the `/speckit.implement` command to execute your implementation
|
|||||||
```
|
```
|
||||||
|
|
||||||
The `/speckit.implement` command will:
|
The `/speckit.implement` command will:
|
||||||
|
|
||||||
- Validate that all prerequisites are in place (constitution, spec, plan, and tasks)
|
- Validate that all prerequisites are in place (constitution, spec, plan, and tasks)
|
||||||
- Parse the task breakdown from `tasks.md`
|
- Parse the task breakdown from `tasks.md`
|
||||||
- Execute tasks in the correct order, respecting dependencies and parallel execution markers
|
- Execute tasks in the correct order, respecting dependencies and parallel execution markers
|
||||||
|
|||||||
22
SECURITY.md
22
SECURITY.md
@@ -1,10 +1,10 @@
|
|||||||
Thanks for helping make GitHub safe for everyone.
|
# Security Policy
|
||||||
|
|
||||||
# Security
|
Thanks for helping make GitHub safe for everyone.
|
||||||
|
|
||||||
GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub).
|
GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub).
|
||||||
|
|
||||||
Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation.
|
Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation.
|
||||||
|
|
||||||
## Reporting Security Issues
|
## Reporting Security Issues
|
||||||
|
|
||||||
@@ -16,16 +16,16 @@ 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:
|
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)
|
- 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
|
- 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)
|
- The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
* Any special configuration required to reproduce the issue
|
- Any special configuration required to reproduce the issue
|
||||||
* Step-by-step instructions to reproduce the issue
|
- Step-by-step instructions to reproduce the issue
|
||||||
* Proof-of-concept or exploit code (if possible)
|
- Proof-of-concept or exploit code (if possible)
|
||||||
* Impact of the issue, including how an attacker might exploit the issue
|
- Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
This information will help us triage your report more quickly.
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
## Policy
|
## Policy
|
||||||
|
|
||||||
See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
|
See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Support
|
# Support
|
||||||
|
|
||||||
## How to file issues and get help
|
## How to file issues and get help
|
||||||
|
|
||||||
|
|||||||
1
docs/.gitignore
vendored
1
docs/.gitignore
vendored
@@ -6,3 +6,4 @@ obj/
|
|||||||
# Temporary files
|
# Temporary files
|
||||||
*.tmp
|
*.tmp
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ This folder contains the documentation source files for Spec Kit, built using [D
|
|||||||
To build the documentation locally:
|
To build the documentation locally:
|
||||||
|
|
||||||
1. Install DocFX:
|
1. Install DocFX:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet tool install -g docfx
|
dotnet tool install -g docfx
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Build the documentation:
|
2. Build the documentation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd docs
|
cd docs
|
||||||
docfx docfx.json --serve
|
docfx docfx.json --serve
|
||||||
|
|||||||
@@ -68,3 +68,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Spec-Driven Development **flips the script** on traditional software development
|
|||||||
|
|
||||||
Spec-Driven Development is a structured process that emphasizes:
|
Spec-Driven Development is a structured process that emphasizes:
|
||||||
|
|
||||||
- **Intent-driven development** where specifications define the "_what_" before the "_how_"
|
- **Intent-driven development** where specifications define the "*what*" before the "*how*"
|
||||||
- **Rich specification creation** using guardrails and organizational principles
|
- **Rich specification creation** using guardrails and organizational principles
|
||||||
- **Multi-step refinement** rather than one-shot code generation from prompts
|
- **Multi-step refinement** rather than one-shot code generation from prompts
|
||||||
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
||||||
@@ -36,19 +36,23 @@ Spec-Driven Development is a structured process that emphasizes:
|
|||||||
Our research and experimentation focus on:
|
Our research and experimentation focus on:
|
||||||
|
|
||||||
### Technology Independence
|
### Technology Independence
|
||||||
|
|
||||||
- Create applications using diverse technology stacks
|
- Create applications using diverse technology stacks
|
||||||
- Validate the hypothesis that Spec-Driven Development is a process not tied to specific technologies, programming languages, or frameworks
|
- Validate the hypothesis that Spec-Driven Development is a process not tied to specific technologies, programming languages, or frameworks
|
||||||
|
|
||||||
### Enterprise Constraints
|
### Enterprise Constraints
|
||||||
|
|
||||||
- Demonstrate mission-critical application development
|
- Demonstrate mission-critical application development
|
||||||
- Incorporate organizational constraints (cloud providers, tech stacks, engineering practices)
|
- Incorporate organizational constraints (cloud providers, tech stacks, engineering practices)
|
||||||
- Support enterprise design systems and compliance requirements
|
- Support enterprise design systems and compliance requirements
|
||||||
|
|
||||||
### User-Centric Development
|
### User-Centric Development
|
||||||
|
|
||||||
- Build applications for different user cohorts and preferences
|
- Build applications for different user cohorts and preferences
|
||||||
- Support various development approaches (from vibe-coding to AI-native development)
|
- Support various development approaches (from vibe-coding to AI-native development)
|
||||||
|
|
||||||
### Creative & Iterative Processes
|
### Creative & Iterative Processes
|
||||||
|
|
||||||
- Validate the concept of parallel implementation exploration
|
- Validate the concept of parallel implementation exploration
|
||||||
- Provide robust iterative feature development workflows
|
- Provide robust iterative feature development workflows
|
||||||
- Extend processes to handle upgrades and modernization tasks
|
- Extend processes to handle upgrades and modernization tasks
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- **Linux/macOS** (or Windows; PowerShell scripts now supported without WSL)
|
- **Linux/macOS** (or Windows; PowerShell scripts now supported without WSL)
|
||||||
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), or [Gemini CLI](https://github.com/google-gemini/gemini-cli)
|
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Codebuddy CLI](https://www.codebuddy.ai/cli) or [Gemini CLI](https://github.com/google-gemini/gemini-cli)
|
||||||
- [uv](https://docs.astral.sh/uv/) for package management
|
- [uv](https://docs.astral.sh/uv/) for package management
|
||||||
- [Python 3.11+](https://www.python.org/downloads/)
|
- [Python 3.11+](https://www.python.org/downloads/)
|
||||||
- [Git](https://git-scm.com/downloads)
|
- [Git](https://git-scm.com/downloads)
|
||||||
@@ -34,6 +34,7 @@ You can proactively specify your AI agent during initialization:
|
|||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai claude
|
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai claude
|
||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai gemini
|
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai gemini
|
||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai copilot
|
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai copilot
|
||||||
|
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai codebuddy
|
||||||
```
|
```
|
||||||
|
|
||||||
### Specify Script Type (Shell vs PowerShell)
|
### Specify Script Type (Shell vs PowerShell)
|
||||||
@@ -41,11 +42,13 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <project_name
|
|||||||
All automation scripts now have both Bash (`.sh`) and PowerShell (`.ps1`) variants.
|
All automation scripts now have both Bash (`.sh`) and PowerShell (`.ps1`) variants.
|
||||||
|
|
||||||
Auto behavior:
|
Auto behavior:
|
||||||
|
|
||||||
- Windows default: `ps`
|
- Windows default: `ps`
|
||||||
- Other OS default: `sh`
|
- Other OS default: `sh`
|
||||||
- Interactive mode: you'll be prompted unless you pass `--script`
|
- Interactive mode: you'll be prompted unless you pass `--script`
|
||||||
|
|
||||||
Force a specific script type:
|
Force a specific script type:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --script sh
|
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --script sh
|
||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --script ps
|
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --script ps
|
||||||
@@ -62,6 +65,7 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <project_name
|
|||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
After initialization, you should see the following commands available in your AI agent:
|
After initialization, you should see the following commands available in your AI agent:
|
||||||
|
|
||||||
- `/speckit.specify` - Create specifications
|
- `/speckit.specify` - Create specifications
|
||||||
- `/speckit.plan` - Generate implementation plans
|
- `/speckit.plan` - Generate implementation plans
|
||||||
- `/speckit.tasks` - Break down into actionable tasks
|
- `/speckit.tasks` - Break down into actionable tasks
|
||||||
|
|||||||
@@ -73,12 +73,14 @@ uvx --from /mnt/c/GitHub/spec-kit specify init demo-anywhere --ai copilot --igno
|
|||||||
```
|
```
|
||||||
|
|
||||||
Set an environment variable for convenience:
|
Set an environment variable for convenience:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export SPEC_KIT_SRC=/mnt/c/GitHub/spec-kit
|
export SPEC_KIT_SRC=/mnt/c/GitHub/spec-kit
|
||||||
uvx --from "$SPEC_KIT_SRC" specify init demo-env --ai copilot --ignore-agent-tools --script ps
|
uvx --from "$SPEC_KIT_SRC" specify init demo-env --ai copilot --ignore-agent-tools --script ps
|
||||||
```
|
```
|
||||||
|
|
||||||
(Optional) Define a shell function:
|
(Optional) Define a shell function:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
specify-dev() { uvx --from /mnt/c/GitHub/spec-kit specify "$@"; }
|
specify-dev() { uvx --from /mnt/c/GitHub/spec-kit specify "$@"; }
|
||||||
# Then
|
# Then
|
||||||
@@ -93,11 +95,13 @@ After running an `init`, check that shell scripts are executable on POSIX system
|
|||||||
ls -l scripts | grep .sh
|
ls -l scripts | grep .sh
|
||||||
# Expect owner execute bit (e.g. -rwxr-xr-x)
|
# Expect owner execute bit (e.g. -rwxr-xr-x)
|
||||||
```
|
```
|
||||||
|
|
||||||
On Windows you will instead use the `.ps1` scripts (no chmod needed).
|
On Windows you will instead use the `.ps1` scripts (no chmod needed).
|
||||||
|
|
||||||
## 6. Run Lint / Basic Checks (Add Your Own)
|
## 6. Run Lint / Basic Checks (Add Your Own)
|
||||||
|
|
||||||
Currently no enforced lint config is bundled, but you can quickly sanity check importability:
|
Currently no enforced lint config is bundled, but you can quickly sanity check importability:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -c "import specify_cli; print('Import OK')"
|
python -c "import specify_cli; print('Import OK')"
|
||||||
```
|
```
|
||||||
@@ -110,6 +114,7 @@ Validate packaging before publishing:
|
|||||||
uv build
|
uv build
|
||||||
ls dist/
|
ls dist/
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the built artifact into a fresh throwaway environment if needed.
|
Install the built artifact into a fresh throwaway environment if needed.
|
||||||
|
|
||||||
## 8. Using a Temporary Workspace
|
## 8. Using a Temporary Workspace
|
||||||
@@ -120,6 +125,7 @@ When testing `init --here` in a dirty directory, create a temp workspace:
|
|||||||
mkdir /tmp/spec-test && cd /tmp/spec-test
|
mkdir /tmp/spec-test && cd /tmp/spec-test
|
||||||
python -m src.specify_cli init --here --ai claude --ignore-agent-tools --script sh # if repo copied here
|
python -m src.specify_cli init --here --ai claude --ignore-agent-tools --script sh # if repo copied here
|
||||||
```
|
```
|
||||||
|
|
||||||
Or copy only the modified CLI portion if you want a lighter sandbox.
|
Or copy only the modified CLI portion if you want a lighter sandbox.
|
||||||
|
|
||||||
## 9. Debug Network / TLS Skips
|
## 9. Debug Network / TLS Skips
|
||||||
@@ -130,6 +136,7 @@ If you need to bypass TLS validation while experimenting:
|
|||||||
specify check --skip-tls
|
specify check --skip-tls
|
||||||
specify init demo --skip-tls --ai gemini --ignore-agent-tools --script ps
|
specify init demo --skip-tls --ai gemini --ignore-agent-tools --script ps
|
||||||
```
|
```
|
||||||
|
|
||||||
(Use only for local experimentation.)
|
(Use only for local experimentation.)
|
||||||
|
|
||||||
## 10. Rapid Edit Loop Summary
|
## 10. Rapid Edit Loop Summary
|
||||||
@@ -146,6 +153,7 @@ specify init demo --skip-tls --ai gemini --ignore-agent-tools --script ps
|
|||||||
## 11. Cleaning Up
|
## 11. Cleaning Up
|
||||||
|
|
||||||
Remove build artifacts / virtual env quickly:
|
Remove build artifacts / virtual env quickly:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rm -rf .venv dist build *.egg-info
|
rm -rf .venv dist build *.egg-info
|
||||||
```
|
```
|
||||||
@@ -165,4 +173,3 @@ rm -rf .venv dist build *.egg-info
|
|||||||
- Update docs and run through Quick Start using your modified CLI
|
- Update docs and run through Quick Start using your modified CLI
|
||||||
- Open a PR when satisfied
|
- Open a PR when satisfied
|
||||||
- (Optional) Tag a release once changes land in `main`
|
- (Optional) Tag a release once changes land in `main`
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME
|
|||||||
```
|
```
|
||||||
|
|
||||||
Pick script type explicitly (optional):
|
Pick script type explicitly (optional):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME> --script ps # Force PowerShell
|
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME> --script ps # Force PowerShell
|
||||||
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME> --script sh # Force POSIX shell
|
uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME> --script sh # Force POSIX shell
|
||||||
|
|||||||
@@ -15,3 +15,4 @@
|
|||||||
items:
|
items:
|
||||||
- name: Local Development
|
- name: Local Development
|
||||||
href: local-development.md
|
href: local-development.md
|
||||||
|
|
||||||
|
|||||||
@@ -47,4 +47,4 @@
|
|||||||
<!-- Example: All PRs/reviews must verify compliance; Complexity must be justified; Use [GUIDANCE_FILE] for runtime development guidance -->
|
<!-- Example: All PRs/reviews must verify compliance; Complexity must be justified; Use [GUIDANCE_FILE] for runtime development guidance -->
|
||||||
|
|
||||||
**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
|
**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
|
||||||
<!-- Example: Version: 2.1.1 | Ratified: 2025-06-13 | Last Amended: 2025-07-16 -->
|
<!-- Example: Version: 2.1.1 | Ratified: 2025-06-13 | Last Amended: 2025-07-16 -->
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "specify-cli"
|
name = "specify-cli"
|
||||||
version = "0.0.18"
|
version = "0.0.20"
|
||||||
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
|
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -21,3 +21,4 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["src/specify_cli"]
|
packages = ["src/specify_cli"]
|
||||||
|
|
||||||
|
|||||||
@@ -163,4 +163,4 @@ else
|
|||||||
if $INCLUDE_TASKS; then
|
if $INCLUDE_TASKS; then
|
||||||
check_file "$TASKS" "tasks.md"
|
check_file "$TASKS" "tasks.md"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -19,21 +19,21 @@ get_current_branch() {
|
|||||||
echo "$SPECIFY_FEATURE"
|
echo "$SPECIFY_FEATURE"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Then check git if available
|
# Then check git if available
|
||||||
if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
|
if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
|
||||||
git rev-parse --abbrev-ref HEAD
|
git rev-parse --abbrev-ref HEAD
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For non-git repos, try to find the latest feature directory
|
# For non-git repos, try to find the latest feature directory
|
||||||
local repo_root=$(get_repo_root)
|
local repo_root=$(get_repo_root)
|
||||||
local specs_dir="$repo_root/specs"
|
local specs_dir="$repo_root/specs"
|
||||||
|
|
||||||
if [[ -d "$specs_dir" ]]; then
|
if [[ -d "$specs_dir" ]]; then
|
||||||
local latest_feature=""
|
local latest_feature=""
|
||||||
local highest=0
|
local highest=0
|
||||||
|
|
||||||
for dir in "$specs_dir"/*; do
|
for dir in "$specs_dir"/*; do
|
||||||
if [[ -d "$dir" ]]; then
|
if [[ -d "$dir" ]]; then
|
||||||
local dirname=$(basename "$dir")
|
local dirname=$(basename "$dir")
|
||||||
@@ -47,13 +47,13 @@ get_current_branch() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ -n "$latest_feature" ]]; then
|
if [[ -n "$latest_feature" ]]; then
|
||||||
echo "$latest_feature"
|
echo "$latest_feature"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "main" # Final fallback
|
echo "main" # Final fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,35 +65,77 @@ has_git() {
|
|||||||
check_feature_branch() {
|
check_feature_branch() {
|
||||||
local branch="$1"
|
local branch="$1"
|
||||||
local has_git_repo="$2"
|
local has_git_repo="$2"
|
||||||
|
|
||||||
# For non-git repos, we can't enforce branch naming but still provide output
|
# For non-git repos, we can't enforce branch naming but still provide output
|
||||||
if [[ "$has_git_repo" != "true" ]]; then
|
if [[ "$has_git_repo" != "true" ]]; then
|
||||||
echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
|
echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! "$branch" =~ ^[0-9]{3}- ]]; then
|
if [[ ! "$branch" =~ ^[0-9]{3}- ]]; then
|
||||||
echo "ERROR: Not on a feature branch. Current branch: $branch" >&2
|
echo "ERROR: Not on a feature branch. Current branch: $branch" >&2
|
||||||
echo "Feature branches should be named like: 001-feature-name" >&2
|
echo "Feature branches should be named like: 001-feature-name" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
get_feature_dir() { echo "$1/specs/$2"; }
|
get_feature_dir() { echo "$1/specs/$2"; }
|
||||||
|
|
||||||
|
# Find feature directory by numeric prefix instead of exact branch match
|
||||||
|
# This allows multiple branches to work on the same spec (e.g., 004-fix-bug, 004-add-feature)
|
||||||
|
find_feature_dir_by_prefix() {
|
||||||
|
local repo_root="$1"
|
||||||
|
local branch_name="$2"
|
||||||
|
local specs_dir="$repo_root/specs"
|
||||||
|
|
||||||
|
# Extract numeric prefix from branch (e.g., "004" from "004-whatever")
|
||||||
|
if [[ ! "$branch_name" =~ ^([0-9]{3})- ]]; then
|
||||||
|
# If branch doesn't have numeric prefix, fall back to exact match
|
||||||
|
echo "$specs_dir/$branch_name"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local prefix="${BASH_REMATCH[1]}"
|
||||||
|
|
||||||
|
# Search for directories in specs/ that start with this prefix
|
||||||
|
local matches=()
|
||||||
|
if [[ -d "$specs_dir" ]]; then
|
||||||
|
for dir in "$specs_dir"/"$prefix"-*; do
|
||||||
|
if [[ -d "$dir" ]]; then
|
||||||
|
matches+=("$(basename "$dir")")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Handle results
|
||||||
|
if [[ ${#matches[@]} -eq 0 ]]; then
|
||||||
|
# No match found - return the branch name path (will fail later with clear error)
|
||||||
|
echo "$specs_dir/$branch_name"
|
||||||
|
elif [[ ${#matches[@]} -eq 1 ]]; then
|
||||||
|
# Exactly one match - perfect!
|
||||||
|
echo "$specs_dir/${matches[0]}"
|
||||||
|
else
|
||||||
|
# Multiple matches - this shouldn't happen with proper naming convention
|
||||||
|
echo "ERROR: Multiple spec directories found with prefix '$prefix': ${matches[*]}" >&2
|
||||||
|
echo "Please ensure only one spec directory exists per numeric prefix." >&2
|
||||||
|
echo "$specs_dir/$branch_name" # Return something to avoid breaking the script
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
get_feature_paths() {
|
get_feature_paths() {
|
||||||
local repo_root=$(get_repo_root)
|
local repo_root=$(get_repo_root)
|
||||||
local current_branch=$(get_current_branch)
|
local current_branch=$(get_current_branch)
|
||||||
local has_git_repo="false"
|
local has_git_repo="false"
|
||||||
|
|
||||||
if has_git; then
|
if has_git; then
|
||||||
has_git_repo="true"
|
has_git_repo="true"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local feature_dir=$(get_feature_dir "$repo_root" "$current_branch")
|
# Use prefix-based lookup to support multiple branches per spec
|
||||||
|
local feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch")
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
REPO_ROOT='$repo_root'
|
REPO_ROOT='$repo_root'
|
||||||
CURRENT_BRANCH='$current_branch'
|
CURRENT_BRANCH='$current_branch'
|
||||||
@@ -111,3 +153,4 @@ EOF
|
|||||||
|
|
||||||
check_file() { [[ -f "$1" ]] && echo " ✓ $2" || echo " ✗ $2"; }
|
check_file() { [[ -f "$1" ]] && echo " ✓ $2" || echo " ✗ $2"; }
|
||||||
check_dir() { [[ -d "$1" && -n $(ls -A "$1" 2>/dev/null) ]] && echo " ✓ $2" || echo " ✗ $2"; }
|
check_dir() { [[ -d "$1" && -n $(ls -A "$1" 2>/dev/null) ]] && echo " ✓ $2" || echo " ✗ $2"; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,18 +3,52 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
JSON_MODE=false
|
JSON_MODE=false
|
||||||
|
SHORT_NAME=""
|
||||||
ARGS=()
|
ARGS=()
|
||||||
for arg in "$@"; do
|
i=1
|
||||||
|
while [ $i -le $# ]; do
|
||||||
|
arg="${!i}"
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--json) JSON_MODE=true ;;
|
--json)
|
||||||
--help|-h) echo "Usage: $0 [--json] <feature_description>"; exit 0 ;;
|
JSON_MODE=true
|
||||||
*) ARGS+=("$arg") ;;
|
;;
|
||||||
|
--short-name)
|
||||||
|
if [ $((i + 1)) -gt $# ]; then
|
||||||
|
echo 'Error: --short-name requires a value' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
i=$((i + 1))
|
||||||
|
next_arg="${!i}"
|
||||||
|
# Check if the next argument is another option (starts with --)
|
||||||
|
if [[ "$next_arg" == --* ]]; then
|
||||||
|
echo 'Error: --short-name requires a value' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SHORT_NAME="$next_arg"
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --json Output in JSON format"
|
||||||
|
echo " --short-name <name> Provide a custom short name (2-4 words) for the branch"
|
||||||
|
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'"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
ARGS+=("$arg")
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
i=$((i + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
FEATURE_DESCRIPTION="${ARGS[*]}"
|
FEATURE_DESCRIPTION="${ARGS[*]}"
|
||||||
if [ -z "$FEATURE_DESCRIPTION" ]; then
|
if [ -z "$FEATURE_DESCRIPTION" ]; then
|
||||||
echo "Usage: $0 [--json] <feature_description>" >&2
|
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -67,9 +101,84 @@ fi
|
|||||||
NEXT=$((HIGHEST + 1))
|
NEXT=$((HIGHEST + 1))
|
||||||
FEATURE_NUM=$(printf "%03d" "$NEXT")
|
FEATURE_NUM=$(printf "%03d" "$NEXT")
|
||||||
|
|
||||||
BRANCH_NAME=$(echo "$FEATURE_DESCRIPTION" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//')
|
# Function to generate branch name with stop word filtering and length filtering
|
||||||
WORDS=$(echo "$BRANCH_NAME" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//')
|
generate_branch_name() {
|
||||||
BRANCH_NAME="${FEATURE_NUM}-${WORDS}"
|
local description="$1"
|
||||||
|
|
||||||
|
# Common stop words to filter out
|
||||||
|
local stop_words="^(i|a|an|the|to|for|of|in|on|at|by|with|from|is|are|was|were|be|been|being|have|has|had|do|does|did|will|would|should|could|can|may|might|must|shall|this|that|these|those|my|your|our|their|want|need|add|get|set)$"
|
||||||
|
|
||||||
|
# Convert to lowercase and split into words
|
||||||
|
local clean_name=$(echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
|
||||||
|
|
||||||
|
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
|
||||||
|
local meaningful_words=()
|
||||||
|
for word in $clean_name; do
|
||||||
|
# Skip empty words
|
||||||
|
[ -z "$word" ] && continue
|
||||||
|
|
||||||
|
# Keep words that are NOT stop words AND (length >= 3 OR are potential acronyms)
|
||||||
|
if ! echo "$word" | grep -qiE "$stop_words"; then
|
||||||
|
if [ ${#word} -ge 3 ]; then
|
||||||
|
meaningful_words+=("$word")
|
||||||
|
elif echo "$description" | grep -q "\b${word^^}\b"; then
|
||||||
|
# Keep short words if they appear as uppercase in original (likely acronyms)
|
||||||
|
meaningful_words+=("$word")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If we have meaningful words, use first 3-4 of them
|
||||||
|
if [ ${#meaningful_words[@]} -gt 0 ]; then
|
||||||
|
local max_words=3
|
||||||
|
if [ ${#meaningful_words[@]} -eq 4 ]; then max_words=4; fi
|
||||||
|
|
||||||
|
local result=""
|
||||||
|
local count=0
|
||||||
|
for word in "${meaningful_words[@]}"; do
|
||||||
|
if [ $count -ge $max_words ]; then break; fi
|
||||||
|
if [ -n "$result" ]; then result="$result-"; fi
|
||||||
|
result="$result$word"
|
||||||
|
count=$((count + 1))
|
||||||
|
done
|
||||||
|
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/-$//'
|
||||||
|
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/-$//')
|
||||||
|
else
|
||||||
|
# Generate from description with smart filtering
|
||||||
|
BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
|
||||||
|
fi
|
||||||
|
|
||||||
|
BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
|
||||||
|
|
||||||
|
# GitHub enforces a 244-byte limit on branch names
|
||||||
|
# Validate and truncate if necessary
|
||||||
|
MAX_BRANCH_LENGTH=244
|
||||||
|
if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
|
||||||
|
# Calculate how much we need to trim from suffix
|
||||||
|
# Account for: feature number (3) + hyphen (1) = 4 chars
|
||||||
|
MAX_SUFFIX_LENGTH=$((MAX_BRANCH_LENGTH - 4))
|
||||||
|
|
||||||
|
# Truncate suffix at word boundary if possible
|
||||||
|
TRUNCATED_SUFFIX=$(echo "$BRANCH_SUFFIX" | cut -c1-$MAX_SUFFIX_LENGTH)
|
||||||
|
# Remove trailing hyphen if truncation created one
|
||||||
|
TRUNCATED_SUFFIX=$(echo "$TRUNCATED_SUFFIX" | sed 's/-$//')
|
||||||
|
|
||||||
|
ORIGINAL_BRANCH_NAME="$BRANCH_NAME"
|
||||||
|
BRANCH_NAME="${FEATURE_NUM}-${TRUNCATED_SUFFIX}"
|
||||||
|
|
||||||
|
>&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
|
||||||
|
>&2 echo "[specify] Original: $ORIGINAL_BRANCH_NAME (${#ORIGINAL_BRANCH_NAME} bytes)"
|
||||||
|
>&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$HAS_GIT" = true ]; then
|
if [ "$HAS_GIT" = true ]; then
|
||||||
git checkout -b "$BRANCH_NAME"
|
git checkout -b "$BRANCH_NAME"
|
||||||
|
|||||||
@@ -58,3 +58,4 @@ else
|
|||||||
echo "BRANCH: $CURRENT_BRANCH"
|
echo "BRANCH: $CURRENT_BRANCH"
|
||||||
echo "HAS_GIT: $HAS_GIT"
|
echo "HAS_GIT: $HAS_GIT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,12 @@
|
|||||||
#
|
#
|
||||||
# 5. Multi-Agent Support
|
# 5. Multi-Agent Support
|
||||||
# - Handles agent-specific file paths and naming conventions
|
# - Handles agent-specific file paths and naming conventions
|
||||||
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, or Amazon Q Developer CLI
|
# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Amp, or Amazon Q Developer CLI
|
||||||
# - Can update single agents or all existing agent files
|
# - Can update single agents or all existing agent files
|
||||||
# - Creates default Claude file if no agent files exist
|
# - Creates default Claude file if no agent files exist
|
||||||
#
|
#
|
||||||
# Usage: ./update-agent-context.sh [agent_type]
|
# Usage: ./update-agent-context.sh [agent_type]
|
||||||
# Agent types: claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|kilocode|auggie|q
|
# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|q
|
||||||
# Leave empty to update all existing agent files
|
# Leave empty to update all existing agent files
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -69,6 +69,8 @@ WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
|
|||||||
KILOCODE_FILE="$REPO_ROOT/.kilocode/rules/specify-rules.md"
|
KILOCODE_FILE="$REPO_ROOT/.kilocode/rules/specify-rules.md"
|
||||||
AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md"
|
AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md"
|
||||||
ROO_FILE="$REPO_ROOT/.roo/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"
|
||||||
Q_FILE="$REPO_ROOT/AGENTS.md"
|
Q_FILE="$REPO_ROOT/AGENTS.md"
|
||||||
|
|
||||||
# Template file
|
# Template file
|
||||||
@@ -249,7 +251,7 @@ get_commands_for_language() {
|
|||||||
echo "cargo test && cargo clippy"
|
echo "cargo test && cargo clippy"
|
||||||
;;
|
;;
|
||||||
*"JavaScript"*|*"TypeScript"*)
|
*"JavaScript"*|*"TypeScript"*)
|
||||||
echo "npm test && npm run lint"
|
echo "npm test \\&\\& npm run lint"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "# Add commands for $lang"
|
echo "# Add commands for $lang"
|
||||||
@@ -389,12 +391,25 @@ update_existing_agent_file() {
|
|||||||
new_change_entry="- $CURRENT_BRANCH: Added $NEW_DB"
|
new_change_entry="- $CURRENT_BRANCH: Added $NEW_DB"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check if sections exist in the file
|
||||||
|
local has_active_technologies=0
|
||||||
|
local has_recent_changes=0
|
||||||
|
|
||||||
|
if grep -q "^## Active Technologies" "$target_file" 2>/dev/null; then
|
||||||
|
has_active_technologies=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "^## Recent Changes" "$target_file" 2>/dev/null; then
|
||||||
|
has_recent_changes=1
|
||||||
|
fi
|
||||||
|
|
||||||
# Process file line by line
|
# Process file line by line
|
||||||
local in_tech_section=false
|
local in_tech_section=false
|
||||||
local in_changes_section=false
|
local in_changes_section=false
|
||||||
local tech_entries_added=false
|
local tech_entries_added=false
|
||||||
local changes_entries_added=false
|
local changes_entries_added=false
|
||||||
local existing_changes_count=0
|
local existing_changes_count=0
|
||||||
|
local file_ended=false
|
||||||
|
|
||||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
# Handle Active Technologies section
|
# Handle Active Technologies section
|
||||||
@@ -455,6 +470,22 @@ update_existing_agent_file() {
|
|||||||
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
|
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
|
||||||
if [[ $in_tech_section == true ]] && [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
if [[ $in_tech_section == true ]] && [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
||||||
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
||||||
|
tech_entries_added=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If sections don't exist, add them at the end of the file
|
||||||
|
if [[ $has_active_technologies -eq 0 ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
|
||||||
|
echo "" >> "$temp_file"
|
||||||
|
echo "## Active Technologies" >> "$temp_file"
|
||||||
|
printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
|
||||||
|
tech_entries_added=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $has_recent_changes -eq 0 ]] && [[ -n "$new_change_entry" ]]; then
|
||||||
|
echo "" >> "$temp_file"
|
||||||
|
echo "## Recent Changes" >> "$temp_file"
|
||||||
|
echo "$new_change_entry" >> "$temp_file"
|
||||||
|
changes_entries_added=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Move temp file to target atomically
|
# Move temp file to target atomically
|
||||||
@@ -557,7 +588,7 @@ update_specific_agent() {
|
|||||||
copilot)
|
copilot)
|
||||||
update_agent_file "$COPILOT_FILE" "GitHub Copilot"
|
update_agent_file "$COPILOT_FILE" "GitHub Copilot"
|
||||||
;;
|
;;
|
||||||
cursor)
|
cursor-agent)
|
||||||
update_agent_file "$CURSOR_FILE" "Cursor IDE"
|
update_agent_file "$CURSOR_FILE" "Cursor IDE"
|
||||||
;;
|
;;
|
||||||
qwen)
|
qwen)
|
||||||
@@ -581,12 +612,18 @@ update_specific_agent() {
|
|||||||
roo)
|
roo)
|
||||||
update_agent_file "$ROO_FILE" "Roo Code"
|
update_agent_file "$ROO_FILE" "Roo Code"
|
||||||
;;
|
;;
|
||||||
|
codebuddy)
|
||||||
|
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
|
||||||
|
;;
|
||||||
|
amp)
|
||||||
|
update_agent_file "$AMP_FILE" "Amp"
|
||||||
|
;;
|
||||||
q)
|
q)
|
||||||
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log_error "Unknown agent type '$agent_type'"
|
log_error "Unknown agent type '$agent_type'"
|
||||||
log_error "Expected: claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|kilocode|auggie|roo|q"
|
log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|q"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -646,6 +683,11 @@ update_all_existing_agents() {
|
|||||||
found_agent=true
|
found_agent=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$CODEBUDDY_FILE" ]]; then
|
||||||
|
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
|
||||||
|
found_agent=true
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -f "$Q_FILE" ]]; then
|
if [[ -f "$Q_FILE" ]]; then
|
||||||
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
||||||
found_agent=true
|
found_agent=true
|
||||||
@@ -674,7 +716,8 @@ print_summary() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
log_info "Usage: $0 [claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|kilocode|auggie|q]"
|
|
||||||
|
log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|codebuddy|q]"
|
||||||
}
|
}
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
@@ -726,3 +769,4 @@ main() {
|
|||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||||
main "$@"
|
main "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -145,4 +145,4 @@ if ($Json) {
|
|||||||
if ($IncludeTasks) {
|
if ($IncludeTasks) {
|
||||||
Test-FileExists -Path $paths.TASKS -Description 'tasks.md' | Out-Null
|
Test-FileExists -Path $paths.TASKS -Description 'tasks.md' | Out-Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,3 +134,4 @@ function Test-DirHasFiles {
|
|||||||
return $false
|
return $false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,20 +3,39 @@
|
|||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param(
|
param(
|
||||||
[switch]$Json,
|
[switch]$Json,
|
||||||
|
[string]$ShortName,
|
||||||
|
[switch]$Help,
|
||||||
[Parameter(ValueFromRemainingArguments = $true)]
|
[Parameter(ValueFromRemainingArguments = $true)]
|
||||||
[string[]]$FeatureDescription
|
[string[]]$FeatureDescription
|
||||||
)
|
)
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# Show help if requested
|
||||||
|
if ($Help) {
|
||||||
|
Write-Host "Usage: ./create-new-feature.ps1 [-Json] [-ShortName <name>] <feature description>"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Options:"
|
||||||
|
Write-Host " -Json Output in JSON format"
|
||||||
|
Write-Host " -ShortName <name> Provide a custom short name (2-4 words) for the branch"
|
||||||
|
Write-Host " -Help Show this help message"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Examples:"
|
||||||
|
Write-Host " ./create-new-feature.ps1 'Add user authentication system' -ShortName 'user-auth'"
|
||||||
|
Write-Host " ./create-new-feature.ps1 'Implement OAuth2 integration for API'"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if feature description provided
|
||||||
if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) {
|
if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) {
|
||||||
Write-Error "Usage: ./create-new-feature.ps1 [-Json] <feature description>"
|
Write-Error "Usage: ./create-new-feature.ps1 [-Json] [-ShortName <name>] <feature description>"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
$featureDesc = ($FeatureDescription -join ' ').Trim()
|
$featureDesc = ($FeatureDescription -join ' ').Trim()
|
||||||
|
|
||||||
# Resolve repository root. Prefer git information when available, but fall back
|
# Resolve repository root. Prefer git information when available, but fall back
|
||||||
# to searching for repository markers so the workflow still functions in repositories that
|
# to searching for repository markers so the workflow still functions in repositories that
|
||||||
# were initialised with --no-git.
|
# were initialized with --no-git.
|
||||||
function Find-RepositoryRoot {
|
function Find-RepositoryRoot {
|
||||||
param(
|
param(
|
||||||
[string]$StartDir,
|
[string]$StartDir,
|
||||||
@@ -72,9 +91,82 @@ if (Test-Path $specsDir) {
|
|||||||
$next = $highest + 1
|
$next = $highest + 1
|
||||||
$featureNum = ('{0:000}' -f $next)
|
$featureNum = ('{0:000}' -f $next)
|
||||||
|
|
||||||
$branchName = $featureDesc.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''
|
# Function to generate branch name with stop word filtering and length filtering
|
||||||
$words = ($branchName -split '-') | Where-Object { $_ } | Select-Object -First 3
|
function Get-BranchName {
|
||||||
$branchName = "$featureNum-$([string]::Join('-', $words))"
|
param([string]$Description)
|
||||||
|
|
||||||
|
# Common stop words to filter out
|
||||||
|
$stopWords = @(
|
||||||
|
'i', 'a', 'an', 'the', 'to', 'for', 'of', 'in', 'on', 'at', 'by', 'with', 'from',
|
||||||
|
'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had',
|
||||||
|
'do', 'does', 'did', 'will', 'would', 'should', 'could', 'can', 'may', 'might', 'must', 'shall',
|
||||||
|
'this', 'that', 'these', 'those', 'my', 'your', 'our', 'their',
|
||||||
|
'want', 'need', 'add', 'get', 'set'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Convert to lowercase and extract words (alphanumeric only)
|
||||||
|
$cleanName = $Description.ToLower() -replace '[^a-z0-9\s]', ' '
|
||||||
|
$words = $cleanName -split '\s+' | Where-Object { $_ }
|
||||||
|
|
||||||
|
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
|
||||||
|
$meaningfulWords = @()
|
||||||
|
foreach ($word in $words) {
|
||||||
|
# Skip stop words
|
||||||
|
if ($stopWords -contains $word) { continue }
|
||||||
|
|
||||||
|
# Keep words that are length >= 3 OR appear as uppercase in original (likely acronyms)
|
||||||
|
if ($word.Length -ge 3) {
|
||||||
|
$meaningfulWords += $word
|
||||||
|
} elseif ($Description -match "\b$($word.ToUpper())\b") {
|
||||||
|
# Keep short words if they appear as uppercase in original (likely acronyms)
|
||||||
|
$meaningfulWords += $word
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# If we have meaningful words, use first 3-4 of them
|
||||||
|
if ($meaningfulWords.Count -gt 0) {
|
||||||
|
$maxWords = if ($meaningfulWords.Count -eq 4) { 4 } else { 3 }
|
||||||
|
$result = ($meaningfulWords | Select-Object -First $maxWords) -join '-'
|
||||||
|
return $result
|
||||||
|
} else {
|
||||||
|
# Fallback to original logic if no meaningful words found
|
||||||
|
$result = $Description.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''
|
||||||
|
$fallbackWords = ($result -split '-') | Where-Object { $_ } | Select-Object -First 3
|
||||||
|
return [string]::Join('-', $fallbackWords)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate branch name
|
||||||
|
if ($ShortName) {
|
||||||
|
# Use provided short name, just clean it up
|
||||||
|
$branchSuffix = $ShortName.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''
|
||||||
|
} else {
|
||||||
|
# Generate from description with smart filtering
|
||||||
|
$branchSuffix = Get-BranchName -Description $featureDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
$branchName = "$featureNum-$branchSuffix"
|
||||||
|
|
||||||
|
# GitHub enforces a 244-byte limit on branch names
|
||||||
|
# Validate and truncate if necessary
|
||||||
|
$maxBranchLength = 244
|
||||||
|
if ($branchName.Length -gt $maxBranchLength) {
|
||||||
|
# Calculate how much we need to trim from suffix
|
||||||
|
# Account for: feature number (3) + hyphen (1) = 4 chars
|
||||||
|
$maxSuffixLength = $maxBranchLength - 4
|
||||||
|
|
||||||
|
# Truncate suffix
|
||||||
|
$truncatedSuffix = $branchSuffix.Substring(0, [Math]::Min($branchSuffix.Length, $maxSuffixLength))
|
||||||
|
# Remove trailing hyphen if truncation created one
|
||||||
|
$truncatedSuffix = $truncatedSuffix -replace '-$', ''
|
||||||
|
|
||||||
|
$originalBranchName = $branchName
|
||||||
|
$branchName = "$featureNum-$truncatedSuffix"
|
||||||
|
|
||||||
|
Write-Warning "[specify] Branch name exceeded GitHub's 244-byte limit"
|
||||||
|
Write-Warning "[specify] Original: $originalBranchName ($($originalBranchName.Length) bytes)"
|
||||||
|
Write-Warning "[specify] Truncated to: $branchName ($($branchName.Length) bytes)"
|
||||||
|
}
|
||||||
|
|
||||||
if ($hasGit) {
|
if ($hasGit) {
|
||||||
try {
|
try {
|
||||||
@@ -115,3 +207,4 @@ if ($Json) {
|
|||||||
Write-Output "HAS_GIT: $hasGit"
|
Write-Output "HAS_GIT: $hasGit"
|
||||||
Write-Output "SPECIFY_FEATURE environment variable set to: $branchName"
|
Write-Output "SPECIFY_FEATURE environment variable set to: $branchName"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,3 +59,4 @@ if ($Json) {
|
|||||||
Write-Output "BRANCH: $($paths.CURRENT_BRANCH)"
|
Write-Output "BRANCH: $($paths.CURRENT_BRANCH)"
|
||||||
Write-Output "HAS_GIT: $($paths.HAS_GIT)"
|
Write-Output "HAS_GIT: $($paths.HAS_GIT)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ Mirrors the behavior of scripts/bash/update-agent-context.sh:
|
|||||||
2. Plan Data Extraction
|
2. Plan Data Extraction
|
||||||
3. Agent File Management (create from template or update existing)
|
3. Agent File Management (create from template or update existing)
|
||||||
4. Content Generation (technology stack, recent changes, timestamp)
|
4. Content Generation (technology stack, recent changes, timestamp)
|
||||||
5. Multi-Agent Support (claude, gemini, copilot, cursor, qwen, opencode, codex, windsurf, kilocode, auggie, roo, q)
|
5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, amp, q)
|
||||||
|
|
||||||
.PARAMETER AgentType
|
.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).
|
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(
|
param(
|
||||||
[Parameter(Position=0)]
|
[Parameter(Position=0)]
|
||||||
[ValidateSet('claude','gemini','copilot','cursor','qwen','opencode','codex','windsurf','kilocode','auggie','roo','q')]
|
[ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','q')]
|
||||||
[string]$AgentType
|
[string]$AgentType
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,6 +54,8 @@ $WINDSURF_FILE = Join-Path $REPO_ROOT '.windsurf/rules/specify-rules.md'
|
|||||||
$KILOCODE_FILE = Join-Path $REPO_ROOT '.kilocode/rules/specify-rules.md'
|
$KILOCODE_FILE = Join-Path $REPO_ROOT '.kilocode/rules/specify-rules.md'
|
||||||
$AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md'
|
$AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md'
|
||||||
$ROO_FILE = Join-Path $REPO_ROOT '.roo/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'
|
||||||
$Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
$Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
||||||
|
|
||||||
$TEMPLATE_FILE = Join-Path $REPO_ROOT '.specify/templates/agent-file-template.md'
|
$TEMPLATE_FILE = Join-Path $REPO_ROOT '.specify/templates/agent-file-template.md'
|
||||||
@@ -369,7 +371,7 @@ function Update-SpecificAgent {
|
|||||||
'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' }
|
'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' }
|
||||||
'gemini' { Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI' }
|
'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' }
|
||||||
'cursor' { Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE' }
|
'cursor-agent' { Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE' }
|
||||||
'qwen' { Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code' }
|
'qwen' { Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code' }
|
||||||
'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' }
|
'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' }
|
||||||
'codex' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex CLI' }
|
'codex' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex CLI' }
|
||||||
@@ -377,8 +379,10 @@ function Update-SpecificAgent {
|
|||||||
'kilocode' { Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code' }
|
'kilocode' { Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code' }
|
||||||
'auggie' { Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI' }
|
'auggie' { Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI' }
|
||||||
'roo' { Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code' }
|
'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' }
|
||||||
'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' }
|
'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|qwen|opencode|codex|windsurf|kilocode|auggie|roo|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|q'; return $false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +399,7 @@ function Update-AllExistingAgents {
|
|||||||
if (Test-Path $KILOCODE_FILE) { if (-not (Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code')) { $ok = $false }; $found = $true }
|
if (Test-Path $KILOCODE_FILE) { if (-not (Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code')) { $ok = $false }; $found = $true }
|
||||||
if (Test-Path $AUGGIE_FILE) { if (-not (Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI')) { $ok = $false }; $found = $true }
|
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 $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 $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $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) {
|
if (-not $found) {
|
||||||
Write-Info 'No existing agent files found, creating default Claude file...'
|
Write-Info 'No existing agent files found, creating default Claude file...'
|
||||||
@@ -410,7 +415,7 @@ function Print-Summary {
|
|||||||
if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" }
|
if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" }
|
||||||
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" }
|
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" }
|
||||||
Write-Host ''
|
Write-Host ''
|
||||||
Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor|qwen|opencode|codex|windsurf|kilocode|auggie|roo|q]'
|
Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|q]'
|
||||||
}
|
}
|
||||||
|
|
||||||
function Main {
|
function Main {
|
||||||
@@ -431,3 +436,4 @@ function Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Main
|
Main
|
||||||
|
|
||||||
|
|||||||
@@ -64,19 +64,92 @@ def _github_auth_headers(cli_token: str | None = None) -> dict:
|
|||||||
token = _github_token(cli_token)
|
token = _github_token(cli_token)
|
||||||
return {"Authorization": f"Bearer {token}"} if token else {}
|
return {"Authorization": f"Bearer {token}"} if token else {}
|
||||||
|
|
||||||
AI_CHOICES = {
|
# Agent configuration with name, folder, install URL, and CLI tool requirement
|
||||||
"copilot": "GitHub Copilot",
|
AGENT_CONFIG = {
|
||||||
"claude": "Claude Code",
|
"copilot": {
|
||||||
"gemini": "Gemini CLI",
|
"name": "GitHub Copilot",
|
||||||
"cursor": "Cursor",
|
"folder": ".github/",
|
||||||
"qwen": "Qwen Code",
|
"install_url": None, # IDE-based, no CLI check needed
|
||||||
"opencode": "opencode",
|
"requires_cli": False,
|
||||||
"codex": "Codex CLI",
|
},
|
||||||
"windsurf": "Windsurf",
|
"claude": {
|
||||||
"kilocode": "Kilo Code",
|
"name": "Claude Code",
|
||||||
"auggie": "Auggie CLI",
|
"folder": ".claude/",
|
||||||
"roo": "Roo Code",
|
"install_url": "https://docs.anthropic.com/en/docs/claude-code/setup",
|
||||||
"q": "Amazon Q Developer CLI",
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"gemini": {
|
||||||
|
"name": "Gemini CLI",
|
||||||
|
"folder": ".gemini/",
|
||||||
|
"install_url": "https://github.com/google-gemini/gemini-cli",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"cursor-agent": {
|
||||||
|
"name": "Cursor",
|
||||||
|
"folder": ".cursor/",
|
||||||
|
"install_url": None, # IDE-based
|
||||||
|
"requires_cli": False,
|
||||||
|
},
|
||||||
|
"qwen": {
|
||||||
|
"name": "Qwen Code",
|
||||||
|
"folder": ".qwen/",
|
||||||
|
"install_url": "https://github.com/QwenLM/qwen-code",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"opencode": {
|
||||||
|
"name": "opencode",
|
||||||
|
"folder": ".opencode/",
|
||||||
|
"install_url": "https://opencode.ai",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"codex": {
|
||||||
|
"name": "Codex CLI",
|
||||||
|
"folder": ".codex/",
|
||||||
|
"install_url": "https://github.com/openai/codex",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"windsurf": {
|
||||||
|
"name": "Windsurf",
|
||||||
|
"folder": ".windsurf/",
|
||||||
|
"install_url": None, # IDE-based
|
||||||
|
"requires_cli": False,
|
||||||
|
},
|
||||||
|
"kilocode": {
|
||||||
|
"name": "Kilo Code",
|
||||||
|
"folder": ".kilocode/",
|
||||||
|
"install_url": None, # IDE-based
|
||||||
|
"requires_cli": False,
|
||||||
|
},
|
||||||
|
"auggie": {
|
||||||
|
"name": "Auggie CLI",
|
||||||
|
"folder": ".augment/",
|
||||||
|
"install_url": "https://docs.augmentcode.com/cli/setup-auggie/install-auggie-cli",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"codebuddy": {
|
||||||
|
"name": "CodeBuddy",
|
||||||
|
"folder": ".codebuddy/",
|
||||||
|
"install_url": "https://www.codebuddy.ai/cli",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"roo": {
|
||||||
|
"name": "Roo Code",
|
||||||
|
"folder": ".roo/",
|
||||||
|
"install_url": None, # IDE-based
|
||||||
|
"requires_cli": False,
|
||||||
|
},
|
||||||
|
"q": {
|
||||||
|
"name": "Amazon Q Developer CLI",
|
||||||
|
"folder": ".amazonq/",
|
||||||
|
"install_url": "https://aws.amazon.com/developer/learning/q-developer-cli/",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
|
"amp": {
|
||||||
|
"name": "Amp",
|
||||||
|
"folder": ".agents/",
|
||||||
|
"install_url": "https://ampcode.com/manual#install",
|
||||||
|
"requires_cli": True,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"}
|
SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"}
|
||||||
@@ -131,7 +204,7 @@ class StepTracker:
|
|||||||
s["detail"] = detail
|
s["detail"] = detail
|
||||||
self._maybe_refresh()
|
self._maybe_refresh()
|
||||||
return
|
return
|
||||||
# If not present, add it
|
|
||||||
self.steps.append({"key": key, "label": key, "status": status, "detail": detail})
|
self.steps.append({"key": key, "label": key, "status": status, "detail": detail})
|
||||||
self._maybe_refresh()
|
self._maybe_refresh()
|
||||||
|
|
||||||
@@ -148,7 +221,6 @@ class StepTracker:
|
|||||||
label = step["label"]
|
label = step["label"]
|
||||||
detail_text = step["detail"].strip() if step["detail"] else ""
|
detail_text = step["detail"].strip() if step["detail"] else ""
|
||||||
|
|
||||||
# Circles (unchanged styling)
|
|
||||||
status = step["status"]
|
status = step["status"]
|
||||||
if status == "done":
|
if status == "done":
|
||||||
symbol = "[green]●[/green]"
|
symbol = "[green]●[/green]"
|
||||||
@@ -272,7 +344,6 @@ def select_with_arrows(options: dict, prompt_text: str = "Select an option", def
|
|||||||
console.print("\n[red]Selection failed.[/red]")
|
console.print("\n[red]Selection failed.[/red]")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
# Suppress explicit selection print; tracker / later logic will report consolidated status
|
|
||||||
return selected_key
|
return selected_key
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
@@ -296,7 +367,6 @@ app = typer.Typer(
|
|||||||
|
|
||||||
def show_banner():
|
def show_banner():
|
||||||
"""Display the ASCII art banner."""
|
"""Display the ASCII art banner."""
|
||||||
# Create gradient effect with different colors
|
|
||||||
banner_lines = BANNER.strip().split('\n')
|
banner_lines = BANNER.strip().split('\n')
|
||||||
colors = ["bright_blue", "blue", "cyan", "bright_cyan", "white", "bright_white"]
|
colors = ["bright_blue", "blue", "cyan", "bright_cyan", "white", "bright_white"]
|
||||||
|
|
||||||
@@ -312,8 +382,6 @@ def show_banner():
|
|||||||
@app.callback()
|
@app.callback()
|
||||||
def callback(ctx: typer.Context):
|
def callback(ctx: typer.Context):
|
||||||
"""Show banner when no subcommand is provided."""
|
"""Show banner when no subcommand is provided."""
|
||||||
# Show banner only when no subcommand and no help flag
|
|
||||||
# (help is handled by BannerGroup)
|
|
||||||
if ctx.invoked_subcommand is None and "--help" not in sys.argv and "-h" not in sys.argv:
|
if ctx.invoked_subcommand is None and "--help" not in sys.argv and "-h" not in sys.argv:
|
||||||
show_banner()
|
show_banner()
|
||||||
console.print(Align.center("[dim]Run 'specify --help' for usage information[/dim]"))
|
console.print(Align.center("[dim]Run 'specify --help' for usage information[/dim]"))
|
||||||
@@ -337,18 +405,16 @@ def run_command(cmd: list[str], check_return: bool = True, capture: bool = False
|
|||||||
raise
|
raise
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def check_tool_for_tracker(tool: str, tracker: StepTracker) -> bool:
|
def check_tool(tool: str, tracker: StepTracker = None) -> bool:
|
||||||
"""Check if a tool is installed and update tracker."""
|
"""Check if a tool is installed. Optionally update tracker.
|
||||||
if shutil.which(tool):
|
|
||||||
tracker.complete(tool, "available")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
tracker.error(tool, "not found")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def check_tool(tool: str, install_hint: str) -> bool:
|
|
||||||
"""Check if a tool is installed."""
|
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tool: Name of the tool to check
|
||||||
|
tracker: Optional StepTracker to update with results
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if tool is found, False otherwise
|
||||||
|
"""
|
||||||
# Special handling for Claude CLI after `claude migrate-installer`
|
# Special handling for Claude CLI after `claude migrate-installer`
|
||||||
# See: https://github.com/github/spec-kit/issues/123
|
# See: https://github.com/github/spec-kit/issues/123
|
||||||
# The migrate-installer command REMOVES the original executable from PATH
|
# The migrate-installer command REMOVES the original executable from PATH
|
||||||
@@ -356,12 +422,19 @@ def check_tool(tool: str, install_hint: str) -> bool:
|
|||||||
# This path should be prioritized over other claude executables in PATH
|
# This path should be prioritized over other claude executables in PATH
|
||||||
if tool == "claude":
|
if tool == "claude":
|
||||||
if CLAUDE_LOCAL_PATH.exists() and CLAUDE_LOCAL_PATH.is_file():
|
if CLAUDE_LOCAL_PATH.exists() and CLAUDE_LOCAL_PATH.is_file():
|
||||||
|
if tracker:
|
||||||
|
tracker.complete(tool, "available")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if shutil.which(tool):
|
found = shutil.which(tool) is not None
|
||||||
return True
|
|
||||||
else:
|
if tracker:
|
||||||
return False
|
if found:
|
||||||
|
tracker.complete(tool, "available")
|
||||||
|
else:
|
||||||
|
tracker.error(tool, "not found")
|
||||||
|
|
||||||
|
return found
|
||||||
|
|
||||||
def is_git_repo(path: Path = None) -> bool:
|
def is_git_repo(path: Path = None) -> bool:
|
||||||
"""Check if the specified path is inside a git repository."""
|
"""Check if the specified path is inside a git repository."""
|
||||||
@@ -383,29 +456,108 @@ def is_git_repo(path: Path = None) -> bool:
|
|||||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def init_git_repo(project_path: Path, quiet: bool = False) -> bool:
|
def init_git_repo(project_path: Path, quiet: bool = False) -> Tuple[bool, Optional[str]]:
|
||||||
"""Initialize a git repository in the specified path.
|
"""Initialize a git repository in the specified path.
|
||||||
quiet: if True suppress console output (tracker handles status)
|
|
||||||
|
Args:
|
||||||
|
project_path: Path to initialize git repository in
|
||||||
|
quiet: if True suppress console output (tracker handles status)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (success: bool, error_message: Optional[str])
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
original_cwd = Path.cwd()
|
original_cwd = Path.cwd()
|
||||||
os.chdir(project_path)
|
os.chdir(project_path)
|
||||||
if not quiet:
|
if not quiet:
|
||||||
console.print("[cyan]Initializing git repository...[/cyan]")
|
console.print("[cyan]Initializing git repository...[/cyan]")
|
||||||
subprocess.run(["git", "init"], check=True, capture_output=True)
|
subprocess.run(["git", "init"], check=True, capture_output=True, text=True)
|
||||||
subprocess.run(["git", "add", "."], check=True, capture_output=True)
|
subprocess.run(["git", "add", "."], check=True, capture_output=True, text=True)
|
||||||
subprocess.run(["git", "commit", "-m", "Initial commit from Specify template"], check=True, capture_output=True)
|
subprocess.run(["git", "commit", "-m", "Initial commit from Specify template"], check=True, capture_output=True, text=True)
|
||||||
if not quiet:
|
if not quiet:
|
||||||
console.print("[green]✓[/green] Git repository initialized")
|
console.print("[green]✓[/green] Git repository initialized")
|
||||||
return True
|
return True, None
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
|
error_msg = f"Command: {' '.join(e.cmd)}\nExit code: {e.returncode}"
|
||||||
|
if e.stderr:
|
||||||
|
error_msg += f"\nError: {e.stderr.strip()}"
|
||||||
|
elif e.stdout:
|
||||||
|
error_msg += f"\nOutput: {e.stdout.strip()}"
|
||||||
|
|
||||||
if not quiet:
|
if not quiet:
|
||||||
console.print(f"[red]Error initializing git repository:[/red] {e}")
|
console.print(f"[red]Error initializing git repository:[/red] {e}")
|
||||||
return False
|
return False, error_msg
|
||||||
finally:
|
finally:
|
||||||
os.chdir(original_cwd)
|
os.chdir(original_cwd)
|
||||||
|
|
||||||
|
def handle_vscode_settings(sub_item, dest_file, rel_path, verbose=False, tracker=None) -> None:
|
||||||
|
"""Handle merging or copying of .vscode/settings.json files."""
|
||||||
|
def log(message, color="green"):
|
||||||
|
if verbose and not tracker:
|
||||||
|
console.print(f"[{color}]{message}[/] {rel_path}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(sub_item, 'r', encoding='utf-8') as f:
|
||||||
|
new_settings = json.load(f)
|
||||||
|
|
||||||
|
if dest_file.exists():
|
||||||
|
merged = merge_json_files(dest_file, new_settings, verbose=verbose and not tracker)
|
||||||
|
with open(dest_file, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(merged, f, indent=4)
|
||||||
|
f.write('\n')
|
||||||
|
log("Merged:", "green")
|
||||||
|
else:
|
||||||
|
shutil.copy2(sub_item, dest_file)
|
||||||
|
log("Copied (no existing settings.json):", "blue")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Warning: Could not merge, copying instead: {e}", "yellow")
|
||||||
|
shutil.copy2(sub_item, dest_file)
|
||||||
|
|
||||||
|
def merge_json_files(existing_path: Path, new_content: dict, verbose: bool = False) -> dict:
|
||||||
|
"""Merge new JSON content into existing JSON file.
|
||||||
|
|
||||||
|
Performs a deep merge where:
|
||||||
|
- New keys are added
|
||||||
|
- Existing keys are preserved unless overwritten by new content
|
||||||
|
- Nested dictionaries are merged recursively
|
||||||
|
- Lists and other values are replaced (not merged)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
existing_path: Path to existing JSON file
|
||||||
|
new_content: New JSON content to merge in
|
||||||
|
verbose: Whether to print merge details
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Merged JSON content as dict
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(existing_path, 'r', encoding='utf-8') as f:
|
||||||
|
existing_content = json.load(f)
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError):
|
||||||
|
# If file doesn't exist or is invalid, just use new content
|
||||||
|
return new_content
|
||||||
|
|
||||||
|
def deep_merge(base: dict, update: dict) -> dict:
|
||||||
|
"""Recursively merge update dict into base dict."""
|
||||||
|
result = base.copy()
|
||||||
|
for key, value in update.items():
|
||||||
|
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
||||||
|
# Recursively merge nested dictionaries
|
||||||
|
result[key] = deep_merge(result[key], value)
|
||||||
|
else:
|
||||||
|
# Add new key or replace existing value
|
||||||
|
result[key] = value
|
||||||
|
return result
|
||||||
|
|
||||||
|
merged = deep_merge(existing_content, new_content)
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
console.print(f"[cyan]Merged JSON file:[/cyan] {existing_path.name}")
|
||||||
|
|
||||||
|
return merged
|
||||||
|
|
||||||
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]:
|
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_owner = "github"
|
||||||
repo_name = "spec-kit"
|
repo_name = "spec-kit"
|
||||||
@@ -438,7 +590,6 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
|
|||||||
console.print(Panel(str(e), title="Fetch Error", border_style="red"))
|
console.print(Panel(str(e), title="Fetch Error", border_style="red"))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
# Find the template asset for the specified AI assistant
|
|
||||||
assets = release_data.get("assets", [])
|
assets = release_data.get("assets", [])
|
||||||
pattern = f"spec-kit-template-{ai_assistant}-{script_type}"
|
pattern = f"spec-kit-template-{ai_assistant}-{script_type}"
|
||||||
matching_assets = [
|
matching_assets = [
|
||||||
@@ -523,7 +674,6 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
"""
|
"""
|
||||||
current_dir = Path.cwd()
|
current_dir = Path.cwd()
|
||||||
|
|
||||||
# Step: fetch + download combined
|
|
||||||
if tracker:
|
if tracker:
|
||||||
tracker.start("fetch", "contacting GitHub API")
|
tracker.start("fetch", "contacting GitHub API")
|
||||||
try:
|
try:
|
||||||
@@ -556,12 +706,10 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
console.print("Extracting template...")
|
console.print("Extracting template...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Create project directory only if not using current directory
|
|
||||||
if not is_current_dir:
|
if not is_current_dir:
|
||||||
project_path.mkdir(parents=True)
|
project_path.mkdir(parents=True)
|
||||||
|
|
||||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||||
# List all files in the ZIP for debugging
|
|
||||||
zip_contents = zip_ref.namelist()
|
zip_contents = zip_ref.namelist()
|
||||||
if tracker:
|
if tracker:
|
||||||
tracker.start("zip-list")
|
tracker.start("zip-list")
|
||||||
@@ -569,13 +717,11 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
elif verbose:
|
elif verbose:
|
||||||
console.print(f"[cyan]ZIP contains {len(zip_contents)} items[/cyan]")
|
console.print(f"[cyan]ZIP contains {len(zip_contents)} items[/cyan]")
|
||||||
|
|
||||||
# For current directory, extract to a temp location first
|
|
||||||
if is_current_dir:
|
if is_current_dir:
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
temp_path = Path(temp_dir)
|
temp_path = Path(temp_dir)
|
||||||
zip_ref.extractall(temp_path)
|
zip_ref.extractall(temp_path)
|
||||||
|
|
||||||
# Check what was extracted
|
|
||||||
extracted_items = list(temp_path.iterdir())
|
extracted_items = list(temp_path.iterdir())
|
||||||
if tracker:
|
if tracker:
|
||||||
tracker.start("extracted-summary")
|
tracker.start("extracted-summary")
|
||||||
@@ -583,7 +729,6 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
elif verbose:
|
elif verbose:
|
||||||
console.print(f"[cyan]Extracted {len(extracted_items)} items to temp location[/cyan]")
|
console.print(f"[cyan]Extracted {len(extracted_items)} items to temp location[/cyan]")
|
||||||
|
|
||||||
# Handle GitHub-style ZIP with a single root directory
|
|
||||||
source_dir = temp_path
|
source_dir = temp_path
|
||||||
if len(extracted_items) == 1 and extracted_items[0].is_dir():
|
if len(extracted_items) == 1 and extracted_items[0].is_dir():
|
||||||
source_dir = extracted_items[0]
|
source_dir = extracted_items[0]
|
||||||
@@ -593,20 +738,22 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
elif verbose:
|
elif verbose:
|
||||||
console.print(f"[cyan]Found nested directory structure[/cyan]")
|
console.print(f"[cyan]Found nested directory structure[/cyan]")
|
||||||
|
|
||||||
# Copy contents to current directory
|
|
||||||
for item in source_dir.iterdir():
|
for item in source_dir.iterdir():
|
||||||
dest_path = project_path / item.name
|
dest_path = project_path / item.name
|
||||||
if item.is_dir():
|
if item.is_dir():
|
||||||
if dest_path.exists():
|
if dest_path.exists():
|
||||||
if verbose and not tracker:
|
if verbose and not tracker:
|
||||||
console.print(f"[yellow]Merging directory:[/yellow] {item.name}")
|
console.print(f"[yellow]Merging directory:[/yellow] {item.name}")
|
||||||
# Recursively copy directory contents
|
|
||||||
for sub_item in item.rglob('*'):
|
for sub_item in item.rglob('*'):
|
||||||
if sub_item.is_file():
|
if sub_item.is_file():
|
||||||
rel_path = sub_item.relative_to(item)
|
rel_path = sub_item.relative_to(item)
|
||||||
dest_file = dest_path / rel_path
|
dest_file = dest_path / rel_path
|
||||||
dest_file.parent.mkdir(parents=True, exist_ok=True)
|
dest_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
shutil.copy2(sub_item, dest_file)
|
# Special handling for .vscode/settings.json - merge instead of overwrite
|
||||||
|
if dest_file.name == "settings.json" and dest_file.parent.name == ".vscode":
|
||||||
|
handle_vscode_settings(sub_item, dest_file, rel_path, verbose, tracker)
|
||||||
|
else:
|
||||||
|
shutil.copy2(sub_item, dest_file)
|
||||||
else:
|
else:
|
||||||
shutil.copytree(item, dest_path)
|
shutil.copytree(item, dest_path)
|
||||||
else:
|
else:
|
||||||
@@ -616,10 +763,8 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
if verbose and not tracker:
|
if verbose and not tracker:
|
||||||
console.print(f"[cyan]Template files merged into current directory[/cyan]")
|
console.print(f"[cyan]Template files merged into current directory[/cyan]")
|
||||||
else:
|
else:
|
||||||
# Extract directly to project directory (original behavior)
|
|
||||||
zip_ref.extractall(project_path)
|
zip_ref.extractall(project_path)
|
||||||
|
|
||||||
# Check what was extracted
|
|
||||||
extracted_items = list(project_path.iterdir())
|
extracted_items = list(project_path.iterdir())
|
||||||
if tracker:
|
if tracker:
|
||||||
tracker.start("extracted-summary")
|
tracker.start("extracted-summary")
|
||||||
@@ -629,16 +774,14 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
for item in extracted_items:
|
for item in extracted_items:
|
||||||
console.print(f" - {item.name} ({'dir' if item.is_dir() else 'file'})")
|
console.print(f" - {item.name} ({'dir' if item.is_dir() else 'file'})")
|
||||||
|
|
||||||
# Handle GitHub-style ZIP with a single root directory
|
|
||||||
if len(extracted_items) == 1 and extracted_items[0].is_dir():
|
if len(extracted_items) == 1 and extracted_items[0].is_dir():
|
||||||
# Move contents up one level
|
|
||||||
nested_dir = extracted_items[0]
|
nested_dir = extracted_items[0]
|
||||||
temp_move_dir = project_path.parent / f"{project_path.name}_temp"
|
temp_move_dir = project_path.parent / f"{project_path.name}_temp"
|
||||||
# Move the nested directory contents to temp location
|
|
||||||
shutil.move(str(nested_dir), str(temp_move_dir))
|
shutil.move(str(nested_dir), str(temp_move_dir))
|
||||||
# Remove the now-empty project directory
|
|
||||||
project_path.rmdir()
|
project_path.rmdir()
|
||||||
# Rename temp directory to project directory
|
|
||||||
shutil.move(str(temp_move_dir), str(project_path))
|
shutil.move(str(temp_move_dir), str(project_path))
|
||||||
if tracker:
|
if tracker:
|
||||||
tracker.add("flatten", "Flatten nested directory")
|
tracker.add("flatten", "Flatten nested directory")
|
||||||
@@ -654,7 +797,7 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
console.print(f"[red]Error extracting template:[/red] {e}")
|
console.print(f"[red]Error extracting template:[/red] {e}")
|
||||||
if debug:
|
if debug:
|
||||||
console.print(Panel(str(e), title="Extraction Error", border_style="red"))
|
console.print(Panel(str(e), title="Extraction Error", border_style="red"))
|
||||||
# Clean up project directory if created and not current directory
|
|
||||||
if not is_current_dir and project_path.exists():
|
if not is_current_dir and project_path.exists():
|
||||||
shutil.rmtree(project_path)
|
shutil.rmtree(project_path)
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
@@ -664,7 +807,7 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
|
|||||||
finally:
|
finally:
|
||||||
if tracker:
|
if tracker:
|
||||||
tracker.add("cleanup", "Remove temporary archive")
|
tracker.add("cleanup", "Remove temporary archive")
|
||||||
# Clean up downloaded ZIP file
|
|
||||||
if zip_path.exists():
|
if zip_path.exists():
|
||||||
zip_path.unlink()
|
zip_path.unlink()
|
||||||
if tracker:
|
if tracker:
|
||||||
@@ -722,7 +865,7 @@ def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None =
|
|||||||
@app.command()
|
@app.command()
|
||||||
def init(
|
def init(
|
||||||
project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"),
|
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, qwen, opencode, codex, windsurf, kilocode, auggie 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, or q"),
|
||||||
script_type: str = typer.Option(None, "--script", help="Script type to use: sh or ps"),
|
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"),
|
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"),
|
no_git: bool = typer.Option(False, "--no-git", help="Skip git repository initialization"),
|
||||||
@@ -737,7 +880,7 @@ def init(
|
|||||||
|
|
||||||
This command will:
|
This command will:
|
||||||
1. Check that required tools are installed (git is optional)
|
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, Windsurf, Kilo Code, Auggie CLI, or Amazon Q Developer CLI)
|
2. Let you choose your AI assistant
|
||||||
3. Download the appropriate template from GitHub
|
3. Download the appropriate template from GitHub
|
||||||
4. Extract the template to a new project directory or current directory
|
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)
|
5. Initialize a fresh git repository (if not --no-git and no existing repo)
|
||||||
@@ -752,13 +895,13 @@ def init(
|
|||||||
specify init . # Initialize in current directory (interactive AI selection)
|
specify init . # Initialize in current directory (interactive AI selection)
|
||||||
specify init --here --ai claude # Alternative syntax for current directory
|
specify init --here --ai claude # Alternative syntax for current directory
|
||||||
specify init --here --ai codex
|
specify init --here --ai codex
|
||||||
|
specify init --here --ai codebuddy
|
||||||
specify init --here
|
specify init --here
|
||||||
specify init --here --force # Skip confirmation when current directory not empty
|
specify init --here --force # Skip confirmation when current directory not empty
|
||||||
"""
|
"""
|
||||||
|
|
||||||
show_banner()
|
show_banner()
|
||||||
|
|
||||||
# Handle '.' as shorthand for current directory (equivalent to --here)
|
|
||||||
if project_name == ".":
|
if project_name == ".":
|
||||||
here = True
|
here = True
|
||||||
project_name = None # Clear project_name to use existing validation logic
|
project_name = None # Clear project_name to use existing validation logic
|
||||||
@@ -809,91 +952,57 @@ def init(
|
|||||||
f"{'Working Path':<15} [dim]{current_dir}[/dim]",
|
f"{'Working Path':<15} [dim]{current_dir}[/dim]",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add target path only if different from working dir
|
|
||||||
if not here:
|
if not here:
|
||||||
setup_lines.append(f"{'Target Path':<15} [dim]{project_path}[/dim]")
|
setup_lines.append(f"{'Target Path':<15} [dim]{project_path}[/dim]")
|
||||||
|
|
||||||
console.print(Panel("\n".join(setup_lines), border_style="cyan", padding=(1, 2)))
|
console.print(Panel("\n".join(setup_lines), border_style="cyan", padding=(1, 2)))
|
||||||
|
|
||||||
# Check git only if we might need it (not --no-git)
|
|
||||||
# Only set to True if the user wants it and the tool is available
|
|
||||||
should_init_git = False
|
should_init_git = False
|
||||||
if not no_git:
|
if not no_git:
|
||||||
should_init_git = check_tool("git", "https://git-scm.com/downloads")
|
should_init_git = check_tool("git")
|
||||||
if not should_init_git:
|
if not should_init_git:
|
||||||
console.print("[yellow]Git not found - will skip repository initialization[/yellow]")
|
console.print("[yellow]Git not found - will skip repository initialization[/yellow]")
|
||||||
|
|
||||||
if ai_assistant:
|
if ai_assistant:
|
||||||
if ai_assistant not in AI_CHOICES:
|
if ai_assistant not in AGENT_CONFIG:
|
||||||
console.print(f"[red]Error:[/red] Invalid AI assistant '{ai_assistant}'. Choose from: {', '.join(AI_CHOICES.keys())}")
|
console.print(f"[red]Error:[/red] Invalid AI assistant '{ai_assistant}'. Choose from: {', '.join(AGENT_CONFIG.keys())}")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
selected_ai = ai_assistant
|
selected_ai = ai_assistant
|
||||||
else:
|
else:
|
||||||
# Use arrow-key selection interface
|
# Create options dict for selection (agent_key: display_name)
|
||||||
|
ai_choices = {key: config["name"] for key, config in AGENT_CONFIG.items()}
|
||||||
selected_ai = select_with_arrows(
|
selected_ai = select_with_arrows(
|
||||||
AI_CHOICES,
|
ai_choices,
|
||||||
"Choose your AI assistant:",
|
"Choose your AI assistant:",
|
||||||
"copilot"
|
"copilot"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check agent tools unless ignored
|
|
||||||
if not ignore_agent_tools:
|
if not ignore_agent_tools:
|
||||||
agent_tool_missing = False
|
agent_config = AGENT_CONFIG.get(selected_ai)
|
||||||
install_url = ""
|
if agent_config and agent_config["requires_cli"]:
|
||||||
if selected_ai == "claude":
|
install_url = agent_config["install_url"]
|
||||||
if not check_tool("claude", "https://docs.anthropic.com/en/docs/claude-code/setup"):
|
if not check_tool(selected_ai):
|
||||||
install_url = "https://docs.anthropic.com/en/docs/claude-code/setup"
|
error_panel = Panel(
|
||||||
agent_tool_missing = True
|
f"[cyan]{selected_ai}[/cyan] not found\n"
|
||||||
elif selected_ai == "gemini":
|
f"Install from: [cyan]{install_url}[/cyan]\n"
|
||||||
if not check_tool("gemini", "https://github.com/google-gemini/gemini-cli"):
|
f"{agent_config['name']} is required to continue with this project type.\n\n"
|
||||||
install_url = "https://github.com/google-gemini/gemini-cli"
|
"Tip: Use [cyan]--ignore-agent-tools[/cyan] to skip this check",
|
||||||
agent_tool_missing = True
|
title="[red]Agent Detection Error[/red]",
|
||||||
elif selected_ai == "qwen":
|
border_style="red",
|
||||||
if not check_tool("qwen", "https://github.com/QwenLM/qwen-code"):
|
padding=(1, 2)
|
||||||
install_url = "https://github.com/QwenLM/qwen-code"
|
)
|
||||||
agent_tool_missing = True
|
console.print()
|
||||||
elif selected_ai == "opencode":
|
console.print(error_panel)
|
||||||
if not check_tool("opencode", "https://opencode.ai"):
|
raise typer.Exit(1)
|
||||||
install_url = "https://opencode.ai"
|
|
||||||
agent_tool_missing = True
|
|
||||||
elif selected_ai == "codex":
|
|
||||||
if not check_tool("codex", "https://github.com/openai/codex"):
|
|
||||||
install_url = "https://github.com/openai/codex"
|
|
||||||
agent_tool_missing = True
|
|
||||||
elif selected_ai == "auggie":
|
|
||||||
if not check_tool("auggie", "https://docs.augmentcode.com/cli/setup-auggie/install-auggie-cli"):
|
|
||||||
install_url = "https://docs.augmentcode.com/cli/setup-auggie/install-auggie-cli"
|
|
||||||
agent_tool_missing = True
|
|
||||||
elif selected_ai == "q":
|
|
||||||
if not check_tool("q", "https://github.com/aws/amazon-q-developer-cli"):
|
|
||||||
install_url = "https://aws.amazon.com/developer/learning/q-developer-cli/"
|
|
||||||
agent_tool_missing = True
|
|
||||||
# GitHub Copilot and Cursor checks are not needed as they're typically available in supported IDEs
|
|
||||||
|
|
||||||
if agent_tool_missing:
|
|
||||||
error_panel = Panel(
|
|
||||||
f"[cyan]{selected_ai}[/cyan] not found\n"
|
|
||||||
f"Install with: [cyan]{install_url}[/cyan]\n"
|
|
||||||
f"{AI_CHOICES[selected_ai]} is required to continue with this project type.\n\n"
|
|
||||||
"Tip: Use [cyan]--ignore-agent-tools[/cyan] to skip this check",
|
|
||||||
title="[red]Agent Detection Error[/red]",
|
|
||||||
border_style="red",
|
|
||||||
padding=(1, 2)
|
|
||||||
)
|
|
||||||
console.print()
|
|
||||||
console.print(error_panel)
|
|
||||||
raise typer.Exit(1)
|
|
||||||
|
|
||||||
# Determine script type (explicit, interactive, or OS default)
|
|
||||||
if script_type:
|
if script_type:
|
||||||
if script_type not in SCRIPT_TYPE_CHOICES:
|
if script_type not in SCRIPT_TYPE_CHOICES:
|
||||||
console.print(f"[red]Error:[/red] Invalid script type '{script_type}'. Choose from: {', '.join(SCRIPT_TYPE_CHOICES.keys())}")
|
console.print(f"[red]Error:[/red] Invalid script type '{script_type}'. Choose from: {', '.join(SCRIPT_TYPE_CHOICES.keys())}")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
selected_script = script_type
|
selected_script = script_type
|
||||||
else:
|
else:
|
||||||
# Auto-detect default
|
|
||||||
default_script = "ps" if os.name == "nt" else "sh"
|
default_script = "ps" if os.name == "nt" else "sh"
|
||||||
# Provide interactive selection similar to AI if stdin is a TTY
|
|
||||||
if sys.stdin.isatty():
|
if sys.stdin.isatty():
|
||||||
selected_script = select_with_arrows(SCRIPT_TYPE_CHOICES, "Choose script type (or press Enter)", default_script)
|
selected_script = select_with_arrows(SCRIPT_TYPE_CHOICES, "Choose script type (or press Enter)", default_script)
|
||||||
else:
|
else:
|
||||||
@@ -902,12 +1011,10 @@ def init(
|
|||||||
console.print(f"[cyan]Selected AI assistant:[/cyan] {selected_ai}")
|
console.print(f"[cyan]Selected AI assistant:[/cyan] {selected_ai}")
|
||||||
console.print(f"[cyan]Selected script type:[/cyan] {selected_script}")
|
console.print(f"[cyan]Selected script type:[/cyan] {selected_script}")
|
||||||
|
|
||||||
# Download and set up project
|
|
||||||
# New tree-based progress (no emojis); include earlier substeps
|
|
||||||
tracker = StepTracker("Initialize Specify Project")
|
tracker = StepTracker("Initialize Specify Project")
|
||||||
# Flag to allow suppressing legacy headings
|
|
||||||
sys._specify_tracker_active = True
|
sys._specify_tracker_active = True
|
||||||
# Pre steps recorded as completed before live rendering
|
|
||||||
tracker.add("precheck", "Check required tools")
|
tracker.add("precheck", "Check required tools")
|
||||||
tracker.complete("precheck", "ok")
|
tracker.complete("precheck", "ok")
|
||||||
tracker.add("ai-select", "Select AI assistant")
|
tracker.add("ai-select", "Select AI assistant")
|
||||||
@@ -927,30 +1034,31 @@ def init(
|
|||||||
]:
|
]:
|
||||||
tracker.add(key, label)
|
tracker.add(key, label)
|
||||||
|
|
||||||
# Use transient so live tree is replaced by the final static render (avoids duplicate output)
|
# Track git error message outside Live context so it persists
|
||||||
|
git_error_message = None
|
||||||
|
|
||||||
with Live(tracker.render(), console=console, refresh_per_second=8, transient=True) as live:
|
with Live(tracker.render(), console=console, refresh_per_second=8, transient=True) as live:
|
||||||
tracker.attach_refresh(lambda: live.update(tracker.render()))
|
tracker.attach_refresh(lambda: live.update(tracker.render()))
|
||||||
try:
|
try:
|
||||||
# Create a httpx client with verify based on skip_tls
|
|
||||||
verify = not skip_tls
|
verify = not skip_tls
|
||||||
local_ssl_context = ssl_context if verify else False
|
local_ssl_context = ssl_context if verify else False
|
||||||
local_client = httpx.Client(verify=local_ssl_context)
|
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, github_token=github_token)
|
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)
|
ensure_executable_scripts(project_path, tracker=tracker)
|
||||||
|
|
||||||
# Git step
|
|
||||||
if not no_git:
|
if not no_git:
|
||||||
tracker.start("git")
|
tracker.start("git")
|
||||||
if is_git_repo(project_path):
|
if is_git_repo(project_path):
|
||||||
tracker.complete("git", "existing repo detected")
|
tracker.complete("git", "existing repo detected")
|
||||||
elif should_init_git:
|
elif should_init_git:
|
||||||
if init_git_repo(project_path, quiet=True):
|
success, error_msg = init_git_repo(project_path, quiet=True)
|
||||||
|
if success:
|
||||||
tracker.complete("git", "initialized")
|
tracker.complete("git", "initialized")
|
||||||
else:
|
else:
|
||||||
tracker.error("git", "init failed")
|
tracker.error("git", "init failed")
|
||||||
|
git_error_message = error_msg
|
||||||
else:
|
else:
|
||||||
tracker.skip("git", "git not available")
|
tracker.skip("git", "git not available")
|
||||||
else:
|
else:
|
||||||
@@ -973,31 +1081,32 @@ def init(
|
|||||||
shutil.rmtree(project_path)
|
shutil.rmtree(project_path)
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
finally:
|
finally:
|
||||||
# Force final render
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Final static tree (ensures finished state visible after Live context ends)
|
|
||||||
console.print(tracker.render())
|
console.print(tracker.render())
|
||||||
console.print("\n[bold green]Project ready.[/bold green]")
|
console.print("\n[bold green]Project ready.[/bold green]")
|
||||||
|
|
||||||
|
# Show git error details if initialization failed
|
||||||
|
if git_error_message:
|
||||||
|
console.print()
|
||||||
|
git_error_panel = Panel(
|
||||||
|
f"[yellow]Warning:[/yellow] Git repository initialization failed\n\n"
|
||||||
|
f"{git_error_message}\n\n"
|
||||||
|
f"[dim]You can initialize git manually later with:[/dim]\n"
|
||||||
|
f"[cyan]cd {project_path if not here else '.'}[/cyan]\n"
|
||||||
|
f"[cyan]git init[/cyan]\n"
|
||||||
|
f"[cyan]git add .[/cyan]\n"
|
||||||
|
f"[cyan]git commit -m \"Initial commit\"[/cyan]",
|
||||||
|
title="[red]Git Initialization Failed[/red]",
|
||||||
|
border_style="red",
|
||||||
|
padding=(1, 2)
|
||||||
|
)
|
||||||
|
console.print(git_error_panel)
|
||||||
|
|
||||||
# Agent folder security notice
|
# Agent folder security notice
|
||||||
agent_folder_map = {
|
agent_config = AGENT_CONFIG.get(selected_ai)
|
||||||
"claude": ".claude/",
|
if agent_config:
|
||||||
"gemini": ".gemini/",
|
agent_folder = agent_config["folder"]
|
||||||
"cursor": ".cursor/",
|
|
||||||
"qwen": ".qwen/",
|
|
||||||
"opencode": ".opencode/",
|
|
||||||
"codex": ".codex/",
|
|
||||||
"windsurf": ".windsurf/",
|
|
||||||
"kilocode": ".kilocode/",
|
|
||||||
"auggie": ".augment/",
|
|
||||||
"copilot": ".github/",
|
|
||||||
"roo": ".roo/",
|
|
||||||
"q": ".amazonq/"
|
|
||||||
}
|
|
||||||
|
|
||||||
if selected_ai in agent_folder_map:
|
|
||||||
agent_folder = agent_folder_map[selected_ai]
|
|
||||||
security_notice = Panel(
|
security_notice = Panel(
|
||||||
f"Some agents may store credentials, auth tokens, or other identifying and private artifacts in the agent folder within your project.\n"
|
f"Some agents may store credentials, auth tokens, or other identifying and private artifacts in the agent folder within your project.\n"
|
||||||
f"Consider adding [cyan]{agent_folder}[/cyan] (or parts of it) to [cyan].gitignore[/cyan] to prevent accidental credential leakage.",
|
f"Consider adding [cyan]{agent_folder}[/cyan] (or parts of it) to [cyan].gitignore[/cyan] to prevent accidental credential leakage.",
|
||||||
@@ -1008,7 +1117,6 @@ def init(
|
|||||||
console.print()
|
console.print()
|
||||||
console.print(security_notice)
|
console.print(security_notice)
|
||||||
|
|
||||||
# Boxed "Next steps" section
|
|
||||||
steps_lines = []
|
steps_lines = []
|
||||||
if not here:
|
if not here:
|
||||||
steps_lines.append(f"1. Go to the project folder: [cyan]cd {project_name}[/cyan]")
|
steps_lines.append(f"1. Go to the project folder: [cyan]cd {project_name}[/cyan]")
|
||||||
@@ -1061,32 +1169,28 @@ def check():
|
|||||||
tracker = StepTracker("Check Available Tools")
|
tracker = StepTracker("Check Available Tools")
|
||||||
|
|
||||||
tracker.add("git", "Git version control")
|
tracker.add("git", "Git version control")
|
||||||
tracker.add("claude", "Claude Code CLI")
|
git_ok = check_tool("git", tracker=tracker)
|
||||||
tracker.add("gemini", "Gemini CLI")
|
|
||||||
tracker.add("qwen", "Qwen Code CLI")
|
|
||||||
tracker.add("code", "Visual Studio Code")
|
|
||||||
tracker.add("code-insiders", "Visual Studio Code Insiders")
|
|
||||||
tracker.add("cursor-agent", "Cursor IDE agent")
|
|
||||||
tracker.add("windsurf", "Windsurf IDE")
|
|
||||||
tracker.add("kilocode", "Kilo Code IDE")
|
|
||||||
tracker.add("opencode", "opencode")
|
|
||||||
tracker.add("codex", "Codex CLI")
|
|
||||||
tracker.add("auggie", "Auggie CLI")
|
|
||||||
tracker.add("q", "Amazon Q Developer CLI")
|
|
||||||
|
|
||||||
git_ok = check_tool_for_tracker("git", tracker)
|
agent_results = {}
|
||||||
claude_ok = check_tool_for_tracker("claude", tracker)
|
for agent_key, agent_config in AGENT_CONFIG.items():
|
||||||
gemini_ok = check_tool_for_tracker("gemini", tracker)
|
agent_name = agent_config["name"]
|
||||||
qwen_ok = check_tool_for_tracker("qwen", tracker)
|
requires_cli = agent_config["requires_cli"]
|
||||||
code_ok = check_tool_for_tracker("code", tracker)
|
|
||||||
code_insiders_ok = check_tool_for_tracker("code-insiders", tracker)
|
tracker.add(agent_key, agent_name)
|
||||||
cursor_ok = check_tool_for_tracker("cursor-agent", tracker)
|
|
||||||
windsurf_ok = check_tool_for_tracker("windsurf", tracker)
|
if requires_cli:
|
||||||
kilocode_ok = check_tool_for_tracker("kilocode", tracker)
|
agent_results[agent_key] = check_tool(agent_key, tracker=tracker)
|
||||||
opencode_ok = check_tool_for_tracker("opencode", tracker)
|
else:
|
||||||
codex_ok = check_tool_for_tracker("codex", tracker)
|
# IDE-based agent - skip CLI check and mark as optional
|
||||||
auggie_ok = check_tool_for_tracker("auggie", tracker)
|
tracker.skip(agent_key, "IDE-based, no CLI check")
|
||||||
q_ok = check_tool_for_tracker("q", tracker)
|
agent_results[agent_key] = False # Don't count IDE agents as "found"
|
||||||
|
|
||||||
|
# Check VS Code variants (not in agent config)
|
||||||
|
tracker.add("code", "Visual Studio Code")
|
||||||
|
code_ok = check_tool("code", tracker=tracker)
|
||||||
|
|
||||||
|
tracker.add("code-insiders", "Visual Studio Code Insiders")
|
||||||
|
code_insiders_ok = check_tool("code-insiders", tracker=tracker)
|
||||||
|
|
||||||
console.print(tracker.render())
|
console.print(tracker.render())
|
||||||
|
|
||||||
@@ -1094,7 +1198,8 @@ def check():
|
|||||||
|
|
||||||
if not git_ok:
|
if not git_ok:
|
||||||
console.print("[dim]Tip: Install git for repository management[/dim]")
|
console.print("[dim]Tip: Install git for repository management[/dim]")
|
||||||
if not (claude_ok or gemini_ok or cursor_ok or qwen_ok or windsurf_ok or kilocode_ok or opencode_ok or codex_ok or auggie_ok or q_ok):
|
|
||||||
|
if not any(agent_results.values()):
|
||||||
console.print("[dim]Tip: Install an AI assistant for the best experience[/dim]")
|
console.print("[dim]Tip: Install an AI assistant for the best experience[/dim]")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -1102,3 +1207,4 @@ def main():
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|||||||
@@ -3,21 +3,26 @@
|
|||||||
Auto-generated from all feature plans. Last updated: [DATE]
|
Auto-generated from all feature plans. Last updated: [DATE]
|
||||||
|
|
||||||
## Active Technologies
|
## Active Technologies
|
||||||
|
|
||||||
[EXTRACTED FROM ALL PLAN.MD FILES]
|
[EXTRACTED FROM ALL PLAN.MD FILES]
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
```
|
|
||||||
|
```text
|
||||||
[ACTUAL STRUCTURE FROM PLANS]
|
[ACTUAL STRUCTURE FROM PLANS]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]
|
[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]
|
[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]
|
||||||
|
|
||||||
## Recent Changes
|
## Recent Changes
|
||||||
|
|
||||||
[LAST 3 FEATURES AND WHAT THEY ADDED]
|
[LAST 3 FEATURES AND WHAT THEY ADDED]
|
||||||
|
|
||||||
<!-- MANUAL ADDITIONS START -->
|
<!-- MANUAL ADDITIONS START -->
|
||||||
<!-- MANUAL ADDITIONS END -->
|
<!-- MANUAL ADDITIONS END -->
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|
||||||
Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/tasks` has successfully produced a complete `tasks.md`.
|
Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/speckit.tasks` has successfully produced a complete `tasks.md`.
|
||||||
|
|
||||||
## Operating Constraints
|
## Operating Constraints
|
||||||
|
|
||||||
**STRICTLY READ-ONLY**: Do **not** modify any files. Output a structured analysis report. Offer an optional remediation plan (user must explicitly approve before any follow-up editing commands would be invoked manually).
|
**STRICTLY READ-ONLY**: Do **not** modify any files. Output a structured analysis report. Offer an optional remediation plan (user must explicitly approve before any follow-up editing commands would be invoked manually).
|
||||||
|
|
||||||
**Constitution Authority**: The project constitution (`/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/analyze`.
|
**Constitution Authority**: The project constitution (`/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit.analyze`.
|
||||||
|
|
||||||
## Execution Steps
|
## Execution Steps
|
||||||
|
|
||||||
@@ -157,9 +157,9 @@ Output a Markdown report (no file writes) with the following structure:
|
|||||||
|
|
||||||
At end of report, output a concise Next Actions block:
|
At end of report, output a concise Next Actions block:
|
||||||
|
|
||||||
- If CRITICAL issues exist: Recommend resolving before `/implement`
|
- If CRITICAL issues exist: Recommend resolving before `/speckit.implement`
|
||||||
- If only LOW/MEDIUM: User may proceed, but provide improvement suggestions
|
- If only LOW/MEDIUM: User may proceed, but provide improvement suggestions
|
||||||
- Provide explicit command suggestions: e.g., "Run /specify with refinement", "Run /plan to adjust architecture", "Manually edit tasks.md to add coverage for 'performance-metrics'"
|
- Provide explicit command suggestions: e.g., "Run /speckit.specify with refinement", "Run /speckit.plan to adjust architecture", "Manually edit tasks.md to add coverage for 'performance-metrics'"
|
||||||
|
|
||||||
### 8. Offer Remediation
|
### 8. Offer Remediation
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ scripts:
|
|||||||
**CRITICAL CONCEPT**: Checklists are **UNIT TESTS FOR REQUIREMENTS WRITING** - they validate the quality, clarity, and completeness of requirements in a given domain.
|
**CRITICAL CONCEPT**: Checklists are **UNIT TESTS FOR REQUIREMENTS WRITING** - they validate the quality, clarity, and completeness of requirements in a given domain.
|
||||||
|
|
||||||
**NOT for verification/testing**:
|
**NOT for verification/testing**:
|
||||||
|
|
||||||
- ❌ NOT "Verify the button clicks correctly"
|
- ❌ NOT "Verify the button clicks correctly"
|
||||||
- ❌ NOT "Test error handling works"
|
- ❌ NOT "Test error handling works"
|
||||||
- ❌ NOT "Confirm the API returns 200"
|
- ❌ NOT "Confirm the API returns 200"
|
||||||
- ❌ NOT checking if code/implementation matches the spec
|
- ❌ NOT checking if code/implementation matches the spec
|
||||||
|
|
||||||
**FOR requirements quality validation**:
|
**FOR requirements quality validation**:
|
||||||
|
|
||||||
- ✅ "Are visual hierarchy requirements defined for all card types?" (completeness)
|
- ✅ "Are visual hierarchy requirements defined for all card types?" (completeness)
|
||||||
- ✅ "Is 'prominent display' quantified with specific sizing/positioning?" (clarity)
|
- ✅ "Is 'prominent display' quantified with specific sizing/positioning?" (clarity)
|
||||||
- ✅ "Are hover state requirements consistent across all interactive elements?" (consistency)
|
- ✅ "Are hover state requirements consistent across all interactive elements?" (consistency)
|
||||||
@@ -80,7 +82,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- spec.md: Feature requirements and scope
|
- spec.md: Feature requirements and scope
|
||||||
- plan.md (if exists): Technical details, dependencies
|
- plan.md (if exists): Technical details, dependencies
|
||||||
- tasks.md (if exists): Implementation tasks
|
- tasks.md (if exists): Implementation tasks
|
||||||
|
|
||||||
**Context Loading Strategy**:
|
**Context Loading Strategy**:
|
||||||
- Load only necessary portions relevant to active focus areas (avoid full-file dumping)
|
- Load only necessary portions relevant to active focus areas (avoid full-file dumping)
|
||||||
- Prefer summarizing long sections into concise scenario/requirement bullets
|
- Prefer summarizing long sections into concise scenario/requirement bullets
|
||||||
@@ -91,7 +93,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- Create `FEATURE_DIR/checklists/` directory if it doesn't exist
|
- Create `FEATURE_DIR/checklists/` directory if it doesn't exist
|
||||||
- Generate unique checklist filename:
|
- Generate unique checklist filename:
|
||||||
- Use short, descriptive name based on domain (e.g., `ux.md`, `api.md`, `security.md`)
|
- Use short, descriptive name based on domain (e.g., `ux.md`, `api.md`, `security.md`)
|
||||||
- Format: `[domain].md`
|
- Format: `[domain].md`
|
||||||
- If file exists, append to existing file
|
- If file exists, append to existing file
|
||||||
- Number items sequentially starting from CHK001
|
- Number items sequentially starting from CHK001
|
||||||
- Each `/speckit.checklist` run creates a NEW file (never overwrites existing checklists)
|
- Each `/speckit.checklist` run creates a NEW file (never overwrites existing checklists)
|
||||||
@@ -103,7 +105,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- **Consistency**: Do requirements align with each other?
|
- **Consistency**: Do requirements align with each other?
|
||||||
- **Measurability**: Can requirements be objectively verified?
|
- **Measurability**: Can requirements be objectively verified?
|
||||||
- **Coverage**: Are all scenarios/edge cases addressed?
|
- **Coverage**: Are all scenarios/edge cases addressed?
|
||||||
|
|
||||||
**Category Structure** - Group items by requirement quality dimensions:
|
**Category Structure** - Group items by requirement quality dimensions:
|
||||||
- **Requirement Completeness** (Are all necessary requirements documented?)
|
- **Requirement Completeness** (Are all necessary requirements documented?)
|
||||||
- **Requirement Clarity** (Are requirements specific and unambiguous?)
|
- **Requirement Clarity** (Are requirements specific and unambiguous?)
|
||||||
@@ -114,14 +116,14 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- **Non-Functional Requirements** (Performance, Security, Accessibility, etc. - are they specified?)
|
- **Non-Functional Requirements** (Performance, Security, Accessibility, etc. - are they specified?)
|
||||||
- **Dependencies & Assumptions** (Are they documented and validated?)
|
- **Dependencies & Assumptions** (Are they documented and validated?)
|
||||||
- **Ambiguities & Conflicts** (What needs clarification?)
|
- **Ambiguities & Conflicts** (What needs clarification?)
|
||||||
|
|
||||||
**HOW TO WRITE CHECKLIST ITEMS - "Unit Tests for English"**:
|
**HOW TO WRITE CHECKLIST ITEMS - "Unit Tests for English"**:
|
||||||
|
|
||||||
❌ **WRONG** (Testing implementation):
|
❌ **WRONG** (Testing implementation):
|
||||||
- "Verify landing page displays 3 episode cards"
|
- "Verify landing page displays 3 episode cards"
|
||||||
- "Test hover states work on desktop"
|
- "Test hover states work on desktop"
|
||||||
- "Confirm logo click navigates home"
|
- "Confirm logo click navigates home"
|
||||||
|
|
||||||
✅ **CORRECT** (Testing requirements quality):
|
✅ **CORRECT** (Testing requirements quality):
|
||||||
- "Are the exact number and layout of featured episodes specified?" [Completeness]
|
- "Are the exact number and layout of featured episodes specified?" [Completeness]
|
||||||
- "Is 'prominent display' quantified with specific sizing/positioning?" [Clarity]
|
- "Is 'prominent display' quantified with specific sizing/positioning?" [Clarity]
|
||||||
@@ -130,7 +132,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- "Is the fallback behavior specified when logo image fails to load?" [Edge Cases]
|
- "Is the fallback behavior specified when logo image fails to load?" [Edge Cases]
|
||||||
- "Are loading states defined for asynchronous episode data?" [Completeness]
|
- "Are loading states defined for asynchronous episode data?" [Completeness]
|
||||||
- "Does the spec define visual hierarchy for competing UI elements?" [Clarity]
|
- "Does the spec define visual hierarchy for competing UI elements?" [Clarity]
|
||||||
|
|
||||||
**ITEM STRUCTURE**:
|
**ITEM STRUCTURE**:
|
||||||
Each item should follow this pattern:
|
Each item should follow this pattern:
|
||||||
- Question format asking about requirement quality
|
- Question format asking about requirement quality
|
||||||
@@ -138,28 +140,28 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- Include quality dimension in brackets [Completeness/Clarity/Consistency/etc.]
|
- Include quality dimension in brackets [Completeness/Clarity/Consistency/etc.]
|
||||||
- Reference spec section `[Spec §X.Y]` when checking existing requirements
|
- Reference spec section `[Spec §X.Y]` when checking existing requirements
|
||||||
- Use `[Gap]` marker when checking for missing requirements
|
- Use `[Gap]` marker when checking for missing requirements
|
||||||
|
|
||||||
**EXAMPLES BY QUALITY DIMENSION**:
|
**EXAMPLES BY QUALITY DIMENSION**:
|
||||||
|
|
||||||
Completeness:
|
Completeness:
|
||||||
- "Are error handling requirements defined for all API failure modes? [Gap]"
|
- "Are error handling requirements defined for all API failure modes? [Gap]"
|
||||||
- "Are accessibility requirements specified for all interactive elements? [Completeness]"
|
- "Are accessibility requirements specified for all interactive elements? [Completeness]"
|
||||||
- "Are mobile breakpoint requirements defined for responsive layouts? [Gap]"
|
- "Are mobile breakpoint requirements defined for responsive layouts? [Gap]"
|
||||||
|
|
||||||
Clarity:
|
Clarity:
|
||||||
- "Is 'fast loading' quantified with specific timing thresholds? [Clarity, Spec §NFR-2]"
|
- "Is 'fast loading' quantified with specific timing thresholds? [Clarity, Spec §NFR-2]"
|
||||||
- "Are 'related episodes' selection criteria explicitly defined? [Clarity, Spec §FR-5]"
|
- "Are 'related episodes' selection criteria explicitly defined? [Clarity, Spec §FR-5]"
|
||||||
- "Is 'prominent' defined with measurable visual properties? [Ambiguity, Spec §FR-4]"
|
- "Is 'prominent' defined with measurable visual properties? [Ambiguity, Spec §FR-4]"
|
||||||
|
|
||||||
Consistency:
|
Consistency:
|
||||||
- "Do navigation requirements align across all pages? [Consistency, Spec §FR-10]"
|
- "Do navigation requirements align across all pages? [Consistency, Spec §FR-10]"
|
||||||
- "Are card component requirements consistent between landing and detail pages? [Consistency]"
|
- "Are card component requirements consistent between landing and detail pages? [Consistency]"
|
||||||
|
|
||||||
Coverage:
|
Coverage:
|
||||||
- "Are requirements defined for zero-state scenarios (no episodes)? [Coverage, Edge Case]"
|
- "Are requirements defined for zero-state scenarios (no episodes)? [Coverage, Edge Case]"
|
||||||
- "Are concurrent user interaction scenarios addressed? [Coverage, Gap]"
|
- "Are concurrent user interaction scenarios addressed? [Coverage, Gap]"
|
||||||
- "Are requirements specified for partial data loading failures? [Coverage, Exception Flow]"
|
- "Are requirements specified for partial data loading failures? [Coverage, Exception Flow]"
|
||||||
|
|
||||||
Measurability:
|
Measurability:
|
||||||
- "Are visual hierarchy requirements measurable/testable? [Acceptance Criteria, Spec §FR-1]"
|
- "Are visual hierarchy requirements measurable/testable? [Acceptance Criteria, Spec §FR-1]"
|
||||||
- "Can 'balanced visual weight' be objectively verified? [Measurability, Spec §FR-2]"
|
- "Can 'balanced visual weight' be objectively verified? [Measurability, Spec §FR-2]"
|
||||||
@@ -195,7 +197,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- ❌ "Click", "navigate", "render", "load", "execute"
|
- ❌ "Click", "navigate", "render", "load", "execute"
|
||||||
- ❌ Test cases, test plans, QA procedures
|
- ❌ Test cases, test plans, QA procedures
|
||||||
- ❌ Implementation details (frameworks, APIs, algorithms)
|
- ❌ Implementation details (frameworks, APIs, algorithms)
|
||||||
|
|
||||||
**✅ REQUIRED PATTERNS** - These test requirements quality:
|
**✅ REQUIRED PATTERNS** - These test requirements quality:
|
||||||
- ✅ "Are [requirement type] defined/specified/documented for [scenario]?"
|
- ✅ "Are [requirement type] defined/specified/documented for [scenario]?"
|
||||||
- ✅ "Is [vague term] quantified/clarified with specific criteria?"
|
- ✅ "Is [vague term] quantified/clarified with specific criteria?"
|
||||||
@@ -225,6 +227,7 @@ To avoid clutter, use descriptive types and clean up obsolete checklists when do
|
|||||||
**UX Requirements Quality:** `ux.md`
|
**UX Requirements Quality:** `ux.md`
|
||||||
|
|
||||||
Sample items (testing the requirements, NOT the implementation):
|
Sample items (testing the requirements, NOT the implementation):
|
||||||
|
|
||||||
- "Are visual hierarchy requirements defined with measurable criteria? [Clarity, Spec §FR-1]"
|
- "Are visual hierarchy requirements defined with measurable criteria? [Clarity, Spec §FR-1]"
|
||||||
- "Is the number and positioning of UI elements explicitly specified? [Completeness, Spec §FR-1]"
|
- "Is the number and positioning of UI elements explicitly specified? [Completeness, Spec §FR-1]"
|
||||||
- "Are interaction state requirements (hover, focus, active) consistently defined? [Consistency]"
|
- "Are interaction state requirements (hover, focus, active) consistently defined? [Consistency]"
|
||||||
@@ -235,6 +238,7 @@ Sample items (testing the requirements, NOT the implementation):
|
|||||||
**API Requirements Quality:** `api.md`
|
**API Requirements Quality:** `api.md`
|
||||||
|
|
||||||
Sample items:
|
Sample items:
|
||||||
|
|
||||||
- "Are error response formats specified for all failure scenarios? [Completeness]"
|
- "Are error response formats specified for all failure scenarios? [Completeness]"
|
||||||
- "Are rate limiting requirements quantified with specific thresholds? [Clarity]"
|
- "Are rate limiting requirements quantified with specific thresholds? [Clarity]"
|
||||||
- "Are authentication requirements consistent across all endpoints? [Consistency]"
|
- "Are authentication requirements consistent across all endpoints? [Consistency]"
|
||||||
@@ -244,6 +248,7 @@ Sample items:
|
|||||||
**Performance Requirements Quality:** `performance.md`
|
**Performance Requirements Quality:** `performance.md`
|
||||||
|
|
||||||
Sample items:
|
Sample items:
|
||||||
|
|
||||||
- "Are performance requirements quantified with specific metrics? [Clarity]"
|
- "Are performance requirements quantified with specific metrics? [Clarity]"
|
||||||
- "Are performance targets defined for all critical user journeys? [Coverage]"
|
- "Are performance targets defined for all critical user journeys? [Coverage]"
|
||||||
- "Are performance requirements under different load conditions specified? [Completeness]"
|
- "Are performance requirements under different load conditions specified? [Completeness]"
|
||||||
@@ -253,6 +258,7 @@ Sample items:
|
|||||||
**Security Requirements Quality:** `security.md`
|
**Security Requirements Quality:** `security.md`
|
||||||
|
|
||||||
Sample items:
|
Sample items:
|
||||||
|
|
||||||
- "Are authentication requirements specified for all protected resources? [Coverage]"
|
- "Are authentication requirements specified for all protected resources? [Coverage]"
|
||||||
- "Are data protection requirements defined for sensitive information? [Completeness]"
|
- "Are data protection requirements defined for sensitive information? [Completeness]"
|
||||||
- "Is the threat model documented and requirements aligned to it? [Traceability]"
|
- "Is the threat model documented and requirements aligned to it? [Traceability]"
|
||||||
@@ -282,9 +288,10 @@ Sample items:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Key Differences:**
|
**Key Differences:**
|
||||||
|
|
||||||
- Wrong: Tests if the system works correctly
|
- Wrong: Tests if the system works correctly
|
||||||
- Correct: Tests if the requirements are written correctly
|
- Correct: Tests if the requirements are written correctly
|
||||||
- Wrong: Verification of behavior
|
- Wrong: Verification of behavior
|
||||||
- Correct: Validation of requirement quality
|
- Correct: Validation of requirement quality
|
||||||
- Wrong: "Does it do X?"
|
- Wrong: "Does it do X?"
|
||||||
- Correct: "Is X clearly specified?"
|
- Correct: "Is X clearly specified?"
|
||||||
|
|||||||
@@ -87,50 +87,63 @@ Execution steps:
|
|||||||
3. Generate (internally) a prioritized queue of candidate clarification questions (maximum 5). Do NOT output them all at once. Apply these constraints:
|
3. Generate (internally) a prioritized queue of candidate clarification questions (maximum 5). Do NOT output them all at once. Apply these constraints:
|
||||||
- Maximum of 10 total questions across the whole session.
|
- Maximum of 10 total questions across the whole session.
|
||||||
- Each question must be answerable with EITHER:
|
- Each question must be answerable with EITHER:
|
||||||
* A short multiple‑choice selection (2–5 distinct, mutually exclusive options), OR
|
- A short multiple‑choice selection (2–5 distinct, mutually exclusive options), OR
|
||||||
* A one-word / short‑phrase answer (explicitly constrain: "Answer in <=5 words").
|
- 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.
|
- 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.
|
- 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).
|
- 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.
|
- 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.
|
- If more than 5 categories remain unresolved, select the top 5 by (Impact * Uncertainty) heuristic.
|
||||||
|
|
||||||
4. Sequential questioning loop (interactive):
|
4. Sequential questioning loop (interactive):
|
||||||
- Present EXACTLY ONE question at a time.
|
- Present EXACTLY ONE question at a time.
|
||||||
- For multiple‑choice questions render options as a Markdown table:
|
- For multiple‑choice questions:
|
||||||
|
- **Analyze all options** and determine the **most suitable option** based on:
|
||||||
|
- Best practices for the project type
|
||||||
|
- Common patterns in similar implementations
|
||||||
|
- Risk reduction (security, performance, maintainability)
|
||||||
|
- Alignment with any explicit project goals or constraints visible in the spec
|
||||||
|
- Present your **recommended option prominently** at the top with clear reasoning (1-2 sentences explaining why this is the best choice).
|
||||||
|
- Format as: `**Recommended:** Option [X] - <reasoning>`
|
||||||
|
- Then render all options as a Markdown table:
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| A | <Option A description> |
|
| A | <Option A description> |
|
||||||
| B | <Option B description> |
|
| B | <Option B description> |
|
||||||
| C | <Option C description> | (add D/E as needed up to 5)
|
| C | <Option C description> (add D/E as needed up to 5) |
|
||||||
| Short | Provide a different short answer (<=5 words) | (Include only if free-form alternative is appropriate)
|
| Short | Provide a different short answer (<=5 words) (Include only if free-form alternative is appropriate) |
|
||||||
|
|
||||||
- For short‑answer style (no meaningful discrete options), output a single line after the question: `Format: Short answer (<=5 words)`.
|
- After the table, add: `You can reply with the option letter (e.g., "A"), accept the recommendation by saying "yes" or "recommended", or provide your own short answer.`
|
||||||
|
- For short‑answer style (no meaningful discrete options):
|
||||||
|
- Provide your **suggested answer** based on best practices and context.
|
||||||
|
- Format as: `**Suggested:** <your proposed answer> - <brief reasoning>`
|
||||||
|
- Then output: `Format: Short answer (<=5 words). You can accept the suggestion by saying "yes" or "suggested", or provide your own answer.`
|
||||||
- After the user answers:
|
- After the user answers:
|
||||||
* Validate the answer maps to one option or fits the <=5 word constraint.
|
- If the user replies with "yes", "recommended", or "suggested", use your previously stated recommendation/suggestion as the answer.
|
||||||
* If ambiguous, ask for a quick disambiguation (count still belongs to same question; do not advance).
|
- Otherwise, validate the answer maps to one option or fits the <=5 word constraint.
|
||||||
* Once satisfactory, record it in working memory (do not yet write to disk) and move to the next queued question.
|
- If ambiguous, ask for a quick disambiguation (count still belongs to same question; do not advance).
|
||||||
|
- Once satisfactory, record it in working memory (do not yet write to disk) and move to the next queued question.
|
||||||
- Stop asking further questions when:
|
- Stop asking further questions when:
|
||||||
* All critical ambiguities resolved early (remaining queued items become unnecessary), OR
|
- All critical ambiguities resolved early (remaining queued items become unnecessary), OR
|
||||||
* User signals completion ("done", "good", "no more"), OR
|
- User signals completion ("done", "good", "no more"), OR
|
||||||
* You reach 5 asked questions.
|
- You reach 5 asked questions.
|
||||||
- Never reveal future queued questions in advance.
|
- Never reveal future queued questions in advance.
|
||||||
- If no valid questions exist at start, immediately report no critical ambiguities.
|
- If no valid questions exist at start, immediately report no critical ambiguities.
|
||||||
|
|
||||||
5. Integration after EACH accepted answer (incremental update approach):
|
5. Integration after EACH accepted answer (incremental update approach):
|
||||||
- Maintain in-memory representation of the spec (loaded once at start) plus the raw file contents.
|
- Maintain in-memory representation of the spec (loaded once at start) plus the raw file contents.
|
||||||
- For the first integrated answer in this session:
|
- For the first integrated answer in this session:
|
||||||
* Ensure a `## Clarifications` section exists (create it just after the highest-level contextual/overview section per the spec template if missing).
|
- Ensure a `## Clarifications` section exists (create it just after the highest-level contextual/overview section per the spec template if missing).
|
||||||
* Under it, create (if not present) a `### Session YYYY-MM-DD` subheading for today.
|
- Under it, create (if not present) a `### Session YYYY-MM-DD` subheading for today.
|
||||||
- Append a bullet line immediately after acceptance: `- Q: <question> → A: <final answer>`.
|
- Append a bullet line immediately after acceptance: `- Q: <question> → A: <final answer>`.
|
||||||
- Then immediately apply the clarification to the most appropriate section(s):
|
- Then immediately apply the clarification to the most appropriate section(s):
|
||||||
* Functional ambiguity → Update or add a bullet in Functional Requirements.
|
- Functional ambiguity → Update or add a bullet in Functional Requirements.
|
||||||
* User interaction / actor distinction → Update User Stories or Actors subsection (if present) with clarified role, constraint, or scenario.
|
- User interaction / actor distinction → Update User Stories or Actors subsection (if present) with clarified role, constraint, or scenario.
|
||||||
* Data shape / entities → Update Data Model (add fields, types, relationships) preserving ordering; note added constraints succinctly.
|
- Data shape / entities → Update Data Model (add fields, types, relationships) preserving ordering; note added constraints succinctly.
|
||||||
* Non-functional constraint → Add/modify measurable criteria in Non-Functional / Quality Attributes section (convert vague adjective to metric or explicit target).
|
- Non-functional constraint → Add/modify measurable criteria in Non-Functional / Quality Attributes section (convert vague adjective to metric or explicit target).
|
||||||
* Edge case / negative flow → Add a new bullet under Edge Cases / Error Handling (or create such subsection if template provides placeholder for it).
|
- Edge case / negative flow → Add a new bullet under Edge Cases / Error Handling (or create such subsection if template provides placeholder for it).
|
||||||
* Terminology conflict → Normalize term across spec; retain original only if necessary by adding `(formerly referred to as "X")` once.
|
- Terminology conflict → Normalize term across spec; retain original only if necessary by adding `(formerly referred to as "X")` once.
|
||||||
- If the clarification invalidates an earlier ambiguous statement, replace that statement instead of duplicating; leave no obsolete contradictory text.
|
- If the clarification invalidates an earlier ambiguous statement, replace that statement instead of duplicating; leave no obsolete contradictory text.
|
||||||
- Save the spec file AFTER each integration to minimize risk of context loss (atomic overwrite).
|
- Save the spec file AFTER each integration to minimize risk of context loss (atomic overwrite).
|
||||||
- Preserve formatting: do not reorder unrelated sections; keep heading hierarchy intact.
|
- Preserve formatting: do not reorder unrelated sections; keep heading hierarchy intact.
|
||||||
@@ -155,12 +168,13 @@ Execution steps:
|
|||||||
- Suggested next command.
|
- Suggested next command.
|
||||||
|
|
||||||
Behavior rules:
|
Behavior rules:
|
||||||
|
|
||||||
- If no meaningful ambiguities found (or all potential questions would be low-impact), respond: "No critical ambiguities detected worth formal clarification." and suggest proceeding.
|
- If no meaningful ambiguities found (or all potential questions would be low-impact), respond: "No critical ambiguities detected worth formal clarification." and suggest proceeding.
|
||||||
- If spec file missing, instruct user to run `/speckit.specify` first (do not create a new spec here).
|
- If spec file missing, instruct user to run `/speckit.specify` first (do not create a new spec here).
|
||||||
- Never exceed 5 total asked questions (clarification retries for a single question do not count as new questions).
|
- Never exceed 5 total asked questions (clarification retries for a single question do not count as new questions).
|
||||||
- Avoid speculative tech stack questions unless the absence blocks functional clarity.
|
- Avoid speculative tech stack questions unless the absence blocks functional clarity.
|
||||||
- Respect user early termination signals ("stop", "done", "proceed").
|
- Respect user early termination signals ("stop", "done", "proceed").
|
||||||
- If no questions asked due to full coverage, output a compact coverage summary (all categories Clear) then suggest advancing.
|
- If no questions asked due to full coverage, output a compact coverage summary (all categories Clear) then suggest advancing.
|
||||||
- If quota reached with unresolved high-impact categories remaining, explicitly flag them under Deferred with rationale.
|
- If quota reached with unresolved high-impact categories remaining, explicitly flag them under Deferred with rationale.
|
||||||
|
|
||||||
Context for prioritization: {ARGS}
|
Context for prioritization: {ARGS}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
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
|
||||||
---
|
---
|
||||||
|
|
||||||
## User Input
|
## User Input
|
||||||
@@ -25,9 +25,9 @@ Follow this execution flow:
|
|||||||
- Otherwise infer from existing repo context (README, docs, prior constitution versions if embedded).
|
- Otherwise infer from existing repo context (README, docs, prior constitution versions if embedded).
|
||||||
- For governance dates: `RATIFICATION_DATE` is the original adoption date (if unknown ask or mark TODO), `LAST_AMENDED_DATE` is today if changes are made, otherwise keep previous.
|
- For governance dates: `RATIFICATION_DATE` is the original adoption date (if unknown ask or mark TODO), `LAST_AMENDED_DATE` is today if changes are made, otherwise keep previous.
|
||||||
- `CONSTITUTION_VERSION` must increment according to semantic versioning rules:
|
- `CONSTITUTION_VERSION` must increment according to semantic versioning rules:
|
||||||
* MAJOR: Backward incompatible governance/principle removals or redefinitions.
|
- MAJOR: Backward incompatible governance/principle removals or redefinitions.
|
||||||
* MINOR: New principle/section added or materially expanded guidance.
|
- MINOR: New principle/section added or materially expanded guidance.
|
||||||
* PATCH: Clarifications, wording, typo fixes, non-semantic refinements.
|
- PATCH: Clarifications, wording, typo fixes, non-semantic refinements.
|
||||||
- If version bump type ambiguous, propose reasoning before finalizing.
|
- If version bump type ambiguous, propose reasoning before finalizing.
|
||||||
|
|
||||||
3. Draft the updated constitution content:
|
3. Draft the updated constitution content:
|
||||||
@@ -65,6 +65,7 @@ Follow this execution flow:
|
|||||||
- Suggested commit message (e.g., `docs: amend constitution to vX.Y.Z (principle additions + governance update)`).
|
- Suggested commit message (e.g., `docs: amend constitution to vX.Y.Z (principle additions + governance update)`).
|
||||||
|
|
||||||
Formatting & Style Requirements:
|
Formatting & Style Requirements:
|
||||||
|
|
||||||
- Use Markdown headings exactly as in the template (do not demote/promote levels).
|
- Use Markdown headings exactly as in the template (do not demote/promote levels).
|
||||||
- Wrap long rationale lines to keep readability (<100 chars ideally) but do not hard enforce with awkward breaks.
|
- Wrap long rationale lines to keep readability (<100 chars ideally) but do not hard enforce with awkward breaks.
|
||||||
- Keep a single blank line between sections.
|
- Keep a single blank line between sections.
|
||||||
|
|||||||
@@ -20,31 +20,33 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
2. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
|
2. **Check checklists status** (if FEATURE_DIR/checklists/ exists):
|
||||||
- Scan all checklist files in the checklists/ directory
|
- Scan all checklist files in the checklists/ directory
|
||||||
- For each checklist, count:
|
- For each checklist, count:
|
||||||
* Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
|
- Total items: All lines matching `- [ ]` or `- [X]` or `- [x]`
|
||||||
* Completed items: Lines matching `- [X]` or `- [x]`
|
- Completed items: Lines matching `- [X]` or `- [x]`
|
||||||
* Incomplete items: Lines matching `- [ ]`
|
- Incomplete items: Lines matching `- [ ]`
|
||||||
- Create a status table:
|
- Create a status table:
|
||||||
```
|
|
||||||
|
```text
|
||||||
| Checklist | Total | Completed | Incomplete | Status |
|
| Checklist | Total | Completed | Incomplete | Status |
|
||||||
|-----------|-------|-----------|------------|--------|
|
|-----------|-------|-----------|------------|--------|
|
||||||
| ux.md | 12 | 12 | 0 | ✓ PASS |
|
| ux.md | 12 | 12 | 0 | ✓ PASS |
|
||||||
| test.md | 8 | 5 | 3 | ✗ FAIL |
|
| test.md | 8 | 5 | 3 | ✗ FAIL |
|
||||||
| security.md | 6 | 6 | 0 | ✓ PASS |
|
| security.md | 6 | 6 | 0 | ✓ PASS |
|
||||||
```
|
```
|
||||||
|
|
||||||
- Calculate overall status:
|
- Calculate overall status:
|
||||||
* **PASS**: All checklists have 0 incomplete items
|
- **PASS**: All checklists have 0 incomplete items
|
||||||
* **FAIL**: One or more checklists have incomplete items
|
- **FAIL**: One or more checklists have incomplete items
|
||||||
|
|
||||||
- **If any checklist is incomplete**:
|
- **If any checklist is incomplete**:
|
||||||
* Display the table with incomplete item counts
|
- Display the table with incomplete item counts
|
||||||
* **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
|
- **STOP** and ask: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
|
||||||
* Wait for user response before continuing
|
- Wait for user response before continuing
|
||||||
* If user says "no" or "wait" or "stop", halt execution
|
- If user says "no" or "wait" or "stop", halt execution
|
||||||
* If user says "yes" or "proceed" or "continue", proceed to step 3
|
- If user says "yes" or "proceed" or "continue", proceed to step 3
|
||||||
|
|
||||||
- **If all checklists are complete**:
|
- **If all checklists are complete**:
|
||||||
* Display the table showing all checklists passed
|
- Display the table showing all checklists passed
|
||||||
* Automatically proceed to step 3
|
- Automatically proceed to step 3
|
||||||
|
|
||||||
3. Load and analyze the implementation context:
|
3. Load and analyze the implementation context:
|
||||||
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
|
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
|
||||||
@@ -54,27 +56,70 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- **IF EXISTS**: Read research.md for technical decisions and constraints
|
- **IF EXISTS**: Read research.md for technical decisions and constraints
|
||||||
- **IF EXISTS**: Read quickstart.md for integration scenarios
|
- **IF EXISTS**: Read quickstart.md for integration scenarios
|
||||||
|
|
||||||
4. Parse tasks.md structure and extract:
|
4. **Project Setup Verification**:
|
||||||
|
- **REQUIRED**: Create/verify ignore files based on actual project setup:
|
||||||
|
|
||||||
|
**Detection & Creation Logic**:
|
||||||
|
- Check if the following command succeeds to determine if the repository is a git repo (create/verify .gitignore if so):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git rev-parse --git-dir 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
- Check if Dockerfile* exists or Docker in plan.md → create/verify .dockerignore
|
||||||
|
- Check if .eslintrc*or eslint.config.* exists → create/verify .eslintignore
|
||||||
|
- 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
|
||||||
|
- Check if .helmignore needed (helm charts present) → create/verify .helmignore
|
||||||
|
|
||||||
|
**If ignore file already exists**: Verify it contains essential patterns, append missing critical patterns only
|
||||||
|
**If ignore file missing**: Create with full pattern set for detected technology
|
||||||
|
|
||||||
|
**Common Patterns by Technology** (from plan.md tech stack):
|
||||||
|
- **Node.js/JavaScript/TypeScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
|
||||||
|
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
|
||||||
|
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
|
||||||
|
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
|
||||||
|
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
|
||||||
|
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
|
||||||
|
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
|
||||||
|
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
|
||||||
|
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
|
||||||
|
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
|
||||||
|
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
|
||||||
|
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
|
||||||
|
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
|
||||||
|
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
|
||||||
|
|
||||||
|
**Tool-Specific Patterns**:
|
||||||
|
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
|
||||||
|
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
|
||||||
|
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
|
||||||
|
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
|
||||||
|
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
|
||||||
|
|
||||||
|
5. Parse tasks.md structure and extract:
|
||||||
- **Task phases**: Setup, Tests, Core, Integration, Polish
|
- **Task phases**: Setup, Tests, Core, Integration, Polish
|
||||||
- **Task dependencies**: Sequential vs parallel execution rules
|
- **Task dependencies**: Sequential vs parallel execution rules
|
||||||
- **Task details**: ID, description, file paths, parallel markers [P]
|
- **Task details**: ID, description, file paths, parallel markers [P]
|
||||||
- **Execution flow**: Order and dependency requirements
|
- **Execution flow**: Order and dependency requirements
|
||||||
|
|
||||||
5. Execute implementation following the task plan:
|
6. Execute implementation following the task plan:
|
||||||
- **Phase-by-phase execution**: Complete each phase before moving to the next
|
- **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
|
- **Respect dependencies**: Run sequential tasks in order, parallel tasks [P] can run together
|
||||||
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
|
- **Follow TDD approach**: Execute test tasks before their corresponding implementation tasks
|
||||||
- **File-based coordination**: Tasks affecting the same files must run sequentially
|
- **File-based coordination**: Tasks affecting the same files must run sequentially
|
||||||
- **Validation checkpoints**: Verify each phase completion before proceeding
|
- **Validation checkpoints**: Verify each phase completion before proceeding
|
||||||
|
|
||||||
6. Implementation execution rules:
|
7. Implementation execution rules:
|
||||||
- **Setup first**: Initialize project structure, dependencies, configuration
|
- **Setup first**: Initialize project structure, dependencies, configuration
|
||||||
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
|
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
|
||||||
- **Core development**: Implement models, services, CLI commands, endpoints
|
- **Core development**: Implement models, services, CLI commands, endpoints
|
||||||
- **Integration work**: Database connections, middleware, logging, external services
|
- **Integration work**: Database connections, middleware, logging, external services
|
||||||
- **Polish and validation**: Unit tests, performance optimization, documentation
|
- **Polish and validation**: Unit tests, performance optimization, documentation
|
||||||
|
|
||||||
7. Progress tracking and error handling:
|
8. Progress tracking and error handling:
|
||||||
- Report progress after each completed task
|
- Report progress after each completed task
|
||||||
- Halt execution if any non-parallel task fails
|
- Halt execution if any non-parallel task fails
|
||||||
- For parallel tasks [P], continue with successful tasks, report failed ones
|
- For parallel tasks [P], continue with successful tasks, report failed ones
|
||||||
@@ -82,11 +127,12 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- Suggest next steps if implementation cannot proceed
|
- Suggest next steps if implementation cannot proceed
|
||||||
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
|
- **IMPORTANT** For completed tasks, make sure to mark the task off as [X] in the tasks file.
|
||||||
|
|
||||||
8. Completion validation:
|
9. Completion validation:
|
||||||
- Verify all required tasks are completed
|
- Verify all required tasks are completed
|
||||||
- Check that implemented features match the original specification
|
- Check that implemented features match the original specification
|
||||||
- Validate that tests pass and coverage meets requirements
|
- Validate that tests pass and coverage meets requirements
|
||||||
- Confirm the implementation follows the technical plan
|
- Confirm the implementation follows the technical plan
|
||||||
- Report final status with summary of completed work
|
- 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.
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
|
|
||||||
1. **Setup**: Run `{SCRIPT}` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. 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. **Setup**: Run `{SCRIPT}` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. 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").
|
||||||
|
|
||||||
2. **Load context**: Read FEATURE_SPEC and `.specify/memory/constitution.md`. Load IMPL_PLAN template (already copied).
|
2. **Load context**: Read FEATURE_SPEC and `/memory/constitution.md`. Load IMPL_PLAN template (already copied).
|
||||||
|
|
||||||
3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to:
|
3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to:
|
||||||
- Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION")
|
- Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION")
|
||||||
@@ -43,7 +43,8 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- For each integration → patterns task
|
- For each integration → patterns task
|
||||||
|
|
||||||
2. **Generate and dispatch research agents**:
|
2. **Generate and dispatch research agents**:
|
||||||
```
|
|
||||||
|
```text
|
||||||
For each unknown in Technical Context:
|
For each unknown in Technical Context:
|
||||||
Task: "Research {unknown} for {feature context}"
|
Task: "Research {unknown} for {feature context}"
|
||||||
For each technology choice:
|
For each technology choice:
|
||||||
|
|||||||
@@ -19,11 +19,32 @@ The text the user typed after `/speckit.specify` in the triggering message **is*
|
|||||||
|
|
||||||
Given that feature description, do this:
|
Given that feature description, 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.
|
1. **Generate a concise short name** (2-4 words) for the branch:
|
||||||
**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. 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").
|
- Analyze the feature description and extract the most meaningful keywords
|
||||||
2. Load `templates/spec-template.md` to understand required sections.
|
- Create a 2-4 word short name that captures the essence of the feature
|
||||||
|
- Use action-noun format when possible (e.g., "add-user-auth", "fix-payment-bug")
|
||||||
|
- Preserve technical terms and acronyms (OAuth2, API, JWT, etc.)
|
||||||
|
- Keep it concise but descriptive enough to understand the feature at a glance
|
||||||
|
- Examples:
|
||||||
|
- "I want to add user authentication" → "user-auth"
|
||||||
|
- "Implement OAuth2 integration for the API" → "oauth2-api-integration"
|
||||||
|
- "Create a dashboard for analytics" → "analytics-dashboard"
|
||||||
|
- "Fix payment processing timeout bug" → "fix-payment-timeout"
|
||||||
|
|
||||||
3. Follow this execution flow:
|
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.
|
||||||
|
|
||||||
|
**IMPORTANT**:
|
||||||
|
|
||||||
|
- Append the short-name argument to the `{SCRIPT}` command with the 2-4 word short name you created in step 1
|
||||||
|
- Bash: `--short-name "your-generated-short-name"`
|
||||||
|
- PowerShell: `-ShortName "your-generated-short-name"`
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
4. Follow this execution flow:
|
||||||
|
|
||||||
1. Parse user description from Input
|
1. Parse user description from Input
|
||||||
If empty: ERROR "No feature description provided"
|
If empty: ERROR "No feature description provided"
|
||||||
@@ -49,12 +70,12 @@ Given that feature description, do this:
|
|||||||
7. Identify Key Entities (if data involved)
|
7. Identify Key Entities (if data involved)
|
||||||
8. Return: SUCCESS (spec ready for planning)
|
8. Return: SUCCESS (spec ready for planning)
|
||||||
|
|
||||||
4. 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.
|
5. 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.
|
||||||
|
|
||||||
5. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria:
|
6. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria:
|
||||||
|
|
||||||
a. **Create Spec Quality Checklist**: Generate a checklist file at `FEATURE_DIR/checklists/requirements.md` using the checklist template structure with these validation items:
|
a. **Create Spec Quality Checklist**: Generate a checklist file at `FEATURE_DIR/checklists/requirements.md` using the checklist template structure with these validation items:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Specification Quality Checklist: [FEATURE NAME]
|
# Specification Quality Checklist: [FEATURE NAME]
|
||||||
|
|
||||||
@@ -91,26 +112,26 @@ Given that feature description, do this:
|
|||||||
|
|
||||||
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
- Items marked incomplete require spec updates before `/speckit.clarify` or `/speckit.plan`
|
||||||
```
|
```
|
||||||
|
|
||||||
b. **Run Validation Check**: Review the spec against each checklist item:
|
b. **Run Validation Check**: Review the spec against each checklist item:
|
||||||
- For each item, determine if it passes or fails
|
- For each item, determine if it passes or fails
|
||||||
- Document specific issues found (quote relevant spec sections)
|
- Document specific issues found (quote relevant spec sections)
|
||||||
|
|
||||||
c. **Handle Validation Results**:
|
c. **Handle Validation Results**:
|
||||||
|
|
||||||
- **If all items pass**: Mark checklist complete and proceed to step 6
|
- **If all items pass**: Mark checklist complete and proceed to step 6
|
||||||
|
|
||||||
- **If items fail (excluding [NEEDS CLARIFICATION])**:
|
- **If items fail (excluding [NEEDS CLARIFICATION])**:
|
||||||
1. List the failing items and specific issues
|
1. List the failing items and specific issues
|
||||||
2. Update the spec to address each issue
|
2. Update the spec to address each issue
|
||||||
3. Re-run validation until all items pass (max 3 iterations)
|
3. Re-run validation until all items pass (max 3 iterations)
|
||||||
4. If still failing after 3 iterations, document remaining issues in checklist notes and warn user
|
4. If still failing after 3 iterations, document remaining issues in checklist notes and warn user
|
||||||
|
|
||||||
- **If [NEEDS CLARIFICATION] markers remain**:
|
- **If [NEEDS CLARIFICATION] markers remain**:
|
||||||
1. Extract all [NEEDS CLARIFICATION: ...] markers from the spec
|
1. Extract all [NEEDS CLARIFICATION: ...] markers from the spec
|
||||||
2. **LIMIT CHECK**: If more than 3 markers exist, keep only the 3 most critical (by scope/security/UX impact) and make informed guesses for the rest
|
2. **LIMIT CHECK**: If more than 3 markers exist, keep only the 3 most critical (by scope/security/UX impact) and make informed guesses for the rest
|
||||||
3. For each clarification needed (max 3), present options to user in this format:
|
3. For each clarification needed (max 3), present options to user in this format:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
## Question [N]: [Topic]
|
## Question [N]: [Topic]
|
||||||
|
|
||||||
@@ -129,7 +150,7 @@ Given that feature description, do this:
|
|||||||
|
|
||||||
**Your choice**: _[Wait for user response]_
|
**Your choice**: _[Wait for user response]_
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **CRITICAL - Table Formatting**: Ensure markdown tables are properly formatted:
|
4. **CRITICAL - Table Formatting**: Ensure markdown tables are properly formatted:
|
||||||
- Use consistent spacing with pipes aligned
|
- Use consistent spacing with pipes aligned
|
||||||
- Each cell should have spaces around content: `| Content |` not `|Content|`
|
- Each cell should have spaces around content: `| Content |` not `|Content|`
|
||||||
@@ -140,10 +161,10 @@ Given that feature description, do this:
|
|||||||
7. Wait for user to respond with their choices for all questions (e.g., "Q1: A, Q2: Custom - [details], Q3: B")
|
7. Wait for user to respond with their choices for all questions (e.g., "Q1: A, Q2: Custom - [details], Q3: B")
|
||||||
8. Update the spec by replacing each [NEEDS CLARIFICATION] marker with the user's selected or provided answer
|
8. Update the spec by replacing each [NEEDS CLARIFICATION] marker with the user's selected or provided answer
|
||||||
9. Re-run validation after all clarifications are resolved
|
9. Re-run validation after all clarifications are resolved
|
||||||
|
|
||||||
d. **Update Checklist**: After each validation iteration, update the checklist file with current pass/fail status
|
d. **Update Checklist**: After each validation iteration, update the checklist file with current pass/fail status
|
||||||
|
|
||||||
6. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`).
|
7. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`).
|
||||||
|
|
||||||
**NOTE:** The script creates and checks out the new branch and initializes the spec file before writing.
|
**NOTE:** The script creates and checks out the new branch and initializes the spec file before writing.
|
||||||
|
|
||||||
@@ -178,7 +199,7 @@ When creating this spec from a user prompt:
|
|||||||
- Feature scope and boundaries (include/exclude specific use cases)
|
- Feature scope and boundaries (include/exclude specific use cases)
|
||||||
- User types and permissions (if multiple conflicting interpretations possible)
|
- User types and permissions (if multiple conflicting interpretations possible)
|
||||||
- Security/compliance requirements (when legally/financially significant)
|
- Security/compliance requirements (when legally/financially significant)
|
||||||
|
|
||||||
**Examples of reasonable defaults** (don't ask about these):
|
**Examples of reasonable defaults** (don't ask about these):
|
||||||
|
|
||||||
- Data retention: Industry-standard practices for the domain
|
- Data retention: Industry-standard practices for the domain
|
||||||
|
|||||||
@@ -22,27 +22,13 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- **Optional**: data-model.md (entities), contracts/ (API endpoints), research.md (decisions), quickstart.md (test scenarios)
|
- **Optional**: data-model.md (entities), contracts/ (API endpoints), research.md (decisions), quickstart.md (test scenarios)
|
||||||
- Note: Not all projects have all documents. Generate tasks based on what's available.
|
- Note: Not all projects have all documents. Generate tasks based on what's available.
|
||||||
|
|
||||||
3. **Execute task generation workflow** (follow the template structure):
|
3. **Execute task generation workflow**:
|
||||||
- Load plan.md and extract tech stack, libraries, project structure
|
- Load plan.md and extract tech stack, libraries, project structure
|
||||||
- **Load spec.md and extract user stories with their priorities (P1, P2, P3, etc.)**
|
- Load spec.md and extract user stories with their priorities (P1, P2, P3, etc.)
|
||||||
- If data-model.md exists: Extract entities → map to user stories
|
- If data-model.md exists: Extract entities and map to user stories
|
||||||
- If contracts/ exists: Each file → map endpoints to user stories
|
- If contracts/ exists: Map endpoints to user stories
|
||||||
- If research.md exists: Extract decisions → generate setup tasks
|
- If research.md exists: Extract decisions for setup tasks
|
||||||
- **Generate tasks ORGANIZED BY USER STORY**:
|
- Generate tasks organized by user story (see Task Generation Rules below)
|
||||||
- Setup tasks (shared infrastructure needed by all stories)
|
|
||||||
- **Foundational tasks (prerequisites that must complete before ANY user story can start)**
|
|
||||||
- For each user story (in priority order P1, P2, P3...):
|
|
||||||
- Group all tasks needed to complete JUST that story
|
|
||||||
- Include models, services, endpoints, UI components specific to that story
|
|
||||||
- Mark which tasks are [P] parallelizable
|
|
||||||
- If tests requested: Include tests specific to that story
|
|
||||||
- Polish/Integration tasks (cross-cutting concerns)
|
|
||||||
- **Tests are OPTIONAL**: Only generate test tasks if explicitly requested in the feature spec or user asks for TDD approach
|
|
||||||
- Apply task rules:
|
|
||||||
- Different files = mark [P] for parallel
|
|
||||||
- Same file = sequential (no [P])
|
|
||||||
- If tests requested: Tests before implementation (TDD order)
|
|
||||||
- Number tasks sequentially (T001, T002...)
|
|
||||||
- Generate dependency graph showing user story completion order
|
- Generate dependency graph showing user story completion order
|
||||||
- Create parallel execution examples per user story
|
- Create parallel execution examples per user story
|
||||||
- Validate task completeness (each user story has all needed tasks, independently testable)
|
- Validate task completeness (each user story has all needed tasks, independently testable)
|
||||||
@@ -52,12 +38,9 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- Phase 1: Setup tasks (project initialization)
|
- Phase 1: Setup tasks (project initialization)
|
||||||
- Phase 2: Foundational tasks (blocking prerequisites for all user stories)
|
- Phase 2: Foundational tasks (blocking prerequisites for all user stories)
|
||||||
- Phase 3+: One phase per user story (in priority order from spec.md)
|
- Phase 3+: One phase per user story (in priority order from spec.md)
|
||||||
- Each phase includes: story goal, independent test criteria, tests (if requested), implementation tasks
|
- Each phase includes: story goal, independent test criteria, tests (if requested), implementation tasks
|
||||||
- Clear [Story] labels (US1, US2, US3...) for each task
|
|
||||||
- [P] markers for parallelizable tasks within each story
|
|
||||||
- Checkpoint markers after each story phase
|
|
||||||
- Final Phase: Polish & cross-cutting concerns
|
- Final Phase: Polish & cross-cutting concerns
|
||||||
- Numbered tasks (T001, T002...) in execution order
|
- All tasks must follow the strict checklist format (see Task Generation Rules below)
|
||||||
- Clear file paths for each task
|
- Clear file paths for each task
|
||||||
- Dependencies section showing story completion order
|
- Dependencies section showing story completion order
|
||||||
- Parallel execution examples per story
|
- Parallel execution examples per story
|
||||||
@@ -69,6 +52,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
|||||||
- Parallel opportunities identified
|
- Parallel opportunities identified
|
||||||
- Independent test criteria for each story
|
- Independent test criteria for each story
|
||||||
- Suggested MVP scope (typically just User Story 1)
|
- Suggested MVP scope (typically just User Story 1)
|
||||||
|
- Format validation: Confirm ALL tasks follow the checklist format (checkbox, ID, labels, file paths)
|
||||||
|
|
||||||
Context for task generation: {ARGS}
|
Context for task generation: {ARGS}
|
||||||
|
|
||||||
@@ -76,10 +60,44 @@ The tasks.md should be immediately executable - each task must be specific enoug
|
|||||||
|
|
||||||
## Task Generation Rules
|
## Task Generation Rules
|
||||||
|
|
||||||
**IMPORTANT**: Tests are optional. Only generate test tasks if the user explicitly requested testing or TDD approach in the feature specification.
|
|
||||||
|
|
||||||
**CRITICAL**: Tasks MUST be organized by user story to enable independent implementation and testing.
|
**CRITICAL**: Tasks MUST be organized by user story to enable independent implementation and testing.
|
||||||
|
|
||||||
|
**Tests are OPTIONAL**: Only generate test tasks if explicitly requested in the feature specification or if user requests TDD approach.
|
||||||
|
|
||||||
|
### Checklist Format (REQUIRED)
|
||||||
|
|
||||||
|
Every task MUST strictly follow this format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
- [ ] [TaskID] [P?] [Story?] Description with file path
|
||||||
|
```
|
||||||
|
|
||||||
|
**Format Components**:
|
||||||
|
|
||||||
|
1. **Checkbox**: ALWAYS start with `- [ ]` (markdown checkbox)
|
||||||
|
2. **Task ID**: Sequential number (T001, T002, T003...) in execution order
|
||||||
|
3. **[P] marker**: Include ONLY if task is parallelizable (different files, no dependencies on incomplete tasks)
|
||||||
|
4. **[Story] label**: REQUIRED for user story phase tasks only
|
||||||
|
- Format: [US1], [US2], [US3], etc. (maps to user stories from spec.md)
|
||||||
|
- Setup phase: NO story label
|
||||||
|
- Foundational phase: NO story label
|
||||||
|
- User Story phases: MUST have story label
|
||||||
|
- Polish phase: NO story label
|
||||||
|
5. **Description**: Clear action with exact file path
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
|
||||||
|
- ✅ CORRECT: `- [ ] T001 Create project structure per implementation plan`
|
||||||
|
- ✅ CORRECT: `- [ ] T005 [P] Implement authentication middleware in src/middleware/auth.py`
|
||||||
|
- ✅ CORRECT: `- [ ] T012 [P] [US1] Create User model in src/models/user.py`
|
||||||
|
- ✅ CORRECT: `- [ ] T014 [US1] Implement UserService in src/services/user_service.py`
|
||||||
|
- ❌ WRONG: `- [ ] Create User model` (missing ID and Story label)
|
||||||
|
- ❌ WRONG: `T001 [US1] Create model` (missing checkbox)
|
||||||
|
- ❌ WRONG: `- [ ] [US1] Create User model` (missing Task ID)
|
||||||
|
- ❌ WRONG: `- [ ] T001 [US1] Create model` (missing file path)
|
||||||
|
|
||||||
|
### Task Organization
|
||||||
|
|
||||||
1. **From User Stories (spec.md)** - PRIMARY ORGANIZATION:
|
1. **From User Stories (spec.md)** - PRIMARY ORGANIZATION:
|
||||||
- Each user story (P1, P2, P3...) gets its own phase
|
- Each user story (P1, P2, P3...) gets its own phase
|
||||||
- Map all related components to their story:
|
- Map all related components to their story:
|
||||||
@@ -88,28 +106,26 @@ The tasks.md should be immediately executable - each task must be specific enoug
|
|||||||
- Endpoints/UI needed for that story
|
- Endpoints/UI needed for that story
|
||||||
- If tests requested: Tests specific to that story
|
- If tests requested: Tests specific to that story
|
||||||
- Mark story dependencies (most stories should be independent)
|
- Mark story dependencies (most stories should be independent)
|
||||||
|
|
||||||
2. **From Contracts**:
|
2. **From Contracts**:
|
||||||
- Map each contract/endpoint → to the user story it serves
|
- Map each contract/endpoint → to the user story it serves
|
||||||
- If tests requested: Each contract → contract test task [P] before implementation in that story's phase
|
- If tests requested: Each contract → contract test task [P] before implementation in that story's phase
|
||||||
|
|
||||||
3. **From Data Model**:
|
3. **From Data Model**:
|
||||||
- Map each entity → to the user story(ies) that need it
|
- Map each entity to the user story(ies) that need it
|
||||||
- If entity serves multiple stories: Put in earliest story or Setup phase
|
- If entity serves multiple stories: Put in earliest story or Setup phase
|
||||||
- Relationships → service layer tasks in appropriate story phase
|
- Relationships → service layer tasks in appropriate story phase
|
||||||
|
|
||||||
4. **From Setup/Infrastructure**:
|
4. **From Setup/Infrastructure**:
|
||||||
- Shared infrastructure → Setup phase (Phase 1)
|
- Shared infrastructure → Setup phase (Phase 1)
|
||||||
- Foundational/blocking tasks → Foundational phase (Phase 2)
|
- Foundational/blocking tasks → Foundational phase (Phase 2)
|
||||||
- Examples: Database schema setup, authentication framework, core libraries, base configurations
|
|
||||||
- These MUST complete before any user story can be implemented
|
|
||||||
- Story-specific setup → within that story's phase
|
- Story-specific setup → within that story's phase
|
||||||
|
|
||||||
5. **Ordering**:
|
### Phase Structure
|
||||||
- Phase 1: Setup (project initialization)
|
|
||||||
- Phase 2: Foundational (blocking prerequisites - must complete before user stories)
|
|
||||||
- Phase 3+: User Stories in priority order (P1, P2, P3...)
|
|
||||||
- Within each story: Tests (if requested) → Models → Services → Endpoints → Integration
|
|
||||||
- Final Phase: Polish & Cross-Cutting Concerns
|
|
||||||
- Each user story phase should be a complete, independently testable increment
|
|
||||||
|
|
||||||
|
- **Phase 1**: Setup (project initialization)
|
||||||
|
- **Phase 2**: Foundational (blocking prerequisites - MUST complete before user stories)
|
||||||
|
- **Phase 3+**: User Stories in priority order (P1, P2, P3...)
|
||||||
|
- Within each story: Tests (if requested) → Models → Services → Endpoints → Integration
|
||||||
|
- Each phase should be a complete, independently testable increment
|
||||||
|
- **Final Phase**: Polish & Cross-Cutting Concerns
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
### Documentation (this feature)
|
### Documentation (this feature)
|
||||||
|
|
||||||
```
|
```text
|
||||||
specs/[###-feature]/
|
specs/[###-feature]/
|
||||||
├── plan.md # This file (/speckit.plan command output)
|
├── plan.md # This file (/speckit.plan command output)
|
||||||
├── research.md # Phase 0 output (/speckit.plan command)
|
├── research.md # Phase 0 output (/speckit.plan command)
|
||||||
@@ -55,7 +55,7 @@ specs/[###-feature]/
|
|||||||
not include Option labels.
|
not include Option labels.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
```
|
```text
|
||||||
# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
|
# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
|
||||||
src/
|
src/
|
||||||
├── models/
|
├── models/
|
||||||
@@ -96,7 +96,7 @@ directories captured above]
|
|||||||
|
|
||||||
## Complexity Tracking
|
## Complexity Tracking
|
||||||
|
|
||||||
*Fill ONLY if Constitution Check has violations that must be justified*
|
> **Fill ONLY if Constitution Check has violations that must be justified**
|
||||||
|
|
||||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||||
|-----------|------------|-------------------------------------|
|
|-----------|------------|-------------------------------------|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
description: "Task list template for feature implementation"
|
description: "Task list template for feature implementation"
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -12,11 +13,13 @@ description: "Task list template for feature implementation"
|
|||||||
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
||||||
|
|
||||||
## Format: `[ID] [P?] [Story] Description`
|
## Format: `[ID] [P?] [Story] Description`
|
||||||
|
|
||||||
- **[P]**: Can run in parallel (different files, no dependencies)
|
- **[P]**: Can run in parallel (different files, no dependencies)
|
||||||
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
||||||
- Include exact file paths in descriptions
|
- Include exact file paths in descriptions
|
||||||
|
|
||||||
## Path Conventions
|
## Path Conventions
|
||||||
|
|
||||||
- **Single project**: `src/`, `tests/` at repository root
|
- **Single project**: `src/`, `tests/` at repository root
|
||||||
- **Web app**: `backend/src/`, `frontend/src/`
|
- **Web app**: `backend/src/`, `frontend/src/`
|
||||||
- **Mobile**: `api/src/`, `ios/src/` or `android/src/`
|
- **Mobile**: `api/src/`, `ios/src/` or `android/src/`
|
||||||
@@ -78,7 +81,7 @@ Examples of foundational tasks (adjust based on your project):
|
|||||||
|
|
||||||
### Tests for User Story 1 (OPTIONAL - only if tests requested) ⚠️
|
### Tests for User Story 1 (OPTIONAL - only if tests requested) ⚠️
|
||||||
|
|
||||||
**NOTE: Write these tests FIRST, ensure they FAIL before implementation**
|
> **NOTE: Write these tests FIRST, ensure they FAIL before implementation**
|
||||||
|
|
||||||
- [ ] T010 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py
|
- [ ] T010 [P] [US1] Contract test for [endpoint] in tests/contract/test_[name].py
|
||||||
- [ ] T011 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py
|
- [ ] T011 [P] [US1] Integration test for [user journey] in tests/integration/test_[name].py
|
||||||
@@ -246,5 +249,3 @@ With multiple developers:
|
|||||||
- Commit after each task or logical group
|
- Commit after each task or logical group
|
||||||
- Stop at any checkpoint to validate story independently
|
- Stop at any checkpoint to validate story independently
|
||||||
- Avoid: vague tasks, same file conflicts, cross-story dependencies that break independence
|
- Avoid: vague tasks, same file conflicts, cross-story dependencies that break independence
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
},
|
},
|
||||||
"chat.tools.terminal.autoApprove": {
|
"chat.tools.terminal.autoApprove": {
|
||||||
".specify/scripts/bash/": true,
|
".specify/scripts/bash/": true,
|
||||||
".specify/scripts/ps/": true
|
".specify/scripts/powershell/": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user