8.8 KiB
name, description, arguments
| name | description | arguments | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| install-skill | Install a skill from GitHub to project scope (.claude/skills/) |
|
Install Skill from GitHub
You are installing a Claude Code skill from a GitHub repository to project scope.
Parse the Input
Parse the source argument: $ARGUMENTS.source
Supported formats:
user/repo- Clone repo, look for skill at root or inskills/directoryuser/repo:skill-name- Install specific skill fromskills/<skill-name>/user/repo#branch- Use specific branchuser/repo#branch:skill-name- Branch + specific skilluser/repo --all- Install all skills found in repo
Extract:
owner: GitHub username/orgrepo: Repository namebranch: Branch name (default: repo's default branch)skillPath: Path to skill within repo (optional)installAll: Boolean flag for --all
Determine Installation Mode
Check for mode flags in $ARGUMENTS.mode or within $ARGUMENTS.source:
Flag detection:
-
First check
$ARGUMENTS.mode:- If
--copyorcopy:mode = "copy" - If
--submoduleorsubmodule:mode = "submodule"
- If
-
If not found, check if flag is appended to source string:
- Split
$ARGUMENTS.sourceby spaces - If last token is
--copy:mode = "copy", remove flag from source - If last token is
--submodule:mode = "submodule", remove flag from source
- Split
-
If no flag found, prompt user:
Interactive prompt (when no flag):
Use AskUserQuestion:
question: "How would you like to install this skill?"
header: "Install Mode"
multiSelect: false
options:
- label: "Submodule (recommended)"
description: "Full repo as git submodule, easy updates via git submodule update"
- label: "Copy"
description: "Only skill files copied, minimal footprint, re-run install to update"
Map user response to mode variable:
- "Submodule (recommended)" →
mode = "submodule" - "Copy" →
mode = "copy"
Default: If user doesn't respond or cancels, default to mode = "submodule".
The mode variable (value: "copy" or "submodule") is used in subsequent installation steps.
Installation Process
Step 1: Setup directories
mkdir -p .claude/skills
Step 2: Find skills to install
If --all flag:
- Look for
skills/directory in cloned repo - Find all subdirectories containing
SKILL.md - Collect list of skill names
If specific skill path:
- Check if
skills/<skill-name>/SKILL.mdexists - If not, check if
<skill-name>/SKILL.mdexists at root - If not found, report error with helpful message
If no skill specified:
- Check if repo root has
SKILL.md(repo IS the skill) - If not, check if
skills/directory exists and has exactly one skill - If multiple skills found, list them and ask user to specify
Step 3: Validate each skill
For each skill to install:
- Verify
SKILL.mdexists - Read frontmatter and validate:
namefield exists (max 64 chars)descriptionfield exists (max 1024 chars)
- Warn if validation fails but continue
Step 4: Execute Installation Based on Mode
If mode is "copy":
2a. Clone to temporary directory:
TEMP_DIR=$(mktemp -d)
git clone --depth=1 https://github.com/<owner>/<repo>.git "$TEMP_DIR"
If specific branch:
git clone --depth=1 --branch <branch> https://github.com/<owner>/<repo>.git "$TEMP_DIR"
2b. Get commit SHA before cleanup:
COMMIT_SHA=$(git -C "$TEMP_DIR" rev-parse HEAD)
2c. Copy skill directory:
mkdir -p .claude/skills
cp -r "$TEMP_DIR/<skillPath>" ".claude/skills/<skill-name>"
2d. Clean up temp directory:
rm -rf "$TEMP_DIR"
If mode is "submodule":
2a. Check if this is a git repository:
git rev-parse --git-dir > /dev/null 2>&1
If not a git repo, error:
Error: Submodule mode requires a git repository.
Either initialize git first (git init) or use --copy mode.
2b. Check if submodule already exists:
if [ -d ".claude/submodules/<repo>" ]; then
# Verify it's the same source
EXISTING_URL=$(git config --file .gitmodules submodule..claude/submodules/<repo>.url)
EXPECTED_URL="https://github.com/<owner>/<repo>.git"
if [ "$EXISTING_URL" = "$EXPECTED_URL" ]; then
# Same URL - use existing submodule, skip git submodule add
echo "Submodule already exists with matching URL, using existing"
else
# Different URL - error
echo "Error: Submodule exists but URL differs"
echo " Existing: $EXISTING_URL"
echo " Expected: $EXPECTED_URL"
exit 1
fi
fi
2c. Add submodule if not exists:
Skip if submodule already exists with matching URL (from step 2b).
Otherwise:
mkdir -p .claude/submodules
git submodule add https://github.com/<owner>/<repo>.git .claude/submodules/<repo>
If specific branch:
git submodule add -b <branch> https://github.com/<owner>/<repo>.git .claude/submodules/<repo>
2d. Get commit SHA:
COMMIT_SHA=$(git -C ".claude/submodules/<repo>" rev-parse HEAD)
Step 5: Create symlinks (submodule mode only)
Skip this step if mode is "copy" - files are already in .claude/skills/<name>/.
For submodule mode, create symlink:
Check if .claude/skills/<skill-name> already exists:
- If symlink pointing to same target: skip, already installed
- If symlink pointing elsewhere or regular directory: ask user to overwrite or skip
Create relative symlink:
mkdir -p .claude/skills
ln -s ../submodules/<repo>/<skillPath> .claude/skills/<skill-name>
For example, if skill is at skills/brainstorming/:
ln -s ../submodules/superpowers/skills/brainstorming .claude/skills/brainstorming
Step 6: Update registry
Read or create .claude/local-plugins.yaml:
version: 2
skills: {}
submodules: {}
Migration: If .claude/local-plugins.json exists (v1), migrate it first:
- Read JSON content
- Convert each repo's skills to v2 format with
mode: legacy - Write to
.claude/local-plugins.yaml - Delete
.claude/local-plugins.json
Add skill entry:
skills:
<skill-name>:
mode: <copy|submodule>
source: github.com/<owner>/<repo>
repo: <repo>
branch: <branch>
skillPath: <path/to/skill>
installedAt: <ISO timestamp>
commitSha: <sha>
If submodule mode, also update submodules section:
submodules:
<repo>:
source: github.com/<owner>/<repo>
path: .claude/submodules/<repo>
skills:
- <skill-name>
If repo already in submodules, just append skill name to the skills list.
Write YAML: Use proper YAML formatting with 2-space indentation.
Step 7: Update .gitignore (copy mode only)
Skip this step for submodule mode - submodules are tracked by git naturally.
For copy mode, the skill files in .claude/skills/<name>/ will be committed directly. No .gitignore changes needed.
Note: The old .claude/plugins/local/ pattern can be removed from .gitignore if present, as we no longer use that directory.
Step 8: Report success
Copy mode output:
Installing skill from github.com/<owner>/<repo>...
├── Mode: Copy
├── Downloading: <skillPath>
├── Copying to: .claude/skills/<skill-name>
└── Status: Installed successfully
Skill "<skill-name>" is now available in this project.
Submodule mode output:
Installing skill from github.com/<owner>/<repo>...
├── Mode: Submodule
├── Adding submodule: .claude/submodules/<repo>
├── Creating symlink: .claude/skills/<skill-name>
└── Status: Installed successfully
Skill "<skill-name>" is now available in this project.
Note: Team members should run `git submodule update --init` after cloning.
Error Handling
Repository not found:
Error: Repository not found: github.com/<owner>/<repo>
Check the repository URL and ensure it's public or you have access.
No SKILL.md found:
Error: No SKILL.md found at <owner>/<repo>:<path>
Expected structure:
skill-name/
└── SKILL.md (required)
Available skills in this repo:
- skill-a (skills/skill-a/)
- skill-b (skills/skill-b/)
Try: /install-skill <owner>/<repo>:skill-a
Network error:
Error: Failed to clone repository
Check your network connection and try again.
Notes
- Always use relative symlinks so they work when repo is moved
- The
.claude/plugins/local/directory should NOT be committed (add to .gitignore) - The
.claude/skills/<name>symlinks SHOULD be committed (team sharing) - Team members need to run
/install-skillafter cloning to populate local repos