
Autosync Ic Skills
- 47 installs
- 28 repo stars
- Updated August 4, 2026
- dfinity/icskills
Install a SessionStart hook and sync script so a Claude Code project auto-updates its Internet Computer skills every session.
About
A one-time installer that adds a SessionStart hook and sync script so a Claude Code project keeps its Internet Computer skills current automatically. A developer uses it to bootstrap always-latest IC/Motoko skills into a project.
- Installs a SessionStart hook plus a differential sync script
- Mirrors the latest Internet Computer skills into .claude/skills each session
Autosync Ic Skills by the numbers
- 47 all-time installs (skills.sh)
- Ranked #335 of 782 Skill Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dfinity/icskills --skill autosync-ic-skillsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 47 |
|---|---|
| repo stars | ★ 28 |
| Last updated | August 4, 2026 |
| Repository | dfinity/icskills ↗ |
What it does
Install a SessionStart hook and sync script so a Claude Code project auto-updates its Internet Computer skills every session.
Files
Set up self-updating Internet Computer skills
This skill installs a small amount of project configuration so that every new Claude Code session automatically downloads the latest Internet Computer skills into .claude/skills/, where Claude discovers and triggers them natively.
It is a one-time installer. After you complete the steps below, the user never needs this link again — the installed SessionStart hook does the work from then on.
What you will create
1. .claude/sync-ic-skills.sh — a differential sync script that mirrors the live skill index into .claude/skills/. 2. A SessionStart hook in .claude/settings.json that runs that script. 3. An immediate first run, so skills are present right away.
The script is a differential mirror. It fetches the discovery index once and compares each skill's published hash against a stored manifest, re-downloading only the skills that actually changed (and pruning ones removed upstream). Unchanged skills are skipped with no per-file downloads, and the script stays silent unless something changed. If the server does not publish a hash for a skill, the script falls back to re-downloading it every run, so it remains correct either way.
Important: tell the user what to expect
Adding a hook means a shell script will run automatically at the start of future sessions. Claude Code will ask the user to review and trust the new hook before it activates — this is expected and correct. Let the user know:
"I'm adding aSessionStarthook that runs.claude/sync-ic-skills.sh. Claude Code
will ask you to approve/trust it before it runs automatically. After that, your IC
skills stay current on every session."
Do not attempt to bypass that approval.
Step 0 — Check prerequisites (curl, jq)
The sync script needs curl (virtually always present) and jq (often not). Before writing anything, check for them:
command -v curl >/dev/null 2>&1 && echo "curl: ok" || echo "curl: MISSING"
command -v jq >/dev/null 2>&1 && echo "jq: ok" || echo "jq: MISSING"- If
jqis missing, offer to install it (ask the user before running an install
command). Pick the right one for their platform:
- macOS (Homebrew):
brew install jq - Debian/Ubuntu:
sudo apt-get update && sudo apt-get install -y jq - Fedora/RHEL:
sudo dnf install -y jq - Alpine:
apk add jq - Arch:
sudo pacman -S --noconfirm jq - Windows (winget):
winget install jqlang.jq - If the user declines, still proceed — the script is written to degrade gracefully
(it exits cleanly with a warning when jq is absent), and they can install jq later and the next session will sync.
Step 1 — Download the sync script
The script is published as a file alongside this skill, so you fetch it verbatim rather than transcribing it (this guarantees byte-exact content). Create the .claude directory and download it:
mkdir -p .claude
curl -fsSL https://skills.internetcomputer.org/.well-known/skills/autosync-ic-skills/scripts/sync-ic-skills.sh \
-o .claude/sync-ic-skills.shDo not hand-write or paraphrase the script — always fetch the published copy so the sync logic stays correct as it is updated upstream.
What the script does (for the user's awareness):
- Fetches
https://skills.internetcomputer.org/.well-known/skills/index.jsononce. - For each skill, compares the published
hashagainst.claude/skills/.ic-managed.json
(a { "<skill>": "<hash>" } manifest of skills it manages) and re-downloads only the skills whose hash changed or are new.
- Prunes skills it previously installed that are no longer in the index.
- Prints a one-line
added / updated / removedsummary only when something changed;
otherwise it is silent.
- Degrades gracefully: exits cleanly (keeping cached skills) if the network is down or
jq is missing, and falls back to re-downloading skills the server publishes no hash for.
Step 2 — Register the SessionStart hook (idempotently)
Add a SessionStart hook to .claude/settings.json that runs the script.
- If
.claude/settings.jsondoes not exist, create it with the content below. - If it does exist, merge — preserve all existing keys, hooks, and
permissions. Only add the SessionStart entry, and only if an equivalent `bash .claude/sync-ic-skills.sh` command is not already present (do not create a duplicate). Parse the existing JSON, insert into the hooks.SessionStart array, and write it back; never blindly overwrite the file.
The entry to ensure is present:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{ "type": "command", "command": "bash .claude/sync-ic-skills.sh" }
]
}
]
}
}Step 3 — Run it once now
Run the script immediately so the skills are available in this session without waiting for the next session start:
bash .claude/sync-ic-skills.shStep 4 — Verify and report
- Confirm
.claude/skills/now contains skill directories (e.g.motoko,
asset-canister, internet-identity, …) each with a SKILL.md.
- Confirm
.claude/skills/.ic-managed.jsonmaps each synced skill name to its hash. - Tell the user: how many skills were installed, that the
SessionStarthook is in
place, and that they'll be prompted to trust the hook before it auto-runs next session. From then on, their IC skills refresh automatically every session.
Notes
- Safe to re-run. Re-invoking this skill or the script is idempotent: the hook is
not duplicated, and only skills tracked in .ic-managed.json are ever pruned.
- Differential by hash. The script keys off the per-skill
hashfield in the
discovery index, so a normal session that touches nothing downloads only index.json and exits silently. Skills are re-downloaded only when their hash changes. Migrating from an older version of this script (whose manifest was a bare name array) is handled automatically on the next run.
- Optional mid-session refresh. For very long-running sessions, the user can also
run bash .claude/sync-ic-skills.sh manually, or schedule it (e.g. via /loop or a cron routine) — but the SessionStart hook covers the normal case.
#!/usr/bin/env bash
# sync-ic-skills.sh — mirror the latest Internet Computer skills into .claude/skills/
#
# Differential sync: fetches the discovery index once and re-downloads only the
# skills whose published `hash` changed (or are new). Skills already at the current
# hash are skipped entirely — no per-file downloads. Prints a one-line summary only
# when something actually changed.
#
# Idempotent and offline-safe. Only skills this script installed are ever pruned,
# so your own local skills are never touched.
set -euo pipefail
BASE="https://skills.internetcomputer.org/.well-known/skills"
INDEX_URL="$BASE/index.json"
DEST=".claude/skills"
MANIFEST="$DEST/.ic-managed.json" # { "<skill>": "<hash>" } of skills this script manages
mkdir -p "$DEST"
# --- Temp files. NEW_MANIFEST is built up as we go, then swapped in atomically. ---
TMP_INDEX="$(mktemp)"
NEW_MANIFEST="$(mktemp)"
trap 'rm -f "$TMP_INDEX" "$NEW_MANIFEST"' EXIT
# --- Fetch the index. On any network failure, keep cached skills and exit cleanly. ---
if ! curl -fsSL --max-time 20 "$INDEX_URL" -o "$TMP_INDEX"; then
echo "[autosync-ic-skills] could not reach $INDEX_URL — keeping cached skills" >&2
exit 0
fi
# --- jq is required to parse the index. If absent, warn and exit without failing. ---
if ! command -v jq >/dev/null 2>&1; then
echo "[autosync-ic-skills] 'jq' not found — install jq to enable IC skill sync" >&2
exit 0
fi
# --- Previously-managed skill names. Supports the legacy manifest format
# (a bare array of names, no hashes) as well as the current object form. ---
managed_names() {
[ -f "$MANIFEST" ] || return 0
jq -r 'if type == "object" then keys[] elif type == "array" then .[] else empty end' \
"$MANIFEST" 2>/dev/null || true
}
# --- Stored hash for a skill, or empty if unknown (new skill, or legacy manifest). ---
stored_hash() {
[ -f "$MANIFEST" ] || return 0
jq -r --arg n "$1" 'if type == "object" then (.[$n] // "") else "" end' \
"$MANIFEST" 2>/dev/null || true
}
# --- Append a name->hash pair to the new manifest being built. ---
record() {
local tmp; tmp="$(mktemp)"
jq --arg n "$1" --arg h "$2" '.[$n] = $h' "$NEW_MANIFEST" > "$tmp" && mv "$tmp" "$NEW_MANIFEST"
}
NEW_NAMES="$(jq -r '.skills[].name' "$TMP_INDEX")"
MANAGED="$(managed_names)"
echo '{}' > "$NEW_MANIFEST"
# --- Prune: drop previously-managed skills that are no longer in the index. ---
removed=0
while IFS= read -r old; do
[ -n "$old" ] || continue
if ! grep -qxF "$old" <<<"$NEW_NAMES"; then
rm -rf "${DEST:?}/$old"
removed=$((removed + 1))
echo "[autosync-ic-skills] removed: $old" >&2
fi
done <<<"$MANAGED"
# --- Sync: download only skills whose hash changed (new / hashless always download). ---
added=0; updated=0; unchanged=0
while IFS= read -r entry; do
name="$(jq -r '.name' <<<"$entry")"
[ -n "$name" ] && [ "$name" != "null" ] || continue
new_hash="$(jq -r '.hash // ""' <<<"$entry")"
old_hash="$(stored_hash "$name")"
# Skip when the hash is known, unchanged, and the files are already on disk.
if [ -n "$new_hash" ] && [ "$new_hash" = "$old_hash" ] && [ -d "$DEST/$name" ]; then
unchanged=$((unchanged + 1))
record "$name" "$new_hash"
continue
fi
# Otherwise (re)download every file for this skill.
ok=1
mkdir -p "$DEST/$name"
while IFS= read -r f; do
[ -n "$f" ] || continue
mkdir -p "$(dirname "$DEST/$name/$f")" # files may live in subdirs (e.g. scripts/)
if ! curl -fsSL --max-time 20 "$BASE/$name/$f" -o "$DEST/$name/$f"; then
echo "[autosync-ic-skills] warning: failed to fetch $name/$f" >&2
ok=0
fi
done < <(jq -r '.files[]?' <<<"$entry")
if [ "$ok" -eq 1 ]; then
# Record the new hash so the next run can skip this skill. A hashless server
# records an empty hash, which never equals new_hash -> always re-downloads.
record "$name" "$new_hash"
if grep -qxF "$name" <<<"$MANAGED"; then
updated=$((updated + 1))
else
added=$((added + 1))
fi
else
# Download incomplete: keep the old hash so the next run retries this skill.
record "$name" "$old_hash"
fi
done < <(jq -c '.skills[]' "$TMP_INDEX")
# --- Swap in the updated manifest. ---
mv "$NEW_MANIFEST" "$MANIFEST"
# --- Report only when something changed; stay silent on a no-op sync. ---
# SessionStart hook stdout/stderr is NOT shown in the Claude Code UI — only JSON
# fields are surfaced. We emit a single JSON object on stdout:
# - systemMessage -> rendered to the USER as a visible system notice
# - additionalContext -> injected into Claude's context so it can mention it too
if [ $((added + updated + removed)) -gt 0 ]; then
summary="[autosync-ic-skills] ${added} added, ${updated} updated, ${removed} removed (${unchanged} unchanged) in $DEST"
jq -n --arg msg "$summary" '{
systemMessage: $msg,
hookSpecificOutput: {
reloadSkills: true,
hookEventName: "SessionStart",
additionalContext: $msg
}
}'
fi