diff --git a/scripts/bash/check-prerequisites.sh b/scripts/bash/check-prerequisites.sh index 98e387c271..fed6a0a8f4 100644 --- a/scripts/bash/check-prerequisites.sh +++ b/scripts/bash/check-prerequisites.sh @@ -84,10 +84,12 @@ check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1 # If paths-only mode, output paths and exit (support JSON + paths-only combined) if $PATHS_ONLY; then + SPECS_DIR="$(get_specs_dir "$REPO_ROOT")" || exit 1 if $JSON_MODE; then # Minimal JSON paths payload (no validation performed) - printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \ - "$REPO_ROOT" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS" + printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s","SPECS_DIR":"%s"}\n' \ + "$(json_escape "$REPO_ROOT")" "$(json_escape "$CURRENT_BRANCH")" "$(json_escape "$FEATURE_DIR")" \ + "$(json_escape "$FEATURE_SPEC")" "$(json_escape "$IMPL_PLAN")" "$(json_escape "$TASKS")" "$(json_escape "$SPECS_DIR")" else echo "REPO_ROOT: $REPO_ROOT" echo "BRANCH: $CURRENT_BRANCH" @@ -95,6 +97,7 @@ if $PATHS_ONLY; then echo "FEATURE_SPEC: $FEATURE_SPEC" echo "IMPL_PLAN: $IMPL_PLAN" echo "TASKS: $TASKS" + echo "SPECS_DIR: $SPECS_DIR" fi exit 0 fi @@ -148,7 +151,9 @@ if $JSON_MODE; then json_docs="[${json_docs%,}]" fi - printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s}\n' "$FEATURE_DIR" "$json_docs" + SPECS_DIR="$(get_specs_dir "$REPO_ROOT")" || exit 1 + # Note: $json_docs is not escaped because it is already a pre-formatted JSON array + printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s,"SPECS_DIR":"%s"}\n' "$(json_escape "$FEATURE_DIR")" "$json_docs" "$(json_escape "$SPECS_DIR")" else # Text output echo "FEATURE_DIR:$FEATURE_DIR" diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 2c3165e41d..e7b5d50902 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -1,6 +1,23 @@ #!/usr/bin/env bash # Common functions and variables for all scripts +# Escape a string for safe inclusion in JSON (handles all JSON-required escapes) +json_escape() { + local str="$1" + # Escape backslashes first, then quotes, then control characters + str="${str//\\/\\\\}" + str="${str//\"/\\\"}" + str="${str//$'\n'/\\n}" + str="${str//$'\r'/\\r}" + str="${str//$'\t'/\\t}" + str="${str//$'\b'/\\b}" + str="${str//$'\f'/\\f}" + # Remove any remaining control characters (U+0000-U+001F) that are + # not covered above, since they are invalid unescaped in JSON strings. + str="$(printf '%s' "$str" | tr -d '\000-\006\016-\037')" + printf '%s' "$str" +} + # Get repository root, with fallback for non-git repositories get_repo_root() { if git rev-parse --show-toplevel >/dev/null 2>&1; then @@ -12,6 +29,24 @@ get_repo_root() { fi } +# Get specs directory, with support for external location via SPECIFY_SPECS_DIR +get_specs_dir() { + local repo_root="${1:-$(get_repo_root)}" + local specs_dir + + if [[ -n "${SPECIFY_SPECS_DIR:-}" ]]; then + specs_dir="$SPECIFY_SPECS_DIR" + # Resolve relative paths against repo root + if [[ "$specs_dir" != /* ]]; then + specs_dir="$repo_root/$specs_dir" + fi + else + specs_dir="$repo_root/specs" + fi + + echo "$specs_dir" +} + # Get current branch, with fallback for non-git repositories get_current_branch() { # First check if SPECIFY_FEATURE environment variable is set @@ -28,7 +63,7 @@ get_current_branch() { # For non-git repos, try to find the latest feature directory local repo_root=$(get_repo_root) - local specs_dir="$repo_root/specs" + local specs_dir="$(get_specs_dir "$repo_root")" if [[ -d "$specs_dir" ]]; then local latest_feature="" @@ -66,6 +101,12 @@ check_feature_branch() { local branch="$1" local has_git_repo="$2" + # When SPECIFY_SPECS_DIR is set (e.g., worktree mode), skip branch naming + # validation since the branch/worktree may not follow the NNN- convention. + if [[ -n "${SPECIFY_SPECS_DIR:-}" ]]; then + return 0 + fi + # For non-git repos, we can't enforce branch naming but still provide output if [[ "$has_git_repo" != "true" ]]; then echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2 @@ -81,14 +122,14 @@ check_feature_branch() { return 0 } -get_feature_dir() { echo "$1/specs/$2"; } +get_feature_dir() { echo "$(get_specs_dir "$1")/$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" + local specs_dir="$(get_specs_dir "$repo_root")" # Extract numeric prefix from branch (e.g., "004" from "004-whatever") if [[ ! "$branch_name" =~ ^([0-9]{3})- ]]; then diff --git a/scripts/bash/create-new-feature.sh b/scripts/bash/create-new-feature.sh index c40cfd77f0..7ebb9b2c26 100644 --- a/scripts/bash/create-new-feature.sh +++ b/scripts/bash/create-new-feature.sh @@ -5,6 +5,7 @@ set -e JSON_MODE=false SHORT_NAME="" BRANCH_NUMBER="" +NO_BRANCH=false ARGS=() i=1 while [ $i -le $# ]; do @@ -13,6 +14,9 @@ while [ $i -le $# ]; do --json) JSON_MODE=true ;; + --no-branch) + NO_BRANCH=true + ;; --short-name) if [ $((i + 1)) -gt $# ]; then echo 'Error: --short-name requires a value' >&2 @@ -41,17 +45,19 @@ while [ $i -le $# ]; do BRANCH_NUMBER="$next_arg" ;; --help|-h) - echo "Usage: $0 [--json] [--short-name ] [--number N] " + echo "Usage: $0 [--json] [--short-name ] [--number N] [--no-branch] " echo "" echo "Options:" echo " --json Output in JSON format" echo " --short-name Provide a custom short name (2-4 words) for the branch" echo " --number N Specify branch number manually (overrides auto-detection)" + echo " --no-branch Skip branch creation/checkout and git fetch" 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' --number 5" + echo " $0 --no-branch 'Fix payment timeout' --short-name 'fix-payment'" exit 0 ;; *) @@ -160,6 +166,10 @@ clean_branch_name() { # were initialised with --no-git. SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Source shared functions (get_specs_dir, json_escape, etc.) +# shellcheck source=common.sh +source "${SCRIPT_DIR}/common.sh" + if git rev-parse --show-toplevel >/dev/null 2>&1; then REPO_ROOT=$(git rev-parse --show-toplevel) HAS_GIT=true @@ -174,9 +184,19 @@ fi cd "$REPO_ROOT" -SPECS_DIR="$REPO_ROOT/specs" +SPECS_DIR="$(get_specs_dir "$REPO_ROOT")" || exit 1 mkdir -p "$SPECS_DIR" +# Scaffold _shared directory with README if it doesn't exist yet +SHARED_DIR="$SPECS_DIR/_shared" +if [ ! -d "$SHARED_DIR" ]; then + mkdir -p "$SHARED_DIR" + SHARED_README="$REPO_ROOT/.specify/templates/_shared/README.md" + if [ -f "$SHARED_README" ]; then + cp "$SHARED_README" "$SHARED_DIR/README.md" + fi +fi + # Function to generate branch name with stop word filtering and length filtering generate_branch_name() { local description="$1" @@ -234,13 +254,21 @@ else BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION") fi +# When SPECIFY_SPECS_DIR is set, automatically enable --no-branch since the +# caller controls the branch lifecycle (e.g., a git worktree dedicated to this +# feature). +if [ -n "${SPECIFY_SPECS_DIR:-}" ]; then + NO_BRANCH=true +fi + # Determine branch number if [ -z "$BRANCH_NUMBER" ]; then - if [ "$HAS_GIT" = true ]; then + if [ "$HAS_GIT" = true ] && [ "$NO_BRANCH" = false ]; then # Check existing branches on remotes BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR") else - # Fall back to local directory check + # Fall back to local directory check (also used in --no-branch mode to + # avoid running git fetch --all --prune against the parent repo) HIGHEST=$(get_highest_from_specs "$SPECS_DIR") BRANCH_NUMBER=$((HIGHEST + 1)) fi @@ -271,7 +299,9 @@ if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then >&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)" fi -if [ "$HAS_GIT" = true ]; then +if [ "$NO_BRANCH" = true ]; then + >&2 echo "[specify] --no-branch: skipping branch creation" +elif [ "$HAS_GIT" = true ]; then git checkout -b "$BRANCH_NAME" else >&2 echo "[specify] Warning: Git repository not detected; skipped branch creation for $BRANCH_NAME" @@ -288,7 +318,8 @@ if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE" export SPECIFY_FEATURE="$BRANCH_NAME" if $JSON_MODE; then - printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$BRANCH_NAME" "$SPEC_FILE" "$FEATURE_NUM" + printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s","SPECS_DIR":"%s","NO_BRANCH":%s}\n' \ + "$(json_escape "$BRANCH_NAME")" "$(json_escape "$SPEC_FILE")" "$(json_escape "$FEATURE_NUM")" "$(json_escape "$SPECS_DIR")" "$NO_BRANCH" else echo "BRANCH_NAME: $BRANCH_NAME" echo "SPEC_FILE: $SPEC_FILE" diff --git a/scripts/powershell/check-prerequisites.ps1 b/scripts/powershell/check-prerequisites.ps1 index 91667e9ef1..dab4120fdc 100644 --- a/scripts/powershell/check-prerequisites.ps1 +++ b/scripts/powershell/check-prerequisites.ps1 @@ -65,6 +65,8 @@ if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH -HasGit:$paths.HAS_GI # If paths-only mode, output paths and exit (support combined -Json -PathsOnly) if ($PathsOnly) { + $specsDir = Get-SpecsDir -RepoRoot $paths.REPO_ROOT + if (-not $specsDir) { exit 1 } if ($Json) { [PSCustomObject]@{ REPO_ROOT = $paths.REPO_ROOT @@ -73,6 +75,7 @@ if ($PathsOnly) { FEATURE_SPEC = $paths.FEATURE_SPEC IMPL_PLAN = $paths.IMPL_PLAN TASKS = $paths.TASKS + SPECS_DIR = $specsDir } | ConvertTo-Json -Compress } else { Write-Output "REPO_ROOT: $($paths.REPO_ROOT)" @@ -81,6 +84,7 @@ if ($PathsOnly) { Write-Output "FEATURE_SPEC: $($paths.FEATURE_SPEC)" Write-Output "IMPL_PLAN: $($paths.IMPL_PLAN)" Write-Output "TASKS: $($paths.TASKS)" + Write-Output "SPECS_DIR: $specsDir" } exit 0 } @@ -127,9 +131,12 @@ if ($IncludeTasks -and (Test-Path $paths.TASKS)) { # Output results if ($Json) { # JSON output + $specsDir = Get-SpecsDir -RepoRoot $paths.REPO_ROOT + if (-not $specsDir) { exit 1 } [PSCustomObject]@{ FEATURE_DIR = $paths.FEATURE_DIR - AVAILABLE_DOCS = $docs + AVAILABLE_DOCS = $docs + SPECS_DIR = $specsDir } | ConvertTo-Json -Compress } else { # Text output diff --git a/scripts/powershell/common.ps1 b/scripts/powershell/common.ps1 index b0be273545..05d6e767b0 100644 --- a/scripts/powershell/common.ps1 +++ b/scripts/powershell/common.ps1 @@ -15,6 +15,21 @@ function Get-RepoRoot { return (Resolve-Path (Join-Path $PSScriptRoot "../../..")).Path } +# Get specs directory, with support for external location via SPECIFY_SPECS_DIR +function Get-SpecsDir { + param([string]$RepoRoot = (Get-RepoRoot)) + + if ($env:SPECIFY_SPECS_DIR) { + $specsDir = $env:SPECIFY_SPECS_DIR + # Resolve relative paths against repo root + if (-not [System.IO.Path]::IsPathRooted($specsDir)) { + $specsDir = Join-Path $RepoRoot $specsDir + } + return $specsDir + } + return Join-Path $RepoRoot "specs" +} + function Get-CurrentBranch { # First check if SPECIFY_FEATURE environment variable is set if ($env:SPECIFY_FEATURE) { @@ -33,7 +48,7 @@ function Get-CurrentBranch { # For non-git repos, try to find the latest feature directory $repoRoot = Get-RepoRoot - $specsDir = Join-Path $repoRoot "specs" + $specsDir = Get-SpecsDir -RepoRoot $repoRoot if (Test-Path $specsDir) { $latestFeature = "" @@ -73,6 +88,12 @@ function Test-FeatureBranch { [bool]$HasGit = $true ) + # When SPECIFY_SPECS_DIR is set (e.g., worktree mode), skip branch naming + # validation since the branch/worktree may not follow the NNN- convention. + if ($env:SPECIFY_SPECS_DIR) { + return $true + } + # For non-git repos, we can't enforce branch naming but still provide output if (-not $HasGit) { Write-Warning "[specify] Warning: Git repository not detected; skipped branch validation" @@ -89,7 +110,7 @@ function Test-FeatureBranch { function Get-FeatureDir { param([string]$RepoRoot, [string]$Branch) - Join-Path $RepoRoot "specs/$Branch" + Join-Path (Get-SpecsDir -RepoRoot $RepoRoot) $Branch } function Get-FeaturePathsEnv { diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index 2f0172e35d..59eaa1233b 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -5,6 +5,7 @@ param( [switch]$Json, [string]$ShortName, [int]$Number = 0, + [switch]$NoBranch, [switch]$Help, [Parameter(ValueFromRemainingArguments = $true)] [string[]]$FeatureDescription @@ -19,6 +20,7 @@ if ($Help) { Write-Host " -Json Output in JSON format" Write-Host " -ShortName Provide a custom short name (2-4 words) for the branch" Write-Host " -Number N Specify branch number manually (overrides auto-detection)" + Write-Host " -NoBranch Skip branch creation (auto-enabled when SPECIFY_SPECS_DIR is set)" Write-Host " -Help Show this help message" Write-Host "" Write-Host "Examples:" @@ -149,9 +151,29 @@ try { Set-Location $repoRoot -$specsDir = Join-Path $repoRoot 'specs' +# Auto-enable --no-branch when SPECIFY_SPECS_DIR is set (e.g., worktree scenario +# where the caller controls the branch lifecycle). +if (-not $NoBranch -and $env:SPECIFY_SPECS_DIR) { + $NoBranch = $true +} + +$specsDir = Get-SpecsDir -RepoRoot $repoRoot +if (-not $specsDir) { + Write-Host "`n[specify] ERROR: Invalid SPECIFY_SPECS_DIR configuration. Aborting." -ForegroundColor Red + exit 1 +} New-Item -ItemType Directory -Path $specsDir -Force | Out-Null +# Scaffold _shared directory with README if it doesn't exist yet +$sharedDir = Join-Path $specsDir '_shared' +if (-not (Test-Path $sharedDir)) { + New-Item -ItemType Directory -Path $sharedDir -Force | Out-Null + $sharedReadme = Join-Path $repoRoot '.specify/templates/_shared/README.md' + if (Test-Path $sharedReadme) { + Copy-Item $sharedReadme (Join-Path $sharedDir 'README.md') -Force + } +} + # Function to generate branch name with stop word filtering and length filtering function Get-BranchName { param([string]$Description) @@ -208,11 +230,12 @@ if ($ShortName) { # Determine branch number if ($Number -eq 0) { - if ($hasGit) { + if ($hasGit -and -not $NoBranch) { # Check existing branches on remotes $Number = Get-NextBranchNumber -SpecsDir $specsDir } else { - # Fall back to local directory check + # Fall back to local directory check (also used in --no-branch mode + # to avoid running git fetch --all --prune against the parent repo) $Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1 } } @@ -241,7 +264,9 @@ if ($branchName.Length -gt $maxBranchLength) { Write-Warning "[specify] Truncated to: $branchName ($($branchName.Length) bytes)" } -if ($hasGit) { +if ($NoBranch) { + Write-Warning "[specify] --no-branch: skipping branch creation" +} elseif ($hasGit) { try { git checkout -b $branchName | Out-Null } catch { @@ -271,6 +296,8 @@ if ($Json) { SPEC_FILE = $specFile FEATURE_NUM = $featureNum HAS_GIT = $hasGit + SPECS_DIR = $specsDir + NO_BRANCH = $NoBranch } $obj | ConvertTo-Json -Compress } else { diff --git a/templates/_shared/README.md b/templates/_shared/README.md new file mode 100644 index 0000000000..5581db23bb --- /dev/null +++ b/templates/_shared/README.md @@ -0,0 +1,39 @@ +# Shared Context + +This directory holds project-wide standards and conventions that apply across +all feature specs. Every `.md` file placed here is automatically loaded as +read-only context by the following Spec Kit commands: + +- **specify** -- informs spec structure and alignment with project standards +- **clarify** -- validates spec alignment and informs ambiguity detection +- **plan** -- guides technical decisions in implementation plans +- **tasks** -- informs task structure and sequencing +- **implement** -- guides implementation decisions and coding patterns +- **checklist** -- incorporates project-wide requirements into validation +- **analyze** -- uses standards as additional validation criteria + +## What to put here + +Create `.md` files for any project-wide standards you want consistently applied: + +- **Architecture decisions** -- system boundaries, data flow, service topology +- **API conventions** -- endpoint naming, versioning, request/response patterns +- **Coding standards** -- naming, formatting, error handling, logging patterns +- **Security requirements** -- authentication, authorization, input validation +- **Accessibility standards** -- WCAG compliance, ARIA patterns +- **Testing conventions** -- coverage expectations, mocking strategies, test naming + +## Example + +``` +specs/_shared/ + api-conventions.md + coding-standards.md + security-requirements.md +``` + +## Notes + +- Files are **read-only** -- Spec Kit commands never modify shared context. +- Only `.md` files are loaded; other file types are ignored. +- This directory is optional. If absent, commands proceed without shared context. diff --git a/templates/commands/analyze.md b/templates/commands/analyze.md index 827d4e4caf..1f1cf6ee0e 100644 --- a/templates/commands/analyze.md +++ b/templates/commands/analyze.md @@ -67,6 +67,10 @@ Load only the minimal necessary context from each artifact: - Load `/memory/constitution.md` for principle validation +**From shared context (if available):** + +- **IF `SPECS_DIR/_shared/` exists**: Read all `.md` files for project-wide standards (architecture decisions, coding conventions, security requirements). Use these as additional validation criteria alongside the constitution. + ### 3. Build Semantic Models Create internal representations (do not include raw artifacts in output): diff --git a/templates/commands/checklist.md b/templates/commands/checklist.md index e32a2c843b..651181eae9 100644 --- a/templates/commands/checklist.md +++ b/templates/commands/checklist.md @@ -82,6 +82,7 @@ You **MUST** consider the user input before proceeding (if not empty). - spec.md: Feature requirements and scope - plan.md (if exists): Technical details, dependencies - tasks.md (if exists): Implementation tasks + - **IF `SPECS_DIR/_shared/` exists**: Read all `.md` files for project-wide standards (security requirements, accessibility standards, coding conventions). Incorporate these into checklist generation to ensure project-wide requirements are validated. **Context Loading Strategy**: - Load only necessary portions relevant to active focus areas (avoid full-file dumping) diff --git a/templates/commands/clarify.md b/templates/commands/clarify.md index 4de842aa60..b29b315c52 100644 --- a/templates/commands/clarify.md +++ b/templates/commands/clarify.md @@ -32,7 +32,11 @@ Execution steps: - If JSON parsing fails, abort and instruct user to re-run `/speckit.specify` or verify feature branch environment. - 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 the current spec file. Perform a structured ambiguity & coverage scan using this taxonomy. For each category, mark status: Clear / Partial / Missing. Produce an internal coverage map used for prioritization (do not output raw map unless no questions will be asked). +2. Load the current spec file from `FEATURE_SPEC`. + +3. Load shared project context. **IF `SPECS_DIR/_shared/` exists** (SPECS_DIR is in the JSON output): Read all `.md` files from it for project-wide context (architecture decisions, conventions, standards). Use this shared context to validate spec alignment with project standards and inform ambiguity detection in the next step. If the directory does not exist, proceed without shared context. + +4. Perform a structured ambiguity & coverage scan using this taxonomy. For each category, mark status: Clear / Partial / Missing. Produce an internal coverage map used for prioritization (do not output raw map unless no questions will be asked). Functional Scope & Behavior: - Core user goals & success criteria @@ -88,7 +92,7 @@ Execution steps: - Clarification would not materially change implementation or validation strategy - Information is better deferred to planning phase (note internally) -3. Generate (internally) a prioritized queue of candidate clarification questions (maximum 5). Do NOT output them all at once. Apply these constraints: +5. 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. - Each question must be answerable with EITHER: - A short multiple‑choice selection (2–5 distinct, mutually exclusive options), OR @@ -99,7 +103,7 @@ Execution steps: - Favor clarifications that reduce downstream rework risk or prevent misaligned acceptance tests. - If more than 5 categories remain unresolved, select the top 5 by (Impact * Uncertainty) heuristic. -4. Sequential questioning loop (interactive): +6. Sequential questioning loop (interactive): - Present EXACTLY ONE question at a time. - For multiple‑choice questions: - **Analyze all options** and determine the **most suitable option** based on: @@ -135,7 +139,7 @@ Execution steps: - Never reveal future queued questions in advance. - If no valid questions exist at start, immediately report no critical ambiguities. -5. Integration after EACH accepted answer (incremental update approach): +7. Integration after EACH accepted answer (incremental update approach): - Maintain in-memory representation of the spec (loaded once at start) plus the raw file contents. - 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). @@ -153,7 +157,7 @@ Execution steps: - Preserve formatting: do not reorder unrelated sections; keep heading hierarchy intact. - Keep each inserted clarification minimal and testable (avoid narrative drift). -6. Validation (performed after EACH write plus final pass): +8. Validation (performed after EACH write plus final pass): - Clarifications session contains exactly one bullet per accepted answer (no duplicates). - Total asked (accepted) questions ≤ 5. - Updated sections contain no lingering vague placeholders the new answer was meant to resolve. @@ -161,9 +165,9 @@ Execution steps: - Markdown structure valid; only allowed new headings: `## Clarifications`, `### Session YYYY-MM-DD`. - Terminology consistency: same canonical term used across all updated sections. -7. Write the updated spec back to `FEATURE_SPEC`. +9. Write the updated spec back to `FEATURE_SPEC`. -8. Report completion (after questioning loop ends or early termination): +10. Report completion (after questioning loop ends or early termination): - Number of questions asked & answered. - Path to updated spec. - Sections touched (list names). diff --git a/templates/commands/implement.md b/templates/commands/implement.md index 39abb1e6c8..d5f0397256 100644 --- a/templates/commands/implement.md +++ b/templates/commands/implement.md @@ -55,6 +55,7 @@ You **MUST** consider the user input before proceeding (if not empty). - **IF EXISTS**: Read contracts/ for API specifications and test requirements - **IF EXISTS**: Read research.md for technical decisions and constraints - **IF EXISTS**: Read quickstart.md for integration scenarios + - **IF `SPECS_DIR/_shared/` exists**: Read all `.md` files for project-wide context (coding standards, API conventions, security requirements). Use this to guide implementation decisions and ensure alignment with established patterns. 4. **Project Setup Verification**: - **REQUIRED**: Create/verify ignore files based on actual project setup: diff --git a/templates/commands/plan.md b/templates/commands/plan.md index 147da0afa0..5da02a084e 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -28,7 +28,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"). -2. **Load context**: Read FEATURE_SPEC and `/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). **IF `SPECS_DIR/_shared/` exists**: Read all `.md` files from it for project-wide context (architecture decisions, API conventions, coding standards). Use this to inform technical decisions and ensure alignment with established patterns. 3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to: - Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION") diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 3c952d683e..172f1ac1c0 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -39,9 +39,11 @@ Given that feature description, do this: - "Create a dashboard for analytics" → "analytics-dashboard" - "Fix payment processing timeout bug" → "fix-payment-timeout" -2. **Check for existing branches before creating new one**: +2. **Set up feature branch and run the create-new-feature script**: - a. First, fetch all remote branches to ensure we have the latest information: + **IF `--no-branch` is NOT present in the user's input**, perform branch scanning first: + + a. Fetch all remote branches to ensure we have the latest information: ```bash git fetch --all --prune @@ -50,30 +52,38 @@ Given that feature description, do this: b. Find the highest feature number across all sources for the short-name: - Remote branches: `git ls-remote --heads origin | grep -E 'refs/heads/[0-9]+-$'` - Local branches: `git branch | grep -E '^[* ]*[0-9]+-$'` - - Specs directories: Check for directories matching `specs/[0-9]+-` + - Specs directories: Check for directories matching the specs directory for `[0-9]+-` c. Determine the next available number: - Extract all numbers from all three sources - Find the highest number N - Use N+1 for the new branch number + **IF `--no-branch` IS present in the user's input**, skip steps 2a-2c entirely. The script will determine the feature number from local directories only and will not create or switch git branches. Pass `--no-branch` through to the script. + d. Run the script `{SCRIPT}` with the calculated number and short-name: - Pass `--number N+1` and `--short-name "your-short-name"` along with the feature description + - If `--no-branch` was specified, also pass `--no-branch` to the script - Bash example: `{SCRIPT} --json --number 5 --short-name "user-auth" "Add user authentication"` + - Bash example (no-branch): `{SCRIPT} --json --no-branch --short-name "user-auth" "Add user authentication"` - PowerShell example: `{SCRIPT} -Json -Number 5 -ShortName "user-auth" "Add user authentication"` + - PowerShell example (no-branch): `{SCRIPT} -Json -NoBranch -ShortName "user-auth" "Add user authentication"` **IMPORTANT**: - - Check all three sources (remote branches, local branches, specs directories) to find the highest number + - When doing branch scanning (steps 2a-2c), check all three sources (remote branches, local branches, specs directories) to find the highest number - Only match branches/directories with the exact short-name pattern - If no existing branches/directories found with this short-name, start with number 1 - You must only ever run this script once per feature - The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for - The JSON output will contain BRANCH_NAME and SPEC_FILE paths + - If NO_BRANCH is true in the JSON output, the script skipped branch creation/checkout (the current branch is used as-is) - For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot") 3. Load `templates/spec-template.md` to understand required sections. -4. Follow this execution flow: +4. **Load shared context (if available)**: Check if `SPECS_DIR/_shared/` directory exists (SPECS_DIR is provided in the JSON output from the setup script). If it exists, read all `.md` files from it. These contain project-wide standards (architecture decisions, API conventions, coding standards, security requirements). Use this context to inform spec structure and ensure alignment with established patterns. Do not modify shared files. + +5. Follow this execution flow: 1. Parse user description from Input If empty: ERROR "No feature description provided" @@ -99,9 +109,9 @@ Given that feature description, do this: 7. Identify Key Entities (if data involved) 8. Return: SUCCESS (spec ready for planning) -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. +6. 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. -6. **Specification Quality Validation**: After writing the initial spec, validate it against quality criteria: +7. **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: @@ -193,9 +203,9 @@ Given that feature description, do this: d. **Update Checklist**: After each validation iteration, update the checklist file with current pass/fail status -7. Report completion with branch name, spec file path, checklist results, and readiness for the next phase (`/speckit.clarify` or `/speckit.plan`). +8. 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:** By default, the script creates and checks out a new branch and initializes the spec file before writing. If `NO_BRANCH` is `true` in the JSON output (set by `--no-branch` flag or automatically when the user has configured a custom specs directory via `SPECIFY_SPECS_DIR`), the script skipped branch creation/checkout -- the current branch is used as-is. When reporting completion in no-branch mode, note that the branch was not created by the script. ## General Guidelines diff --git a/templates/commands/tasks.md b/templates/commands/tasks.md index d69d43763e..da598a4ee5 100644 --- a/templates/commands/tasks.md +++ b/templates/commands/tasks.md @@ -29,6 +29,7 @@ You **MUST** consider the user input before proceeding (if not empty). 2. **Load design documents**: Read from FEATURE_DIR: - **Required**: plan.md (tech stack, libraries, structure), spec.md (user stories with priorities) - **Optional**: data-model.md (entities), contracts/ (API endpoints), research.md (decisions), quickstart.md (test scenarios) + - **IF `SPECS_DIR/_shared/` exists**: Read all `.md` files for project-wide context (coding standards, conventions). Use this to inform task structure and ensure alignment with established patterns. - Note: Not all projects have all documents. Generate tasks based on what's available. 3. **Execute task generation workflow**: