Symlink Skills
Symlinks every directory under <repo>/skills/ into each configured target,
making each skill in the registry globally discoverable. Edits in the repo are
picked up live because the symlinks point at the real files.
Default targets:
~/.claude/skills/(Claude Code's standard skill directory)~/.agents/skills/(other agents that follow the same convention)~/.cursor/skills/~/.config/opencode/skills/on macOS,~/.opencode/skills/elsewhere (auto-detected via$OSTYPE; override withOPENCODE_SKILLS_DIR)
Run
From the repo root:
./skills/symlink-skills/link.sh # link all skills into all default targets
./skills/symlink-skills/link.sh --interactive # fzf checklist per target (pick which skills)
./skills/symlink-skills/link.sh --only gcm,depcheck # link only named skills (comma-separated)
./skills/symlink-skills/link.sh --skip web-perf,changelog # link all except named skills
./skills/symlink-skills/link.sh --dry-run # preview without changes
./skills/symlink-skills/link.sh --force # replace existing files / mis-pointed symlinks
./skills/symlink-skills/link.sh --unlink # remove only symlinks created by this skill
Pick targets explicitly (skips the defaults entirely once --target is set):
# Just Claude Code:
./skills/symlink-skills/link.sh --target ~/.claude/skills
# Multiple custom targets:
./skills/symlink-skills/link.sh --target ~/.claude/skills --target /work/.agents/skills
# Interactive per-target selection:
./skills/symlink-skills/link.sh --interactive --target ~/.claude/skills
--interactive (-i) shows an fzf multi-select checklist for each target — Tab/Space to toggle skills, Enter to confirm, Esc to skip that target. Falls back to all skills if fzf isn't installed. --only and --skip bypass the checklist.
Or override any default via env var:
CLAUDE_SKILLS_DIR=/tmp/fake-claude/skills \
AGENTS_SKILLS_DIR=/tmp/fake-agents/skills \
CURSOR_SKILLS_DIR=/tmp/fake-cursor/skills \
OPENCODE_SKILLS_DIR=/tmp/fake-opencode/skills \
./skills/symlink-skills/link.sh
Behaviour
- Idempotent. Re-running is safe; correct symlinks are left alone.
- Safe by default. If
<target>/<name>exists as a real directory (or as a symlink to a different target), the script refuses to overwrite it and exits non-zero. Pass--forceto replace. - Per-target reporting. Each target is processed in turn with its own pass/fail summary.
- Scoped unlink.
--unlinkremoves only symlinks under each target whose target resolves back into this repo. Other files and symlinks are untouched. - Returns non-zero if any skill could not be linked in any target.
Why
Editing skills in one place (this repo) and having them auto-available in
every agent that reads from ~/.claude/skills/ or ~/.agents/skills/ beats
maintaining multiple copies.