---
name: update-skills
description: Check for and pull updates to shared skills. Handles both project submodules and global standalone clones in ~/.claude/skills/. Use when checking for skill updates, pulling latest versions, or verifying skill health.
argument-hint: "[all | skill-name]"
allowed-tools:
  - Bash
  - Read
---

# Update Skills

Check for and pull updates to shared skills. Two sources:

1. **Project submodules** (`.claude/skills/` in `$CLAUDE_PROJECT_DIR`): Agent-specific skills tracked as git submodules.
2. **Global clones** (`~/.claude/skills/`): Skills shared by all agents, cloned as standalone git repos.

## Usage

```
/update-skills           Check all skills for available updates (both sources)
/update-skills all       Pull all available updates
/update-skills context7  Pull updates for a specific skill (checks both locations)
```

## Step 0: Create Task List

Use `TaskCreate` to create these tasks:
1. Check global skills for updates
2. Check project submodules for updates
3. Report status
4. Pull updates (if requested)
5. Verify updated versions

Mark each task `in_progress` when you start it and `completed` when done.

## Procedure

### Step 1: Check global skills

```bash
for dir in ~/.claude/skills/*/; do
  [ -d "$dir/.git" ] || continue
  name=$(basename "$dir")
  cd "$dir"
  LOCAL=$(git rev-parse HEAD 2>/dev/null)
  git fetch origin --quiet 2>/dev/null
  REMOTE=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/HEAD 2>/dev/null)
  if [ -z "$REMOTE" ]; then
    echo "UNREACHABLE [global] $name (cannot reach remote)"
  elif [ "$LOCAL" != "$REMOTE" ]; then
    BEHIND=$(git rev-list HEAD..origin/main --count 2>/dev/null || echo "?")
    echo "STALE [global] $name behind=$BEHIND"
  else
    echo "CURRENT [global] $name"
  fi
  cd - > /dev/null
done
```

### Step 2: Check project submodules

```bash
cd "$CLAUDE_PROJECT_DIR"
git submodule foreach --quiet '
  LOCAL=$(git rev-parse HEAD)
  REMOTE=$(git ls-remote origin HEAD 2>/dev/null | cut -f1)
  if [ -z "$REMOTE" ]; then
    echo "UNREACHABLE [project] $name (cannot reach remote)"
  elif [ "$LOCAL" != "$REMOTE" ]; then
    BEHIND=$(git rev-list HEAD..origin/main --count 2>/dev/null || echo "?")
    echo "STALE [project] $name behind=$BEHIND"
  else
    echo "CURRENT [project] $name"
  fi
'
```

### Step 3: Report results

Format the output as a table:

| Source | Skill | Status | Behind |
|--------|-------|--------|--------|

- **CURRENT**: Up to date, no action needed
- **STALE**: Updates available, show how many commits behind
- **UNREACHABLE**: Cannot contact remote (network issue or repo moved)

If no argument was provided, stop here (check-only mode). Show the table and ask if the user wants to pull updates.

### Step 4: Pull updates (if argument is "all" or a specific skill name)

**Global skills:**
```bash
for dir in ~/.claude/skills/*/; do
  [ -d "$dir/.git" ] || continue
  name=$(basename "$dir")
  cd "$dir"
  git pull --ff-only origin main 2>&1 | grep -v "Already up to date" && echo "Updated [global] $name"
  cd - > /dev/null
done
```

**Project submodules:**
```bash
cd "$CLAUDE_PROJECT_DIR"
git submodule update --remote --merge
```

For a **specific skill**, check global first, then project:
```bash
# Global
if [ -d "$HOME/.claude/skills/SKILL_NAME/.git" ]; then
  cd "$HOME/.claude/skills/SKILL_NAME" && git pull --ff-only origin main
fi

# Project submodule
cd "$CLAUDE_PROJECT_DIR"
git submodule update --remote --merge .claude/skills/SKILL_NAME 2>/dev/null
```

### Step 5: Verify

After updating, confirm versions:

```bash
echo "=== Global Skills ==="
for dir in ~/.claude/skills/*/; do
  [ -d "$dir/.git" ] || continue
  echo "$(basename "$dir"): $(cd "$dir" && git rev-parse --short HEAD)"
done

echo "=== Project Submodules ==="
cd "$CLAUDE_PROJECT_DIR"
git submodule foreach --quiet 'echo "$name: $(git rev-parse --short HEAD)"'
```

Report what was updated and the new commit hashes.
