|
| 1 | +--- |
| 2 | +name: setup-ic-skills |
| 3 | +description: One-time installer that makes a Claude Code project keep its Internet Computer skills up to date automatically. Sets up a SessionStart hook plus a sync script so .claude/skills/ always mirrors the latest skills published at skills.internetcomputer.org. Use when a user wants to install, bootstrap, or enable "always-latest" Internet Computer / IC / ICP / Motoko skills in a project, or pastes the link to this skill. This is a one-time setup action, not ongoing IC knowledge — after it runs, the installed hook keeps skills current on every session. Do NOT use for IC coding questions themselves — this only configures auto-updating skills. |
| 4 | +license: Apache-2.0 |
| 5 | +metadata: |
| 6 | + title: Setup IC Skills |
| 7 | + category: Infrastructure |
| 8 | +--- |
| 9 | + |
| 10 | +# Set up self-updating Internet Computer skills |
| 11 | + |
| 12 | +This skill installs a small amount of project configuration so that **every new |
| 13 | +Claude Code session automatically downloads the latest Internet Computer skills** |
| 14 | +into `.claude/skills/`, where Claude discovers and triggers them natively. |
| 15 | + |
| 16 | +It is a **one-time installer**. After you complete the steps below, the user never |
| 17 | +needs this link again — the installed `SessionStart` hook does the work from then on. |
| 18 | + |
| 19 | +## What you will create |
| 20 | + |
| 21 | +1. `.claude/sync-ic-skills.sh` — mirrors the live skill index into `.claude/skills/`. |
| 22 | +2. A `SessionStart` hook in `.claude/settings.json` that runs that script. |
| 23 | +3. An immediate first run, so skills are present right away. |
| 24 | + |
| 25 | +The sync is a **mirror**: it always re-downloads the current skills, so it picks up |
| 26 | +new skills, updated versions of existing skills, and removals — with no version |
| 27 | +metadata required on the server side. |
| 28 | + |
| 29 | +## Important: tell the user what to expect |
| 30 | + |
| 31 | +Adding a hook means a shell script will run automatically at the start of future |
| 32 | +sessions. Claude Code will ask the user to **review and trust** the new hook before |
| 33 | +it activates — this is expected and correct. Let the user know: |
| 34 | + |
| 35 | +> "I'm adding a `SessionStart` hook that runs `.claude/sync-ic-skills.sh`. Claude Code |
| 36 | +> will ask you to approve/trust it before it runs automatically. After that, your IC |
| 37 | +> skills stay current on every session." |
| 38 | +
|
| 39 | +Do **not** attempt to bypass that approval. |
| 40 | + |
| 41 | +## Step 0 — Check prerequisites (`curl`, `jq`) |
| 42 | + |
| 43 | +The sync script needs `curl` (virtually always present) and `jq` (often not). |
| 44 | +Before writing anything, check for them: |
| 45 | + |
| 46 | +```bash |
| 47 | +command -v curl >/dev/null 2>&1 && echo "curl: ok" || echo "curl: MISSING" |
| 48 | +command -v jq >/dev/null 2>&1 && echo "jq: ok" || echo "jq: MISSING" |
| 49 | +``` |
| 50 | + |
| 51 | +- If `jq` is **missing**, offer to install it (ask the user before running an install |
| 52 | + command). Pick the right one for their platform: |
| 53 | + - macOS (Homebrew): `brew install jq` |
| 54 | + - Debian/Ubuntu: `sudo apt-get update && sudo apt-get install -y jq` |
| 55 | + - Fedora/RHEL: `sudo dnf install -y jq` |
| 56 | + - Alpine: `apk add jq` |
| 57 | + - Arch: `sudo pacman -S --noconfirm jq` |
| 58 | + - Windows (winget): `winget install jqlang.jq` |
| 59 | +- If the user declines, still proceed — the script is written to degrade gracefully |
| 60 | + (it exits cleanly with a warning when `jq` is absent), and they can install `jq` |
| 61 | + later and the next session will sync. |
| 62 | + |
| 63 | +## Step 1 — Write the sync script |
| 64 | + |
| 65 | +Create `.claude/sync-ic-skills.sh` with **exactly** this content: |
| 66 | + |
| 67 | +```bash |
| 68 | +#!/usr/bin/env bash |
| 69 | +# sync-ic-skills.sh — mirror the latest Internet Computer skills into .claude/skills/ |
| 70 | +# Idempotent and offline-safe. Only skills this script installed are ever pruned, |
| 71 | +# so your own local skills are never touched. |
| 72 | +set -euo pipefail |
| 73 | + |
| 74 | +BASE="https://skills.internetcomputer.org/.well-known/skills" |
| 75 | +INDEX_URL="$BASE/index.json" |
| 76 | +DEST=".claude/skills" |
| 77 | +MANIFEST="$DEST/.ic-managed.json" # tracks which skills this script manages |
| 78 | + |
| 79 | +mkdir -p "$DEST" |
| 80 | + |
| 81 | +# --- Fetch the index. On any network failure, keep cached skills and exit cleanly. --- |
| 82 | +TMP_INDEX="$(mktemp)" |
| 83 | +trap 'rm -f "$TMP_INDEX"' EXIT |
| 84 | +if ! curl -fsSL --max-time 20 "$INDEX_URL" -o "$TMP_INDEX"; then |
| 85 | + echo "[ic-skills] could not reach $INDEX_URL — keeping cached skills" >&2 |
| 86 | + exit 0 |
| 87 | +fi |
| 88 | + |
| 89 | +# --- jq is required to parse the index. If absent, warn and exit without failing. --- |
| 90 | +if ! command -v jq >/dev/null 2>&1; then |
| 91 | + echo "[ic-skills] 'jq' not found — install jq to enable IC skill sync" >&2 |
| 92 | + exit 0 |
| 93 | +fi |
| 94 | + |
| 95 | +NEW_NAMES="$(jq -r '.[].name' "$TMP_INDEX")" |
| 96 | + |
| 97 | +# --- Prune: drop previously-managed skills that are no longer in the index. --- |
| 98 | +if [ -f "$MANIFEST" ]; then |
| 99 | + while IFS= read -r old; do |
| 100 | + [ -n "$old" ] || continue |
| 101 | + if ! grep -qxF "$old" <<<"$NEW_NAMES"; then |
| 102 | + rm -rf "${DEST:?}/$old" |
| 103 | + echo "[ic-skills] pruned removed skill: $old" >&2 |
| 104 | + fi |
| 105 | + done < <(jq -r '.[]?' "$MANIFEST" 2>/dev/null || true) |
| 106 | +fi |
| 107 | + |
| 108 | +# --- Download every skill's files (overwrite == always latest). --- |
| 109 | +jq -c '.[]' "$TMP_INDEX" | while IFS= read -r entry; do |
| 110 | + name="$(jq -r '.name' <<<"$entry")" |
| 111 | + [ -n "$name" ] && [ "$name" != "null" ] || continue |
| 112 | + mkdir -p "$DEST/$name" |
| 113 | + while IFS= read -r f; do |
| 114 | + [ -n "$f" ] || continue |
| 115 | + if ! curl -fsSL --max-time 20 "$BASE/$name/$f" -o "$DEST/$name/$f"; then |
| 116 | + echo "[ic-skills] warning: failed to fetch $name/$f" >&2 |
| 117 | + fi |
| 118 | + done < <(jq -r '.files[]?' <<<"$entry") |
| 119 | +done |
| 120 | + |
| 121 | +# --- Record managed skill names for the next prune pass. --- |
| 122 | +jq '[.[].name]' "$TMP_INDEX" > "$MANIFEST" |
| 123 | +echo "[ic-skills] synced $(jq 'length' "$TMP_INDEX") Internet Computer skills into $DEST" >&2 |
| 124 | +``` |
| 125 | + |
| 126 | +## Step 2 — Register the SessionStart hook (idempotently) |
| 127 | + |
| 128 | +Add a `SessionStart` hook to `.claude/settings.json` that runs the script. |
| 129 | + |
| 130 | +- If `.claude/settings.json` does **not** exist, create it with the content below. |
| 131 | +- If it **does** exist, **merge** — preserve all existing keys, hooks, and |
| 132 | + permissions. Only add the `SessionStart` entry, and **only if an equivalent |
| 133 | + `bash .claude/sync-ic-skills.sh` command is not already present** (do not create a |
| 134 | + duplicate). Parse the existing JSON, insert into the `hooks.SessionStart` array, |
| 135 | + and write it back; never blindly overwrite the file. |
| 136 | + |
| 137 | +The entry to ensure is present: |
| 138 | + |
| 139 | +```json |
| 140 | +{ |
| 141 | + "hooks": { |
| 142 | + "SessionStart": [ |
| 143 | + { |
| 144 | + "hooks": [ |
| 145 | + { "type": "command", "command": "bash .claude/sync-ic-skills.sh" } |
| 146 | + ] |
| 147 | + } |
| 148 | + ] |
| 149 | + } |
| 150 | +} |
| 151 | +``` |
| 152 | + |
| 153 | +## Step 3 — Run it once now |
| 154 | + |
| 155 | +Run the script immediately so the skills are available in this session without |
| 156 | +waiting for the next session start: |
| 157 | + |
| 158 | +```bash |
| 159 | +bash .claude/sync-ic-skills.sh |
| 160 | +``` |
| 161 | + |
| 162 | +## Step 4 — Verify and report |
| 163 | + |
| 164 | +- Confirm `.claude/skills/` now contains skill directories (e.g. `motoko`, |
| 165 | + `asset-canister`, `internet-identity`, …) each with a `SKILL.md`. |
| 166 | +- Confirm `.claude/skills/.ic-managed.json` lists the synced skill names. |
| 167 | +- Tell the user: how many skills were installed, that the `SessionStart` hook is in |
| 168 | + place, and that they'll be prompted to trust the hook before it auto-runs next |
| 169 | + session. From then on, their IC skills refresh automatically every session. |
| 170 | + |
| 171 | +## Notes |
| 172 | + |
| 173 | +- **Safe to re-run.** Re-invoking this skill or the script is idempotent: the hook is |
| 174 | + not duplicated, and only skills tracked in `.ic-managed.json` are ever pruned. |
| 175 | +- **No server-side versioning needed.** Because the script re-mirrors current content, |
| 176 | + it captures new skills, new versions, and removals automatically. If the index later |
| 177 | + adds `sha256`/`version` fields, the script can be upgraded to a differential sync, |
| 178 | + but that is not required for correctness. |
| 179 | +- **Optional mid-session refresh.** For very long-running sessions, the user can also |
| 180 | + run `bash .claude/sync-ic-skills.sh` manually, or schedule it (e.g. via `/loop` or a |
| 181 | + cron routine) — but the SessionStart hook covers the normal case. |
0 commit comments