FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

skill install: handle a repository that is a collection of skills by ralyodio · Pull Request #437 · moshcoder/moshcode · GitHub

skill install: handle a repository that is a collection of skills - #437

Merged
ralyodio merged 1 commit into
mainfrom
worktree-skill-install-collections
Aug 28, 2026
Merged

skill install: handle a repository that is a collection of skills#437
ralyodio merged 1 commit into
mainfrom
worktree-skill-install-collections

Conversation

Copy link
Copy Markdown
Contributor

The bug

skill install assumes a repository is one skill. It clones the source into <skills-dir>/<name> and stops.

Claude and Kimi discover skills by scanning exactly one level deep. So a repository whose skills live in subdirectories — a collection — lands every one of them a level too deep, where nothing will ever find them.

git clone still exits 0, so moshcode reports the install succeeded. The user gets a green summary and zero usable skills, with nothing to suggest otherwise. That silence is the part worth fixing: a loud failure here would have been harmless.

Verified against a real 13-skill collection before the change:

before settle:
  one level deep (what engines scan): 0     <- installed, undiscoverable

The change

  • skillCollection(dir) reports what a clone actually contains: single (a SKILL.md at the root), collection (subdirectories holding one), or empty.
  • settleSkillClone(dir) resolves a clone into the shape engines scan:
    • single is left exactly as cloned — the existing behaviour, unchanged.
    • collection has each skill moved up beside its siblings and the wrapper removed. The wrapper holds the repository's README, tooling and CI, none of which is a skill.
    • empty is removed rather than left as a directory that can never resolve.
  • The claude and kimi actions carry their clone target as settle, and the runner resolves it after a successful clone. Gemini installs natively and is never settled.
  • A clone containing no SKILL.md anywhere is now reported as failed, with that reason, instead of counting as installed.
  • Results carry kind, skills and kept, so the summary can say what actually landed.

After:

after settle:
  kind: collection | installed: 13 | kept: 0
  one level deep (what engines scan): 13
  wrapper removed: true

Safety

A skill whose name is already taken is left alone and reported in kept. This runs inside the user's real skills directory, so a name collision must never silently replace a skill they already had. There's a test pinning exactly that.

On the test changes

settle is injectable alongside run, matching how the suite already stubs subprocesses.

Three existing tests stubbed run without it. With a stubbed clone nothing ever lands, so the real settle correctly found an empty directory and reported failure — the new strictness working as intended, on a fixture that was never meant to exercise it. Those tests now stub both. The skillInstallAction deep-equals were updated to assert the new settle field rather than ignore it.

Verification

  • New suite: test/skill-install-collections.test.mjs, 12 tests covering shape detection, settling, collision safety, and that a failed clone is never settled.
  • Full suite green: 2171 pass, 0 fail (282 pre-existing skips).
  • End to end against a real collection: 0 discoverable before, 13 after, wrapper removed.

Extends prd/0003, which set out the fan-out but assumed one repository is one skill.


🤖 Generated with Claude Code

https://claude.ai/code/session_01B7KVQWbU17PR2mCUn8jjpH

`skill install` assumed a repository is one skill: it clones the source into
`<skills-dir>/<name>` and stops. Claude and Kimi discover skills by scanning
exactly one level deep, so a repository whose skills live in subdirectories
lands every one of them a level too deep, where nothing will ever find them.

`git clone` still exits 0, so moshcode reports the install succeeded. The user
gets a green summary and zero usable skills, with nothing to suggest otherwise.

- `skillCollection(dir)` reports what a clone actually contains: `single` (a
  SKILL.md at the root), `collection` (subdirectories holding one), or `empty`
- `settleSkillClone(dir)` resolves a clone into the shape engines scan. A
  single skill is left alone; a collection has each skill moved up beside its
  siblings and the wrapper removed, since the wrapper holds the repository's
  README, tooling and CI, none of which is a skill; an empty clone is removed
  rather than left as a directory that can never resolve
- claude and kimi actions carry the clone target as `settle`, so the runner
  resolves them after a successful clone. Gemini installs natively and is
  never settled
- a clone containing no SKILL.md anywhere is now reported as failed with that
  reason, instead of counting as installed
- results carry `kind`, `skills` and `kept`, so the summary can say what landed

A skill whose name is already taken is left alone and reported in `kept`. This
runs inside the user's real skills directory, so a name collision must never
silently replace a skill they already had.

`settle` is injectable alongside `run`, matching how the suite already stubs
subprocesses. Three existing tests stubbed `run` without it, so the real settle
correctly found an empty directory where a stubbed clone never landed; they now
stub both.

Verified end to end against a real 13-skill collection: 0 discoverable before,
13 after, wrapper removed. Full suite green (2171 pass, 0 fail).

Extends prd/0003.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B7KVQWbU17PR2mCUn8jjpH

Copy link
Copy Markdown

ThreatCrush Security Scan

0 finding(s) in the 6 file(s) this pull request changes.

Nothing in the files this pull request changes.

59 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 5 | **MEDIUM**: 48 | **LOW**: 6

Not introduced by this pull request. The full set is in the Security tab.

Severity Rule Location
HIGH js-ssrf-outbound-request apps/pwa/public/sw.js:45
HIGH tls-verification-disabled apps/pwa/src/lib/moshpit-gateway.mjs:299
HIGH sh-remote-script-execution install.sh:79
HIGH sh-remote-script-execution install.sh:83
HIGH tls-verification-disabled src/dns.mjs:766
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:74
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:88
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:114
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:301
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:305
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:350
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:574
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:755
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:757
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:816
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:862
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:932
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1035
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1058
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1080

…and 39 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

ralyodio merged commit e7f58ab into main Aug 28, 2026
6 checks passed
ralyodio deleted the worktree-skill-install-collections branch August 28, 2026 21:45
ralyodio mentioned this pull request Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant


Back | FazBrowse Home | New Git URL