Repro
- Own a skill (bought via buy_skill).
unequip_skill(mint) — SKILL.md removed from claude/codex/openclaw/AGENTNET_SKILL_DIRS dirs, mint added to ~/.agentnet/skills.json's disposed array. Confirmed working.
install_skill(mint) (the documented re-equip path, plans/qa/external-hosts-qa.md §D.4) — SKILL.md correctly reinstalled to all dirs. Balance unchanged, as expected.
- Check
~/.agentnet/skills.json — the mint is still in disposed.
Root cause
install_skill's tool handler (packages/core/src/skill-market/index.ts:343-370) calls SkillSync.installBoughtAll() / installBoughtToDir() directly. It never calls SkillSync.reEquip() (packages/core/src/skill-market/ingest/index.ts:249), which is the method that both restores the files AND calls undisposeNftSkill() to clear the flag.
Impact
Per the comment on disposed in registry.ts, the session-start owned-sync (injectOwned) skips any mint still in disposed. So a skill re-equipped via install_skill reinstalls now, but silently un-equips itself again on the next session start — even though the user just explicitly asked for it back, with no error or signal that this will happen.
Fix
Have the install_skill tool handler call SkillSync.reEquip() instead of (or in addition to, if a skill was never disposed) installBoughtAll/installBoughtToDir — or at minimum call undisposeNftSkill(skillId) alongside the existing install call.
Found during the QA run for issue #105 (Eliza + cross-host wrap-up), §D.3/D.4.
Repro
unequip_skill(mint)— SKILL.md removed from claude/codex/openclaw/AGENTNET_SKILL_DIRS dirs, mint added to~/.agentnet/skills.json'sdisposedarray. Confirmed working.install_skill(mint)(the documented re-equip path,plans/qa/external-hosts-qa.md§D.4) — SKILL.md correctly reinstalled to all dirs. Balance unchanged, as expected.~/.agentnet/skills.json— the mint is still indisposed.Root cause
install_skill's tool handler (packages/core/src/skill-market/index.ts:343-370) callsSkillSync.installBoughtAll()/installBoughtToDir()directly. It never callsSkillSync.reEquip()(packages/core/src/skill-market/ingest/index.ts:249), which is the method that both restores the files AND callsundisposeNftSkill()to clear the flag.Impact
Per the comment on
disposedinregistry.ts, the session-start owned-sync (injectOwned) skips any mint still indisposed. So a skill re-equipped viainstall_skillreinstalls now, but silently un-equips itself again on the next session start — even though the user just explicitly asked for it back, with no error or signal that this will happen.Fix
Have the
install_skilltool handler callSkillSync.reEquip()instead of (or in addition to, if a skill was never disposed)installBoughtAll/installBoughtToDir— or at minimum callundisposeNftSkill(skillId)alongside the existing install call.Found during the QA run for issue #105 (Eliza + cross-host wrap-up), §D.3/D.4.