kushi-agents 6.1.2 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/package.json +1 -1
  2. package/plugin/instructions/agentskills-compliance.instructions.md +144 -0
  3. package/plugin/instructions/dashboard-artifact.instructions.md +132 -0
  4. package/plugin/instructions/guided-tour.instructions.md +100 -0
  5. package/plugin/instructions/karpathy-state-layout.instructions.md +124 -0
  6. package/plugin/instructions/schema-evolve.instructions.md +73 -0
  7. package/plugin/instructions/skill-authoring.instructions.md +147 -0
  8. package/plugin/instructions/skill-evals.instructions.md +130 -0
  9. package/plugin/runners/bootstrap.mjs +55 -22
  10. package/plugin/runners/lib/runlog.mjs +153 -6
  11. package/plugin/runners/migrate-to-v550.mjs +192 -0
  12. package/plugin/runners/pull-email.mjs +194 -3
  13. package/plugin/runners/pull-meetings.mjs +207 -4
  14. package/plugin/runners/pull-onenote.mjs +239 -3
  15. package/plugin/runners/pull-sharepoint.mjs +284 -3
  16. package/plugin/runners/pull-state.mjs +297 -0
  17. package/plugin/runners/pull-teams.mjs +170 -3
  18. package/plugin/runners/refresh.mjs +9 -1
  19. package/plugin/runners/test/fixtures/email-abn-amro.json +13 -0
  20. package/plugin/runners/test/fixtures/email-novel-error.json +9 -0
  21. package/plugin/runners/test/fixtures/meetings-abn-amro.json +10 -0
  22. package/plugin/runners/test/fixtures/meetings-body-unavailable.json +10 -0
  23. package/plugin/runners/test/fixtures/onenote-abn-amro.json +30 -0
  24. package/plugin/runners/test/fixtures/onenote-partial.json +21 -0
  25. package/plugin/runners/test/fixtures/refresh-dir/email.json +7 -4
  26. package/plugin/runners/test/fixtures/refresh-dir/teams.json +6 -4
  27. package/plugin/runners/test/fixtures/sharepoint-abn-amro.json +12 -0
  28. package/plugin/runners/test/fixtures/teams-abn-amro.json +11 -0
  29. package/plugin/runners/test/integration/migrate-to-v550.integration.test.mjs +138 -0
  30. package/plugin/runners/test/integration/pull-email.integration.test.mjs +149 -0
  31. package/plugin/runners/test/integration/pull-meetings.integration.test.mjs +92 -0
  32. package/plugin/runners/test/integration/pull-onenote.integration.test.mjs +86 -0
  33. package/plugin/runners/test/integration/pull-sharepoint.integration.test.mjs +93 -0
  34. package/plugin/runners/test/integration/pull-teams.integration.test.mjs +91 -0
  35. package/plugin/runners/test/unit/runlog.test.mjs +1 -1
  36. package/plugin/skills/build-state/SKILL.md +195 -0
  37. package/plugin/skills/build-state/evals/evals.json +31 -0
  38. package/plugin/skills/dashboard/SKILL.md +132 -0
  39. package/plugin/skills/dashboard/evals/evals.json +33 -0
  40. package/plugin/skills/lint-state/.created-by-skill-creator +0 -0
  41. package/plugin/skills/lint-state/SKILL.md +98 -0
  42. package/plugin/skills/lint-state/evals/evals.json +34 -0
  43. package/plugin/skills/lint-state/lint.ps1 +218 -0
  44. package/plugin/skills/promote/.created-by-skill-creator +1 -0
  45. package/plugin/skills/promote/SKILL.md +125 -0
  46. package/plugin/skills/promote/evals/evals.json +35 -0
  47. package/plugin/skills/schema-evolve/.created-by-skill-creator +0 -0
  48. package/plugin/skills/schema-evolve/SKILL.md +106 -0
  49. package/plugin/skills/schema-evolve/evals/evals.json +37 -0
  50. package/plugin/skills/skill-checker/SKILL.md +136 -0
  51. package/plugin/skills/skill-checker/check-skill.ps1 +416 -0
  52. package/plugin/skills/skill-checker/evals/evals.json +41 -0
  53. package/plugin/skills/skill-creator/SKILL.md +134 -0
  54. package/plugin/skills/skill-creator/evals/evals.json +40 -0
  55. package/plugin/skills/skill-creator/generate-eval-review.ps1 +101 -0
  56. package/plugin/skills/skill-creator/optimize-description.ps1 +87 -0
  57. package/plugin/skills/skill-creator/scaffold.ps1 +180 -0
  58. package/plugin/skills/skill-creator/templates/evals-starter.template.json +27 -0
  59. package/plugin/skills/skill-creator/templates/gotchas-stub.template.md +9 -0
  60. package/plugin/skills/skill-creator/templates/skill-skeleton.template.md +28 -0
  61. package/plugin/skills/teach/.created-by-skill-creator +0 -0
  62. package/plugin/skills/teach/SKILL.md +79 -0
  63. package/plugin/skills/teach/evals/evals.json +59 -0
  64. package/plugin/skills/tour/SKILL.md +85 -0
  65. package/plugin/skills/tour/build-tour.ps1 +185 -0
  66. package/plugin/skills/tour/evals/evals.json +33 -0
  67. package/plugin/templates/state/00_overview.template.md +44 -0
  68. package/plugin/templates/state/01_decisions.template.md +41 -0
  69. package/plugin/templates/state/02_stakeholders.template.md +48 -0
  70. package/plugin/templates/state/03_architecture-and-solution.template.md +56 -0
  71. package/plugin/templates/state/04_workshops-and-key-meetings.template.md +43 -0
  72. package/plugin/templates/state/05_action-items.template.md +29 -0
  73. package/plugin/templates/state/06_risks-and-issues.template.md +43 -0
  74. package/plugin/templates/state/07_timeline-and-milestones.template.md +45 -0
  75. package/plugin/templates/state/08_artifacts-and-deliverables.template.md +55 -0
  76. package/plugin/templates/state/09_open-questions.template.md +62 -0
  77. package/plugin/templates/state/AGENTS.template.md +33 -0
  78. package/plugin/templates/state/CLAUDE.template.md +33 -0
  79. package/plugin/templates/state/README.md +41 -0
  80. package/plugin/templates/state/answers.README.md +7 -0
  81. package/plugin/templates/state/hot.template.md +12 -0
  82. package/plugin/templates/state/index.template.md +41 -0
  83. package/plugin/templates/state/log.template.md +14 -0
  84. package/plugin/templates/state/page.template.md +22 -0
  85. package/plugin/templates/state/review-queue.template.md +10 -0
  86. package/plugin/runners/test/integration/csc-pull.integration.test.mjs +0 -160
@@ -0,0 +1,101 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Renders an HTML side-by-side eval-review viewer for a skill.
4
+
5
+ .DESCRIPTION
6
+ Scans Evidence/_evals/ for the most recent per-run JSON files belonging to
7
+ -Skill, picks the two newest (or up to -MaxRuns), and renders a static HTML page
8
+ that shows per-case pass/fail + duration side-by-side. Output is gitignored.
9
+
10
+ If no eval runs are found, emits a stub page noting "no runs yet — run
11
+ `npm run eval -- <skill>` first" so the viewer command never silently fails.
12
+
13
+ .PARAMETER Skill
14
+ Skill name (matches plugin/skills/<name>/).
15
+
16
+ .PARAMETER Output
17
+ Override output path. Default: Evidence/_skill-creator/<skill>/review.html.
18
+
19
+ .PARAMETER MaxRuns
20
+ Maximum number of runs to include side-by-side (default 2).
21
+
22
+ .PARAMETER Root
23
+ Repo root (default: 3 levels above this script).
24
+ #>
25
+ [CmdletBinding()]
26
+ param(
27
+ [Parameter(Mandatory=$true)][string]$Skill,
28
+ [string]$Output,
29
+ [int]$MaxRuns = 2,
30
+ [string]$Root = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path
31
+ )
32
+
33
+ $ErrorActionPreference = 'Stop'
34
+
35
+ if (-not $Output) {
36
+ $Output = Join-Path $Root "Evidence/_skill-creator/$Skill/review.html"
37
+ }
38
+ $outDir = Split-Path -Parent $Output
39
+ New-Item -ItemType Directory -Force -Path $outDir | Out-Null
40
+
41
+ $evalsDir = Join-Path $Root 'Evidence/_evals'
42
+ $runs = @()
43
+ if (Test-Path $evalsDir) {
44
+ $runs = Get-ChildItem -Path $evalsDir -Filter '*.json' -File -ErrorAction SilentlyContinue |
45
+ Sort-Object LastWriteTime -Descending |
46
+ Where-Object {
47
+ try {
48
+ $j = Get-Content -Raw $_.FullName | ConvertFrom-Json
49
+ $j.cases | Where-Object { $_.skill -eq $Skill -or $j.skill -eq $Skill }
50
+ } catch { $false }
51
+ } |
52
+ Select-Object -First $MaxRuns
53
+ }
54
+
55
+ function HtmlEncode { param([string]$s) [System.Net.WebUtility]::HtmlEncode([string]$s) }
56
+
57
+ $sb = New-Object System.Text.StringBuilder
58
+ [void]$sb.AppendLine('<!doctype html><html><head><meta charset="utf-8">')
59
+ [void]$sb.AppendLine("<title>Skill review — $(HtmlEncode $Skill)</title>")
60
+ [void]$sb.AppendLine('<style>body{font-family:system-ui,sans-serif;margin:2em;}table{border-collapse:collapse;width:100%;}th,td{border:1px solid #ccc;padding:.4em .6em;text-align:left;vertical-align:top;}.pass{background:#dfd}.fail{background:#fdd}.skip{background:#eee;color:#666}.meta{color:#666;font-size:.9em}code{background:#f4f4f4;padding:0 .2em}</style>')
61
+ [void]$sb.AppendLine('</head><body>')
62
+ [void]$sb.AppendLine("<h1>Skill review — <code>$(HtmlEncode $Skill)</code></h1>")
63
+ [void]$sb.AppendLine("<p class='meta'>Generated $(Get-Date -Format o). Source: <code>Evidence/_evals/</code> (gitignored).</p>")
64
+
65
+ if (-not $runs -or $runs.Count -eq 0) {
66
+ [void]$sb.AppendLine("<p><strong>No eval runs found for <code>$(HtmlEncode $Skill)</code>.</strong></p>")
67
+ [void]$sb.AppendLine("<p>Run <code>npm run eval -- $(HtmlEncode $Skill)</code> first, then re-render.</p>")
68
+ } else {
69
+ [void]$sb.AppendLine('<table><thead><tr><th>Case</th>')
70
+ foreach ($r in $runs) { [void]$sb.AppendLine("<th>$(HtmlEncode $r.Name)</th>") }
71
+ [void]$sb.AppendLine('</tr></thead><tbody>')
72
+
73
+ # Build a unified case-id list across runs.
74
+ $parsed = $runs | ForEach-Object { Get-Content -Raw $_.FullName | ConvertFrom-Json }
75
+ $caseIds = @()
76
+ foreach ($p in $parsed) {
77
+ foreach ($c in $p.cases) { if ($caseIds -notcontains $c.id) { $caseIds += $c.id } }
78
+ }
79
+ foreach ($cid in $caseIds) {
80
+ [void]$sb.AppendLine("<tr><td><code>$(HtmlEncode $cid)</code></td>")
81
+ for ($i = 0; $i -lt $parsed.Count; $i++) {
82
+ $hit = $parsed[$i].cases | Where-Object { $_.id -eq $cid } | Select-Object -First 1
83
+ if (-not $hit) {
84
+ [void]$sb.AppendLine("<td class='skip'>—</td>")
85
+ } else {
86
+ $cls = if ($hit.skipped) { 'skip' } elseif ($hit.pass) { 'pass' } else { 'fail' }
87
+ $label = if ($hit.skipped) { 'skip' } elseif ($hit.pass) { 'pass' } else { 'fail' }
88
+ $dur = if ($hit.duration_ms) { "$($hit.duration_ms) ms" } else { '' }
89
+ [void]$sb.AppendLine("<td class='$cls'><strong>$label</strong> <span class='meta'>$dur</span></td>")
90
+ }
91
+ }
92
+ [void]$sb.AppendLine('</tr>')
93
+ }
94
+ [void]$sb.AppendLine('</tbody></table>')
95
+ }
96
+
97
+ [void]$sb.AppendLine('</body></html>')
98
+
99
+ Set-Content -LiteralPath $Output -Value $sb.ToString() -Encoding UTF8
100
+ Write-Host "skill-creator: wrote review viewer → $Output"
101
+ exit 0
@@ -0,0 +1,87 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Rewrites a kushi skill description per the agentskills.io optimization rules.
4
+
5
+ .DESCRIPTION
6
+ Applies these transforms (idempotent):
7
+ 1. Ensure the description leads with "USE WHEN " in the first 160 chars.
8
+ 2. Ensure a "DO NOT USE" clause is present.
9
+ 3. Strip marketing words: powerful, comprehensive, blazing, seamless, simple,
10
+ effortless, robust, cutting-edge, world-class.
11
+ 4. Collapse internal whitespace; trim to 1024 chars.
12
+
13
+ Prints a unified diff (current → rewritten) by default; -Quiet emits only the
14
+ rewritten string for piping into scaffold.ps1.
15
+
16
+ .PARAMETER Description
17
+ The description string to rewrite.
18
+
19
+ .PARAMETER Quiet
20
+ Suppress the diff; print only the rewritten string.
21
+ #>
22
+ [CmdletBinding()]
23
+ param(
24
+ [Parameter(Mandatory=$true)][string]$Description,
25
+ [switch]$Quiet
26
+ )
27
+
28
+ $ErrorActionPreference = 'Stop'
29
+
30
+ function Optimize-Description {
31
+ param([string]$Text)
32
+ if (-not $Text) { return '' }
33
+
34
+ $out = $Text.Trim()
35
+
36
+ # 1) Marketing-word strip.
37
+ $bad = @('powerful', 'comprehensive', 'blazing', 'seamless', 'simple',
38
+ 'effortless', 'robust', 'cutting-edge', 'world-class', 'next-generation')
39
+ foreach ($w in $bad) {
40
+ $out = [regex]::Replace($out, "\b$w\s*", '', 'IgnoreCase')
41
+ }
42
+
43
+ # 2) Collapse whitespace.
44
+ $out = [regex]::Replace($out, '\s+', ' ').Trim()
45
+
46
+ # 3) Ensure leading USE WHEN.
47
+ if ($out.Substring(0, [Math]::Min(160, $out.Length)) -notmatch '\bUSE WHEN\b') {
48
+ # If a plain "When " is present, upgrade it; else prepend a placeholder.
49
+ if ($out -match '^\s*[Ww]hen\b') {
50
+ $out = $out -replace '^\s*[Ww]hen\b', 'USE WHEN'
51
+ } else {
52
+ $out = "USE WHEN <TODO: trigger>. $out"
53
+ }
54
+ }
55
+
56
+ # 4) Ensure a DO NOT USE clause.
57
+ if ($out -notmatch '(?i)\bDO NOT USE\b') {
58
+ # Insert after the first sentence terminator if any.
59
+ if ($out -match '^(.+?\.)\s+(.+)$') {
60
+ $out = "$($Matches[1]) DO NOT USE FOR <TODO: near-miss>. $($Matches[2])"
61
+ } else {
62
+ $out = "$out DO NOT USE FOR <TODO: near-miss>."
63
+ }
64
+ }
65
+
66
+ # 5) Re-collapse whitespace after edits.
67
+ $out = [regex]::Replace($out, '\s+', ' ').Trim()
68
+
69
+ # 6) Hard cap 1024 chars.
70
+ if ($out.Length -gt 1024) { $out = $out.Substring(0, 1024) }
71
+
72
+ return $out
73
+ }
74
+
75
+ $rewritten = Optimize-Description -Text $Description
76
+
77
+ if (-not $Quiet) {
78
+ Write-Host "--- before"
79
+ Write-Host $Description
80
+ Write-Host "+++ after"
81
+ Write-Host $rewritten
82
+ Write-Host ""
83
+ }
84
+
85
+ # Always emit the rewritten string on stdout (consumed by scaffold.ps1).
86
+ [Console]::Out.Write($rewritten)
87
+ exit 0
@@ -0,0 +1,180 @@
1
+ <#
2
+ .SYNOPSIS
3
+ skill-creator scaffold — emits a conformant plugin/skills/<name>/ tree.
4
+
5
+ .DESCRIPTION
6
+ Reads templates/skill-skeleton.template.md + evals-starter.template.json + (for
7
+ pull/writer) gotchas-stub.template.md, substitutes {{NAME}}/{{DESCRIPTION}}/
8
+ {{TYPE_SECTION}}, and writes the new skill folder. Adds a `.created-by-skill-
9
+ creator` marker so D34.creator-output-conforms can enforce strict lint.
10
+
11
+ Doctrine: plugin/instructions/skill-authoring.instructions.md.
12
+
13
+ .PARAMETER Name
14
+ Skill directory + front-matter name. Kebab-case, verb-led.
15
+
16
+ .PARAMETER Type
17
+ One of: pull, writer, orchestrator, other.
18
+ pull → injects ## Gotchas section
19
+ writer → injects ## Validation loop section
20
+ orchestrator → injects ## Step checklist section
21
+ other → injects ## Steps (generic) — author must add at least one of
22
+ Gotchas / Validation loop / Step checklist before lint passes.
23
+
24
+ .PARAMETER Description
25
+ Front-matter description string. Auto-rewritten via optimize-description.ps1.
26
+
27
+ .PARAMETER Force
28
+ Overwrite an existing skill folder.
29
+
30
+ .PARAMETER DryRun
31
+ Print actions only; write nothing.
32
+
33
+ .PARAMETER Root
34
+ Repo root (default: 3 levels above this script).
35
+ #>
36
+ [CmdletBinding()]
37
+ param(
38
+ [Parameter(Mandatory=$true)][string]$Name,
39
+ [Parameter(Mandatory=$true)][ValidateSet('pull','writer','orchestrator','other')][string]$Type,
40
+ [Parameter(Mandatory=$true)][string]$Description,
41
+ [switch]$Force,
42
+ [switch]$DryRun,
43
+ [string]$Root = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path
44
+ )
45
+
46
+ $ErrorActionPreference = 'Stop'
47
+
48
+ if ($Name -notmatch '^[a-z][a-z0-9]*(-[a-z0-9]+)*$') {
49
+ throw "Name '$Name' is not kebab-case. Use lowercase letters, digits, and single hyphens (e.g. 'pull-onenote')."
50
+ }
51
+
52
+ $templatesDir = Join-Path $PSScriptRoot 'templates'
53
+ $optimizer = Join-Path $PSScriptRoot 'optimize-description.ps1'
54
+ $skillDir = Join-Path $Root "plugin/skills/$Name"
55
+ $skillMd = Join-Path $skillDir 'SKILL.md'
56
+ $evalsDir = Join-Path $skillDir 'evals'
57
+ $evalsJson = Join-Path $evalsDir 'evals.json'
58
+ $marker = Join-Path $skillDir '.created-by-skill-creator'
59
+
60
+ if ((Test-Path $skillDir) -and -not $Force) {
61
+ throw "Skill folder already exists: $skillDir. Pass -Force to overwrite."
62
+ }
63
+
64
+ # 1) Optimize description (best-effort; falls back to as-is on error).
65
+ $optimized = $Description
66
+ if (Test-Path $optimizer) {
67
+ try {
68
+ $optimized = (& pwsh -NoProfile -File $optimizer -Description $Description -Quiet).Trim()
69
+ if (-not $optimized) { $optimized = $Description }
70
+ } catch {
71
+ Write-Warning "optimize-description failed: $($_.Exception.Message); using as-is."
72
+ $optimized = $Description
73
+ }
74
+ }
75
+ # Escape double quotes for safe YAML embedding.
76
+ $escaped = $optimized -replace '"', '\"'
77
+
78
+ # 2) Pick type-specific section.
79
+ function Get-TypeSection {
80
+ param([string]$Type, [string]$TemplatesDir)
81
+ switch ($Type) {
82
+ 'pull' {
83
+ $g = Join-Path $TemplatesDir 'gotchas-stub.template.md'
84
+ return (Get-Content -Raw $g)
85
+ }
86
+ 'writer' {
87
+ return @'
88
+ ## Validation loop
89
+
90
+ After writing outputs:
91
+
92
+ 1. Run self-check targeted at this skill: `pwsh plugin/skills/self-check/run.ps1 -Targeted <area>`
93
+ 2. If failures: fix and re-run the affected step (not the whole skill).
94
+ 3. Repeat until self-check exits 0.
95
+ 4. Only then update `run-log.yml` with success status.
96
+
97
+ <!-- TODO(skill-creator): replace <area> with the targeted-scope substring for this skill. -->
98
+ '@
99
+ }
100
+ 'orchestrator' {
101
+ return @'
102
+ ## Step checklist
103
+
104
+ - [ ] Step 1 — <!-- TODO(skill-creator): first concrete action -->
105
+ - [ ] Step 2 — <!-- TODO(skill-creator): second concrete action -->
106
+ - [ ] Step 3 — <!-- TODO(skill-creator): third concrete action -->
107
+ - [ ] Final — Run self-check + evals; only commit on green.
108
+ '@
109
+ }
110
+ default {
111
+ return @'
112
+ ## Steps
113
+
114
+ 1. <!-- TODO(skill-creator): first step -->
115
+ 2. <!-- TODO(skill-creator): second step -->
116
+
117
+ ## Validation loop
118
+
119
+ <!-- TODO(skill-creator): describe how to verify this skill ran correctly.
120
+ Every kushi skill SHOULD ship one of: Gotchas / Validation loop / Step checklist.
121
+ Replace this block with the right section for your skill, or keep it. -->
122
+
123
+ 1. Run `pwsh plugin/skills/self-check/run.ps1 -Targeted <area>`.
124
+ 2. Fix any findings, then re-run.
125
+ '@
126
+ }
127
+ }
128
+ }
129
+ $typeSection = Get-TypeSection -Type $Type -TemplatesDir $templatesDir
130
+
131
+ # 3) Render SKILL.md.
132
+ $skeleton = Get-Content -Raw (Join-Path $templatesDir 'skill-skeleton.template.md')
133
+ $skillContent = $skeleton `
134
+ -replace '\{\{NAME\}\}', $Name `
135
+ -replace '\{\{DESCRIPTION\}\}', $escaped `
136
+ -replace '\{\{TYPE_SECTION\}\}', [regex]::Escape($typeSection)
137
+ # Undo escape (we used [regex]::Escape to preserve $ etc — restore literal).
138
+ $skillContent = $skillContent -replace [regex]::Escape([regex]::Escape($typeSection)), $typeSection
139
+ # Simpler approach: do the replacement once with literal substitution.
140
+ $skillContent = $skeleton.Replace('{{NAME}}', $Name).Replace('{{DESCRIPTION}}', $escaped).Replace('{{TYPE_SECTION}}', $typeSection)
141
+
142
+ # 4) Render evals/evals.json.
143
+ $evalsTemplate = Get-Content -Raw (Join-Path $templatesDir 'evals-starter.template.json')
144
+ $nameSlug = ($Name -replace '[^a-z0-9-]', '-')
145
+ $evalsContent = $evalsTemplate.Replace('{{NAME}}', $Name).Replace('{{NAME_SLUG}}', $nameSlug)
146
+
147
+ # 5) Write everything (or just print under -DryRun).
148
+ $actions = @(
149
+ "mkdir $skillDir",
150
+ "mkdir $evalsDir",
151
+ "write $skillMd ($(($skillContent -split "`n").Count) lines)",
152
+ "write $evalsJson",
153
+ "write $marker"
154
+ )
155
+ Write-Host ""
156
+ Write-Host "skill-creator: scaffolding '$Name' (type=$Type) under $Root"
157
+ foreach ($a in $actions) { Write-Host " - $a" }
158
+ Write-Host ""
159
+
160
+ if ($DryRun) {
161
+ Write-Host "skill-creator: -DryRun set; no files written."
162
+ exit 0
163
+ }
164
+
165
+ if ((Test-Path $skillDir) -and $Force) {
166
+ Remove-Item -LiteralPath $skillDir -Recurse -Force
167
+ }
168
+ New-Item -ItemType Directory -Force -Path $skillDir | Out-Null
169
+ New-Item -ItemType Directory -Force -Path $evalsDir | Out-Null
170
+
171
+ Set-Content -LiteralPath $skillMd -Value $skillContent -Encoding UTF8 -NoNewline
172
+ Set-Content -LiteralPath $evalsJson -Value $evalsContent -Encoding UTF8 -NoNewline
173
+ Set-Content -LiteralPath $marker -Value "Created by skill-creator on $(Get-Date -Format o).`nDelete this file only if the skill is intentionally non-conformant.`n" -Encoding UTF8
174
+
175
+ Write-Host "skill-creator: done. Next steps:"
176
+ Write-Host " 1. grep 'TODO(skill-creator)' $skillMd — fill in placeholders"
177
+ Write-Host " 2. pwsh plugin/skills/skill-checker/check-skill.ps1 -Skill $Name"
178
+ Write-Host " 3. npm run eval -- $Name"
179
+ Write-Host ""
180
+ exit 0
@@ -0,0 +1,27 @@
1
+ {
2
+ "skill": "{{NAME}}",
3
+ "version": "0.1.0",
4
+ "description": "Starter evals for {{NAME}}. Replace cases as soon as the skill has real behavior to assert.",
5
+ "cases": [
6
+ {
7
+ "id": "{{NAME_SLUG}}-skillmd-exists",
8
+ "name": "SKILL.md exists for {{NAME}}",
9
+ "input": "verify {{NAME}} skill artifacts",
10
+ "canary": false,
11
+ "grader_type": "script",
12
+ "expected_assertions": [
13
+ { "type": "file-exists", "path": "plugin/skills/{{NAME}}/SKILL.md" }
14
+ ]
15
+ },
16
+ {
17
+ "id": "{{NAME_SLUG}}-description-optimized",
18
+ "name": "SKILL.md description leads with USE WHEN",
19
+ "input": "verify {{NAME}} description shape",
20
+ "canary": false,
21
+ "grader_type": "script",
22
+ "expected_assertions": [
23
+ { "type": "file-contains", "path": "plugin/skills/{{NAME}}/SKILL.md", "value": "USE WHEN" }
24
+ ]
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,9 @@
1
+ ## Gotchas
2
+
3
+ <!-- TODO(skill-creator): top-5 failure modes. Each bullet starts with the concrete failure, then the correction. -->
4
+
5
+ - **<failure mode 1>** → <correction>
6
+ - **<failure mode 2>** → <correction>
7
+ - **<failure mode 3>** → <correction>
8
+ - **<failure mode 4>** → <correction>
9
+ - **<failure mode 5>** → <correction>
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: "{{NAME}}"
3
+ version: "0.1.0"
4
+ description: "{{DESCRIPTION}}"
5
+ ---
6
+
7
+ # Skill: {{NAME}}
8
+
9
+ <!-- TODO(skill-creator): one-paragraph purpose. What does this skill DO, and when does it trigger? -->
10
+
11
+ User triggers: <!-- TODO(skill-creator): list the literal user phrases / verbs that should route here. -->
12
+
13
+ ## USE WHEN
14
+
15
+ - <!-- TODO(skill-creator): situational trigger 1 -->
16
+ - <!-- TODO(skill-creator): situational trigger 2 -->
17
+
18
+ ## DO NOT USE FOR
19
+
20
+ - <!-- TODO(skill-creator): the most likely near-miss invocation -->
21
+
22
+ {{TYPE_SECTION}}
23
+
24
+ ## References
25
+
26
+ - `plugin/instructions/skill-authoring.instructions.md`
27
+ - `plugin/instructions/agentskills-compliance.instructions.md`
28
+ <!-- TODO(skill-creator): add doctrine + reference pack links relevant to this skill. -->
File without changes
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: "teach"
3
+ version: "1.0.0"
4
+ description: "USE WHEN the user asks 'explain how kushi does X', 'why does refresh do Y', 'what is the difference between A and B in kushi', 'kushi explain <topic>', or wants to understand a kushi concept. DO NOT USE for modifying state/evidence (use build-state/refresh) or for project Q&A (use ask-project). Capability: pure pedagogical output — loads relevant doctrine + genealogy, explains concepts with cross-references, never modifies any State or Evidence."
5
+ ---
6
+
7
+ # Skill: teach
8
+
9
+ Pure pedagogical skill. Explains kushi concepts, architecture decisions, and operational patterns by loading relevant doctrine snippets, cross-references, and genealogy entries.
10
+
11
+ ## Triggers
12
+
13
+ - "explain how kushi does X"
14
+ - "why does refresh do Y"
15
+ - "what's the difference between A and B in kushi"
16
+ - `kushi explain <topic>` (CLI verb)
17
+ - "how does kushi handle contradictions?"
18
+ - "teach me about the CSC format"
19
+
20
+ ## Inputs
21
+
22
+ - `<topic>` — free-text topic (fuzzy-matched to doctrine clusters below).
23
+
24
+ ## Topic → Doctrine mapping
25
+
26
+ | Topic keyword(s) | Primary doctrine | Supporting files |
27
+ |------------------|-----------------|-----------------|
28
+ | contradictions, conflicts | `living-wiki.instructions.md` | `wiki-lint.instructions.md`, `State/_review-queue.md` format |
29
+ | refresh, pull, sources | `refresh-project/SKILL.md` | `verbatim-by-default.instructions.md`, `parallel-execution.instructions.md` |
30
+ | state, build-state, wiki | `living-wiki.instructions.md` | `karpathy-state-layout.instructions.md`, `log-format.instructions.md` |
31
+ | hooks, events, webhooks | `hooks.instructions.md` | `Invoke-Hooks.ps1` |
32
+ | parallel, workers, speed | `parallel-execution.instructions.md` | `auth-and-retry.instructions.md` |
33
+ | otel, telemetry, tracing | `otel.instructions.md` | `Emit-OtelSpan.ps1` |
34
+ | csc, capture, weekly | `comprehensive-structured-capture.instructions.md` | `weekly-csc.instructions.md` |
35
+ | graph, entities, links | `entity-graph.instructions.md` | `link-entities/SKILL.md` |
36
+ | workiq, m365 | `workiq-only.instructions.md` | `workiq-input-sanitization.instructions.md` |
37
+ | schema, conventions, remember | `schema-evolve.instructions.md` | `karpathy-state-layout.instructions.md` |
38
+ | global, global-wiki, cross-engagement | `global-wiki.instructions.md` | `multi-wiki-routing.instructions.md` |
39
+ | routing, --global, --project-only, promote | `multi-wiki-routing.instructions.md` | `global-wiki.instructions.md` |
40
+ | install, setup, hosts | `multi-host-install.instructions.md` | `host-portability.instructions.md` |
41
+ | evals, testing | `skill-evals.instructions.md` | `skill-authoring.instructions.md` |
42
+
43
+ ## Procedure
44
+
45
+ 1. **Match topic** — fuzzy-match user's topic to doctrine cluster. If no match, list available topics with one-line descriptions.
46
+ 2. **Load doctrine** — read the primary doctrine file + first 20 lines of each supporting file.
47
+ 3. **Load genealogy** — find the release that introduced the feature in `docs/genealogy.md`.
48
+ 4. **Explain** — synthesize a clear explanation with:
49
+ - What it does (2-3 sentences)
50
+ - Why it exists (the problem it solved — from genealogy)
51
+ - How it works (key mechanics from doctrine)
52
+ - Where to look (file paths)
53
+ - Related concepts (cross-references)
54
+ 5. **Never modify** — this skill is read-only. No writes to State/, Evidence/, or any file.
55
+
56
+ ## Gotchas
57
+
58
+ 1. **Topic not found**: List available topics with `kushi explain --list`. Don't guess.
59
+ 2. **Too broad**: If topic matches multiple clusters, ask user to narrow down.
60
+ 3. **Version-specific**: Always note which version introduced the feature.
61
+ 4. **No project context needed**: teach operates on the kushi repo itself, not on engagement evidence.
62
+ 5. **Doctrine drift**: Always read the file live — don't cache doctrine content.
63
+
64
+ ## Validation loop
65
+
66
+ After generating explanation:
67
+ 1. Verify all cited file paths exist (glob check).
68
+ 2. Verify genealogy entry referenced is real.
69
+ 3. If a path doesn't exist, remove the citation rather than citing a phantom file.
70
+
71
+ ## References
72
+
73
+ - `release-genealogy.instructions.md` — genealogy format
74
+ - `skill-authoring.instructions.md` — skill structure conventions
75
+ - `docs/genealogy.md` — release lineage
76
+
77
+ ## Issue Recovery
78
+
79
+ When this skill exposes a reusable defect (doctrine gap, missing cross-reference, stale genealogy), apply the [Issue Recovery Rule](../../instructions/issue-recovery.instructions.md): fix the smallest correct repo-owned artifact first, prefer durable fixes over per-run workarounds, then re-run the narrowest failed check. Do NOT use memory as a substitute for correcting the workflow surface.
@@ -0,0 +1,59 @@
1
+ {
2
+ "skill": "teach",
3
+ "cases": [
4
+ {
5
+ "id": "teach-contradictions",
6
+ "name": "Explain contradictions handling",
7
+ "input": "kushi explain contradictions",
8
+ "expected_assertions": [
9
+ { "type": "contains", "value": "living-wiki" },
10
+ { "type": "contains", "value": "callout" },
11
+ { "type": "contains", "value": "_review-queue" }
12
+ ],
13
+ "grader_type": "script"
14
+ },
15
+ {
16
+ "id": "teach-parallel",
17
+ "name": "Explain parallel refresh",
18
+ "input": "explain how parallel pulls work in kushi",
19
+ "expected_assertions": [
20
+ { "type": "contains", "value": "parallel" },
21
+ { "type": "contains", "value": "worker" },
22
+ { "type": "contains", "value": "max_workers" }
23
+ ],
24
+ "grader_type": "script"
25
+ },
26
+ {
27
+ "id": "teach-unknown-topic",
28
+ "name": "Unknown topic suggests alternatives",
29
+ "input": "kushi explain quantum-entanglement",
30
+ "expected_assertions": [
31
+ { "type": "not_contains", "value": "quantum" },
32
+ { "type": "contains", "value": "available" }
33
+ ],
34
+ "grader_type": "script"
35
+ },
36
+ {
37
+ "id": "teach-global-wiki",
38
+ "name": "Explain global wiki",
39
+ "input": "kushi explain global-wiki",
40
+ "expected_assertions": [
41
+ { "type": "contains", "value": "global" },
42
+ { "type": "contains", "value": "scope" },
43
+ { "type": "contains", "value": "promote" }
44
+ ],
45
+ "grader_type": "script"
46
+ },
47
+ {
48
+ "id": "teach-multi-wiki-routing",
49
+ "name": "Explain multi-wiki routing flags",
50
+ "input": "kushi explain routing",
51
+ "expected_assertions": [
52
+ { "type": "contains", "value": "--global" },
53
+ { "type": "contains", "value": "--project-only" },
54
+ { "type": "contains", "value": "project-first" }
55
+ ],
56
+ "grader_type": "script"
57
+ }
58
+ ]
59
+ }
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: "tour"
3
+ version: "1.0.0"
4
+ description: "USE WHEN refresh-project / bootstrap-project completes AND a graph exists, OR the user says \"@Kushi tour <X>\", \"give me the week-in-review for <X>\", \"what should I look at first in <X>?\". DO NOT USE before link-entities has run. Capability: renders <project>/State/tour.md, an auto-generated week-in-review walkthrough. Scores nodes by recency_weight × cross_ref_count; DFS-walks edges in priority order; default top-N = 10."
5
+ ---
6
+
7
+ # Skill: tour
8
+
9
+ > **v5.0.0 — Guided tour producer.** See
10
+ > `..\..\instructions\guided-tour.instructions.md` for the scoring formula,
11
+ > the DFS ordering, the per-stop markdown shape, and the self-check rules.
12
+
13
+ ## When to run
14
+
15
+ - Automatically as part of `refresh-project` (after `link-entities` +
16
+ `build-state` + `dashboard`) and `bootstrap-project` (same chain).
17
+ - Manually: `@Kushi tour <project> [--top N]`.
18
+
19
+ ## Inputs
20
+
21
+ - `<project>` — already-bootstrapped project root.
22
+ - `<project>/Evidence/_graph/project-graph.json` — REQUIRED.
23
+ - `<project>/State/index.md` — OPTIONAL; used to resolve `[[wikilinks]]` to
24
+ related State pages per stop.
25
+
26
+ ## Output
27
+
28
+ - `<project>/State/tour.md`.
29
+
30
+ ## Steps
31
+
32
+
33
+ ## Step checklist
34
+
35
+ Progress-trackable view of the steps below. Each `### Step` block expands the corresponding checkbox.
36
+
37
+ - [ ] Step 1 — Verify inputs
38
+ - [ ] Step 2 — Run the builder
39
+
40
+ ### Step 1 — Verify inputs
41
+
42
+ If `<project>/Evidence/_graph/project-graph.json` does not exist, exit with
43
+ "no graph — run `link-entities` first" and do NOT write `State/tour.md`.
44
+
45
+ ### Step 2 — Run the builder
46
+
47
+ ```pwsh
48
+ pwsh plugin/skills/tour/build-tour.ps1 -ProjectRoot <project> [-TopN <int>]
49
+ ```
50
+
51
+ `build-tour.ps1` reads the graph, scores nodes, DFS-walks, and writes
52
+ `State/tour.md`.
53
+
54
+ ## Hard rules
55
+
56
+ - Idempotent — fully regenerated each run.
57
+ - Citations MUST resolve on disk (self-check D23.tour enforces this).
58
+ - NEVER write outside `<project>/State/tour.md`.
59
+
60
+ ## Triggers
61
+
62
+ - "tour `<X>`"
63
+ - "build tour for `<X>`"
64
+ - "@Kushi tour `<X>`"
65
+ - (auto) end of `refresh-project` / `bootstrap-project`
66
+
67
+ ## References
68
+
69
+ - `..\..\instructions\guided-tour.instructions.md`
70
+ - `..\..\instructions\entity-graph.instructions.md`
71
+ - `..\..\instructions\karpathy-state-layout.instructions.md`
72
+ - `..\..\instructions\issue-recovery.instructions.md`
73
+
74
+ ## Changelog
75
+
76
+ - **v1.0.0 (kushi v5.0.0, 2026-05-26)**: initial release.
77
+
78
+ ## Validation loop
79
+
80
+ After writing outputs:
81
+
82
+ 1. Run self-check targeted at this skill: `pwsh plugin/skills/self-check/run.ps1 -Targeted tour`
83
+ 2. If failures: fix and re-run the affected step (not the whole skill).
84
+ 3. Repeat until self-check exits 0.
85
+ 4. Only then update `run-log.yml` with success status.