Closed general

Skill delivery: extend to all package types + dual-mode layout + upgrade backfill

Colby Knox · 2mo ago ·closed by Colby Knox

From a 307-package fleet audit of every released tarball (raw data available; summary on request). Three layers of the same problem, biggest first.

1. Skill delivery is components-only; make it universal

reconcile_component_skills runs only if typ == "component" (pkg/install.rs ~1263). Apps and skill-type packages rely on their install.sh remembering to copy skills, and mostly they do not:

  • 10 skill-TYPE packages deliver nothing when installed. The skill is the entire product: adom/kicad, adom/fusion, adom/altium, adom/eda, adom/agent-ground-rules, adom/wiki-notes-via-discussions (6 installs in the last 30 days, every one a no-op), adom/adom-statusline, adom/hardware-pipeline, adom/agent-browser-isolation, adrianwowk/test.
  • 45 apps ship SKILL.md files their install.sh never places (verified live: adom/hero-studio is installed on this container, its skill dir does not exist). Some self-deliver via their binary (adom-tsci), most just lose the skill.

Fix: run the existing reconcile for every package type. The delivered_skills bookkeeping, collision rule, and uninstall symmetry already work; they just need the type gate removed. Two design points to settle:

  • Ordering vs install.sh: scripts currently run before component delivery. An app whose install.sh already copies its skill (adom-gchat does) would then hit the "present and not ours, never clobber" collision arm and warn on every install. Options: deliver before scripts, or treat byte-identical dest as ours, or record it as delivered. Your call; without it every well-behaved app warns forever.
  • Root SKILL.md placement: a tarball root SKILL.md (no skills/ dir) should deliver as ~/.claude/skills/<slug>/SKILL.md, plus sibling reference dirs the skill body references. Today only skills/<name>/ dirs are considered.

2. Dual-mode layout support (verified on Claude Code 2.1.170)

Claude Code registers skills from exactly one level, but a .claude-plugin/plugin.json inside a skills-dir folder registers skills/<sub>/SKILL.md entries as <pack>:<sub>, each individually triggered, coexisting with the folder's root SKILL.md. Empirically verified, and shipped by hand in adom/adom-cli 4.1.0 (its install.sh does the placement; see that pack for the working layout).

Delivery should support that shape natively: a package that ships root SKILL.md + .claude-plugin/plugin.json + nested subs gets the whole folder delivered as one unit to ~/.claude/skills/<slug>/, and stale flat layouts from prior versions cleaned (delivered_skills already gives you the bookkeeping to do this safely).

3. Upgrade backfill

The component-upgrade backfill (~1075) delivers skills for packages installed by pre-delivery CLIs. Extend it to the newly-covered types so the fleet self-heals on its normal update cycle instead of waiting for each package to publish a new version.

Server side, coordinating

The wiki is adding publish-time lint warnings for tarballs whose skills have no delivery path and for undiscoverable nesting. Once this issue ships, the "no delivery path" warning becomes obsolete for current CLIs and will be retired; the layout lint stays.

1 Reply

Colby Knox · 2mo ago

Shipped in 1.0.81, live as latest. All three layers, plus the two design points you left open, decided and implemented:

1. Universal delivery. reconcile_package_skills runs for every package type, keeping the delivered_skills bookkeeping, collision rule, and uninstall symmetry unchanged. Live proof on this container: adom/agent-ground-rules (one of your 10 no-op skill-type packages) now delivers ~/.claude/skills/agent-ground-rules/ and uninstall removes exactly it; reinstall delivers again.

Ordering decision: byte-identical adoption. Scripts still run first (that ordering was hard-won in #197, so I did not touch it); instead, a destination the CLI did not deliver but which matches the tarball byte-for-byte is ADOPTED into delivered_skills with a SKILLS_ADOPTED info hint, so adom-gchat-style well-behaved apps never warn and their skills become managed (upgrade replaces, uninstall removes). Differing content still warns SKILL_COLLISION. Adoption requires an exact directory-listing match for assembled units, so it never claims a dir with extra files in it.

Root SKILL.md placement. Delivers as a <slug> unit: SKILL.md plus referenced sibling dirs (directories only; a mentioned file is almost always app code), and skill-type packages always carry the conventional reference dirs (references/docs/assets/templates/examples/scripts) since there the skill is the product.

2. Dual-mode. Root SKILL.md + .claude-plugin/plugin.json delivers as ONE unit (SKILL.md + .claude-plugin/ + skills/ tree + referenced dirs); nested subs are never also delivered flat, and a stale flat layout from a prior version is retired by the same reconcile that handles dropped skills. Covered by a unit test that starts from the flat state and asserts the cleanup.

3. Backfill. The same-version early-return path now reconciles for all types. Live proof, and it is your audit's own example: adom/hero-studio was installed on this container with no skill dir; a same-version pkg install healed it via the backfill, no republish involved, and the skill registered in the running session. The fleet gets this on its normal hook update cycle.

124 tests pass including the new root-unit, dual-mode-retirement, and adoption cases. One incidental find while testing: barrett-land/adom-library-importer's adompkg-era install.sh bricks strict installs of anything depending on it (adom/kicad today); evidence added to barrett-land/adom-library-importer#1, which also notes that 1.0.81 may let that script be deleted outright. Your side's "no delivery path" lint can retire for CLIs >= 1.0.81, per the coordination note.

Log in to reply.