The model: skills live at the user level(installed once, shared across every project); the only thing each repo carries is one config file. That's what all the generalization work bought — skills with no hardcoded repo details can live anywhere and adapt at runtime.
All seven skills, installed once in your global skills dir. Same folder for every project. Update in one place.
Each repo carries only docs/project-tracking/GITHUB-PROJECTS.md — owner, project #, ids, stack, labels, test command, crucible variant. The single seam.
Run the sync script from the repo root — it installs every skill to your user-level directory:
pwsh scripts/install-skills.ps1 # Windows (or plain PowerShell) bash scripts/install-skills.sh # macOS / Linux / Git Bash
Skills land in ~/.claude/skills/<skill-name>/SKILL.md (user level, all projects). A repo that needs its own variant can override at .claude/skills/ — project-level skills win over user-level ones by name. Claude Code reads the shared frontmatter plus its extensions (allowed-tools, context: fork, ${CLAUDE_SKILL_DIR}, …).
~/.claude/skills itself — so scripts/install-skills.(sh|ps1) syncs skills/ (the source of truth) to that single directory and both tools pick it up. Installing to ~/.cursor/skillsas well would double-list every skill in Cursor's slash menu.docs/project-tracking/GITHUB-PROJECTS.md to the repo and fill the Repo config block.owner · repo · project # · project id · status field + option ids · stack · crucible variant · test command · default branch · your area:* labelsgh project field-list <n> --owner <owner> --format json \
--jq '.fields[] | select(.name=="Status") | {id, options: [.options[] | {name, id}]}'area:* slice labels.auto:ready (safe for night-shift) and needs:decision (the loop sets this at a fork).Every skill's canonical SKILL.md is served raw at /skills/<name>/SKILL.md— each skill's page has the download link and a ready-made one-liner. To pull one skill without cloning the repo:
curl -fLo ~/.claude/skills/<name>/SKILL.md --create-dirs https://vilya.jerrodtuck.com/skills/<name>/SKILL.md
One destination is enough — Cursor scans ~/.claude/skills as a compatibility root, so both tools see it.
Because skills are global, they don't use a relative path — they resolve the repo root, then read the config:
root=$(git rev-parse --show-toplevel) cat "$root/docs/project-tracking/GITHUB-PROJECTS.md"
crucible-blazor, test command dotnet test. Next.js repo → crucible-nextjs, test command npm test && npm run build. Both go in the repo's config block.