Skip to content

Exclude top-level skills/_partials/ from skill installation #780

Description

@williamthorsen

Problem

installSkills in packages/agents/src/commands/install.ts (the enumeration loop, ~line 192) iterates content/skills/ entries and skips only _platforms and dotfiles. The shared skills-partials directory content/skills/_partials/ is therefore passed to installSkillEntry, and its .md files are expanded, link-rewritten, and written to the target as ~/.claude/skills/_partials/.

The existing _partials exclusions (preExpandSkillDirectory/collectExpansions ~line 354, writeExpandedSkillDir ~line 380) only match _partials as a child entry during a directory walk; they never fire when _partials is itself the walk root, which is the case here. So the per-skill exclusion works (a _partials/ nested inside a normal skill is skipped), but the top-level shared skills/_partials/ directory is not.

Effect: a stray ~/.claude/skills/_partials/ directory containing duplicated, link-rewritten copies of each shared partial. It has no SKILL.md, so it is not a registered skill — impact is install-tree clutter and a confusing duplicate of content meant to exist only as an include target. Confirmed live: ~/.claude/skills/_partials/acceptance-criteria-scaffold.md and plan-template.md (the latter added by #774) both already exist.

Context

content/skills/ has three reserved underscore-prefixed top-level directories, and they are not interchangeable:

  • _platforms/ — already skipped by the enumeration loop (handled by dedicated platform-specific logic).
  • _partials/ — an install-time include target. Its content is inlined into including skills via 11 <!-- include: --> directives; it has zero runtime references. The installed copy is pure redundancy. This is the bug.
  • _data/ — a runtime dependency. 36 source skills link ../_data/*.md, which the path-rewriter resolves to absolute ~/.claude/skills/_data/... paths the skills read when they execute. It must continue to install.

This distinction is the reason the fix targets _partials by name rather than generalizing to all _-prefixed entries: a blanket entry.startsWith('_') skip would stop installing _data/ and break every skill that reads it.

Proposed approach

Add '_partials' to the skip condition in the installSkills enumeration loop (alongside '_platforms' and the dotfile check), mirroring the per-skill walk exclusion. Do not generalize to an _-prefix skip, per the _data distinction above.

Cleanup of any pre-existing stray ~/.claude/skills/_partials/ is out of scope: dedicated cleanup code would be dead after its first run, and orphans are removed manually. The fix prevents recreation only.

Acceptance criteria

Must have

  • Installing skills does not create a _partials entry in the target skills directory (e.g., no ~/.claude/skills/_partials/).
  • The shared skills/_partials/ directory is treated purely as an include target, consistent with the existing per-skill _partials/ exclusion.
  • Reserved top-level directories referenced at runtime (notably _data/) continue to install unchanged.
  • A test covers exclusion of the top-level skills/_partials/ directory during install, mirroring the existing per-skill _partials exclusion test.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions