diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..d201434 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,15 @@ +{ + "name": "mathias", + "description": "Mathias's private plugin marketplace, hosted on gitea.d-ma.be. Self-hosted by design — nothing here transits GitHub.", + "owner": { + "name": "Mathias", + "url": "https://git.d-ma.be/mathias" + }, + "plugins": [ + { + "name": "skills", + "source": ".", + "description": "Engineering skills, the pre-task-ritual and secret-guard hooks, and the brain/gitea/infra MCP servers as one versioned unit." + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..544321e --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "skills", + "description": "Mathias's engineering skills library, plus the hooks and MCP servers that make it enforceable: TDD, clean code, debugging, specs, discovery, CI, and secret hygiene.", + "version": "0.3.3", + "author": { + "name": "Mathias", + "url": "https://git.d-ma.be/mathias" + }, + "homepage": "https://git.d-ma.be/mathias/skills", + "repository": "https://git.d-ma.be/mathias/skills.git" +} diff --git a/Taskfile.yml b/Taskfile.yml index 9651e95..e61cfea 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -2,22 +2,19 @@ version: '3' # Skills library Taskfile. # -# Primary entry point for project + host installation. Consumer projects -# do NOT depend on this file directly — they ship their own -# `skills:install` target that delegates here via `install.sh`. This -# Taskfile is invoked by maintainers of the skills repo itself, plus by -# install.sh during the post-clone wire step. +# This repo is two things at once: +# 1. A Claude Code PLUGIN (skills + hooks + MCP servers), distributed through +# the marketplace this same repo hosts at .claude-plugin/marketplace.json. +# 2. A plain skills library for harnesses with no plugin system — Crush, Pi, +# OpenCode — wired by install.sh as ONE directory symlink per harness. +# +# The wiring loops that used to live here were five near-identical copies that +# drifted; install.sh owns wiring now and this file delegates to it. vars: REPO_URL: 'https://git.d-ma.be/mathias/skills.git' - CHECKOUT_DIR: '{{.HOME}}/.local/share/skills' - CLAUDE_GLOBAL_DIR: '{{.HOME}}/.claude/skills' - CRUSH_DIR: '{{.HOME}}/.config/crush/skills' - ANTIGRAVITY_DIR: '{{.HOME}}/.gemini/antigravity/skills' - VIBE_DIR: '{{.HOME}}/.vibe/skills' - # Anything at the repo root that is NOT a skill directory. Both - # Taskfile + install.sh share this exclusion regex. - NON_SKILL_ENTRIES: '^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$' + SKILLS_DIR: '{{.TASKFILE_DIR}}/skills' + PLUGIN_MANIFEST: '{{.TASKFILE_DIR}}/.claude-plugin/plugin.json' tasks: @@ -28,134 +25,95 @@ tasks: list: desc: 'Print every skill in this repo' cmds: - - 'ls -1 {{.TASKFILE_DIR}} | grep -Ev "^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$" || true' + - 'ls -1 {{.SKILLS_DIR}}' silent: true install: - desc: 'Wire skills into every supported harness (Claude Code, Crush, Antigravity, Mistral Vibe).' + desc: 'Wire THIS checkout into Crush / Pi / OpenCode. Claude Code uses the plugin instead.' cmds: - - task: install:claude:global - - task: install:claude:repo - - task: install:crush - - task: install:antigravity - - task: install:vibe - - install:claude:global: - desc: 'Per-skill symlinks under ~/.claude/skills/ — visible in every Claude Code project on this host.' - cmds: - - mkdir -p {{.CLAUDE_GLOBAL_DIR}} - - | - for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "{{.NON_SKILL_ENTRIES}}"); do - target="{{.TASKFILE_DIR}}/${skill}" - link="{{.CLAUDE_GLOBAL_DIR}}/${skill}" - if [ -L "$link" ] || [ -e "$link" ]; then - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - continue - fi - rm -rf "$link" - fi - ln -s "$target" "$link" - echo "linked $link → $target" - done - - install:claude:repo: - desc: 'Per-skill symlinks under $(pwd)/.claude/skills/ when invoked inside a git repo.' - cmds: - - | - if ! git rev-parse --show-toplevel >/dev/null 2>&1; then - echo "not in a git repo — skipping per-repo wire"; exit 0 - fi - repo=$(git rev-parse --show-toplevel) - if [ "$repo" = "{{.TASKFILE_DIR}}" ]; then - echo "running from skills repo itself — skipping per-repo wire"; exit 0 - fi - target_dir="$repo/.claude/skills" - mkdir -p "$target_dir" - for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "{{.NON_SKILL_ENTRIES}}"); do - target="{{.TASKFILE_DIR}}/${skill}" - link="${target_dir}/${skill}" - if [ -L "$link" ] || [ -e "$link" ]; then - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - continue - fi - rm -rf "$link" - fi - ln -s "$target" "$link" - echo "linked $link → $target" - done - - install:crush: - desc: 'Per-skill symlinks under ~/.config/crush/skills/ — visible in every Crush session on this host.' - cmds: - - mkdir -p {{.CRUSH_DIR}} - - | - for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "{{.NON_SKILL_ENTRIES}}"); do - target="{{.TASKFILE_DIR}}/${skill}" - link="{{.CRUSH_DIR}}/${skill}" - if [ -L "$link" ] || [ -e "$link" ]; then - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - continue - fi - rm -rf "$link" - fi - ln -s "$target" "$link" - echo "linked $link → $target" - done - - install:antigravity: - desc: 'Per-skill symlinks under ~/.gemini/antigravity/skills/. SKILL.md frontmatter (name + description) is already antigravity-compatible.' - cmds: - - mkdir -p {{.ANTIGRAVITY_DIR}} - - | - for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "{{.NON_SKILL_ENTRIES}}"); do - target="{{.TASKFILE_DIR}}/${skill}" - link="{{.ANTIGRAVITY_DIR}}/${skill}" - if [ -L "$link" ] || [ -e "$link" ]; then - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - continue - fi - rm -rf "$link" - fi - ln -s "$target" "$link" - echo "linked $link → $target" - done - - install:vibe: - desc: 'Per-skill file symlinks under ~/.vibe/skills/.md → /SKILL.md for Mistral Vibe (flat .md layout, not a directory).' - cmds: - - mkdir -p {{.VIBE_DIR}} - - | - for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "{{.NON_SKILL_ENTRIES}}"); do - target="{{.TASKFILE_DIR}}/${skill}/SKILL.md" - [ -f "$target" ] || continue - link="{{.VIBE_DIR}}/${skill}.md" - if [ -L "$link" ] || [ -e "$link" ]; then - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - continue - fi - rm -rf "$link" - fi - ln -s "$target" "$link" - echo "linked $link → $target" - done + - SKILLS_SKIP_FETCH=1 SKILLS_CHECKOUT_DIR='{{.TASKFILE_DIR}}' bash '{{.TASKFILE_DIR}}/install.sh' update: - desc: 'git pull the canonical checkout then re-run install.' + desc: 'Fast-forward this checkout and re-wire.' cmds: - - | - if [ ! -d "{{.CHECKOUT_DIR}}/.git" ]; then - echo "no canonical checkout at {{.CHECKOUT_DIR}} — run install.sh first"; exit 1 - fi - git -C "{{.CHECKOUT_DIR}}" pull --ff-only + - git -C '{{.TASKFILE_DIR}}' pull --ff-only - task: install + doctor: + desc: 'Report drift across every harness on this host. Non-zero exit means something is wrong.' + cmds: + - '{{.TASKFILE_DIR}}/bin/doctor' + + validate: + desc: 'Validate the plugin + marketplace manifests with the Claude Code CLI.' + cmds: + - claude plugin validate '{{.TASKFILE_DIR}}' + + test: + desc: 'Run the shell test suite (hooks + doctor).' + cmds: + - | + fail=0 + for t in '{{.TASKFILE_DIR}}'/tests/*_test.sh; do + [ -f "$t" ] || continue + echo "--- $(basename "$t")" + sh "$t" || fail=1 + done + exit $fail + + check: + desc: 'Structure gate — layout, frontmatter, manifest/tag parity. Runs in CI.' + cmds: + - | + fail=0 + + # 1. No stray entries at the repo root. A loose foo.md where + # skills/foo/SKILL.md was meant loads in NO harness and errors in + # none either — it just silently does nothing. (See #23.) + for entry in "{{.TASKFILE_DIR}}"/*; do + base=$(basename "$entry") + case "$base" in + install.sh|Taskfile.yml|README.md|SKILLS_INDEX.md|skills|hooks|bin|tests) continue ;; + esac + echo "ERROR: unexpected entry at repo root: $base" >&2 + fail=1 + done + + # 2. Every skill is a directory with a SKILL.md carrying name + description. + count=0 + for dir in "{{.SKILLS_DIR}}"/*; do + name=$(basename "$dir") + if [ ! -d "$dir" ]; then + echo "ERROR: skills/$name is not a directory" >&2; fail=1; continue + fi + if [ ! -f "$dir/SKILL.md" ]; then + echo "ERROR: skills/$name missing SKILL.md" >&2; fail=1; continue + fi + head -n 20 "$dir/SKILL.md" | grep -q '^name:' || { echo "ERROR: skills/$name SKILL.md has no 'name:' frontmatter" >&2; fail=1; } + head -n 20 "$dir/SKILL.md" | grep -q '^description:' || { echo "ERROR: skills/$name SKILL.md has no 'description:' frontmatter" >&2; fail=1; } + count=$((count + 1)) + done + + # 3. Plugin manifest version must match the latest tag, or installers + # never see the update (Claude Code gates updates on this field). + if [ -f '{{.PLUGIN_MANIFEST}}' ]; then + manifest_v=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' '{{.PLUGIN_MANIFEST}}' | head -1) + tag_v=$(git -C '{{.TASKFILE_DIR}}' describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo '') + if [ -n "$tag_v" ] && [ "$manifest_v" != "$tag_v" ]; then + echo "ERROR: plugin.json version ($manifest_v) != latest tag ($tag_v)" >&2 + fail=1 + fi + else + echo "ERROR: missing .claude-plugin/plugin.json" >&2; fail=1 + fi + + if [ $fail -ne 0 ]; then + echo "check FAILED" >&2; exit 1 + fi + echo "check OK — $count skills, manifest matches tag" + release: - desc: 'Tag HEAD per Bump-Type in the latest commit footer. Normally CI handles this — run locally only when CI is unavailable.' + desc: 'Tag HEAD per Bump-Type in the latest commit footer. Normally CI handles this.' cmds: - | latest=$(git -C "{{.TASKFILE_DIR}}" describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") @@ -172,26 +130,3 @@ tasks: echo "tagging $next (previous $latest, bump=${bump:-patch})" git -C "{{.TASKFILE_DIR}}" tag -a "$next" -m "release $next" echo "now: git push origin $next" - - check: - desc: 'Sanity check — every skill dir has a SKILL.md, no stray files at root.' - cmds: - - | - missing=0 - for skill in $(ls -1 "{{.TASKFILE_DIR}}" | grep -Ev "^(Taskfile.yml|install.sh|README.md|SKILLS_INDEX.md|.gitea|.git$)$"); do - dir="{{.TASKFILE_DIR}}/${skill}" - if [ ! -d "$dir" ]; then - echo "ERROR: $skill is not a directory" >&2 - missing=$((missing + 1)) - continue - fi - if [ ! -f "$dir/SKILL.md" ]; then - echo "ERROR: $dir missing SKILL.md" >&2 - missing=$((missing + 1)) - fi - done - if [ $missing -gt 0 ]; then - echo "$missing skill(s) failed structure check" >&2 - exit 1 - fi - echo "all skills have SKILL.md" diff --git a/install.sh b/install.sh index 8f19351..6ee5a73 100755 --- a/install.sh +++ b/install.sh @@ -5,25 +5,55 @@ # curl -fsSL https://git.d-ma.be/mathias/skills/raw/branch/main/install.sh | bash # # Pinned to a specific tag: -# SKILLS_REF=v0.1.0 bash install.sh +# SKILLS_REF=v0.4.0 bash install.sh # # Idempotent: re-running pulls the latest changes for the configured ref -# (default: main) and re-wires symlinks. Existing correct links are -# left alone; mismatched ones are replaced. +# (default: main) and re-wires the links. +# +# Claude Code is NOT wired here. It installs this repo as a plugin from the +# marketplace this repo also hosts: +# +# /plugin marketplace add https://git.d-ma.be/mathias/skills.git +# /plugin install skills@mathias +# +# That path carries the hooks and MCP server definitions too, which symlinks +# cannot. This script covers the harnesses with no plugin system: Crush, Pi +# and OpenCode. +# +# Wiring model — one directory link per harness, never one per skill: +# +# ~/.agents/skills -> $CHECKOUT_DIR/skills (canonical; Pi reads it directly) +# ~/.config/crush/skills -> ~/.agents/skills +# ~/.config/opencode/skills -> ~/.agents/skills +# +# Adding a skill to the repo therefore wires it everywhere with no re-run, +# and a broken link is one broken link rather than 42. +# +# CHECKOUT_DIR deliberately defaults OUTSIDE any file-synced or +# cross-platform-shared directory. Do not "fix" it to point into ~/dev: on a +# fleet whose workspace is shared between macOS (/Users/...) and Linux +# (/home/...), an absolute link stored there is broken on one side by +# construction. See mathias/skills#23. set -euo pipefail REPO_URL="${SKILLS_REPO_URL:-https://git.d-ma.be/mathias/skills.git}" REF="${SKILLS_REF:-main}" CHECKOUT_DIR="${SKILLS_CHECKOUT_DIR:-$HOME/.local/share/skills}" -CLAUDE_GLOBAL_DIR="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}" +AGENTS_DIR="${AGENTS_SKILLS_DIR:-$HOME/.agents/skills}" CRUSH_DIR="${CRUSH_SKILLS_DIR:-$HOME/.config/crush/skills}" -ANTIGRAVITY_DIR="${ANTIGRAVITY_SKILLS_DIR:-$HOME/.gemini/antigravity/skills}" -VIBE_SKILLS_DIR="${VIBE_SKILLS_DIR:-$HOME/.vibe/skills}" +OPENCODE_DIR="${OPENCODE_SKILLS_DIR:-$HOME/.config/opencode/skills}" log() { printf '[skills] %s\n' "$*"; } ensure_checkout() { + # Wiring an existing working checkout (task install) must not fetch or + # move HEAD — that would discard in-progress work. + if [ "${SKILLS_SKIP_FETCH:-}" = "1" ]; then + [ -d "$CHECKOUT_DIR/skills" ] || { log "no skills/ under $CHECKOUT_DIR"; exit 1; } + log "using $CHECKOUT_DIR as-is (SKILLS_SKIP_FETCH=1)" + return + fi if [ -d "$CHECKOUT_DIR/.git" ]; then log "updating $CHECKOUT_DIR" git -C "$CHECKOUT_DIR" fetch --tags --quiet @@ -40,109 +70,47 @@ ensure_checkout() { fi } -list_skills() { - # Every top-level entry that isn't a known meta file. - (cd "$CHECKOUT_DIR" && ls -1) | grep -Ev '^(Taskfile\.yml|install\.sh|README\.md|SKILLS_INDEX\.md|\.gitea|\.git)$' || true +count_skills() { + find "$CHECKOUT_DIR/skills" -mindepth 2 -maxdepth 2 -name SKILL.md 2>/dev/null | wc -l | tr -d ' ' } -link_skill() { - # link_skill - local target_dir="$1" - local skill="$2" - local target="$CHECKOUT_DIR/$skill" - local link="$target_dir/$skill" - - if [ -L "$link" ] || [ -e "$link" ]; then - local current - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - return +# link_dir +# Replaces whatever is there — including a directory left behind by the old +# per-skill wiring — with a single symlink. +link_dir() { + local link="$1" target="$2" + if [ -L "$link" ]; then + [ "$(readlink "$link")" = "$target" ] && return + rm -f "$link" + elif [ -d "$link" ]; then + # Refuse to discard a directory holding anything but symlinks: that + # would be someone's real skills, not our old wiring. + if find "$link" -mindepth 1 -maxdepth 1 ! -type l | grep -q .; then + log "REFUSING to replace $link — it holds non-symlink entries; move them and re-run" + return 1 fi - rm -rf "$link" + find "$link" -mindepth 1 -maxdepth 1 -type l -delete + rmdir "$link" + elif [ -e "$link" ]; then + rm -f "$link" fi + mkdir -p "$(dirname "$link")" ln -s "$target" "$link" log "linked $link → $target" } -wire_claude_global() { - mkdir -p "$CLAUDE_GLOBAL_DIR" - while IFS= read -r skill; do - [ -n "$skill" ] || continue - link_skill "$CLAUDE_GLOBAL_DIR" "$skill" - done < <(list_skills) -} - -wire_crush() { - # Crush reads skills from ~/.config/crush/skills//SKILL.md. - # Pre-creating the dir is cheap even when Crush isn't installed. - mkdir -p "$CRUSH_DIR" - while IFS= read -r skill; do - [ -n "$skill" ] || continue - link_skill "$CRUSH_DIR" "$skill" - done < <(list_skills) -} - -wire_antigravity() { - # Antigravity (Google's VS Code extension) reads global skills from - # ~/.gemini/antigravity/skills//SKILL.md. Our SKILL.md files - # already carry the required `name` + `description` YAML frontmatter, - # so symlinks are sufficient — no manifest translation step. - mkdir -p "$ANTIGRAVITY_DIR" - while IFS= read -r skill; do - [ -n "$skill" ] || continue - link_skill "$ANTIGRAVITY_DIR" "$skill" - done < <(list_skills) -} - -wire_claude_repo() { - # Only wire per-repo when invoked from inside a git repo and it isn't - # the skills repo itself. - if ! git rev-parse --show-toplevel >/dev/null 2>&1; then - return - fi - local repo - repo=$(git rev-parse --show-toplevel) - if [ "$repo" = "$CHECKOUT_DIR" ]; then - return - fi - local target_dir="$repo/.claude/skills" - mkdir -p "$target_dir" - while IFS= read -r skill; do - [ -n "$skill" ] || continue - link_skill "$target_dir" "$skill" - done < <(list_skills) -} - -wire_vibe() { - # Mistral Vibe reads a flat ~/.vibe/skills/.md — link the SKILL.md - # file directly (not the skill directory, as the other harnesses do). - mkdir -p "$VIBE_SKILLS_DIR" - while IFS= read -r skill; do - [ -n "$skill" ] || continue - local target="$CHECKOUT_DIR/$skill/SKILL.md" - [ -f "$target" ] || continue - local link="$VIBE_SKILLS_DIR/$skill.md" - if [ -L "$link" ] || [ -e "$link" ]; then - local current - current=$(readlink "$link" 2>/dev/null || true) - if [ "$current" = "$target" ]; then - continue - fi - rm -rf "$link" - fi - ln -s "$target" "$link" - log "linked $link → $target" - done < <(list_skills) -} - main() { ensure_checkout - wire_claude_global - wire_claude_repo - wire_crush - wire_antigravity - wire_vibe - log "done — $(list_skills | wc -l | tr -d ' ') skill(s) wired at ref=$REF" + + # Canonical location. Pi reads ~/.agents/skills directly, so it needs no + # harness-specific link of its own. + link_dir "$AGENTS_DIR" "$CHECKOUT_DIR/skills" + + link_dir "$CRUSH_DIR" "$AGENTS_DIR" + link_dir "$OPENCODE_DIR" "$AGENTS_DIR" + + log "done — $(count_skills) skill(s) at ref=$REF, 3 links total" + log "Claude Code: install the plugin instead — /plugin marketplace add $REPO_URL" } main "$@" diff --git a/atdd/SKILL.md b/skills/atdd/SKILL.md similarity index 100% rename from atdd/SKILL.md rename to skills/atdd/SKILL.md diff --git a/clean-code/SKILL.md b/skills/clean-code/SKILL.md similarity index 100% rename from clean-code/SKILL.md rename to skills/clean-code/SKILL.md diff --git a/clean-code/references/clean-code.md b/skills/clean-code/references/clean-code.md similarity index 100% rename from clean-code/references/clean-code.md rename to skills/clean-code/references/clean-code.md diff --git a/clean-code/references/code-smells.md b/skills/clean-code/references/code-smells.md similarity index 100% rename from clean-code/references/code-smells.md rename to skills/clean-code/references/code-smells.md diff --git a/code-review/SKILL.md b/skills/code-review/SKILL.md similarity index 100% rename from code-review/SKILL.md rename to skills/code-review/SKILL.md diff --git a/cognitive-load/SKILL.md b/skills/cognitive-load/SKILL.md similarity index 100% rename from cognitive-load/SKILL.md rename to skills/cognitive-load/SKILL.md diff --git a/debug/SKILL.md b/skills/debug/SKILL.md similarity index 100% rename from debug/SKILL.md rename to skills/debug/SKILL.md diff --git a/discovery-framing/SKILL.md b/skills/discovery-framing/SKILL.md similarity index 100% rename from discovery-framing/SKILL.md rename to skills/discovery-framing/SKILL.md diff --git a/dream/SKILL.md b/skills/dream/SKILL.md similarity index 100% rename from dream/SKILL.md rename to skills/dream/SKILL.md diff --git a/experiment-spec/SKILL.md b/skills/experiment-spec/SKILL.md similarity index 100% rename from experiment-spec/SKILL.md rename to skills/experiment-spec/SKILL.md diff --git a/feature-spec/SKILL.md b/skills/feature-spec/SKILL.md similarity index 100% rename from feature-spec/SKILL.md rename to skills/feature-spec/SKILL.md diff --git a/gitea-ci/SKILL.md b/skills/gitea-ci/SKILL.md similarity index 100% rename from gitea-ci/SKILL.md rename to skills/gitea-ci/SKILL.md diff --git a/grill-me/SKILL.md b/skills/grill-me/SKILL.md similarity index 100% rename from grill-me/SKILL.md rename to skills/grill-me/SKILL.md diff --git a/own-the-task/SKILL.md b/skills/own-the-task/SKILL.md similarity index 100% rename from own-the-task/SKILL.md rename to skills/own-the-task/SKILL.md diff --git a/planning/SKILL.md b/skills/planning/SKILL.md similarity index 100% rename from planning/SKILL.md rename to skills/planning/SKILL.md diff --git a/playwright/SKILL.md b/skills/playwright/SKILL.md similarity index 100% rename from playwright/SKILL.md rename to skills/playwright/SKILL.md diff --git a/problem-analysis/SKILL.md b/skills/problem-analysis/SKILL.md similarity index 100% rename from problem-analysis/SKILL.md rename to skills/problem-analysis/SKILL.md diff --git a/refactoring/SKILL.md b/skills/refactoring/SKILL.md similarity index 100% rename from refactoring/SKILL.md rename to skills/refactoring/SKILL.md diff --git a/regulatory-risk-assessment/SKILL.md b/skills/regulatory-risk-assessment/SKILL.md similarity index 100% rename from regulatory-risk-assessment/SKILL.md rename to skills/regulatory-risk-assessment/SKILL.md diff --git a/secret-hygiene/SKILL.md b/skills/secret-hygiene/SKILL.md similarity index 100% rename from secret-hygiene/SKILL.md rename to skills/secret-hygiene/SKILL.md diff --git a/session-retrospective/SKILL.md b/skills/session-retrospective/SKILL.md similarity index 100% rename from session-retrospective/SKILL.md rename to skills/session-retrospective/SKILL.md diff --git a/solid/SKILL.md b/skills/solid/SKILL.md similarity index 100% rename from solid/SKILL.md rename to skills/solid/SKILL.md diff --git a/solid/references/architecture.md b/skills/solid/references/architecture.md similarity index 100% rename from solid/references/architecture.md rename to skills/solid/references/architecture.md diff --git a/solid/references/complexity.md b/skills/solid/references/complexity.md similarity index 100% rename from solid/references/complexity.md rename to skills/solid/references/complexity.md diff --git a/solid/references/design-patterns.md b/skills/solid/references/design-patterns.md similarity index 100% rename from solid/references/design-patterns.md rename to skills/solid/references/design-patterns.md diff --git a/solid/references/go-adaptation.md b/skills/solid/references/go-adaptation.md similarity index 100% rename from solid/references/go-adaptation.md rename to skills/solid/references/go-adaptation.md diff --git a/solid/references/object-design.md b/skills/solid/references/object-design.md similarity index 100% rename from solid/references/object-design.md rename to skills/solid/references/object-design.md diff --git a/solid/references/solid-principles.md b/skills/solid/references/solid-principles.md similarity index 100% rename from solid/references/solid-principles.md rename to skills/solid/references/solid-principles.md diff --git a/spec-driven-dev/SKILL.md b/skills/spec-driven-dev/SKILL.md similarity index 100% rename from spec-driven-dev/SKILL.md rename to skills/spec-driven-dev/SKILL.md diff --git a/stage-gate-review/SKILL.md b/skills/stage-gate-review/SKILL.md similarity index 100% rename from stage-gate-review/SKILL.md rename to skills/stage-gate-review/SKILL.md diff --git a/superpowers-brainstorming/SKILL.md b/skills/superpowers-brainstorming/SKILL.md similarity index 100% rename from superpowers-brainstorming/SKILL.md rename to skills/superpowers-brainstorming/SKILL.md diff --git a/superpowers-brainstorming/scripts/frame-template.html b/skills/superpowers-brainstorming/scripts/frame-template.html similarity index 100% rename from superpowers-brainstorming/scripts/frame-template.html rename to skills/superpowers-brainstorming/scripts/frame-template.html diff --git a/superpowers-brainstorming/scripts/helper.js b/skills/superpowers-brainstorming/scripts/helper.js similarity index 100% rename from superpowers-brainstorming/scripts/helper.js rename to skills/superpowers-brainstorming/scripts/helper.js diff --git a/superpowers-brainstorming/scripts/server.cjs b/skills/superpowers-brainstorming/scripts/server.cjs similarity index 100% rename from superpowers-brainstorming/scripts/server.cjs rename to skills/superpowers-brainstorming/scripts/server.cjs diff --git a/superpowers-brainstorming/scripts/start-server.sh b/skills/superpowers-brainstorming/scripts/start-server.sh similarity index 100% rename from superpowers-brainstorming/scripts/start-server.sh rename to skills/superpowers-brainstorming/scripts/start-server.sh diff --git a/superpowers-brainstorming/scripts/stop-server.sh b/skills/superpowers-brainstorming/scripts/stop-server.sh similarity index 100% rename from superpowers-brainstorming/scripts/stop-server.sh rename to skills/superpowers-brainstorming/scripts/stop-server.sh diff --git a/superpowers-brainstorming/spec-document-reviewer-prompt.md b/skills/superpowers-brainstorming/spec-document-reviewer-prompt.md similarity index 100% rename from superpowers-brainstorming/spec-document-reviewer-prompt.md rename to skills/superpowers-brainstorming/spec-document-reviewer-prompt.md diff --git a/superpowers-brainstorming/visual-companion.md b/skills/superpowers-brainstorming/visual-companion.md similarity index 100% rename from superpowers-brainstorming/visual-companion.md rename to skills/superpowers-brainstorming/visual-companion.md diff --git a/superpowers-dispatching-parallel-agents/SKILL.md b/skills/superpowers-dispatching-parallel-agents/SKILL.md similarity index 100% rename from superpowers-dispatching-parallel-agents/SKILL.md rename to skills/superpowers-dispatching-parallel-agents/SKILL.md diff --git a/superpowers-executing-plans/SKILL.md b/skills/superpowers-executing-plans/SKILL.md similarity index 100% rename from superpowers-executing-plans/SKILL.md rename to skills/superpowers-executing-plans/SKILL.md diff --git a/superpowers-finishing-a-development-branch/SKILL.md b/skills/superpowers-finishing-a-development-branch/SKILL.md similarity index 100% rename from superpowers-finishing-a-development-branch/SKILL.md rename to skills/superpowers-finishing-a-development-branch/SKILL.md diff --git a/superpowers-receiving-code-review/SKILL.md b/skills/superpowers-receiving-code-review/SKILL.md similarity index 100% rename from superpowers-receiving-code-review/SKILL.md rename to skills/superpowers-receiving-code-review/SKILL.md diff --git a/superpowers-requesting-code-review/SKILL.md b/skills/superpowers-requesting-code-review/SKILL.md similarity index 100% rename from superpowers-requesting-code-review/SKILL.md rename to skills/superpowers-requesting-code-review/SKILL.md diff --git a/superpowers-requesting-code-review/code-reviewer.md b/skills/superpowers-requesting-code-review/code-reviewer.md similarity index 100% rename from superpowers-requesting-code-review/code-reviewer.md rename to skills/superpowers-requesting-code-review/code-reviewer.md diff --git a/superpowers-subagent-driven-development/SKILL.md b/skills/superpowers-subagent-driven-development/SKILL.md similarity index 100% rename from superpowers-subagent-driven-development/SKILL.md rename to skills/superpowers-subagent-driven-development/SKILL.md diff --git a/superpowers-subagent-driven-development/code-quality-reviewer-prompt.md b/skills/superpowers-subagent-driven-development/code-quality-reviewer-prompt.md similarity index 100% rename from superpowers-subagent-driven-development/code-quality-reviewer-prompt.md rename to skills/superpowers-subagent-driven-development/code-quality-reviewer-prompt.md diff --git a/superpowers-subagent-driven-development/implementer-prompt.md b/skills/superpowers-subagent-driven-development/implementer-prompt.md similarity index 100% rename from superpowers-subagent-driven-development/implementer-prompt.md rename to skills/superpowers-subagent-driven-development/implementer-prompt.md diff --git a/superpowers-subagent-driven-development/spec-reviewer-prompt.md b/skills/superpowers-subagent-driven-development/spec-reviewer-prompt.md similarity index 100% rename from superpowers-subagent-driven-development/spec-reviewer-prompt.md rename to skills/superpowers-subagent-driven-development/spec-reviewer-prompt.md diff --git a/superpowers-systematic-debugging/CREATION-LOG.md b/skills/superpowers-systematic-debugging/CREATION-LOG.md similarity index 100% rename from superpowers-systematic-debugging/CREATION-LOG.md rename to skills/superpowers-systematic-debugging/CREATION-LOG.md diff --git a/superpowers-systematic-debugging/SKILL.md b/skills/superpowers-systematic-debugging/SKILL.md similarity index 100% rename from superpowers-systematic-debugging/SKILL.md rename to skills/superpowers-systematic-debugging/SKILL.md diff --git a/superpowers-systematic-debugging/condition-based-waiting-example.ts b/skills/superpowers-systematic-debugging/condition-based-waiting-example.ts similarity index 100% rename from superpowers-systematic-debugging/condition-based-waiting-example.ts rename to skills/superpowers-systematic-debugging/condition-based-waiting-example.ts diff --git a/superpowers-systematic-debugging/condition-based-waiting.md b/skills/superpowers-systematic-debugging/condition-based-waiting.md similarity index 100% rename from superpowers-systematic-debugging/condition-based-waiting.md rename to skills/superpowers-systematic-debugging/condition-based-waiting.md diff --git a/superpowers-systematic-debugging/defense-in-depth.md b/skills/superpowers-systematic-debugging/defense-in-depth.md similarity index 100% rename from superpowers-systematic-debugging/defense-in-depth.md rename to skills/superpowers-systematic-debugging/defense-in-depth.md diff --git a/superpowers-systematic-debugging/find-polluter.sh b/skills/superpowers-systematic-debugging/find-polluter.sh similarity index 100% rename from superpowers-systematic-debugging/find-polluter.sh rename to skills/superpowers-systematic-debugging/find-polluter.sh diff --git a/superpowers-systematic-debugging/root-cause-tracing.md b/skills/superpowers-systematic-debugging/root-cause-tracing.md similarity index 100% rename from superpowers-systematic-debugging/root-cause-tracing.md rename to skills/superpowers-systematic-debugging/root-cause-tracing.md diff --git a/superpowers-systematic-debugging/test-academic.md b/skills/superpowers-systematic-debugging/test-academic.md similarity index 100% rename from superpowers-systematic-debugging/test-academic.md rename to skills/superpowers-systematic-debugging/test-academic.md diff --git a/superpowers-systematic-debugging/test-pressure-1.md b/skills/superpowers-systematic-debugging/test-pressure-1.md similarity index 100% rename from superpowers-systematic-debugging/test-pressure-1.md rename to skills/superpowers-systematic-debugging/test-pressure-1.md diff --git a/superpowers-systematic-debugging/test-pressure-2.md b/skills/superpowers-systematic-debugging/test-pressure-2.md similarity index 100% rename from superpowers-systematic-debugging/test-pressure-2.md rename to skills/superpowers-systematic-debugging/test-pressure-2.md diff --git a/superpowers-systematic-debugging/test-pressure-3.md b/skills/superpowers-systematic-debugging/test-pressure-3.md similarity index 100% rename from superpowers-systematic-debugging/test-pressure-3.md rename to skills/superpowers-systematic-debugging/test-pressure-3.md diff --git a/superpowers-test-driven-development/SKILL.md b/skills/superpowers-test-driven-development/SKILL.md similarity index 100% rename from superpowers-test-driven-development/SKILL.md rename to skills/superpowers-test-driven-development/SKILL.md diff --git a/superpowers-test-driven-development/testing-anti-patterns.md b/skills/superpowers-test-driven-development/testing-anti-patterns.md similarity index 100% rename from superpowers-test-driven-development/testing-anti-patterns.md rename to skills/superpowers-test-driven-development/testing-anti-patterns.md diff --git a/superpowers-using-git-worktrees/SKILL.md b/skills/superpowers-using-git-worktrees/SKILL.md similarity index 100% rename from superpowers-using-git-worktrees/SKILL.md rename to skills/superpowers-using-git-worktrees/SKILL.md diff --git a/superpowers-using-superpowers/SKILL.md b/skills/superpowers-using-superpowers/SKILL.md similarity index 100% rename from superpowers-using-superpowers/SKILL.md rename to skills/superpowers-using-superpowers/SKILL.md diff --git a/superpowers-using-superpowers/references/codex-tools.md b/skills/superpowers-using-superpowers/references/codex-tools.md similarity index 100% rename from superpowers-using-superpowers/references/codex-tools.md rename to skills/superpowers-using-superpowers/references/codex-tools.md diff --git a/superpowers-using-superpowers/references/copilot-tools.md b/skills/superpowers-using-superpowers/references/copilot-tools.md similarity index 100% rename from superpowers-using-superpowers/references/copilot-tools.md rename to skills/superpowers-using-superpowers/references/copilot-tools.md diff --git a/superpowers-using-superpowers/references/gemini-tools.md b/skills/superpowers-using-superpowers/references/gemini-tools.md similarity index 100% rename from superpowers-using-superpowers/references/gemini-tools.md rename to skills/superpowers-using-superpowers/references/gemini-tools.md diff --git a/superpowers-verification-before-completion/SKILL.md b/skills/superpowers-verification-before-completion/SKILL.md similarity index 100% rename from superpowers-verification-before-completion/SKILL.md rename to skills/superpowers-verification-before-completion/SKILL.md diff --git a/superpowers-writing-plans/SKILL.md b/skills/superpowers-writing-plans/SKILL.md similarity index 100% rename from superpowers-writing-plans/SKILL.md rename to skills/superpowers-writing-plans/SKILL.md diff --git a/superpowers-writing-plans/plan-document-reviewer-prompt.md b/skills/superpowers-writing-plans/plan-document-reviewer-prompt.md similarity index 100% rename from superpowers-writing-plans/plan-document-reviewer-prompt.md rename to skills/superpowers-writing-plans/plan-document-reviewer-prompt.md diff --git a/superpowers-writing-skills/SKILL.md b/skills/superpowers-writing-skills/SKILL.md similarity index 100% rename from superpowers-writing-skills/SKILL.md rename to skills/superpowers-writing-skills/SKILL.md diff --git a/superpowers-writing-skills/anthropic-best-practices.md b/skills/superpowers-writing-skills/anthropic-best-practices.md similarity index 100% rename from superpowers-writing-skills/anthropic-best-practices.md rename to skills/superpowers-writing-skills/anthropic-best-practices.md diff --git a/superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md b/skills/superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md similarity index 100% rename from superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md rename to skills/superpowers-writing-skills/examples/CLAUDE_MD_TESTING.md diff --git a/superpowers-writing-skills/graphviz-conventions.dot b/skills/superpowers-writing-skills/graphviz-conventions.dot similarity index 100% rename from superpowers-writing-skills/graphviz-conventions.dot rename to skills/superpowers-writing-skills/graphviz-conventions.dot diff --git a/superpowers-writing-skills/persuasion-principles.md b/skills/superpowers-writing-skills/persuasion-principles.md similarity index 100% rename from superpowers-writing-skills/persuasion-principles.md rename to skills/superpowers-writing-skills/persuasion-principles.md diff --git a/superpowers-writing-skills/render-graphs.js b/skills/superpowers-writing-skills/render-graphs.js similarity index 100% rename from superpowers-writing-skills/render-graphs.js rename to skills/superpowers-writing-skills/render-graphs.js diff --git a/superpowers-writing-skills/testing-skills-with-subagents.md b/skills/superpowers-writing-skills/testing-skills-with-subagents.md similarity index 100% rename from superpowers-writing-skills/testing-skills-with-subagents.md rename to skills/superpowers-writing-skills/testing-skills-with-subagents.md diff --git a/tdd/SKILL.md b/skills/tdd/SKILL.md similarity index 100% rename from tdd/SKILL.md rename to skills/tdd/SKILL.md diff --git a/tdd/references/testing-anti-patterns.md b/skills/tdd/references/testing-anti-patterns.md similarity index 100% rename from tdd/references/testing-anti-patterns.md rename to skills/tdd/references/testing-anti-patterns.md diff --git a/telos-load/SKILL.md b/skills/telos-load/SKILL.md similarity index 100% rename from telos-load/SKILL.md rename to skills/telos-load/SKILL.md diff --git a/test-design/SKILL.md b/skills/test-design/SKILL.md similarity index 100% rename from test-design/SKILL.md rename to skills/test-design/SKILL.md diff --git a/trainer/SKILL.md b/skills/trainer/SKILL.md similarity index 100% rename from trainer/SKILL.md rename to skills/trainer/SKILL.md diff --git a/user-stories/SKILL.md b/skills/user-stories/SKILL.md similarity index 100% rename from user-stories/SKILL.md rename to skills/user-stories/SKILL.md diff --git a/web-shot/SKILL.md b/skills/web-shot/SKILL.md similarity index 100% rename from web-shot/SKILL.md rename to skills/web-shot/SKILL.md diff --git a/web-shot/shot.sh b/skills/web-shot/shot.sh similarity index 100% rename from web-shot/shot.sh rename to skills/web-shot/shot.sh