From 28fdfaa86973d4402eecd89ba6c87d31e1edae03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Den=20Delimarsky=20=F0=9F=8C=BA?= <53200638+localden@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:06:25 -0700 Subject: [PATCH] Initial checkin --- .github/workflows/manual-release.yml | 191 ++++++ .github/workflows/release.yml | 225 ++++++ .gitignore | 199 +----- README.md | 366 +++++++++- media/bootstrap-claude-code.gif | Bin 0 -> 309279 bytes media/logo_large.webp | Bin 0 -> 46884 bytes media/logo_small.webp | Bin 0 -> 6144 bytes media/specify_cli.gif | Bin 0 -> 1786474 bytes memory/constitution.md | 50 ++ memory/constitution_update_checklist.md | 85 +++ pyproject.toml | 22 + scripts/check-task-prerequisites.sh | 62 ++ scripts/common.sh | 77 +++ scripts/create-new-feature.sh | 96 +++ scripts/get-feature-paths.sh | 23 + scripts/setup-plan.sh | 44 ++ scripts/update-agent-context.sh | 234 +++++++ spec-driven.md | 371 ++++++++++ src/specify_cli/__init__.py | 871 ++++++++++++++++++++++++ templates/agent-file-template.md | 23 + templates/commands/plan.md | 41 ++ templates/commands/specify.md | 17 + templates/commands/tasks.md | 63 ++ templates/plan-template.md | 237 +++++++ templates/spec-template.md | 116 ++++ templates/tasks-template.md | 127 ++++ 26 files changed, 3356 insertions(+), 184 deletions(-) create mode 100644 .github/workflows/manual-release.yml create mode 100644 .github/workflows/release.yml create mode 100644 media/bootstrap-claude-code.gif create mode 100644 media/logo_large.webp create mode 100644 media/logo_small.webp create mode 100644 media/specify_cli.gif create mode 100644 memory/constitution.md create mode 100644 memory/constitution_update_checklist.md create mode 100644 pyproject.toml create mode 100644 scripts/check-task-prerequisites.sh create mode 100644 scripts/common.sh create mode 100644 scripts/create-new-feature.sh create mode 100644 scripts/get-feature-paths.sh create mode 100644 scripts/setup-plan.sh create mode 100644 scripts/update-agent-context.sh create mode 100644 spec-driven.md create mode 100644 src/specify_cli/__init__.py create mode 100644 templates/agent-file-template.md create mode 100644 templates/commands/plan.md create mode 100644 templates/commands/specify.md create mode 100644 templates/commands/tasks.md create mode 100644 templates/plan-template.md create mode 100644 templates/spec-template.md create mode 100644 templates/tasks-template.md diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml new file mode 100644 index 000000000..02515174a --- /dev/null +++ b/.github/workflows/manual-release.yml @@ -0,0 +1,191 @@ +name: Manual Release + +on: + workflow_dispatch: + inputs: + version_bump: + description: 'Version bump type' + required: true + default: 'patch' + type: choice + options: + - patch + - minor + - major + +jobs: + manual_release: + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Calculate new version + id: version + run: | + # Get the latest tag, or use v0.0.0 if no tags exist + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT + + # Extract version number + VERSION=$(echo $LATEST_TAG | sed 's/v//') + IFS='.' read -ra VERSION_PARTS <<< "$VERSION" + MAJOR=${VERSION_PARTS[0]:-0} + MINOR=${VERSION_PARTS[1]:-0} + PATCH=${VERSION_PARTS[2]:-0} + + # Increment based on input + case "${{ github.event.inputs.version_bump }}" in + "major") + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + "minor") + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + "patch") + PATCH=$((PATCH + 1)) + ;; + esac + + NEW_VERSION="v$MAJOR.$MINOR.$PATCH" + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version will be: $NEW_VERSION (was $LATEST_TAG)" + + - name: Create release package + run: | + # Create base package directory structure + mkdir -p sdd-package-base + + # Copy common folders to base + echo "Packaging SDD common components..." + + if [ -d "memory" ]; then + cp -r memory sdd-package-base/ + echo "✓ Copied memory folder ($(find memory -type f | wc -l) files)" + else + echo "⚠️ memory folder not found" + fi + + if [ -d "scripts" ]; then + cp -r scripts sdd-package-base/ + echo "✓ Copied scripts folder ($(find scripts -type f | wc -l) files)" + else + echo "⚠️ scripts folder not found" + fi + + # Create Claude Code package + echo "Creating Claude Code package..." + mkdir -p sdd-claude-package + cp -r sdd-package-base/* sdd-claude-package/ + if [ -d "agent_templates/claude" ]; then + cp -r agent_templates/claude sdd-claude-package/.claude + echo "✓ Added Claude Code commands ($(find agent_templates/claude -type f | wc -l) files)" + else + echo "⚠️ agent_templates/claude folder not found" + fi + + # Create Gemini CLI package + echo "Creating Gemini CLI package..." + mkdir -p sdd-gemini-package + cp -r sdd-package-base/* sdd-gemini-package/ + if [ -d "agent_templates/gemini" ]; then + cp -r agent_templates/gemini sdd-gemini-package/.gemini + # Move GEMINI.md to root for easier access + if [ -f "sdd-gemini-package/.gemini/GEMINI.md" ]; then + mv sdd-gemini-package/.gemini/GEMINI.md sdd-gemini-package/GEMINI.md + echo "✓ Moved GEMINI.md to root of Gemini package" + fi + # Remove empty .gemini folder if it only contained GEMINI.md + if [ -d "sdd-gemini-package/.gemini" ] && [ -z "$(find sdd-gemini-package/.gemini -type f)" ]; then + rm -rf sdd-gemini-package/.gemini + echo "✓ Removed empty .gemini folder" + fi + echo "✓ Added Gemini CLI commands ($(find agent_templates/gemini -type f | wc -l) files)" + else + echo "⚠️ agent_templates/gemini folder not found" + fi + + # Create GitHub Copilot package + echo "Creating GitHub Copilot package..." + mkdir -p sdd-copilot-package + cp -r sdd-package-base/* sdd-copilot-package/ + if [ -d "agent_templates/copilot" ]; then + mkdir -p sdd-copilot-package/.github + cp -r agent_templates/copilot/* sdd-copilot-package/.github/ + echo "✓ Added Copilot instructions to .github ($(find agent_templates/copilot -type f | wc -l) files)" + else + echo "⚠️ agent_templates/copilot folder not found" + fi + + # Create archive files for each package + echo "Creating archive files..." + cd sdd-claude-package && zip -r ../spec-kit-template-claude-${{ steps.version.outputs.new_version }}.zip . && cd .. + + cd sdd-gemini-package && zip -r ../spec-kit-template-gemini-${{ steps.version.outputs.new_version }}.zip . && cd .. + + cd sdd-copilot-package && zip -r ../spec-kit-template-copilot-${{ steps.version.outputs.new_version }}.zip . && cd .. + + echo "" + echo "📦 Packages created:" + echo "Claude: $(ls -lh spec-kit-template-claude-*.zip | awk '{print $5}')" + echo "Gemini: $(ls -lh spec-kit-template-gemini-*.zip | awk '{print $5}')" + echo "Copilot: $(ls -lh spec-kit-template-copilot-*.zip | awk '{print $5}')" + echo "Copilot: $(ls -lh sdd-template-copilot-*.zip | awk '{print $5}')" + + - name: Generate detailed release notes + run: | + LAST_TAG=${{ steps.version.outputs.latest_tag }} + + # Get commit range + if [ "$LAST_TAG" = "v0.0.0" ]; then + COMMIT_RANGE="HEAD~10..HEAD" + COMMITS=$(git log --oneline --pretty=format:"- %s" $COMMIT_RANGE 2>/dev/null || echo "- Initial release") + else + COMMIT_RANGE="$LAST_TAG..HEAD" + COMMITS=$(git log --oneline --pretty=format:"- %s" $COMMIT_RANGE 2>/dev/null || echo "- No changes since last release") + fi + + # Count files in each directory + CLAUDE_COUNT=$(find agent_templates/claude -type f 2>/dev/null | wc -l || echo "0") + GEMINI_COUNT=$(find agent_templates/gemini -type f 2>/dev/null | wc -l || echo "0") + COPILOT_COUNT=$(find agent_templates/copilot -type f 2>/dev/null | wc -l || echo "0") + MEMORY_COUNT=$(find memory -type f 2>/dev/null | wc -l || echo "0") + SCRIPTS_COUNT=$(find scripts -type f 2>/dev/null | wc -l || echo "0") + + cat > release_notes.md << EOF + Template release ${{ steps.version.outputs.new_version }} + + Updated specification-driven development templates for GitHub Copilot, Claude Code, and Gemini CLI. + + Download the template for your preferred AI assistant: + - spec-kit-template-copilot-${{ steps.version.outputs.new_version }}.zip + - spec-kit-template-claude-${{ steps.version.outputs.new_version }}.zip + - spec-kit-template-gemini-${{ steps.version.outputs.new_version }}.zip + + Changes since $LAST_TAG: + $COMMITS + EOF + + - name: Create GitHub Release + run: | + # Remove 'v' prefix from version for release title + VERSION_NO_V=${{ steps.version.outputs.new_version }} + VERSION_NO_V=${VERSION_NO_V#v} + + gh release create ${{ steps.version.outputs.new_version }} \ + spec-kit-template-copilot-${{ steps.version.outputs.new_version }}.zip \ + spec-kit-template-claude-${{ steps.version.outputs.new_version }}.zip \ + spec-kit-template-gemini-${{ steps.version.outputs.new_version }}.zip \ + --title "Spec Kit Templates - $VERSION_NO_V" \ + --notes-file release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..098b8cfc6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,225 @@ +name: Create Release + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + release: + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get latest tag + id: get_tag + run: | + # Get the latest tag, or use v0.0.0 if no tags exist + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT + + # Extract version number and increment + VERSION=$(echo $LATEST_TAG | sed 's/v//') + IFS='.' read -ra VERSION_PARTS <<< "$VERSION" + MAJOR=${VERSION_PARTS[0]:-0} + MINOR=${VERSION_PARTS[1]:-0} + PATCH=${VERSION_PARTS[2]:-0} + + # Increment patch version + PATCH=$((PATCH + 1)) + NEW_VERSION="v$MAJOR.$MINOR.$PATCH" + + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version will be: $NEW_VERSION" + + - name: Check if release already exists + id: check_release + run: | + if gh release view ${{ steps.get_tag.outputs.new_version }} >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Release ${{ steps.get_tag.outputs.new_version }} already exists, skipping..." + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Release ${{ steps.get_tag.outputs.new_version }} does not exist, proceeding..." + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create release package + if: steps.check_release.outputs.exists == 'false' + run: | + # Create base package directory structure + mkdir -p sdd-package-base + + # Copy common folders to base + if [ -d "memory" ]; then + cp -r memory sdd-package-base/ + echo "Copied memory folder" + fi + + if [ -d "scripts" ]; then + cp -r scripts sdd-package-base/ + echo "Copied scripts folder" + fi + + if [ -d "templates" ]; then + mkdir -p sdd-package-base/templates + # Copy templates folder but exclude the commands directory + find templates -type f -not -path "templates/commands/*" -exec cp --parents {} sdd-package-base/ \; + echo "Copied templates folder (excluding commands directory)" + fi + + # Generate command files for each agent from source templates + generate_commands() { + local agent=$1 + local ext=$2 + local arg_format=$3 + local output_dir=$4 + + mkdir -p "$output_dir" + + for template in templates/commands/*.md; do + if [[ -f "$template" ]]; then + name=$(basename "$template" .md) + description=$(awk '/^description:/ {gsub(/^description: *"?/, ""); gsub(/"$/, ""); print; exit}' "$template" | tr -d '\r') + content=$(awk '/^---$/{if(++count==2) start=1; next} start' "$template" | sed "s/{ARGS}/$arg_format/g") + + case $ext in + "toml") + { + echo "description = \"$description\"" + echo "" + echo "prompt = \"\"\"" + echo "$content" + echo "\"\"\"" + } > "$output_dir/$name.$ext" + ;; + "md") + echo "$content" > "$output_dir/$name.$ext" + ;; + "prompt.md") + { + echo "# $(echo "$description" | sed 's/\. .*//')" + echo "" + echo "$content" + } > "$output_dir/$name.$ext" + ;; + esac + fi + done + } + + # Create Claude Code package + mkdir -p sdd-claude-package + cp -r sdd-package-base/* sdd-claude-package/ + mkdir -p sdd-claude-package/.claude/commands + generate_commands "claude" "md" "\$ARGUMENTS" "sdd-claude-package/.claude/commands" + echo "Created Claude Code package" + + # Create Gemini CLI package + mkdir -p sdd-gemini-package + cp -r sdd-package-base/* sdd-gemini-package/ + mkdir -p sdd-gemini-package/.gemini/commands + generate_commands "gemini" "toml" "{{args}}" "sdd-gemini-package/.gemini/commands" + if [ -f "agent_templates/gemini/GEMINI.md" ]; then + cp agent_templates/gemini/GEMINI.md sdd-gemini-package/GEMINI.md + fi + echo "Created Gemini CLI package" + + # Create GitHub Copilot package + mkdir -p sdd-copilot-package + cp -r sdd-package-base/* sdd-copilot-package/ + mkdir -p sdd-copilot-package/.github/prompts + generate_commands "copilot" "prompt.md" "\$ARGUMENTS" "sdd-copilot-package/.github/prompts" + echo "Created GitHub Copilot package" + + # Create archive files for each package + cd sdd-claude-package && zip -r ../spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. + + cd sdd-gemini-package && zip -r ../spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. + + cd sdd-copilot-package && zip -r ../spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip . && cd .. + + # List contents for verification + echo "Claude package contents:" + unzip -l spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip | head -10 + echo "Gemini package contents:" + unzip -l spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip | head -10 + echo "Copilot package contents:" + unzip -l spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip | head -10 + + - name: Generate release notes + if: steps.check_release.outputs.exists == 'false' + id: release_notes + run: | + # Get commits since last tag + LAST_TAG=${{ steps.get_tag.outputs.latest_tag }} + if [ "$LAST_TAG" = "v0.0.0" ]; then + COMMITS=$(git log --oneline --pretty=format:"- %s" HEAD~10..HEAD) + else + COMMITS=$(git log --oneline --pretty=format:"- %s" $LAST_TAG..HEAD) + fi + + # Create release notes + cat > release_notes.md << EOF + Template release ${{ steps.get_tag.outputs.new_version }} + + Updated specification-driven development templates for GitHub Copilot, Claude Code, and Gemini CLI. + + Download the template for your preferred AI assistant: + - spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip + - spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip + - spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip + EOF + + echo "Generated release notes:" + cat release_notes.md + + - name: Create GitHub Release + if: steps.check_release.outputs.exists == 'false' + run: | + # Remove 'v' prefix from version for release title + VERSION_NO_V=${{ steps.get_tag.outputs.new_version }} + VERSION_NO_V=${VERSION_NO_V#v} + + gh release create ${{ steps.get_tag.outputs.new_version }} \ + spec-kit-template-copilot-${{ steps.get_tag.outputs.new_version }}.zip \ + spec-kit-template-claude-${{ steps.get_tag.outputs.new_version }}.zip \ + spec-kit-template-gemini-${{ steps.get_tag.outputs.new_version }}.zip \ + --title "Spec Kit Templates - $VERSION_NO_V" \ + --notes-file release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update version in pyproject.toml + if: steps.check_release.outputs.exists == 'false' + run: | + # Update version in pyproject.toml (remove 'v' prefix for Python versioning) + VERSION=${{ steps.get_tag.outputs.new_version }} + PYTHON_VERSION=${VERSION#v} + + if [ -f "pyproject.toml" ]; then + sed -i "s/version = \".*\"/version = \"$PYTHON_VERSION\"/" pyproject.toml + echo "Updated pyproject.toml version to $PYTHON_VERSION" + fi + + - name: Commit version update + if: steps.check_release.outputs.exists == 'false' + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + if git diff --quiet; then + echo "No changes to commit" + else + git add pyproject.toml + git commit -m "chore: bump version to ${{ steps.get_tag.outputs.new_version }}" + git push + fi diff --git a/.gitignore b/.gitignore index b7faf403d..21c7cd017 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,8 @@ -# Byte-compiled / optimized / DLL files +# Python __pycache__/ -*.py[codz] +*.py[cod] *$py.class - -# C extensions *.so - -# Distribution / packaging .Python build/ develop-eggs/ @@ -20,188 +16,25 @@ parts/ sdist/ var/ wheels/ -share/python-wheels/ *.egg-info/ .installed.cfg *.egg -MANIFEST -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py.cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock -#poetry.toml - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. -# https://pdm-project.org/en/latest/usage/project/#working-with-version-control -#pdm.lock -#pdm.toml -.pdm-python -.pdm-build/ - -# pixi -# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. -#pixi.lock -# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one -# in the .venv directory. It is recommended not to include this directory in version control. -.pixi - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.envrc -.venv -env/ +# Virtual environments venv/ ENV/ -env.bak/ -venv.bak/ +env/ +.venv -# Spyder project settings -.spyderproject -.spyproject +# IDE +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# Abstra -# Abstra is an AI-powered process automation framework. -# Ignore directories containing user credentials, local state, and settings. -# Learn more at https://abstra.io/docs -.abstra/ - -# Visual Studio Code -# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore -# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore -# and can be added to the global gitignore or merged into this file. However, if you prefer, -# you could uncomment the following to ignore the entire vscode folder -# .vscode/ - -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc - -# Cursor -# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to -# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data -# refer to https://docs.cursor.com/context/ignore-files -.cursorignore -.cursorindexingignore - -# Marimo -marimo/_static/ -marimo/_lsp/ -__marimo__/ +# Project specific +*.log +.env +.env.local +*.lock diff --git a/README.md b/README.md index c5a34fdf9..c21fe82ce 100644 --- a/README.md +++ b/README.md @@ -1 +1,365 @@ -# spec-kit \ No newline at end of file +
+ + An effort to allow organizations to focus on product scenarios rather than writing undifferentiated code with the help of Spec-Driven Development. +
+ +--- + +## Table of Contents + +- [🤔 What is Spec-Driven Development?](#-what-is-spec-driven-development) +- [⚡ Get started](#-get-started) +- [📚 Core philosophy](#-core-philosophy) +- [🌟 Development phases](#-development-phases) +- [🎯 Experimental goals](#-experimental-goals) +- [🔧 Prerequisites](#-prerequisites) +- [📖 Learn more](#-learn-more) +- [Detailed process](#detailed-process) +- [Troubleshooting](#troubleshooting) + +## 🤔 What is Spec-Driven Development? + +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 + +### 1. Install Specify + +Initialize your project depending on the coding agent you're using: + +```bash +uvx --from git+https://github.com/localden/sdd.git specify initGQ$+Q=_*CI
zBy(J4feSIlzZG`wvr8eS7h}J0h2NbfTwfqTPYkey-|%u}6oE=48xI>Z7PVOSsXb8e
zJnYfW7GWko-$OBbM3zA+m&*VMCIccvS)BzT8{4R?#%9d-J4f&LZHo_FR8>Z31>h$H
zZ&tN>VwKXCjBpgHi>`{CbT9>qDR+xbES8()UYc`{F-r4pCK;Z&bnw48T&>b