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( [string]$Phase, [switch]$Json, [string]$ProjectRoot, [switch]$RequireTasks, [switch]$IncludeTasks, [switch]$PathsOnly, [switch]$Help )
$ErrorActionPreference = 'Stop'
if ($Help) { Write-Output @" Usage: check-prerequisites.ps1 -Phase <PHASE> [-Json] [-ProjectRoot PATH]
Phase-aware prerequisite checking for IIKit workflow.
PHASES: 00 Constitution (no validation) 01 Specify (soft constitution) 02 Clarify (soft constitution, requires spec) bugfix Bug fix (soft constitution) 03 Plan (hard constitution, requires spec, copies template) 04 Checklist (basic constitution, requires spec + plan) 05 Testify (basic constitution, requires spec + plan, soft checklist) 06 Tasks (basic constitution, requires spec + plan, soft checklist) 07 Analyze (hard constitution, requires spec + plan + tasks, soft checklist) 08 Implement (hard constitution, requires spec + plan + tasks, hard checklist) 09 Tasks to Issues (implicit constitution, requires spec + plan + tasks) core Paths only (no validation) status Deterministic status report (non-fatal, computes ready_for/next_step)
OPTIONS: -Json Output in JSON format -ProjectRoot Override project root directory (for testing) -Help Show this help message
LEGACY FLAGS (deprecated): -PathsOnly Use -Phase core instead -RequireTasks Use -Phase 08 instead -IncludeTasks Use -Phase 08 instead
"@ exit 0 }
if (-not $Phase) { if ($PathsOnly) { Write-Warning "DEPRECATED: -PathsOnly is deprecated, use -Phase core" $Phase = 'core' } elseif ($RequireTasks) { Write-Warning "DEPRECATED: -RequireTasks/-IncludeTasks are deprecated, use -Phase 08" $Phase = '08' } else { $Phase = '04' } }
. "$PSScriptRoot/common.ps1"
$phaseConfig = @{ '00' = @{ Const='none'; Spec='no'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='' } '01' = @{ Const='soft'; Spec='no'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='' } '02' = @{ Const='soft'; Spec='required'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='' } 'bugfix' = @{ Const='soft'; Spec='no'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='' } '03' = @{ Const='hard'; Spec='required'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='spec_quality,copy_plan_template' } '04' = @{ Const='basic'; Spec='required'; Plan='required'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='' } '05' = @{ Const='basic'; Spec='required'; Plan='required'; Tasks='no'; IncTasks='no'; Checklist='soft'; Extras='' } '06' = @{ Const='basic'; Spec='required'; Plan='required'; Tasks='no'; IncTasks='no'; Checklist='soft'; Extras='' } '07' = @{ Const='hard'; Spec='required'; Plan='required'; Tasks='required'; IncTasks='yes'; Checklist='soft'; Extras='' } '08' = @{ Const='hard'; Spec='required'; Plan='required'; Tasks='required'; IncTasks='yes'; Checklist='hard'; Extras='' } '09' = @{ Const='implicit'; Spec='required'; Plan='required'; Tasks='required'; IncTasks='yes'; Checklist='none'; Extras='' } 'core' = @{ Const='none'; Spec='no'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='paths_only' } 'status' = @{ Const='none'; Spec='no'; Plan='no'; Tasks='no'; IncTasks='no'; Checklist='none'; Extras='status_mode' } }
if (-not $phaseConfig.ContainsKey($Phase)) { Write-Error "Unknown phase '$Phase'. Valid: 00 01 02 03 04 05 06 07 08 09 bugfix core status" exit 1 }
$cfg = $phaseConfig[$Phase]
if ($IncludeTasks -and $cfg.IncTasks -eq 'no') { $cfg.IncTasks = 'yes' }
if ($ProjectRoot) {
$repoRoot = $ProjectRoot
} else {
$repoRoot = Get-RepoRoot
}
$hasGit = Test-HasGit
$currentBranch = Get-CurrentBranch
$statusNoFeature = $false
$branchResult = Test-FeatureBranch -Branch $currentBranch -HasGit $hasGit
if ($branchResult -eq "NEEDS_SELECTION") {
$featuresJson = Get-FeaturesJson
if ($Json) {
Write-Output "{"needs_selection":true,"features":$featuresJson}"
} else {
Write-Output "NEEDS_SELECTION: true"
Write-Output "Run: /iikit-core use <feature> to select a feature."
}
exit 2
} elseif ($branchResult -eq "ERROR") {
if ($cfg.Extras -match 'status_mode') {
$statusNoFeature = $true
$paths = [PSCustomObject]@{
REPO_ROOT = $repoRoot
CURRENT_BRANCH = $currentBranch
HAS_GIT = $hasGit
FEATURE_DIR = ''
FEATURE_SPEC = ''
IMPL_PLAN = ''
TASKS = ''
RESEARCH = ''
DATA_MODEL = ''
QUICKSTART = ''
CONTRACTS_DIR = ''
}
} else {
exit 1
}
}
if (-not $statusNoFeature) { $paths = Get-FeaturePathsEnv
# Override paths if -ProjectRoot was specified
if ($ProjectRoot) {
$paths.REPO_ROOT = $ProjectRoot
$paths.FEATURE_DIR = Find-FeatureDirByPrefix -RepoRoot $ProjectRoot -BranchName $currentBranch
$paths.FEATURE_SPEC = Join-Path $paths.FEATURE_DIR 'spec.md'
$paths.IMPL_PLAN = Join-Path $paths.FEATURE_DIR 'plan.md'
$paths.TASKS = Join-Path $paths.FEATURE_DIR 'tasks.md'
$paths.RESEARCH = Join-Path $paths.FEATURE_DIR 'research.md'
$paths.DATA_MODEL = Join-Path $paths.FEATURE_DIR 'data-model.md'
$paths.QUICKSTART = Join-Path $paths.FEATURE_DIR 'quickstart.md'
$paths.CONTRACTS_DIR = Join-Path $paths.FEATURE_DIR 'contracts'
}}
if ($cfg.Extras -match 'paths_only') { if ($Json) { $result = [ordered]@{ phase = $Phase constitution_mode = $cfg.Const REPO_ROOT = $paths.REPO_ROOT BRANCH = $paths.CURRENT_BRANCH HAS_GIT = $hasGit FEATURE_DIR = $paths.FEATURE_DIR FEATURE_SPEC = $paths.FEATURE_SPEC IMPL_PLAN = $paths.IMPL_PLAN TASKS = $paths.TASKS AVAILABLE_DOCS = @() validated = [ordered]@{ constitution = $false; spec = $false; plan = $false; tasks = $false } warnings = @() } ($result | ConvertTo-Json -Compress -Depth 3) } else { Write-Output "REPO_ROOT: $($paths.REPO_ROOT)" Write-Output "BRANCH: $($paths.CURRENT_BRANCH)" Write-Output "FEATURE_DIR: $($paths.FEATURE_DIR)" Write-Output "FEATURE_SPEC: $($paths.FEATURE_SPEC)" Write-Output "IMPL_PLAN: $($paths.IMPL_PLAN)" Write-Output "TASKS: $($paths.TASKS)" } # Launch dashboard & "$PSScriptRoot/generate-dashboard-safe.ps1" | Out-Null exit 0 }
if ($cfg.Extras -match 'status_mode') { # --- Artifact existence checks --- $aConstitution = Test-Path (Join-Path $repoRoot 'CONSTITUTION.md') $aSpec = $paths.FEATURE_DIR -and (Test-Path $paths.FEATURE_SPEC -ErrorAction SilentlyContinue) $aPlan = $paths.FEATURE_DIR -and (Test-Path $paths.IMPL_PLAN -ErrorAction SilentlyContinue) $aTasks = $paths.FEATURE_DIR -and (Test-Path $paths.TASKS -ErrorAction SilentlyContinue) $aChecklists = $paths.FEATURE_DIR -and (Test-Path (Join-Path $paths.FEATURE_DIR 'checklists') -PathType Container -ErrorAction SilentlyContinue) $aTestSpecs = $paths.FEATURE_DIR -and (Test-Path (Join-Path $paths.FEATURE_DIR 'tests' 'test-specs.md') -ErrorAction SilentlyContinue)
# --- Non-fatal validation ---
$vConstitution = $false
$vSpec = $false
$vPlan = $false
$vTasks = $false
$warnings = @()
if ($aConstitution) {
try { $vConstitution = Test-Constitution -RepoRoot $repoRoot } catch { $vConstitution = $false }
}
if ($aSpec) {
try { $vSpec = Test-Spec -SpecFile $paths.FEATURE_SPEC } catch { $vSpec = $false }
}
if ($aPlan) {
try { $vPlan = Test-Plan -PlanFile $paths.IMPL_PLAN } catch { $vPlan = $false }
}
if ($aTasks) {
try { $vTasks = Test-Tasks -TasksFile $paths.TASKS } catch { $vTasks = $false }
}
# --- Spec quality (non-fatal) ---
$specQuality = 0
if ($aSpec) {
try { $specQuality = Get-SpecQualityScore -SpecFile $paths.FEATURE_SPEC } catch { $specQuality = 0 }
}
# --- Checklist counting ---
$checklistChecked = 0
$checklistTotal = 0
$checklistComplete = $false
if ($aChecklists) {
$checklistsDir = Join-Path $paths.FEATURE_DIR 'checklists'
Get-ChildItem -Path $checklistsDir -Filter '*.md' -ErrorAction SilentlyContinue | ForEach-Object {
$content = Get-Content -Path $_.FullName -ErrorAction SilentlyContinue
foreach ($line in $content) {
if ($line -match '^- \[.\]') {
$checklistTotal++
if ($line -match '^- \[[xX]\]') {
$checklistChecked++
}
}
}
}
if ($checklistTotal -gt 0 -and $checklistChecked -eq $checklistTotal) {
$checklistComplete = $true
}
}
# --- Feature stage ---
$featureStage = 'unknown'
if ($paths.FEATURE_DIR -and (Test-Path $paths.FEATURE_DIR -PathType Container -ErrorAction SilentlyContinue)) {
$localFeature = Split-Path $paths.FEATURE_DIR -Leaf
$featureStage = Get-FeatureStage -RepoRoot $repoRoot -Feature $localFeature
} elseif ($statusNoFeature) {
$featureStage = 'no-feature'
}
# --- Ready-for computation ---
$readyFor = '00'
$readyFor = '01' # Phase 01 always passable (soft constitution)
if ($vSpec) { $readyFor = '02' }
if ($vConstitution -and $vSpec) { $readyFor = '03' }
if ($vConstitution -and $vSpec -and $vPlan) { $readyFor = '04' }
if ($vConstitution -and $vSpec -and $vPlan) { $readyFor = '05' }
if ($vConstitution -and $vSpec -and $vPlan) { $readyFor = '06' }
if ($vConstitution -and $vSpec -and $vPlan -and $vTasks) { $readyFor = '07' }
if ($vConstitution -and $vSpec -and $vPlan -and $vTasks) { $readyFor = '08' }
if ($vConstitution -and $vSpec -and $vPlan -and $vTasks) { $readyFor = '09' }
# --- Next step + clear_before ---
$nextStep = $null
$clearBefore = $false
if (-not $aConstitution) {
$nextStep = '/iikit-00-constitution'
$clearBefore = $false
} elseif ($statusNoFeature -or -not $paths.FEATURE_DIR -or -not (Test-Path $paths.FEATURE_DIR -PathType Container -ErrorAction SilentlyContinue)) {
$nextStep = '/iikit-01-specify <description>'
$clearBefore = $false
} elseif (-not $vSpec) {
$nextStep = '/iikit-01-specify <description>'
$clearBefore = $false
} elseif (-not $vPlan) {
$nextStep = '/iikit-03-plan'
$clearBefore = $true
} elseif ($aChecklists -and $checklistTotal -gt 0 -and -not $checklistComplete) {
$nextStep = '/iikit-04-checklist'
$clearBefore = $false
} elseif (-not $vTasks) {
$nextStep = '/iikit-06-tasks'
$clearBefore = $true
} elseif ($featureStage -eq 'complete') {
$nextStep = $null
$clearBefore = $false
} else {
$nextStep = '/iikit-08-implement'
$clearBefore = $true
}
# --- Available docs ---
$docs = @()
if ($paths.FEATURE_DIR) {
if (Test-Path $paths.RESEARCH -ErrorAction SilentlyContinue) { $docs += 'research.md' }
if (Test-Path $paths.DATA_MODEL -ErrorAction SilentlyContinue) { $docs += 'data-model.md' }
if ((Test-Path $paths.CONTRACTS_DIR -ErrorAction SilentlyContinue) -and (Get-ChildItem -Path $paths.CONTRACTS_DIR -ErrorAction SilentlyContinue | Select-Object -First 1)) {
$docs += 'contracts/'
}
if (Test-Path $paths.QUICKSTART -ErrorAction SilentlyContinue) { $docs += 'quickstart.md' }
if (Test-Path $paths.TASKS -ErrorAction SilentlyContinue) { $docs += 'tasks.md' }
}
# --- Output ---
if ($Json) {
$result = [ordered]@{
phase = 'status'
FEATURE_DIR = $paths.FEATURE_DIR
FEATURE_SPEC = $paths.FEATURE_SPEC
IMPL_PLAN = $paths.IMPL_PLAN
TASKS = $paths.TASKS
BRANCH = $paths.CURRENT_BRANCH
HAS_GIT = $hasGit
REPO_ROOT = $paths.REPO_ROOT
AVAILABLE_DOCS = $docs
validated = [ordered]@{
constitution = [bool]$vConstitution
spec = [bool]$vSpec
plan = [bool]$vPlan
tasks = [bool]$vTasks
}
warnings = $warnings
artifacts = [ordered]@{
constitution = [ordered]@{ exists = [bool]$aConstitution; valid = [bool]$vConstitution }
spec = [ordered]@{ exists = [bool]$aSpec; valid = [bool]$vSpec; quality = $specQuality }
plan = [ordered]@{ exists = [bool]$aPlan; valid = [bool]$vPlan }
tasks = [ordered]@{ exists = [bool]$aTasks; valid = [bool]$vTasks }
checklists = [ordered]@{ exists = [bool]$aChecklists; checked = $checklistChecked; total = $checklistTotal; complete = [bool]$checklistComplete }
test_specs = [ordered]@{ exists = [bool]$aTestSpecs }
}
feature_stage = $featureStage
ready_for = $readyFor
next_step = $nextStep
clear_before = [bool]$clearBefore
checklist_checked = $checklistChecked
checklist_total = $checklistTotal
}
($result | ConvertTo-Json -Compress -Depth 4)
} else {
Write-Output "Phase: status"
Write-Output "Feature stage: $featureStage"
Write-Output "Ready for: phase $readyFor"
if ($nextStep) {
if ($clearBefore) {
Write-Output "Next step: /clear, then $nextStep"
} else {
Write-Output "Next step: $nextStep"
}
} else {
Write-Output "Next step: (none - feature complete)"
}
Write-Output ""
Write-Output "Artifacts:"
$yOrN = { param($v) if ($v) { '[Y]' } else { '[N]' } }
Write-Output " Constitution: $(& $yOrN $aConstitution) $(if ($vConstitution) { '(valid)' } elseif ($aConstitution) { '(invalid)' })"
Write-Output " Spec: $(& $yOrN $aSpec) $(if ($vSpec) { "(valid, quality $specQuality/10)" } elseif ($aSpec) { '(invalid)' })"
Write-Output " Plan: $(& $yOrN $aPlan) $(if ($vPlan) { '(valid)' } elseif ($aPlan) { '(invalid)' })"
Write-Output " Tasks: $(& $yOrN $aTasks) $(if ($vTasks) { '(valid)' } elseif ($aTasks) { '(invalid)' })"
Write-Output " Checklists: $(if ($aChecklists) { "[Y] ($checklistChecked/$checklistTotal)" } else { '[N]' })"
Write-Output " Test specs: $(& $yOrN $aTestSpecs)"
}
# Launch dashboard
& "$PSScriptRoot/generate-dashboard-safe.ps1" | Out-Null
exit 0}
$warnings = @() $vConstitution = $false $vSpec = $false $vPlan = $false $vTasks = $false
if (-not (Test-Path $paths.FEATURE_DIR -PathType Container)) { Write-Error "Feature directory not found: $($paths.FEATURE_DIR)" Write-Host "Run /iikit-01-specify first to create the feature structure." exit 1 }
switch ($cfg.Const) { 'none' { # Skip } 'soft' { $constPath = Join-Path $repoRoot 'CONSTITUTION.md' if (Test-Path $constPath) { $vConstitution = $true $content = Get-Content -Path $constPath -Raw -ErrorAction SilentlyContinue if ($content -notmatch '## .*Principles|# .*Constitution') { $warnings += 'Constitution may be incomplete - missing principles section' } } else { $warnings += 'Constitution not found; recommended: /iikit-00-constitution' } } default { # basic, hard, implicit if (-not (Test-Constitution -RepoRoot $repoRoot)) { exit 1 } $vConstitution = $true } }
if ($cfg.Spec -eq 'required') { if (-not (Test-Spec -SpecFile $paths.FEATURE_SPEC)) { exit 1 } $vSpec = $true }
$specQuality = $null if ($cfg.Extras -match 'spec_quality') { $specQuality = Get-SpecQualityScore -SpecFile $paths.FEATURE_SPEC Write-Host "Spec quality score: $specQuality/10" -ForegroundColor Cyan if ($specQuality -lt 6) { $warnings += "Spec quality is low ($specQuality/10). Consider running /iikit-02-clarify." } }
if ($cfg.Plan -eq 'required') { if (-not (Test-Plan -PlanFile $paths.IMPL_PLAN)) { exit 1 } $vPlan = $true }
$planTemplateCopied = $null if ($cfg.Extras -match 'copy_plan_template') { New-Item -ItemType Directory -Path $paths.FEATURE_DIR -Force | Out-Null $template = Join-Path $PSScriptRoot '....\templates\plan-template.md' if (Test-Path $template) { Copy-Item $template $paths.IMPL_PLAN -Force Write-Host "Copied plan template to $($paths.IMPL_PLAN)" -ForegroundColor Cyan $planTemplateCopied = $true } else { $warnings += "Plan template not found at $template" New-Item -ItemType File -Path $paths.IMPL_PLAN -Force | Out-Null $planTemplateCopied = $false } }
if ($cfg.Tasks -eq 'required') { if (-not (Test-Tasks -TasksFile $paths.TASKS)) { exit 1 } $vTasks = $true }
$checklistChecked = 0 $checklistTotal = 0 if ($cfg.Checklist -ne 'none') { $checklistsDir = Join-Path $paths.FEATURE_DIR 'checklists' if (Test-Path $checklistsDir) { Get-ChildItem -Path $checklistsDir -Filter '*.md' -ErrorAction SilentlyContinue | ForEach-Object { $content = Get-Content -Path $_.FullName -ErrorAction SilentlyContinue foreach ($line in $content) { if ($line -match '^- [.]') { $checklistTotal++ if ($line -match '^- [[xX]]') { $checklistChecked++ } } } } }
if ($checklistTotal -gt 0 -and $checklistChecked -lt $checklistTotal) {
$pct = [math]::Floor(($checklistChecked * 100) / $checklistTotal)
if ($cfg.Checklist -eq 'hard') {
$warnings += "Checklists incomplete ($checklistChecked/$checklistTotal items, ${pct}%). Must be 100% for implementation."
} else {
$warnings += "Checklists incomplete ($checklistChecked/$checklistTotal items, ${pct}%). Recommend /iikit-04-checklist."
}
}}
$docs = @() if (Test-Path $paths.RESEARCH) { $docs += 'research.md' } if (Test-Path $paths.DATA_MODEL) { $docs += 'data-model.md' } if ((Test-Path $paths.CONTRACTS_DIR) -and (Get-ChildItem -Path $paths.CONTRACTS_DIR -ErrorAction SilentlyContinue | Select-Object -First 1)) { $docs += 'contracts/' } if (Test-Path $paths.QUICKSTART) { $docs += 'quickstart.md' } if ($cfg.IncTasks -eq 'yes' -and (Test-Path $paths.TASKS)) { $docs += 'tasks.md' }
if ($Json) { $result = [ordered]@{ phase = $Phase constitution_mode = $cfg.Const FEATURE_DIR = $paths.FEATURE_DIR FEATURE_SPEC = $paths.FEATURE_SPEC IMPL_PLAN = $paths.IMPL_PLAN TASKS = $paths.TASKS BRANCH = $paths.CURRENT_BRANCH HAS_GIT = $hasGit REPO_ROOT = $paths.REPO_ROOT AVAILABLE_DOCS = $docs validated = [ordered]@{ constitution = $vConstitution spec = $vSpec plan = $vPlan tasks = $vTasks } warnings = $warnings }
# Phase 03 extras
if ($null -ne $specQuality) {
$result['spec_quality'] = $specQuality
}
if ($null -ne $planTemplateCopied) {
$result['plan_template_copied'] = $planTemplateCopied
}
# Checklist info
if ($cfg.Checklist -ne 'none' -and $checklistTotal -gt 0) {
$result['checklist_checked'] = $checklistChecked
$result['checklist_total'] = $checklistTotal
}
($result | ConvertTo-Json -Compress -Depth 3)} else { Write-Output "Phase: $Phase" Write-Output "FEATURE_DIR:$($paths.FEATURE_DIR)" Write-Output "AVAILABLE_DOCS:"
Test-FileExists -Path $paths.RESEARCH -Description 'research.md' | Out-Null
Test-FileExists -Path $paths.DATA_MODEL -Description 'data-model.md' | Out-Null
Test-DirHasFiles -Path $paths.CONTRACTS_DIR -Description 'contracts/' | Out-Null
Test-FileExists -Path $paths.QUICKSTART -Description 'quickstart.md' | Out-Null
if ($cfg.IncTasks -eq 'yes') {
Test-FileExists -Path $paths.TASKS -Description 'tasks.md' | Out-Null
}
if ($warnings.Count -gt 0) {
Write-Output ""
Write-Output "WARNINGS:"
foreach ($w in $warnings) {
Write-Output " - $w"
}
}
if ($null -ne $specQuality) {
Write-Output "Spec quality score: $specQuality/10"
}}
& "$PSScriptRoot/generate-dashboard-safe.ps1" | Out-Null
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