Bug
The embedded praxis-onboarding meta-skill (multi-file tree, internal/skillinstall/embedded/praxis-onboarding/) and a hypothetical server catalog skill named onboarding collide: Skill.PrefixedName() = "praxis-" + name (internal/skillcatalog/skillcatalog.go:67) maps onboarding → praxis-onboarding — the same install dir.
Precedence is then inconsistent:
praxis login installs the embedded meta-skill first, then installFetchedCatalog (cmd/login_setup.go:314) overwrites the dir and replaces the receipt entry (upsert keyed on SkillName+Harness) → server version wins on disk.
praxis update → skillinstall.Refresh() (internal/skillinstall/installer.go:386) sees the receipt entry, isTreeSkill is unconditionally true for the name (embedded.go:35), and rewrites from the embed → embedded version silently clobbers the server content.
IsMetaSkill (dummy.go:392) is always true for the name → logout/profile-switch never removes the server version.
Which content is on disk depends on the last command run. Nothing prevents a catalog skill claiming a meta-skill's name — this also applies to catalog skills named praxis or memory (→ praxis-memory).
Suggested fix
Reserve the meta-skill namespace:
- In
installFetchedCatalog, skip (with a warning) any catalog skill whose PrefixedName() collides with MetaSkillNames() — embedded meta-skills always win locally.
- Optionally: server-side, forbid creating org/personal skills named
praxis, memory, onboarding (agent-factory validation), so authors find out at creation time rather than at install time.
- Add a test: catalog bundle containing
onboarding → install skips it, receipt untouched, embedded content intact after login AND after update.
Found during the praxis skills/gateway audit (2026-07-06).
Bug
The embedded
praxis-onboardingmeta-skill (multi-file tree,internal/skillinstall/embedded/praxis-onboarding/) and a hypothetical server catalog skill namedonboardingcollide:Skill.PrefixedName()="praxis-" + name(internal/skillcatalog/skillcatalog.go:67) mapsonboarding→praxis-onboarding— the same install dir.Precedence is then inconsistent:
praxis logininstalls the embedded meta-skill first, theninstallFetchedCatalog(cmd/login_setup.go:314) overwrites the dir and replaces the receipt entry (upsert keyed on SkillName+Harness) → server version wins on disk.praxis update→skillinstall.Refresh()(internal/skillinstall/installer.go:386) sees the receipt entry,isTreeSkillis unconditionally true for the name (embedded.go:35), and rewrites from the embed → embedded version silently clobbers the server content.IsMetaSkill(dummy.go:392) is always true for the name → logout/profile-switch never removes the server version.Which content is on disk depends on the last command run. Nothing prevents a catalog skill claiming a meta-skill's name — this also applies to catalog skills named
praxisormemory(→praxis-memory).Suggested fix
Reserve the meta-skill namespace:
installFetchedCatalog, skip (with a warning) any catalog skill whosePrefixedName()collides withMetaSkillNames()— embedded meta-skills always win locally.praxis,memory,onboarding(agent-factory validation), so authors find out at creation time rather than at install time.onboarding→ install skips it, receipt untouched, embedded content intact after login AND after update.Found during the praxis skills/gateway audit (2026-07-06).