You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
_resolve_skill (src/dmx/loop_tools.py) supports two skill shapes — dmx's own flat {name}.md and the folder-shaped {name}/SKILL.md (the agentskills.io / Claude Code ecosystem convention, with optional scripts//references//assets/) — but only for shared sources. The project's own .dmx/skills/ override directory, and the bundled skills directory, only ever look for the flat form:
The .dmx/skills/ block (checked first) has no {name}/SKILL.md fallback at all. Neither does the bundled-skills block further down (bundled.rglob(f"{candidate}.md")).
Net effect: dropping a folder-shaped skill directly into a project's own .dmx/skills/my-skill/SKILL.md does nothing — _resolve_skill won't find it there, falls through to shared sources, then bundled, and returns None if nothing else matches that name. The folder shape only works today if it arrives via a vendored shared source (.dmx/vendor/{source}/skills/{name}/SKILL.md).
This looks like an oversight from GH-27 phase 4, not a deliberate scoping choice — that work added the folder-shape fallback specifically so an org's shared-source repo could be an already-standards-shaped skills repo "with zero dmx-specific restructuring." The same convenience (author a skill once, in the standard shape, and have dmx find it wherever it lives) was never extended to a project's own local skills or to dmx's bundled skills.
Proposal
Extract the flat-then-folder lookup GH-27 phase 4 already wrote for shared sources into a small shared helper (_find_skill_in_dir(skills_dir, candidates) -> ResolvedSkill | None, checking {candidate}.md then {candidate}/SKILL.md for each candidate), and use it for all three tiers:
.dmx/skills/ (project override)
.dmx/vendor/{source}/skills/ (shared sources, already does this)
bundled skills/ (dmx's own)
root_path should be set the same way for any tier's folder-shaped match — it's not specific to shared sources, it's needed any time a skill has its own directory for scripts//references//assets/ to resolve against.
Out of scope
Changing catalog.load_skills/_register_skill (MCP slash-command / @app.prompt registration) — that's a separate, larger gap already tracked in Feature: expose shared-source (and app-repo-local) skills as slash commands #35 (shared-source and app-repo-local skills aren't exposed as slash commands at all, regardless of shape). This issue is scoped to the loop runtime's get_skill_definition/_resolve_skill path only.
Adding new skill shapes beyond flat and {name}/SKILL.md.
Acceptance criteria
A skill at .dmx/skills/{name}/SKILL.md (no .dmx/skills/{name}.md present) resolves via _resolve_skill and get_skill_definition, with root_path set to .dmx/skills/{name}.
Same for .dmx/skills/dmx-{name}/SKILL.md.
Same for a bundled skill shipped in the folder shape (if/when dmx ships one that way).
Existing flat-file resolution at every tier is unaffected — flat still wins over folder-shaped when both exist for the same name (matching the existing shared-source precedence, which checks flat first).
Problem
_resolve_skill(src/dmx/loop_tools.py) supports two skill shapes — dmx's own flat{name}.mdand the folder-shaped{name}/SKILL.md(the agentskills.io / Claude Code ecosystem convention, with optionalscripts//references//assets/) — but only for shared sources. The project's own.dmx/skills/override directory, and the bundled skills directory, only ever look for the flat form:The
.dmx/skills/block (checked first) has no{name}/SKILL.mdfallback at all. Neither does the bundled-skills block further down (bundled.rglob(f"{candidate}.md")).Net effect: dropping a folder-shaped skill directly into a project's own
.dmx/skills/my-skill/SKILL.mddoes nothing —_resolve_skillwon't find it there, falls through to shared sources, then bundled, and returnsNoneif nothing else matches that name. The folder shape only works today if it arrives via a vendored shared source (.dmx/vendor/{source}/skills/{name}/SKILL.md).This looks like an oversight from GH-27 phase 4, not a deliberate scoping choice — that work added the folder-shape fallback specifically so an org's shared-source repo could be an already-standards-shaped skills repo "with zero dmx-specific restructuring." The same convenience (author a skill once, in the standard shape, and have dmx find it wherever it lives) was never extended to a project's own local skills or to dmx's bundled skills.
Proposal
Extract the flat-then-folder lookup GH-27 phase 4 already wrote for shared sources into a small shared helper (
_find_skill_in_dir(skills_dir, candidates) -> ResolvedSkill | None, checking{candidate}.mdthen{candidate}/SKILL.mdfor each candidate), and use it for all three tiers:.dmx/skills/(project override).dmx/vendor/{source}/skills/(shared sources, already does this)skills/(dmx's own)root_pathshould be set the same way for any tier's folder-shaped match — it's not specific to shared sources, it's needed any time a skill has its own directory forscripts//references//assets/to resolve against.Out of scope
catalog.load_skills/_register_skill(MCP slash-command /@app.promptregistration) — that's a separate, larger gap already tracked in Feature: expose shared-source (and app-repo-local) skills as slash commands #35 (shared-source and app-repo-local skills aren't exposed as slash commands at all, regardless of shape). This issue is scoped to the loop runtime'sget_skill_definition/_resolve_skillpath only.{name}/SKILL.md.Acceptance criteria
.dmx/skills/{name}/SKILL.md(no.dmx/skills/{name}.mdpresent) resolves via_resolve_skillandget_skill_definition, withroot_pathset to.dmx/skills/{name}..dmx/skills/dmx-{name}/SKILL.md.root_pathsemantics.Context
src/dmx/loop_tools.py—_resolve_skill,ResolvedSkill