Publish: use shared discovery logic instead of requiring skills/ directory#13167
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates gh skill publish to use the shared local skill discovery logic (matching install), removing the hard requirement that skills live under a top-level skills/ directory.
Changes:
- Switch
publishto discover skills viadiscovery.DiscoverLocalSkills()rather than enumeratingskills/. - Update security/code-scanning heuristics to operate over multiple discovered skill directories.
- Update and extend publish tests to cover root-level and namespaced skill discovery.
Show a summary per file
| File | Description |
|---|---|
pkg/cmd/skills/publish/publish.go |
Replaces hardcoded skills/ enumeration with shared discovery, updates downstream logic to handle multiple discovered directories. |
pkg/cmd/skills/publish/publish_test.go |
Adjusts expectations for “no skills” cases and adds coverage for root-level and namespaced discovery. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 2
1d21aa6 to
a40d072
Compare
babakks
left a comment
There was a problem hiding this comment.
LGTM, with a few suggestions and a question.
| Skills are discovered using the same conventions as install: | ||
|
|
||
| - skills/*/SKILL.md | ||
| - skills/{scope}/*/SKILL.md | ||
| - */SKILL.md (root-level) | ||
| - plugins/{scope}/skills/*/SKILL.md | ||
|
|
There was a problem hiding this comment.
As a general comment, these docs will be regarded as markdown and rendered on the website (example). So, it's best to have that in mind when writing --help docs. So, please apply this comment to other skill commands.
In this particular case, let's surround verbatim text with backticks:
| Skills are discovered using the same conventions as install: | |
| - skills/*/SKILL.md | |
| - skills/{scope}/*/SKILL.md | |
| - */SKILL.md (root-level) | |
| - plugins/{scope}/skills/*/SKILL.md | |
| Skills are discovered using the same conventions as install: | |
| - `skills/*/SKILL.md` | |
| - `skills/{scope}/*/SKILL.md` | |
| - `*/SKILL.md` (root-level) | |
| - `plugins/{scope}/skills/*/SKILL.md` | |
There was a problem hiding this comment.
Here too:
| - Install metadata (`metadata.github-*`) is stripped if present |
There was a problem hiding this comment.
And also here:
| Use `--dry-run` to validate without publishing. | |
| Use `--tag` to publish non-interactively with a specific tag. | |
| Use `--fix` to automatically strip install metadata from committed files. |
| // Discover skills using shared discovery logic (same conventions as install) | ||
| skills, err := discovery.DiscoverLocalSkills(dir) |
| if hasCode && hasManifests { | ||
| return filepath.SkipAll | ||
| } |
There was a problem hiding this comment.
This has probably been discussed/clarified but just to double check.
question: returning SkipAll causes filepath.Walk to stop walking the tree and return immediately. Is that what we want? I mean, don't we want to go through all other directories under dir?
There was a problem hiding this comment.
Good Q. Let me dig in.
Replace the hardcoded skills/ directory requirement in the publish
command with the shared DiscoverLocalSkills() function used by install
and other commands. This removes the opinionated restriction that skills
must live under a skills/ directory and supports all discovery
conventions:
- skills/*/SKILL.md
- skills/{scope}/*/SKILL.md
- */SKILL.md (root-level)
- plugins/{scope}/skills/*/SKILL.md
All per-skill validation (frontmatter, spec-compliant naming, metadata
stripping, etc.) is preserved.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a40d072 to
b63f5bf
Compare
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [cli/cli](https://github.com/cli/cli) | minor | `v2.89.0` → `v2.90.0` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>cli/cli (cli/cli)</summary> ### [`v2.90.0`](https://github.com/cli/cli/releases/tag/v2.90.0): GitHub CLI 2.90.0 [Compare Source](cli/cli@v2.89.0...v2.90.0) #### Manage agent skills with `gh skill` (Public Preview) [Agent skills](https://agentskills.io) are portable sets of instructions, scripts, and resources that teach AI coding agents how to perform specific tasks. The new `gh skill` command makes it easy to discover, install, manage, and publish agent skills from GitHub repositories - right from the CLI. ``` # Discover skills gh skill search copilot # Preview a skill without installing gh skill preview github/awesome-copilot documentation-writer # Install a skill gh skill install github/awesome-copilot documentation-writer # Pin to a specific version gh skill install github/awesome-copilot documentation-writer --pin v1.2.0 # Check installed skills for updates gh skill update --all # Validate and publish your own skills gh skill publish --dry-run ``` Skills are automatically installed to the correct directory for your agent host. `gh skill` supports GitHub Copilot, Claude Code, Cursor, Codex, Gemini CLI, and Antigravity. Target a specific agent and scope with `--agent` and `--scope` flags. `gh skill publish` validates skills against the [Agent Skills specification](https://agentskills.io/specification) and checks remote settings like tag protection and immutable releases to improve supply chain security. Read the full announcement on the [GitHub Blog](https://github.blog/changelog/2026-04-16-manage-agent-skills-with-github-cli/). `gh skill` is launching in public preview and is subject to change without notice. #### Official extension suggestions When you run a command that matches a known official extension that isn't installed (e.g. `gh stack`), the CLI now offers to install it instead of showing a generic "unknown command" error. This feature is available for [github/gh-aw](https://github.com/github/gh-aw) and [github/gh-stack](https://github.com/github/gh-stack). When possible, you'll be prompted to install immediately. When prompting isn't possible, the CLI prints the `gh extension install` command to run. #### `gh extension install` no longer requires authentication `gh extension install` previously required a valid auth token even though it only needs to download a public release asset. The auth check has been removed, so you can install extensions without being logged in. #### What's Changed ##### ✨ Features - Add `gh skill` command group: install, preview, search, update, publish by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13165](cli/cli#13165) - Suggest and install official extensions for unknown commands by [@​BagToad](https://github.com/BagToad) in [#​13175](cli/cli#13175) - `gh skill publish`: auto-push unpushed commits before publish by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13171](cli/cli#13171) - Disable auth check for `gh extension install` by [@​BagToad](https://github.com/BagToad) in [#​13176](cli/cli#13176) ##### 🐛 Fixes - Fix infinite loop in `gh release list --limit 0` by [@​Bahtya](https://github.com/Bahtya) in [#​13097](cli/cli#13097) - Ensure `api` and `auth` commands record agentic invocations by [@​williammartin](https://github.com/williammartin) in [#​13046](cli/cli#13046) - Disable auth check for local-only skill flags by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13173](cli/cli#13173) - URL-encode parentPath in skills discovery API call by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13172](cli/cli#13172) - Fix: use target directory remotes in skills publish by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13169](cli/cli#13169) - Fix: preserve namespace in skills search deduplication by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13170](cli/cli#13170) ##### 📚 Docs & Chores - docs: include PGP key fingerprints by [@​babakks](https://github.com/babakks) in [#​13112](cli/cli#13112) - docs: add sha/md5 checksums of keyring files by [@​babakks](https://github.com/babakks) in [#​13150](cli/cli#13150) - docs: fix SHA512 checksum for GPG key by [@​timsu92](https://github.com/timsu92) in [#​13157](cli/cli#13157) - docs(skill): polish skill commandset docs by [@​babakks](https://github.com/babakks) in [#​13183](cli/cli#13183) - Document dependency CVE policy in SECURITY.md by [@​BagToad](https://github.com/BagToad) in [#​13119](cli/cli#13119) - Replace github.com/golang/snappy with klauspost/compress/snappy by [@​thaJeztah](https://github.com/thaJeztah) in [#​13048](cli/cli#13048) - chore: bump to go1.26.2 by [@​babakks](https://github.com/babakks) in [#​13116](cli/cli#13116) - chore: delete experimental script/debian-devel by [@​babakks](https://github.com/babakks) in [#​13127](cli/cli#13127) - Suggest first party extensions by [@​williammartin](https://github.com/williammartin) in [#​13182](cli/cli#13182) - Add cli/skill-reviewers as CODEOWNERS for skills packages by [@​BagToad](https://github.com/BagToad) in [#​13189](cli/cli#13189) - Add [@​cli/code-reviewers](https://github.com/cli/code-reviewers) to all CODEOWNERS rules by [@​BagToad](https://github.com/BagToad) in [#​13190](cli/cli#13190) - Address post-merge review feedback for skills commands by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13185](cli/cli#13185) - Fix skills-publish-dry-run acceptance test error message mismatch by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13187](cli/cli#13187) - Skills: replace real git in publish tests with CommandStubber by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13188](cli/cli#13188) - Remove redundant nil-client fallback in skills publish by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13168](cli/cli#13168) - Publish: use shared discovery logic instead of requiring skills/ directory by [@​SamMorrowDrums](https://github.com/SamMorrowDrums) in [#​13167](cli/cli#13167) #####Dependencies - chore(deps): bump github.com/klauspost/compress from 1.18.4 to 1.18.5 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13071](cli/cli#13071) - chore(deps): bump github.com/yuin/goldmark from 1.7.16 to 1.8.2 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13045](cli/cli#13045) - chore(deps): bump charm.land/bubbles/v2 from 2.0.0 to 2.1.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13051](cli/cli#13051) - chore(deps): bump github.com/sigstore/timestamp-authority/v2 from 2.0.3 to 2.0.6 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13152](cli/cli#13152) - chore(deps): bump github.com/google/go-containerregistry from 0.21.3 to 0.21.4 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13129](cli/cli#13129) - chore(deps): bump github.com/sigstore/protobuf-specs from 0.5.0 to 0.5.1 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13128](cli/cli#13128) - chore(deps): bump github.com/in-toto/attestation from 1.1.2 to 1.2.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13044](cli/cli#13044) - chore(deps): bump advanced-security/filter-sarif from 1.0.1 to 1.1 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​12918](cli/cli#12918) - chore(deps): bump google.golang.org/grpc from 1.79.3 to 1.80.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13076](cli/cli#13076) - chore(deps): bump github.com/hashicorp/go-version from 1.8.0 to 1.9.0 by [@​dependabot](https://github.com/dependabot)\[bot] in [#​13065](cli/cli#13065) #### New Contributors - [@​thaJeztah](https://github.com/thaJeztah) made their first contribution in [#​13048](cli/cli#13048) - [@​Bahtya](https://github.com/Bahtya) made their first contribution in [#​13097](cli/cli#13097) - [@​timsu92](https://github.com/timsu92) made their first contribution in [#​13157](cli/cli#13157) - [@​SamMorrowDrums](https://github.com/SamMorrowDrums) made their first contribution in [#​13173](cli/cli#13173) **Full Changelog**: <cli/cli@v2.89.0...v2.90.0> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMjMuNiIsInVwZGF0ZWRJblZlciI6IjQzLjEyMy42IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
Summary
Replaces the hardcoded
skills/directory requirement in thepublishcommand with the sharedDiscoverLocalSkills()function already used byinstalland other commands.Motivation
The publish command previously required all skills to live under a
skills/directory, but the rest of the CLI (install,search, etc.) already supports multiple discovery conventions. There's no reason for publish to be more restrictive — it's a pointless opinionated restriction that we've moved on from.Changes
publish.go: Replaced manualskills/directory enumeration withdiscovery.DiscoverLocalSkills(dir). All per-skill validation (frontmatter fields, spec-compliant naming, metadata stripping, license checks, body length) is preserved.publish.go: UpdatedcheckSecuritySettingsanddetectCodeAndManifeststo accept multiple skill directories instead of a singleskills/path.publish_test.go: Updated existing tests for the new behavior and added tests for root-level and namespaced skill discovery.Supported conventions (now all discoverable by publish)
skills/*/SKILL.mdskills/{scope}/*/SKILL.md*/SKILL.md(root-level)plugins/{scope}/skills/*/SKILL.mdStacked on
#13165