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.
- package/package.json +1 -1
- package/plugin/instructions/agentskills-compliance.instructions.md +144 -0
- package/plugin/instructions/dashboard-artifact.instructions.md +132 -0
- package/plugin/instructions/guided-tour.instructions.md +100 -0
- package/plugin/instructions/karpathy-state-layout.instructions.md +124 -0
- package/plugin/instructions/schema-evolve.instructions.md +73 -0
- package/plugin/instructions/skill-authoring.instructions.md +147 -0
- package/plugin/instructions/skill-evals.instructions.md +130 -0
- package/plugin/runners/bootstrap.mjs +55 -22
- package/plugin/runners/lib/runlog.mjs +153 -6
- package/plugin/runners/migrate-to-v550.mjs +192 -0
- package/plugin/runners/pull-email.mjs +194 -3
- package/plugin/runners/pull-meetings.mjs +207 -4
- package/plugin/runners/pull-onenote.mjs +239 -3
- package/plugin/runners/pull-sharepoint.mjs +284 -3
- package/plugin/runners/pull-state.mjs +297 -0
- package/plugin/runners/pull-teams.mjs +170 -3
- package/plugin/runners/refresh.mjs +9 -1
- package/plugin/runners/test/fixtures/email-abn-amro.json +13 -0
- package/plugin/runners/test/fixtures/email-novel-error.json +9 -0
- package/plugin/runners/test/fixtures/meetings-abn-amro.json +10 -0
- package/plugin/runners/test/fixtures/meetings-body-unavailable.json +10 -0
- package/plugin/runners/test/fixtures/onenote-abn-amro.json +30 -0
- package/plugin/runners/test/fixtures/onenote-partial.json +21 -0
- package/plugin/runners/test/fixtures/refresh-dir/email.json +7 -4
- package/plugin/runners/test/fixtures/refresh-dir/teams.json +6 -4
- package/plugin/runners/test/fixtures/sharepoint-abn-amro.json +12 -0
- package/plugin/runners/test/fixtures/teams-abn-amro.json +11 -0
- package/plugin/runners/test/integration/migrate-to-v550.integration.test.mjs +138 -0
- package/plugin/runners/test/integration/pull-email.integration.test.mjs +149 -0
- package/plugin/runners/test/integration/pull-meetings.integration.test.mjs +92 -0
- package/plugin/runners/test/integration/pull-onenote.integration.test.mjs +86 -0
- package/plugin/runners/test/integration/pull-sharepoint.integration.test.mjs +93 -0
- package/plugin/runners/test/integration/pull-teams.integration.test.mjs +91 -0
- package/plugin/runners/test/unit/runlog.test.mjs +1 -1
- package/plugin/skills/build-state/SKILL.md +195 -0
- package/plugin/skills/build-state/evals/evals.json +31 -0
- package/plugin/skills/dashboard/SKILL.md +132 -0
- package/plugin/skills/dashboard/evals/evals.json +33 -0
- package/plugin/skills/lint-state/.created-by-skill-creator +0 -0
- package/plugin/skills/lint-state/SKILL.md +98 -0
- package/plugin/skills/lint-state/evals/evals.json +34 -0
- package/plugin/skills/lint-state/lint.ps1 +218 -0
- package/plugin/skills/promote/.created-by-skill-creator +1 -0
- package/plugin/skills/promote/SKILL.md +125 -0
- package/plugin/skills/promote/evals/evals.json +35 -0
- package/plugin/skills/schema-evolve/.created-by-skill-creator +0 -0
- package/plugin/skills/schema-evolve/SKILL.md +106 -0
- package/plugin/skills/schema-evolve/evals/evals.json +37 -0
- package/plugin/skills/skill-checker/SKILL.md +136 -0
- package/plugin/skills/skill-checker/check-skill.ps1 +416 -0
- package/plugin/skills/skill-checker/evals/evals.json +41 -0
- package/plugin/skills/skill-creator/SKILL.md +134 -0
- package/plugin/skills/skill-creator/evals/evals.json +40 -0
- package/plugin/skills/skill-creator/generate-eval-review.ps1 +101 -0
- package/plugin/skills/skill-creator/optimize-description.ps1 +87 -0
- package/plugin/skills/skill-creator/scaffold.ps1 +180 -0
- package/plugin/skills/skill-creator/templates/evals-starter.template.json +27 -0
- package/plugin/skills/skill-creator/templates/gotchas-stub.template.md +9 -0
- package/plugin/skills/skill-creator/templates/skill-skeleton.template.md +28 -0
- package/plugin/skills/teach/.created-by-skill-creator +0 -0
- package/plugin/skills/teach/SKILL.md +79 -0
- package/plugin/skills/teach/evals/evals.json +59 -0
- package/plugin/skills/tour/SKILL.md +85 -0
- package/plugin/skills/tour/build-tour.ps1 +185 -0
- package/plugin/skills/tour/evals/evals.json +33 -0
- package/plugin/templates/state/00_overview.template.md +44 -0
- package/plugin/templates/state/01_decisions.template.md +41 -0
- package/plugin/templates/state/02_stakeholders.template.md +48 -0
- package/plugin/templates/state/03_architecture-and-solution.template.md +56 -0
- package/plugin/templates/state/04_workshops-and-key-meetings.template.md +43 -0
- package/plugin/templates/state/05_action-items.template.md +29 -0
- package/plugin/templates/state/06_risks-and-issues.template.md +43 -0
- package/plugin/templates/state/07_timeline-and-milestones.template.md +45 -0
- package/plugin/templates/state/08_artifacts-and-deliverables.template.md +55 -0
- package/plugin/templates/state/09_open-questions.template.md +62 -0
- package/plugin/templates/state/AGENTS.template.md +33 -0
- package/plugin/templates/state/CLAUDE.template.md +33 -0
- package/plugin/templates/state/README.md +41 -0
- package/plugin/templates/state/answers.README.md +7 -0
- package/plugin/templates/state/hot.template.md +12 -0
- package/plugin/templates/state/index.template.md +41 -0
- package/plugin/templates/state/log.template.md +14 -0
- package/plugin/templates/state/page.template.md +22 -0
- package/plugin/templates/state/review-queue.template.md +10 -0
- 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.
|