Skip to content

fix(skills): support folder-shaped SKILL.md in .dmx/skills/ and bundled skills - #41

Merged
hpieris-dm merged 2 commits into
mainfrom
fix-gh-40-skill-folder-shape-all-tiers
Sep 11, 2026
Merged

hpieris-dm merged 2 commits into
mainfrom
fix-gh-40-skill-folder-shape-all-tiers

Conversation

@hpieris-dm

Copy link
Copy Markdown
Contributor

Fixes #40

Problem

The folder-shaped {name}/SKILL.md fallback added in GH-27 phase 4 only applied to the shared-source tier (.dmx/vendor/{source}/skills/). A skill dropped into a project's own .dmx/skills/ in that same folder shape, or a bundled dmx skill shipped that way, silently failed to resolve — get_skill_definition returned a generic "Skill not found" with no hint that a matching folder existed.

Fix

Extracted the flat-then-folder lookup into a shared helper, _find_skill_in_dir(skills_dir, candidates, workspace_root, *, recursive), and reused it across all three tiers in _resolve_skill:

  1. .dmx/skills/ (project override) — non-recursive, same as before.
  2. .dmx/vendor/{source}/skills/ (shared sources) — unchanged behavior, now sharing the helper.
  3. Bundled skills/ — now recursive for both the flat and folder-shaped form, matching the bundled directory's actual nested category layout (e.g. workflow/0-init/dmx-init.md).

root_path is set whenever the folder-shaped form matches, in any tier. For the bundled tier specifically, the matched directory lives outside workspace_root (it's inside the installed package), so root_path falls back to an absolute path in that case rather than raising.

Existing precedence (app repo > shared sources > bundled) and root_path semantics for shared sources are unchanged — verified by the full existing TestResolveSkillSharedSources suite passing unmodified except for one test that explicitly asserted the old (buggy) app-repo behavior, which is now flipped to assert the fix.

Verification

  • Reproduced the bug against pre-fix main in an isolated worktree: a folder-shaped skill in .dmx/skills/ resolved to None.
  • Confirmed the same scenario resolves correctly on this branch, with the correct root_path.
  • Added tests for all three tiers: app-repo folder-shaped + dmx-prefixed variant, flat-still-beats-folder-shaped in the app repo, app-repo-beats-shared-source-and-bundled precedence, bundled folder-shaped (via a monkeypatched bundled dir, including a nested category subdirectory), and bundled folder-shaped not shadowed by other tiers.
  • Full suite: ruff check, ruff format --check, mypy src/dmx, pytest -q all pass (491 tests).
  • CHANGELOG.md updated under [Unreleased]. No WORKFLOW_VERSION bump — this is a bug fix, not a skill/rule/system-prompt change, per that constant's own bump policy.
  • README's shared-sources section reworded so it no longer implies folder-shaped skill support is exclusive to shared sources.

…ed skills

Extend the folder-shaped {name}/SKILL.md fallback (GH-27 phase 4) beyond
shared sources to every skill-resolution tier: the app repo's own
.dmx/skills/ and dmx's bundled skills directory. Extracted the
flat-then-folder lookup into a shared helper, _find_skill_in_dir, reused
by all three tiers. Existing precedence (app repo > shared sources >
bundled) and root_path semantics are unchanged.

Fixes #40
Found in deep review of the folder-shaped-skill fix above: _resolve_skill
built paths directly from get_skill_definition's name argument with no
validation, so a '../'-laden or absolute name resolved to arbitrary files
outside .dmx/skills/, a shared source's skills/, or the bundled skills
dir. Reproducible on main before this PR (flat lookup already had it for
all tiers; the folder-shaped form had it for shared sources); this PR's
own fix widened the folder-shaped vector from one tier to three.

Add _SKILL_NAME_RE, mirroring shared_sources.py's existing name/subdir
slug validation, and reject non-slug names up front -- same behavior as
'skill not found', no filesystem access attempted.

6 new tests: traversal via flat form, via folder-shaped form, absolute
path, leading-hyphen, and a sanity check that ordinary hyphenated skill
names (the real-world norm) still resolve.
@hpieris-dm
hpieris-dm merged commit 5e2915a into main Sep 11, 2026
13 checks passed
@hpieris-dm
hpieris-dm deleted the fix-gh-40-skill-folder-shape-all-tiers branch September 11, 2026 05:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: _resolve_skill only supports folder-shaped {name}/SKILL.md skills for shared sources, not .dmx/skills/ or bundled

1 participant