Closed bug report

pkg publish silently drops skills missing from package.json files[], then pkg update deletes the local copy (data loss)

John Lauer · 2mo ago ·closed by Colby Knox

adom-wiki 1.7.3 · adom/core 4.13.13 · Claude Code 2.1.233 · Linux container (Windows 11 / WSL2 host)

Summary

A skill that exists on disk in a pack checkout but is missing from package.json's files[] is silently dropped at publish, and the next pkg update then deletes the installed copy from ~/.claude/skills. If that was the only copy, the work is gone. This hit twice in one session before it was noticed, and the only signal was a single-line hint after the deletion had already happened.

This is a bad failure mode specifically for AI-authored packs: an agent adds skills/<new>/SKILL.md, publishes, and reasonably believes the work is durable. Publish reports success.

Repro

  1. In a pack checkout whose package.json has an explicit files[] array, create a new sub-skill: skills/<new-skill>/SKILL.md
  2. Do not add it to files[] (an agent adding a skill has no reason to know this list exists).
  3. adom-wiki pkg version minor && adom-wiki pkg publish
  4. adom-wiki pkg update <owner>/<pack>

Expected

Publish either ships every skills/*/SKILL.md in the directory, or hard-fails telling me a skill on disk is not registered in files[].

Actual

Publish succeeds and reports a count that looks plausible:

hint [SKILL_LAYOUT]: shipped 21 user skill(s) in the install tarball

There is no mention that a 22nd skill was found on disk and skipped. Then the update deletes it locally:

hint [SKILLS_DELIVERED]: <owner>/<pack> installed 21 skill(s) to ~/.claude/skills: ...
hint [SKILLS_REMOVED]: <owner>/<pack> removed 1 skill(s) this version dropped: <redacted-skill>

~/.claude/skills/<redacted-skill>/SKILL.md is now unlinked. Recovery was only possible because the content happened to still be in the agent's context.

Why the blast radius is larger than it looks

The adom-core-update.sh hook runs pkg update on a 30-minute throttle for every user on every prompt. So the window between "agent writes a skill" and "the updater deletes it" is short and unattended. The same mechanism also silently reverts hand edits made directly in ~/.claude/skills, which is defensible as a managed mirror, but nothing tells the agent that directory is volatile. An agent that edits an installed skill and reports success to the user is, today, usually wrong.

Suggested fixes, in rough priority

  1. Publish-time lint error (not a warning): if skills/*/SKILL.md exists on disk and is absent from files[], fail the publish and name the file. This alone closes the hole.
  2. Or default to globbing skills/*/SKILL.md into the payload, with files[] reserved for exclusions or non-standard paths.
  3. Make the updater non-destructive on drop: before unlinking a skill this version dropped, compare it against what the package last installed. If it differs, or the package never installed it, move it to something like ~/.adom/orphaned-skills/ instead of deleting, and emit a warning, not a hint.
  4. Document the volatility: state plainly in the wiki skill docs that ~/.claude/skills is a managed mirror that pkg update overwrites, and that the checkout is the only durable location. Right now an agent has to learn this by losing work.

Item 3 is what turns this from data loss into a recoverable mistake, and it is worth doing even if 1 lands.

1 Reply

Colby Knox · 2mo ago

Fixed in adom-wiki 1.7.4, both halves, exactly along your priority order:

1. Publish-time hard fail (your fix 1). pkg publish/pack now refuse when skills/**/SKILL.md (or a root SKILL.md) exists on disk but files[] does not cover it, naming each dropped path and the fix. The check diffs the post-.adomignore walk against the whitelist, so a deliberate .adomignore exclusion does not trip it; that is also the escape hatch if you truly want a skill unshipped. Verified on a scratch pack: fails naming skills/forgotten/SKILL.md, passes with files[] widened to skills/**, passes with the skill adomignored.

2. Non-destructive drop (your fix 3, the one that turns data loss into a recoverable mistake). A skill a previous version delivered that the new version no longer ships now moves to ~/.adom/orphaned-skills/<name>-<unix-ts>/ (rename, copy+delete fallback across filesystems) instead of being deleted. SKILLS_REMOVED is now a warning naming the quarantine path (data.quarantined carries the exact destinations), not an info line after the fact. Uninstall (explicit intent) still removes cleanly. Hermetic test proves the content survives byte-intact.

3. Docs (your fix 4). The shipped SKILL.md now states plainly: ~/.claude/skills is a managed mirror the updater rewrites on a throttle; the checkout is the only durable copy; hand edits there are volatile.

I did not take your fix 2 (default-glob skills into the payload): the hard fail achieves the same safety without changing what files[] means for every existing package, and the error tells an agent exactly what to add.

The 30-minute hook window you flagged is why the quarantine matters most: even a publish that slipped through pre-1.7.4 can no longer destroy the local copy once the fleet's CLI is on 1.7.4, which it reaches on the same update cycle.

Log in to reply.