CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/intent-integrity-kit

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

Overview
Skills
Evals
Files

update-agent-context.ps1skills/iikit-03-plan/scripts/powershell/

#!/usr/bin/env pwsh <# .SYNOPSIS Update agent context files with information from plan.md (PowerShell version)

.DESCRIPTION Mirrors the behavior of scripts/bash/update-agent-context.sh:

  1. Environment Validation
  2. Plan Data Extraction
  3. Agent File Management (create from template or update existing)
  4. Content Generation (technology stack, recent changes, timestamp)
  5. Multi-Agent Support (claude, gemini, codex, opencode)

.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).

.EXAMPLE ./update-agent-context.ps1 -AgentType claude

.EXAMPLE ./update-agent-context.ps1 # Updates all existing agent files

.NOTES Relies on common helper functions in common.ps1 #> param( [Parameter(Position=0)] [ValidateSet('claude','gemini','codex','opencode')] [string]$AgentType )

$ErrorActionPreference = 'Stop'

Import common helpers

$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path . (Join-Path $ScriptDir 'common.ps1')

Check if we're on a proper feature branch FIRST (may set SPECIFY_FEATURE)

This must happen before Get-FeaturePathsEnv so it uses the corrected feature name

$repoRoot = Get-RepoRoot $hasGit = Test-HasGit $currentBranch = Get-CurrentBranch $branchResult = Test-FeatureBranch -Branch $currentBranch -HasGit $hasGit if ($branchResult -eq "NEEDS_SELECTION") { Write-Host "ERROR: Multiple features exist. Run: /iikit-core use <feature> to select one." -ForegroundColor Red exit 2 } elseif ($branchResult -eq "ERROR") { exit 1 }

Now acquire environment paths (will use SPECIFY_FEATURE if it was set by Test-FeatureBranch)

$envData = Get-FeaturePathsEnv $REPO_ROOT = $envData.REPO_ROOT $CURRENT_BRANCH = $envData.CURRENT_BRANCH $HAS_GIT = $envData.HAS_GIT $IMPL_PLAN = $envData.IMPL_PLAN $NEW_PLAN = $IMPL_PLAN

Agent file paths (simplified to core agents only)

$CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' $GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' $AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md'

Template path relative to script location (works for both .tessl and .claude installs)

$TEMPLATE_FILE = Join-Path $PSScriptRoot '....\templates\agent-file-template.md'

Parsed plan data placeholders

$script:NEW_LANG = '' $script:NEW_FRAMEWORK = '' $script:NEW_DB = '' $script:NEW_PROJECT_TYPE = ''

function Write-Info { param( [Parameter(Mandatory=$true)] [string]$Message ) Write-Host "INFO: $Message" }

function Write-Success { param( [Parameter(Mandatory=$true)] [string]$Message ) Write-Host "SUCCESS: $Message" }

function Write-WarningMsg { param( [Parameter(Mandatory=$true)] [string]$Message ) Write-Warning $Message }

function Write-Err { param( [Parameter(Mandatory=$true)] [string]$Message ) Write-Host "ERROR: $Message" -ForegroundColor Red }

function Validate-Environment { if (-not $CURRENT_BRANCH) { Write-Err 'Unable to determine current feature' if ($HAS_GIT) { Write-Info "Make sure you're on a feature branch" } else { Write-Info 'Run /iikit-core use <feature> or create a new feature first' } exit 1 } if (-not (Test-Path $NEW_PLAN)) { Write-Err "No plan.md found at $NEW_PLAN" Write-Info 'Ensure you are working on a feature with a corresponding spec directory' if (-not $HAS_GIT) { Write-Info 'Run /iikit-core use <feature> or create a new feature first' } exit 1 } if (-not (Test-Path $TEMPLATE_FILE)) { Write-Err "Template file not found at $TEMPLATE_FILE" Write-Info 'Run /iikit-core init to initialize intent-integrity-kit, or add agent-file-template.md to .claude/skills/iikit-core/templates/.' exit 1 } }

function Extract-PlanField { param( [Parameter(Mandatory=$true)] [string]$FieldPattern, [Parameter(Mandatory=$true)] [string]$PlanFile ) if (-not (Test-Path $PlanFile)) { return '' } # Lines like Language/Version: Python 3.12 $regex = "^**$([Regex]::Escape($FieldPattern))**: (.+)$" Get-Content -LiteralPath $PlanFile -Encoding utf8 | ForEach-Object { if ($_ -match $regex) { $val = $Matches[1].Trim() if ($val -notin @('NEEDS CLARIFICATION','N/A')) { return $val } } } | Select-Object -First 1 }

function Parse-PlanData { param( [Parameter(Mandatory=$true)] [string]$PlanFile ) if (-not (Test-Path $PlanFile)) { Write-Err "Plan file not found: $PlanFile"; return $false } Write-Info "Parsing plan data from $PlanFile" $script:NEW_LANG = Extract-PlanField -FieldPattern 'Language/Version' -PlanFile $PlanFile $script:NEW_FRAMEWORK = Extract-PlanField -FieldPattern 'Primary Dependencies' -PlanFile $PlanFile $script:NEW_DB = Extract-PlanField -FieldPattern 'Storage' -PlanFile $PlanFile $script:NEW_PROJECT_TYPE = Extract-PlanField -FieldPattern 'Project Type' -PlanFile $PlanFile

if ($NEW_LANG) { Write-Info "Found language: $NEW_LANG" } else { Write-WarningMsg 'No language information found in plan' }
if ($NEW_FRAMEWORK) { Write-Info "Found framework: $NEW_FRAMEWORK" }
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Info "Found database: $NEW_DB" }
if ($NEW_PROJECT_TYPE) { Write-Info "Found project type: $NEW_PROJECT_TYPE" }
return $true

}

function Format-TechnologyStack { param( [Parameter(Mandatory=$false)] [string]$Lang, [Parameter(Mandatory=$false)] [string]$Framework ) $parts = @() if ($Lang -and $Lang -ne 'NEEDS CLARIFICATION') { $parts += $Lang } if ($Framework -and $Framework -notin @('NEEDS CLARIFICATION','N/A')) { $parts += $Framework } if (-not $parts) { return '' } return ($parts -join ' + ') }

function Get-ProjectStructure { param( [Parameter(Mandatory=$false)] [string]$ProjectType ) if ($ProjectType -match 'web') { return "backend/nfrontend/ntests/" } else { return "src/`ntests/" } }

function Get-CommandsForLanguage { param( [Parameter(Mandatory=$false)] [string]$Lang ) switch -Regex ($Lang) { 'Python' { return "cd src; pytest; ruff check ." } 'Rust' { return "cargo test; cargo clippy" } 'JavaScript|TypeScript' { return "npm test; npm run lint" } default { return "# Add commands for $Lang" } } }

function New-AgentFile { param( [Parameter(Mandatory=$true)] [string]$TargetFile, [Parameter(Mandatory=$true)] [string]$ProjectName, [Parameter(Mandatory=$true)] [datetime]$Date ) if (-not (Test-Path $TEMPLATE_FILE)) { Write-Err "Template not found at $TEMPLATE_FILE"; return $false } $temp = New-TemporaryFile Copy-Item -LiteralPath $TEMPLATE_FILE -Destination $temp -Force

$projectStructure = Get-ProjectStructure -ProjectType $NEW_PROJECT_TYPE
$commands = Get-CommandsForLanguage -Lang $NEW_LANG

$escaped_lang = $NEW_LANG
$escaped_framework = $NEW_FRAMEWORK
$escaped_branch = $CURRENT_BRANCH

$content = Get-Content -LiteralPath $temp -Raw -Encoding utf8
$content = $content -replace '\[PROJECT NAME\]',$ProjectName
$content = $content -replace '\[DATE\]',$Date.ToString('yyyy-MM-dd')

# Build the technology stack string safely
$techStackForTemplate = ""
if ($escaped_lang -and $escaped_framework) {
    $techStackForTemplate = "- $escaped_lang + $escaped_framework ($escaped_branch)"
} elseif ($escaped_lang) {
    $techStackForTemplate = "- $escaped_lang ($escaped_branch)"
} elseif ($escaped_framework) {
    $techStackForTemplate = "- $escaped_framework ($escaped_branch)"
}

$content = $content -replace '\[EXTRACTED FROM ALL PLAN.MD FILES\]',$techStackForTemplate
# For project structure we manually embed (keep newlines)
$escapedStructure = [Regex]::Escape($projectStructure)
$content = $content -replace '\[ACTUAL STRUCTURE FROM PLANS\]',$escapedStructure
# Replace escaped newlines placeholder after all replacements
$content = $content -replace '\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]',$commands

# Build the recent changes string safely
$recentChangesForTemplate = ""
if ($escaped_lang -and $escaped_framework) {
    $recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang} + ${escaped_framework}"
} elseif ($escaped_lang) {
    $recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang}"
} elseif ($escaped_framework) {
    $recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_framework}"
}

$content = $content -replace '\[LAST 3 FEATURES AND WHAT THEY ADDED\]',$recentChangesForTemplate
# Convert literal \n sequences introduced by Escape to real newlines
$content = $content -replace '\\n',[Environment]::NewLine

$parent = Split-Path -Parent $TargetFile
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null }
Set-Content -LiteralPath $TargetFile -Value $content -NoNewline -Encoding utf8
Remove-Item $temp -Force
return $true

}

function Update-AgentFile { param( [Parameter(Mandatory=$true)] [string]$TargetFile, [Parameter(Mandatory=$true)] [string]$AgentName ) if (-not $TargetFile -or -not $AgentName) { Write-Err 'Update-AgentFile requires TargetFile and AgentName'; return $false } Write-Info "Updating $AgentName context file: $TargetFile" $projectName = Split-Path $REPO_ROOT -Leaf $date = Get-Date

$dir = Split-Path -Parent $TargetFile
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }

if (-not (Test-Path $TargetFile)) {
    if (New-AgentFile -TargetFile $TargetFile -ProjectName $projectName -Date $date) {
        Write-Success "Created new $AgentName context file"
    } else {
        Write-Err 'Failed to create new agent file'
        return $false
    }
} else {
    Write-Info "Agent file already exists at $TargetFile"
    Write-Success "Updated existing $AgentName context file"
}
return $true

}

function Update-SpecificAgent { param( [Parameter(Mandatory=$true)] [string]$Type ) switch ($Type) { 'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' } 'gemini' { Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI' } 'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' } 'codex' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex CLI' } default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|codex|opencode'; return $false } } }

function Update-AllExistingAgents { $found = $false $ok = $true if (Test-Path $CLAUDE_FILE) { if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }; $found = $true } if (Test-Path $GEMINI_FILE) { if (-not (Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI')) { $ok = $false }; $found = $true } if (Test-Path $AGENTS_FILE) { if (-not (Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex/opencode')) { $ok = $false }; $found = $true } if (-not $found) { Write-Info 'No existing agent files found, creating default Claude file...' if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false } } return $ok }

function Main { Validate-Environment Write-Info "=== Updating agent context files for feature $CURRENT_BRANCH ===" if (-not (Parse-PlanData -PlanFile $NEW_PLAN)) { Write-Err 'Failed to parse plan data'; exit 1 } $success = $true if ($AgentType) { Write-Info "Updating specific agent: $AgentType" if (-not (Update-SpecificAgent -Type $AgentType)) { $success = $false } } else { Write-Info 'No agent specified, updating all existing agent files...' if (-not (Update-AllExistingAgents)) { $success = $false } } if ($success) { Write-Success 'Agent context update completed successfully'; exit 0 } else { Write-Err 'Agent context update completed with errors'; exit 1 } }

Main

Install with Tessl CLI

npx tessl i tessl-labs/intent-integrity-kit

skills

README.md

tile.json