Skip to content

refactor: flatten skills to top-level directories - #28

Merged
shuvonsec merged 1 commit into
mainfrom
refactor/flatten-skills
Sep 17, 2026
Merged

shuvonsec merged 1 commit into
mainfrom
refactor/flatten-skills

Conversation

@shuvonsec

Copy link
Copy Markdown
Member

Every skill becomes its own top-level directory, so the full catalogue is visible in the repository listing instead of being buried under skills/security/<domain>/<name>/.

Before, finding a skill meant four levels: skills/security/identity/jwt-security/SKILL.md. Now it is jwt-security/SKILL.md.

What moved

38 skills: 8 axguard-* orchestration skills and 30 security domain skills. Every move is a rename, so git log --follow still works on each file.

The registry moves with them: skills/index.yamlskills-index.yaml at the root, with the skills/ prefix stripped from all 38 path entries.

No grouping is lost. ai, application, discovery, identity, infrastructure and operations were only ever directory names — the registry already stored the same value in each skill's domain: field, and still does.

What had to change with it

install.sh — replaced copy_tree_items "skills/*" plus a separate install_security_skills pass with one install_skills function that globs top-level directories containing a SKILL.md. The two-pass split only existed to handle the nesting.

uninstall.sh — this carried its skill and command lists by hand, and they had drifted. The arrays were missing the axguard-security skill and the axguard-contribute.md and axguard-privacy.md commands, so an uninstall silently left three files behind. Both lists are now derived from the repo the same way install.sh derives them, so they cannot drift again.

scripts/validate_skills.py — identified domain skills by testing for skills/security/ in the path, which no longer exists. It now treats any skill not named axguard-* as a domain skill. That is the identical 30/8 split, and the strict checks on domain skills are unchanged: version, domain, license, ## Purpose, ## Research Provenance, and no placeholder CWE/WSTG ids.

tests/test_skills.py — asserted text.count("path: skills/security/") == 30, which is a layout assertion rather than a correctness one. It now asserts that every skill on disk appears in skills-index.yaml. That is strictly stronger and survives future moves.

tests/test_mcp_skill.py — pointed at ROOT / "skills" / "axguard-security". Repointed.

Docs — 12 files updated for the new paths. Two links inside axguard-security/ were broken by the depth change (../../docs/… resolving one level too high) and are fixed.

Verification

  • install.sh --agent all --project → 38 skills and 31 commands in each of .claude, .cursor, .opencode, .codex; 38 skills and 0 commands in .agents, which is correct since shared Agent Skills have no slash commands. Identical to the counts before this change.
  • uninstall.sh --agent all --project → 0 skills and 0 commands remaining in all five. Before this change it would have left 3 files.
  • python scripts/validate_skills.pyskills scanned: 38 OK, with the domain/orchestration split confirmed at 30/8.
  • Validator is not vacuous: deleting a domain: key and breaking a ## Purpose heading in a scratch copy still produces FAIL with both errors named.
  • test_skills.py — all 3 tests pass.
  • Relative links across all 100+ markdown files: 0 broken.
  • No references to skills/security, skills/index.yaml or skills/axguard remain anywhere in the repo.

test_mcp_skill.py imports pytest, which is not installable on my machine (no ensurepip, no pip), so that module is verified by CI rather than locally. Its only change is the one path constant, and the file it points at exists.

Packaging is unaffected — pyproject.toml pins include = ["cli*", "engines*"], so the new root directories are not picked up by setuptools discovery.

Each skill is now its own directory at the repo root, so the whole
catalogue is visible from the repository listing instead of being
buried two levels down under skills/security/<domain>/.

38 skills move: 8 axguard-* orchestration skills and 30 security domain
skills. All moves are renames, so history follows. Domain grouping is
not lost — ai, application, discovery, identity, infrastructure and
operations survive in the domain: field of the registry, which moves
from skills/index.yaml to skills-index.yaml at the root.

install.sh and uninstall.sh now discover skills by globbing top-level
directories that contain a SKILL.md. Both previously carried the list by
hand, and uninstall.sh had drifted: it omitted the axguard-security
skill and the axguard-contribute.md and axguard-privacy.md commands, so
those were left behind on removal. Deriving both lists from the repo
fixes that and stops it recurring.

validate_skills.py identified domain skills by their skills/security/
path. That signal is gone, so it now treats any skill not named
axguard-* as a domain skill — the same 30/8 split — and keeps enforcing
version, domain, license, ## Purpose and ## Research Provenance on them.

test_skills.py asserted exactly 30 entries matching path: skills/security/.
It now asserts every skill on disk is registered in skills-index.yaml,
which is a stronger check and layout-independent.
@shuvonsec
shuvonsec merged commit 8690879 into main Sep 17, 2026
8 checks passed
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.

1 participant