From 74f0450b9cbfc562a9d0f16f73f23745931f048d Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Wed, 24 Jun 2026 11:27:21 +0100 Subject: [PATCH] Link skills into ~/.agents/skills as well as ~/.claude/skills Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/link-skills.sh | 66 +++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/scripts/link-skills.sh b/scripts/link-skills.sh index 9f99b41..aba2bb6 100755 --- a/scripts/link-skills.sh +++ b/scripts/link-skills.sh @@ -1,38 +1,52 @@ #!/usr/bin/env bash set -euo pipefail -# Links all skills in the repository to ~/.claude/skills, so that -# they can be used by the local Claude CLI. +# Links all skills in the repository into the local skill directories used by +# each agent harness: +# - ~/.claude/skills — Claude Code +# - ~/.agents/skills — pi and other Agent-Skills-standard harnesses +# Each entry is a symlink into this repo, so a `git pull` is all that's needed +# to keep installed skills up to date. REPO="$(cd "$(dirname "$0")/.." && pwd)" -DEST="$HOME/.claude/skills" +DESTS=("$HOME/.claude/skills" "$HOME/.agents/skills") -# If ~/.claude/skills is a symlink that resolves into this repo, we'd end up -# writing the per-skill symlinks back into the repo's own skills/ tree. Detect -# and bail out instead of polluting the working copy. -if [ -L "$DEST" ]; then - resolved="$(readlink -f "$DEST")" - case "$resolved" in - "$REPO"|"$REPO"/*) - echo "error: $DEST is a symlink into this repo ($resolved)." >&2 - echo "Remove it (rm \"$DEST\") and re-run; the script will recreate it as a real dir." >&2 - exit 1 - ;; - esac -fi - -mkdir -p "$DEST" - -find "$REPO/skills" -name SKILL.md -not -path '*/node_modules/*' -not -path '*/deprecated/*' -print0 | +# Collect the repo's skills once, link into every destination. +names=() +srcs=() while IFS= read -r -d '' skill_md; do src="$(dirname "$skill_md")" - name="$(basename "$src")" - target="$DEST/$name" + names+=("$(basename "$src")") + srcs+=("$src") +done < <(find "$REPO/skills" -name SKILL.md -not -path '*/node_modules/*' -not -path '*/deprecated/*' -print0) - if [ -e "$target" ] && [ ! -L "$target" ]; then - rm -rf "$target" +for DEST in "${DESTS[@]}"; do + # If $DEST is a symlink that resolves into this repo, we'd end up writing the + # per-skill symlinks back into the repo's own skills/ tree. Detect and bail + # out instead of polluting the working copy. + if [ -L "$DEST" ]; then + resolved="$(readlink -f "$DEST")" + case "$resolved" in + "$REPO"|"$REPO"/*) + echo "error: $DEST is a symlink into this repo ($resolved)." >&2 + echo "Remove it (rm \"$DEST\") and re-run; the script will recreate it as a real dir." >&2 + exit 1 + ;; + esac fi - ln -sfn "$src" "$target" - echo "linked $name -> $src" + mkdir -p "$DEST" + + for i in "${!names[@]}"; do + name="${names[$i]}" + src="${srcs[$i]}" + target="$DEST/$name" + + if [ -e "$target" ] && [ ! -L "$target" ]; then + rm -rf "$target" + fi + + ln -sfn "$src" "$target" + echo "linked $name -> $src ($DEST)" + done done