diff --git a/.github/workflows/scripts/create-release-packages.ps1 b/.github/workflows/scripts/create-release-packages.ps1 index 8f3cfec36..613c978b9 100644 --- a/.github/workflows/scripts/create-release-packages.ps1 +++ b/.github/workflows/scripts/create-release-packages.ps1 @@ -294,6 +294,94 @@ function New-Skills { } } +# Create OpenClaw skills in .openclaw/skills//SKILL.md format. +# OpenClaw discovers skills as directories containing a SKILL.md file, +# invoked as speckit- (e.g. speckit-specify). +function New-OpenClawSkills { + param( + [string]$SkillsDir, + [string]$ScriptVariant + ) + + $templates = Get-ChildItem -Path "templates/commands/*.md" -File -ErrorAction SilentlyContinue + + foreach ($template in $templates) { + $name = [System.IO.Path]::GetFileNameWithoutExtension($template.Name) + $skillName = "speckit-$name" + $skillDir = Join-Path $SkillsDir $skillName + New-Item -ItemType Directory -Force -Path $skillDir | Out-Null + + $fileContent = (Get-Content -Path $template.FullName -Raw) -replace "`r`n", "`n" + + # Extract description + $description = "Spec Kit: $name workflow" + if ($fileContent -match '(?m)^description:\s*(.+)$') { + $description = $matches[1] + } + + # Extract script command + $scriptCommand = "(Missing script command for $ScriptVariant)" + if ($fileContent -match "(?m)^\s*${ScriptVariant}:\s*(.+)$") { + $scriptCommand = $matches[1] + } + + # Extract agent_script command from frontmatter if present + $agentScriptCommand = "" + if ($fileContent -match "(?ms)agent_scripts:.*?^\s*${ScriptVariant}:\s*(.+?)$") { + $agentScriptCommand = $matches[1].Trim() + } + + # Replace {SCRIPT}, strip scripts sections, rewrite paths + $body = $fileContent -replace '\{SCRIPT\}', $scriptCommand + if (-not [string]::IsNullOrEmpty($agentScriptCommand)) { + $body = $body -replace '\{AGENT_SCRIPT\}', $agentScriptCommand + } + + $lines = $body -split "`n" + $outputLines = @() + $inFrontmatter = $false + $skipScripts = $false + $dashCount = 0 + + foreach ($line in $lines) { + if ($line -match '^---$') { + $outputLines += $line + $dashCount++ + $inFrontmatter = ($dashCount -eq 1) + continue + } + if ($inFrontmatter) { + if ($line -match '^(scripts|agent_scripts):$') { $skipScripts = $true; continue } + if ($line -match '^[a-zA-Z].*:' -and $skipScripts) { $skipScripts = $false } + if ($skipScripts -and $line -match '^\s+') { continue } + } + $outputLines += $line + } + + $body = $outputLines -join "`n" + $body = $body -replace '\{ARGS\}', '$ARGUMENTS' + $body = $body -replace '__AGENT__', 'generic' + $body = Rewrite-Paths -Content $body + + # Strip existing frontmatter, keep only body + $templateBody = "" + $fmCount = 0 + $inBody = $false + foreach ($line in ($body -split "`n")) { + if ($line -match '^---$') { + $fmCount++ + if ($fmCount -eq 2) { $inBody = $true } + continue + } + if ($inBody) { $templateBody += "$line`n" } + } + + # Build SKILL.md with OpenClaw metadata block + $skillContent = "---`nname: `"$skillName`"`ndescription: `"$description`"`nmetadata:`n author: `"github-spec-kit`"`n source: `"templates/commands/$name.md`"`n---`n`n$templateBody" + Set-Content -Path (Join-Path $skillDir "SKILL.md") -Value $skillContent -NoNewline + } +} + function Build-Variant { param( [string]$Agent, @@ -478,6 +566,11 @@ function Build-Variant { $cmdDir = Join-Path $baseDir ".iflow/commands" Generate-Commands -Agent 'iflow' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script } + 'openclaw' { + $skillsDir = Join-Path $baseDir ".openclaw/skills" + New-Item -ItemType Directory -Force -Path $skillsDir | Out-Null + New-OpenClawSkills -SkillsDir $skillsDir -ScriptVariant $Script + } 'generic' { $cmdDir = Join-Path $baseDir ".speckit/commands" Generate-Commands -Agent 'generic' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index d07e4a2df..5ffe741de 100755 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -219,6 +219,79 @@ create_skills() { done } +# Create OpenClaw skills in .openclaw/skills//SKILL.md format. +# OpenClaw discovers skills as directories containing a SKILL.md file, +# invoked as speckit- (e.g. speckit-specify). +create_openclaw_skills() { + local skills_dir="$1" + local script_variant="$2" + + for template in templates/commands/*.md; do + [[ -f "$template" ]] || continue + local name + name=$(basename "$template" .md) + local skill_name="speckit-${name}" + local skill_dir="${skills_dir}/${skill_name}" + mkdir -p "$skill_dir" + + local file_content + file_content=$(tr -d '\r' < "$template") + + # Extract description from frontmatter + local description + description=$(printf '%s\n' "$file_content" | awk '/^description:/ {sub(/^description:[[:space:]]*/, ""); print; exit}') + [[ -z "$description" ]] && description="Spec Kit: ${name} workflow" + + # Extract script command + local script_command + script_command=$(printf '%s\n' "$file_content" | awk -v sv="$script_variant" '/^[[:space:]]*'"$script_variant"':[[:space:]]*/ {sub(/^[[:space:]]*'"$script_variant"':[[:space:]]*/, ""); print; exit}') + [[ -z "$script_command" ]] && script_command="(Missing script command for $script_variant)" + + # Extract agent_script command from frontmatter if present + local agent_script_command + agent_script_command=$(printf '%s\n' "$file_content" | awk ' + /^agent_scripts:$/ { in_agent_scripts=1; next } + in_agent_scripts && /^[[:space:]]*'"$script_variant"':[[:space:]]*/ { + sub(/^[[:space:]]*'"$script_variant"':[[:space:]]*/, "") + print + exit + } + in_agent_scripts && /^[a-zA-Z]/ { in_agent_scripts=0 } + ') + + # Build body: replace placeholders, strip scripts sections, rewrite paths + local body + body=$(printf '%s\n' "$file_content" | sed "s|{SCRIPT}|${script_command}|g") + if [[ -n $agent_script_command ]]; then + body=$(printf '%s\n' "$body" | sed "s|{AGENT_SCRIPT}|${agent_script_command}|g") + fi + body=$(printf '%s\n' "$body" | awk ' + /^---$/ { print; if (++dash_count == 1) in_frontmatter=1; else in_frontmatter=0; next } + in_frontmatter && /^scripts:$/ { skip_scripts=1; next } + in_frontmatter && /^agent_scripts:$/ { skip_scripts=1; next } + in_frontmatter && /^[a-zA-Z].*:/ && skip_scripts { skip_scripts=0 } + in_frontmatter && skip_scripts && /^[[:space:]]/ { next } + { print } + ') + body=$(printf '%s\n' "$body" | sed 's/{ARGS}/\$ARGUMENTS/g' | sed 's/__AGENT__/openclaw/g' | rewrite_paths) + + # Strip existing frontmatter and prepend OpenClaw SKILL.md frontmatter + local template_body + template_body=$(printf '%s\n' "$body" | awk '/^---/{p++; if(p==2){found=1; next}} found') + + { + printf -- '---\n' + printf 'name: "%s"\n' "$skill_name" + printf 'description: "%s"\n' "$description" + printf 'metadata:\n' + printf ' author: "github-spec-kit"\n' + printf ' source: "templates/commands/%s.md"\n' "$name" + printf -- '---\n\n' + printf '%s\n' "$template_body" + } > "$skill_dir/SKILL.md" + done +} + build_variant() { local agent=$1 script=$2 local base_dir="$GENRELEASES_DIR/sdd-${agent}-package-${script}" diff --git a/README.md b/README.md index 4d8348303..eb359837d 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,7 @@ Community projects that extend, visualize, or build on Spec Kit: | [IBM Bob](https://www.ibm.com/products/bob) | ✅ | IDE-based agent with slash command support | | [Jules](https://jules.google.com/) | ✅ | | | [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | | +| [OpenClaw](https://openclaw.ai) | ✅ | Persistent AI agent daemon; use `--ai openclaw --ai-skills` | | [opencode](https://opencode.ai/) | ✅ | | | [Pi Coding Agent](https://pi.dev) | ✅ | Pi doesn't have MCP support out of the box, so `taskstoissues` won't work as intended. MCP support can be added via [extensions](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent#extensions) | | [Qwen Code](https://github.com/QwenLM/qwen-code) | ✅ | | diff --git a/templates/commands/skill.md b/templates/commands/skill.md new file mode 100644 index 000000000..a6cec8ab6 --- /dev/null +++ b/templates/commands/skill.md @@ -0,0 +1,45 @@ +--- +name: speckit +description: Full Spec-Driven Development (SDD) workflow powered by github/spec-kit. Use speckit-specify to start a feature, then speckit-plan, speckit-tasks, and speckit-implement in sequence. +metadata: + author: github-spec-kit + source: https://github.com/github/spec-kit + version: 1.0.0 +--- + +# Spec Kit — Spec-Driven Development + +This skill provides the complete Spec-Driven Development workflow from [github/spec-kit](https://github.com/github/spec-kit). +Individual commands are available as separate skills in this directory — each one maps to a phase of the SDD process. + +## Workflow Order + +Always follow this sequence — never skip phases: + +1. **speckit-constitution** — Establish project governing principles *(run once per project)* +2. **speckit-specify** — Turn a feature description into a structured spec +3. **speckit-clarify** — Resolve ambiguities before planning *(optional but recommended)* +4. **speckit-plan** — Create a phased technical implementation plan +5. **speckit-analyze** — Cross-artifact consistency check *(optional, run after tasks)* +6. **speckit-tasks** — Break the plan into ordered, executable tasks +7. **speckit-implement** — Execute tasks one by one +8. **speckit-checklist** — Post-implementation quality checklist + +## Core Rules + +- Read `.specify/memory/constitution.md` before every coding decision +- Show the spec summary to the user and wait for approval before planning +- Show task count to the user and wait for approval before implementing +- Use `.specify/scripts/bash/` (Linux/macOS) or `.specify/scripts/powershell/` (Windows) for all file and branch operations +- Never create, move, or delete files in `specs/` without explicit user instruction + +## Key File Locations + +| File | Purpose | +|------|---------| +| `.specify/memory/constitution.md` | Project governing principles — read before every decision | +| `specs//spec.md` | Feature specification created by `speckit-specify` | +| `specs//plan.md` | Implementation plan created by `speckit-plan` | +| `specs//tasks.md` | Task breakdown created by `speckit-tasks` | +| `.specify/templates/` | Base templates for spec, plan, tasks, and checklist artifacts | +| `.specify/scripts/` | Automation scripts for branch and file management | diff --git a/templates/skill-file-template.md b/templates/skill-file-template.md new file mode 100644 index 000000000..d87f51cf2 --- /dev/null +++ b/templates/skill-file-template.md @@ -0,0 +1,10 @@ +