← back to Cli Printing Press
fix(cli): move extra_commands SKILL.md block to its own top-level section (#1524)
c10d0b553823e8a63428ed8473d36182c7de1d48 · 2026-05-16 13:02:01 -0700 · Trevin Chow
* fix(cli): move extra_commands SKILL.md block to its own top-level section
extra_commands declared in internal-YAML specs (shopify, producthunt,
…) used to render under a **Hand-written commands** subsection nested
inside ## Command Reference. The Cobra emitter never reads the field,
so those rows were promises the generator could not back. verify-skill
walks ## Command Reference for inline backticks shaped like
`<binary> <cmd>` and correctly fails the unknown-command check on
every entry.
Lift the block into its own top-level ## Hand-written Extensions
section with an explainer line that says they require separate
wiring. verify-skill's _extract_inline_commands is scoped to the
Command Reference body (regex in scripts/verify-skill/verify_skill.py),
so a sibling section is invisible to the unknown-command walker.
Generating from catalog/specs/producthunt-spec.yaml and running
`printing-press verify-skill --dir <out>` now exits 0.
Closes #1451
Sweep tracking issue for already-published CLIs (shopify, producthunt):
mvanhorn/printing-press-library#616
* fix(cli): place Hand-written Extensions after Finding the right command
Greptile flagged that inserting `## Hand-written Extensions` between
the Command Reference body and Freshness Contract silently reparented
`### Finding the right command` under the new section for any CLI
with extra_commands but no Freshness Contract (extra_commands +
HasDataLayer=false case).
Markdown nests every `###` under the most recent `##`, so the fix is
positional: render the Extensions block after the `### Finding the
right command` subsection (and before `## Recipes`). `### Finding`
stays a child of `## Command Reference` for every combination of
ExtraCommands + Freshness state. Added a regression assertion that
locks the relative ordering.
End-to-end re-verified: producthunt regens with `## Command Reference`
→ `### Finding the right command` → `## Hand-written Extensions` →
`## Auth Setup`, and verify-skill still exits 0.
---------
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Files touched
M internal/generator/skill_test.goM internal/generator/templates/skill.md.tmpl
Diff
commit c10d0b553823e8a63428ed8473d36182c7de1d48
Author: Trevin Chow <trevin@trevinchow.com>
Date: Sat May 16 13:02:01 2026 -0700
fix(cli): move extra_commands SKILL.md block to its own top-level section (#1524)
* fix(cli): move extra_commands SKILL.md block to its own top-level section
extra_commands declared in internal-YAML specs (shopify, producthunt,
…) used to render under a **Hand-written commands** subsection nested
inside ## Command Reference. The Cobra emitter never reads the field,
so those rows were promises the generator could not back. verify-skill
walks ## Command Reference for inline backticks shaped like
`<binary> <cmd>` and correctly fails the unknown-command check on
every entry.
Lift the block into its own top-level ## Hand-written Extensions
section with an explainer line that says they require separate
wiring. verify-skill's _extract_inline_commands is scoped to the
Command Reference body (regex in scripts/verify-skill/verify_skill.py),
so a sibling section is invisible to the unknown-command walker.
Generating from catalog/specs/producthunt-spec.yaml and running
`printing-press verify-skill --dir <out>` now exits 0.
Closes #1451
Sweep tracking issue for already-published CLIs (shopify, producthunt):
mvanhorn/printing-press-library#616
* fix(cli): place Hand-written Extensions after Finding the right command
Greptile flagged that inserting `## Hand-written Extensions` between
the Command Reference body and Freshness Contract silently reparented
`### Finding the right command` under the new section for any CLI
with extra_commands but no Freshness Contract (extra_commands +
HasDataLayer=false case).
Markdown nests every `###` under the most recent `##`, so the fix is
positional: render the Extensions block after the `### Finding the
right command` subsection (and before `## Recipes`). `### Finding`
stays a child of `## Command Reference` for every combination of
ExtraCommands + Freshness state. Added a regression assertion that
locks the relative ordering.
End-to-end re-verified: producthunt regens with `## Command Reference`
→ `### Finding the right command` → `## Hand-written Extensions` →
`## Auth Setup`, and verify-skill still exits 0.
---------
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
---
internal/generator/skill_test.go | 56 +++++++++++++++++++++++++-----
internal/generator/templates/skill.md.tmpl | 16 +++++----
2 files changed, 57 insertions(+), 15 deletions(-)
diff --git a/internal/generator/skill_test.go b/internal/generator/skill_test.go
index f21b35a6..6e6c20d4 100644
--- a/internal/generator/skill_test.go
+++ b/internal/generator/skill_test.go
@@ -3,6 +3,7 @@ package generator
import (
"os"
"path/filepath"
+ "regexp"
"strings"
"testing"
@@ -358,11 +359,11 @@ func TestSkillRendersAuthBranchPerType(t *testing.T) {
}
// TestSkillRendersExtraCommands asserts that hand-written commands declared
-// in spec.ExtraCommands appear in the generated SKILL.md Command Reference,
-// after the spec-driven resources, with binary prefix and optional args.
-// This closes the drift class where SKILL.md silently omitted hand-written
-// commands like `today`, `streak`, `rivals` because the template only iterated
-// .Resources.
+// in spec.ExtraCommands appear in their own `## Hand-written Extensions`
+// section (NOT inside `## Command Reference`), with binary prefix and optional
+// args. The separate section keeps verify-skill's unknown-command walker
+// (scoped to ## Command Reference) from treating extra_commands as canonical
+// Cobra paths — that drift was the root cause of #1451.
func TestSkillRendersExtraCommands(t *testing.T) {
t.Parallel()
@@ -380,16 +381,55 @@ func TestSkillRendersExtraCommands(t *testing.T) {
require.NoError(t, err)
content := string(skill)
- assert.Contains(t, content, "**Hand-written commands**",
- "Command Reference should include a Hand-written commands subsection when ExtraCommands present")
+ assert.Contains(t, content, "## Hand-written Extensions",
+ "ExtraCommands should be surfaced in their own top-level section, not under ## Command Reference")
assert.Contains(t, content, "`sports-pp-cli trending`",
- "extra command without args should render as just binary + name")
+ "extra command without args should render as binary + name in the Extensions section")
assert.Contains(t, content, "`sports-pp-cli boxscore <event_id>`",
"extra command with args should render args after the name")
assert.Contains(t, content, "Most-followed athletes and teams across all leagues",
"extra command description should appear in the rendered output")
assert.Contains(t, content, "`sports-pp-cli h2h <team1> <team2>`",
"extra command with multi-arg signature should render verbatim")
+
+ // Regression guard for #1451: the Extensions section must live OUTSIDE
+ // the Command Reference section so verify-skill's _extract_inline_commands
+ // walker (scoped to ## Command Reference) does not flag these as
+ // unknown-command findings. Asserted by locating each section's offset
+ // and confirming Extensions starts after Reference ends.
+ cmdRefIdx := strings.Index(content, "## Command Reference")
+ require.NotEqual(t, -1, cmdRefIdx, "Command Reference section is expected to exist")
+ extIdx := strings.Index(content, "## Hand-written Extensions")
+ require.NotEqual(t, -1, extIdx)
+ require.Greater(t, extIdx, cmdRefIdx,
+ "Hand-written Extensions must be a sibling section after Command Reference, not nested inside it")
+
+ // Belt-and-suspenders: confirm the Command Reference section body
+ // (everything between its heading and the next top-level heading)
+ // does NOT contain any extra_commands path. Mirrors the Python
+ // walker's scoping (regex in scripts/verify-skill/verify_skill.py:74)
+ // without lookahead, which Go's RE2 doesn't support.
+ cmdRefHeadingRE := regexp.MustCompile(`(?m)^##\s+Command\s+Reference\s*$`)
+ nextSectionRE := regexp.MustCompile(`(?m)^##\s+`)
+ loc := cmdRefHeadingRE.FindStringIndex(content)
+ require.NotNil(t, loc, "Command Reference section heading should match the walker's regex")
+ afterHeading := content[loc[1]:]
+ if next := nextSectionRE.FindStringIndex(afterHeading); next != nil {
+ afterHeading = afterHeading[:next[0]]
+ }
+ for _, name := range []string{"sports-pp-cli trending", "sports-pp-cli boxscore", "sports-pp-cli h2h"} {
+ assert.NotContains(t, afterHeading, name,
+ "extra command %q must not appear under Command Reference; the unknown-command walker would flag it", name)
+ }
+
+ // Markdown nests every `###` under the most recent `##`. Placing
+ // `## Hand-written Extensions` BEFORE `### Finding the right command`
+ // would silently reparent that subsection. Assert the ordering so a
+ // future template edit doesn't regress the structure.
+ findingIdx := strings.Index(content, "### Finding the right command")
+ require.NotEqual(t, -1, findingIdx, "Finding the right command subsection should exist")
+ require.Greater(t, extIdx, findingIdx,
+ "Hand-written Extensions must come after ### Finding the right command so it doesn't reparent that subsection")
}
// TestSkillFrontmatterMetadataIsClawHubCompliantNestedYAML asserts that the
diff --git a/internal/generator/templates/skill.md.tmpl b/internal/generator/templates/skill.md.tmpl
index cd03910b..b4b57b90 100644
--- a/internal/generator/templates/skill.md.tmpl
+++ b/internal/generator/templates/skill.md.tmpl
@@ -144,13 +144,6 @@ This CLI was generated with browser-observed traffic context.
{{- end}}
{{- end}}
{{end}}
-{{- if .ExtraCommands}}
-
-**Hand-written commands**
-{{range .ExtraCommands}}
-- `{{$.Name}}-pp-cli {{.Name}}{{if .Args}} {{.Args}}{{end}}` — {{oneline .Description}}
-{{- end}}
-{{end}}
{{- if and .HasDataLayer .Cache.Enabled}}
## Freshness Contract
@@ -176,6 +169,15 @@ When you know what you want to do but not which command does it, ask the CLI dir
```
`which` resolves a natural-language capability query to the best matching command from this CLI's curated feature index. Exit code `0` means at least one match; exit code `2` means no confident match — fall back to `--help` or use a narrower query.
+{{- if .ExtraCommands}}
+
+## Hand-written Extensions
+
+These commands are declared by the spec author and require separate hand-written wiring; the generator does not emit Cobra registration for them. They are listed here for discoverability and are intentionally outside `## Command Reference` so the verify-skill unknown-command check does not treat them as generator-owned paths.
+{{range .ExtraCommands}}
+- `{{$.Name}}-pp-cli {{.Name}}{{if .Args}} {{.Args}}{{end}}` — {{oneline .Description}}
+{{- end}}
+{{- end}}
{{- if and .Narrative .Narrative.Recipes}}
## Recipes
← 99637941 fix(skills): require codex completion marker before treating
·
back to Cli Printing Press
·
feat(skills): add /printing-press-amend skill — dogfood + di c31632b3 →