Closing the intent-to-code chasm - specification-driven development with BDD verification chain
Overall
score
96%
Does it follow best practices?
Validation for skill structure
#!/usr/bin/env pwsh
[CmdletBinding()] param( [Parameter(Position = 0, ValueFromRemainingArguments = $true)] [string[]]$FeatureDescription, [Alias('j')] [switch]$Json, [Alias('s')] [string]$ShortName, [Alias('n')] [int]$Number = 0, [Alias('b')] [switch]$SkipBranch, [Alias('h')] [switch]$Help ) $ErrorActionPreference = 'Stop'
if ($Help) { Write-Host "Usage: ./create-new-feature.ps1 [-Json] [-ShortName <name>] [-Number N] [-SkipBranch] <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 " -Number N Specify branch number manually (overrides auto-detection)" Write-Host " -SkipBranch Create feature directory without creating a git 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'" Write-Host " ./create-new-feature.ps1 -SkipBranch 'Fix bug on existing branch'" exit 0 }
if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) { Write-Error "Usage: ./create-new-feature.ps1 [-Json] [-ShortName <name>] <feature description>" exit 1 }
$featureDesc = ($FeatureDescription -join ' ').Trim()
function Find-RepositoryRoot { param( [string]$StartDir, [string[]]$Markers = @('.git', '.specify') ) $current = Resolve-Path $StartDir while ($true) { foreach ($marker in $Markers) { if (Test-Path (Join-Path $current $marker)) { return $current } } $parent = Split-Path $current -Parent if ($parent -eq $current) { # Reached filesystem root without finding markers return $null } $current = $parent } }
function Get-HighestNumberFromSpecs { param([string]$SpecsDir)
$highest = 0
if (Test-Path $SpecsDir) {
Get-ChildItem -Path $SpecsDir -Directory | ForEach-Object {
if ($_.Name -match '^(\d+)') {
$num = [int]$matches[1]
if ($num -gt $highest) { $highest = $num }
}
}
}
return $highest}
function Get-HighestNumberFromBranches { param()
$highest = 0
try {
$branches = git branch -a 2>$null
if ($LASTEXITCODE -eq 0) {
foreach ($branch in $branches) {
# Clean branch name: remove leading markers and remote prefixes
$cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', ''
# Extract feature number if branch matches pattern ###-*
if ($cleanBranch -match '^(\d+)-') {
$num = [int]$matches[1]
if ($num -gt $highest) { $highest = $num }
}
}
}
} catch {
# If git command fails, return 0
Write-Verbose "Could not check Git branches: $_"
}
return $highest}
function Get-NextBranchNumber { param( [string]$SpecsDir )
# Fetch all remotes to get latest branch info (suppress errors if no remotes)
try {
git fetch --all --prune 2>$null | Out-Null
} catch {
# Ignore fetch errors
}
# Get highest number from ALL branches (not just matching short name)
$highestBranch = Get-HighestNumberFromBranches
# Get highest number from ALL specs (not just matching short name)
$highestSpec = Get-HighestNumberFromSpecs -SpecsDir $SpecsDir
# Take the maximum of both
$maxNum = [Math]::Max($highestBranch, $highestSpec)
# Return next number
return $maxNum + 1}
function ConvertTo-CleanBranchName { param([string]$Name)
return $Name.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''}
try { $gitRoot = git rev-parse --show-toplevel 2>$null $hasGit = ($LASTEXITCODE -eq 0) } catch { $hasGit = $false $gitRoot = $null }
$currentDir = Get-Location if (Test-Path (Join-Path $currentDir '.specify')) { # Current working directory is a project root (has .specify) $repoRoot = $currentDir } elseif ($hasGit -and $gitRoot) { # Fall back to git root $repoRoot = $gitRoot } else { # No git or current dir .specify, search for markers $repoRoot = Find-RepositoryRoot -StartDir $PSScriptRoot if (-not $repoRoot) { Write-Error "Error: Could not determine repository root. Please run this script from within the repository." exit 1 } }
Set-Location $repoRoot
$specsDir = Join-Path $repoRoot 'specs' New-Item -ItemType Directory -Path $specsDir -Force | Out-Null
function Get-BranchName { 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 = ConvertTo-CleanBranchName -Name $Description
$fallbackWords = ($result -split '-') | Where-Object { $_ } | Select-Object -First 3
return [string]::Join('-', $fallbackWords)
}}
if ($ShortName) { # Use provided short name, just clean it up $branchSuffix = ConvertTo-CleanBranchName -Name $ShortName } else { # Generate from description with smart filtering $branchSuffix = Get-BranchName -Description $featureDesc }
if ($Number -eq 0) { if ($hasGit) { # Check existing branches on remotes $Number = Get-NextBranchNumber -SpecsDir $specsDir } else { # Fall back to local directory check $Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1 } }
$featureNum = ('{0:000}' -f $Number) $branchName = "$featureNum-$branchSuffix"
$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 ($SkipBranch) { Write-Warning "[specify] Skipping branch creation (-SkipBranch). Feature directory: $branchName" } elseif ($hasGit) { try { git checkout -b $branchName | Out-Null } catch { Write-Warning "Failed to create git branch: $branchName" } } else { Write-Warning "[specify] Warning: Git repository not detected; skipped branch creation for $branchName" }
$featureDir = Join-Path $specsDir $branchName New-Item -ItemType Directory -Path $featureDir -Force | Out-Null
$template = Join-Path $PSScriptRoot '....\templates\spec-template.md' $specFile = Join-Path $featureDir 'spec.md' if (Test-Path $template) { Copy-Item $template $specFile -Force } else { New-Item -ItemType File -Path $specFile | Out-Null }
$env:SPECIFY_FEATURE = $branchName
. "$PSScriptRoot/common.ps1" Write-ActiveFeature -Feature $branchName -RepoRoot $repoRoot
if ($Json) { $obj = [PSCustomObject]@{ BRANCH_NAME = $branchName SPEC_FILE = $specFile FEATURE_NUM = $featureNum HAS_GIT = $hasGit } $obj | ConvertTo-Json -Compress } else { Write-Output "BRANCH_NAME: $branchName" Write-Output "SPEC_FILE: $specFile" Write-Output "FEATURE_NUM: $featureNum" Write-Output "HAS_GIT: $hasGit" }
Install with Tessl CLI
npx tessl i tessl-labs/intent-integrity-kitrules
skills
iikit-00-constitution
scripts
iikit-01-specify
iikit-02-clarify
iikit-03-plan
iikit-04-checklist
scripts
dashboard
iikit-05-testify
iikit-06-tasks
iikit-07-analyze
iikit-08-implement
iikit-09-taskstoissues
iikit-bugfix
scripts
iikit-core
scripts
bash
dashboard
powershell