
Skill Installer
- 13 installs
- 1 repo stars
- Updated January 3, 2026
- skillscatalog/registry
skill-installer is a skill that skill Installer is a meta utility skill for solo builders who treat agent skills like dependencies: you want a verified bundle copied into the right folder for Claude Code, Cursor, Goose,
About
Skill Installer is a meta utility skill for solo builders who treat agent skills like dependencies: you want a verified bundle copied into the right folder for Claude Code, Cursor, Goose, or OpenCode without hand-moving files each time. The package ships a manifest that records SKILL.md and install_skill.py hashes, plus a Python installer that resolves shared config from the skills tree. Use it at the start of a build session when you adopt a new skill from a registry, after you clone a skills monorepo, or when you reset a laptop and need harness paths consistent again. It is deliberately not a marketplace browser—pair it with Prism discovery and then run install for the slug you chose. Expect filesystem and shell side effects; read the script before running in a repo with secrets. MIT-licensed skill metadata in the bundled manifest helps you audit what actually landed on disk.
- Python install_skill.py script with argparse-driven harness targets
- agentskills.io manifest.v1 with per-file SHA-256 integrity entries
- Supports Claude Code, Goose, OpenCode, Cursor, and related agents
- 2-file skill package (SKILL.md + scripts) documented in generated manifest structure
Skill Installer by the numbers
- 13 all-time installs (skills.sh)
- Ranked #495 of 782 Skill Development skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/skillscatalog/registry --skill skill-installerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 13 |
|---|---|
| repo stars | ★ 1 |
| Security audit | 0 / 3 scanners passed |
| Last updated | January 3, 2026 |
| Repository | skillscatalog/registry ↗ |
How do I install curated agent skills from a manifest into Claude Code, Cursor, Goose, OpenCode, and similar harnesses with a repeatable Python installer.?
Install curated agent skills from a manifest into Claude Code, Cursor, Goose, OpenCode, and similar harnesses with a repeatable Python installer.
Who is it for?
Best when you're working on skill development and need structured help with skill installer.
Skip if: Teams with no skill development needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to install curated agent skills from a manifest into Claude Code, Cursor, Goose, OpenCode, and similar harnesses with a repeatable Python installer., or when skill installer is a meta utility skill for solo
What you get
Structured output aligned to skill-installer: Python install_skill.py script with argparse-driven harness targets, agentskills.io manifest.v1 with per-file SHA-256 integrity entries.
Files
Instructions
Use this skill to install Agent Skills from local directories or the catalog to your preferred harness.
Supported Harnesses
| Harness | Install Path | Status |
|---|---|---|
| Claude Code | ~/.claude/skills/{name}/ | Supported |
| Goose | ~/.config/goose/skills/{name}/ | Supported |
| OpenCode | .opencode/skill/{name}/ | Supported |
| Cursor | .cursor/skills/{name}/ | Supported |
How to Use
Install from local directory:
python3 install_skill.py /path/to/my-skill --harness claude-code
python3 install_skill.py ./my-skill --harness gooseInstall from catalog:
python3 install_skill.py anthropic/document-skills --harness claude-code
python3 install_skill.py anthropic/document-skills --harness gooseAuto-detect harness:
python3 install_skill.py /path/to/my-skill
# Detects installed harnesses and prompts for selectionList installed skills:
python3 install_skill.py --list
python3 install_skill.py --list --harness claude-codeUninstall a skill:
python3 install_skill.py --uninstall my-skill --harness claude-codeOutput
Installing skill: document-skills
Source: /path/to/document-skills
Target: ~/.claude/skills/document-skills/
Copying files...
SKILL.md
scripts/pdf_tools.py
references/templates/
Success! Skill installed to Claude Code.
To use: The skill will be available in your next Claude Code session.Examples
Install to Claude Code:
User: Install the skill at ./my-pdf-tool to Claude Code
Agent: Installing skill to Claude Code...
Installed: my-pdf-tool
Location: ~/.claude/skills/my-pdf-tool/
Files: 3 files copied
Restart Claude Code to use the new skill.Install to multiple harnesses:
User: Install ./my-skill to both Claude Code and Goose
Agent: Installing to Claude Code... Done
Installing to Goose... Done
Skill installed to 2 harnesses.Limitations
- Catalog installation requires network access
- Some harnesses require restart to detect new skills
- Project-local harnesses (Cursor, OpenCode) install to current directory
Dependencies
- Python 3.9+
- requests library (for catalog downloads)
{
"$schema": "https://agentskills.io/schemas/manifest.v1.json",
"manifestVersion": "1.0",
"generatedAt": "2026-01-03T03:39:19.983543Z",
"generator": "skill-manifest-generator/1.0.0",
"skill": {
"name": "skill-installer",
"version": "1.0.0"
},
"integrity": {
"algorithm": "sha256",
"hash": "01594ce386bce1e97fe05669cd7f2d270f2735c6bb3f3a4e51ad9db6b237d46b"
},
"files": [
{
"path": "SKILL.md",
"size": 2554,
"sha256": "3fbfb9a95020fad87ad3cf929362413f0c4c12bf157a83e3c5a576e0aaed4eb4",
"type": "manifest"
},
{
"path": "scripts/install_skill.py",
"size": 14632,
"sha256": "2df5a4271aa874269c865f4a311ac410276cd9e5f61d3ef92146569f721fe393",
"type": "script"
}
],
"externalReferences": [],
"structure": {
"maxDepth": 1,
"totalFiles": 2,
"totalBytes": 17186,
"folders": [
"scripts"
]
},
"license": {
"spdxId": "MIT"
}
}
#!/usr/bin/env python3
"""
Agent Skills Installer
Install skills to AI coding agent harnesses.
Supports Claude Code, Goose, OpenCode, Cursor, and others.
"""
import argparse
import json
import os
import shutil
import sys
from pathlib import Path
from typing import Optional
# Add parent directory to path for shared imports
SCRIPT_DIR = Path(__file__).parent
SKILLS_DIR = SCRIPT_DIR.parent.parent
SHARED_DIR = SKILLS_DIR / "_shared"
sys.path.insert(0, str(SHARED_DIR))
# Optional imports
try:
from agentskills_config import get_skill_key, get_api_url, get_auth_header
HAS_CONFIG = True
except ImportError:
HAS_CONFIG = False
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
# ============================================================================
# Harness Definitions
# ============================================================================
HARNESSES = {
"claude-code": {
"name": "Claude Code",
"path": Path.home() / ".claude" / "skills",
"type": "global",
"detect": lambda: (Path.home() / ".claude").exists(),
},
"goose": {
"name": "Goose",
"path": Path.home() / ".config" / "goose" / "skills",
"type": "global",
"detect": lambda: shutil.which("goose") is not None or (Path.home() / ".config" / "goose").exists(),
},
"opencode": {
"name": "OpenCode",
"path": Path.cwd() / ".opencode" / "skill",
"type": "project",
"detect": lambda: (Path.cwd() / ".opencode").exists() or shutil.which("opencode") is not None,
},
"cursor": {
"name": "Cursor",
"path": Path.cwd() / ".cursor" / "skills",
"type": "project",
"detect": lambda: (Path.cwd() / ".cursor").exists(),
},
}
# ============================================================================
# Skill Parsing
# ============================================================================
def get_skill_name(skill_path: Path) -> str:
"""Extract skill name from SKILL.md or directory name."""
skill_md = skill_path / "SKILL.md"
if skill_md.exists():
try:
content = skill_md.read_text()
if content.startswith("---"):
end = content.find("---", 3)
if end > 0:
frontmatter = content[3:end]
for line in frontmatter.split("\n"):
if line.startswith("name:"):
return line.split(":", 1)[1].strip().strip("\"'")
except Exception:
pass
return skill_path.name
def validate_skill(skill_path: Path) -> tuple[bool, str]:
"""Check if path contains a valid skill."""
if not skill_path.exists():
return False, f"Path does not exist: {skill_path}"
if not skill_path.is_dir():
return False, f"Path is not a directory: {skill_path}"
skill_md = skill_path / "SKILL.md"
if not skill_md.exists():
return False, f"Missing SKILL.md in {skill_path}"
return True, ""
# ============================================================================
# Installation Functions
# ============================================================================
def install_skill(
source_path: Path,
harness_id: str,
force: bool = False,
) -> tuple[bool, str]:
"""Install a skill to a harness."""
if harness_id not in HARNESSES:
return False, f"Unknown harness: {harness_id}"
harness = HARNESSES[harness_id]
skill_name = get_skill_name(source_path)
# Determine target path
target_base = harness["path"]
target_path = target_base / skill_name
# Check if already installed
if target_path.exists() and not force:
return False, f"Skill already installed at {target_path}. Use --force to overwrite."
# Create parent directories
try:
target_base.mkdir(parents=True, exist_ok=True)
except PermissionError:
return False, f"Permission denied creating {target_base}"
# Remove existing if force
if target_path.exists() and force:
try:
shutil.rmtree(target_path)
except Exception as e:
return False, f"Failed to remove existing installation: {e}"
# Copy skill files
try:
shutil.copytree(source_path, target_path)
except Exception as e:
return False, f"Failed to copy files: {e}"
return True, str(target_path)
def uninstall_skill(skill_name: str, harness_id: str) -> tuple[bool, str]:
"""Uninstall a skill from a harness."""
if harness_id not in HARNESSES:
return False, f"Unknown harness: {harness_id}"
harness = HARNESSES[harness_id]
target_path = harness["path"] / skill_name
if not target_path.exists():
return False, f"Skill not found: {target_path}"
try:
shutil.rmtree(target_path)
return True, f"Removed {target_path}"
except Exception as e:
return False, f"Failed to remove: {e}"
def list_installed_skills(harness_id: Optional[str] = None) -> dict:
"""List installed skills for one or all harnesses."""
result = {}
harnesses_to_check = [harness_id] if harness_id else HARNESSES.keys()
for hid in harnesses_to_check:
if hid not in HARNESSES:
continue
harness = HARNESSES[hid]
skills_path = harness["path"]
if not skills_path.exists():
result[hid] = []
continue
skills = []
for item in skills_path.iterdir():
if item.is_dir() and (item / "SKILL.md").exists():
skills.append({
"name": item.name,
"path": str(item),
})
result[hid] = skills
return result
def detect_harnesses() -> list[str]:
"""Detect which harnesses are installed."""
detected = []
for hid, harness in HARNESSES.items():
try:
if harness["detect"]():
detected.append(hid)
except Exception:
pass
return detected
# ============================================================================
# Catalog Integration
# ============================================================================
def download_from_catalog(
vendor_key: str,
skill_key: str,
dest_path: Path,
) -> tuple[bool, str]:
"""Download a skill from the catalog."""
if not HAS_REQUESTS:
return False, "requests library not installed. Run: pip install requests"
if not HAS_CONFIG:
return False, "agentskills_config not available"
api_url = get_api_url()
headers = get_auth_header()
try:
# Get skill details
response = requests.get(
f"{api_url}/api/catalog/{vendor_key}/{skill_key}",
headers=headers,
timeout=30,
)
if response.status_code == 404:
return False, f"Skill not found: {vendor_key}/{skill_key}"
if response.status_code != 200:
return False, f"API error: {response.status_code}"
data = response.json()
# Check if we have content
content = data.get("content")
if not content:
# Skill exists but no downloadable content
# Try to get from GitHub if repo URL is available
skill_data = data.get("skill", {})
repo_url = skill_data.get("repo")
if repo_url:
return False, f"Skill found but content not available. Source: {repo_url}"
return False, "Skill found but no downloadable content"
# Create destination directory
dest_path.mkdir(parents=True, exist_ok=True)
# Write files
files_written = 0
for file_path, file_content in content.items():
full_path = dest_path / file_path
full_path.parent.mkdir(parents=True, exist_ok=True)
full_path.write_text(file_content)
files_written += 1
return True, f"Downloaded {files_written} files to {dest_path}"
except requests.exceptions.Timeout:
return False, "Request timed out"
except requests.exceptions.ConnectionError:
return False, f"Could not connect to {api_url}"
except Exception as e:
return False, str(e)
# ============================================================================
# CLI Interface
# ============================================================================
def main():
parser = argparse.ArgumentParser(
description="Install Agent Skills to harnesses",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Install from local directory
python install_skill.py ./my-skill --harness claude-code
python install_skill.py /path/to/skill --harness goose
# Install from catalog
python install_skill.py anthropic/document-skills --harness claude-code
# List installed skills
python install_skill.py --list
python install_skill.py --list --harness claude-code
# Uninstall a skill
python install_skill.py --uninstall my-skill --harness claude-code
Supported harnesses:
claude-code ~/.claude/skills/
goose ~/.config/goose/skills/
opencode .opencode/skill/ (project-local)
cursor .cursor/skills/ (project-local)
""",
)
parser.add_argument(
"source",
nargs="?",
help="Skill path (local) or vendor/skill (catalog)",
)
parser.add_argument(
"--harness", "-H",
choices=list(HARNESSES.keys()),
help="Target harness",
)
parser.add_argument(
"--list", "-l",
action="store_true",
help="List installed skills",
)
parser.add_argument(
"--uninstall", "-u",
metavar="SKILL",
help="Uninstall a skill by name",
)
parser.add_argument(
"--force", "-f",
action="store_true",
help="Overwrite existing installation",
)
parser.add_argument(
"--json",
action="store_true",
help="Output as JSON",
)
args = parser.parse_args()
# List mode
if args.list:
installed = list_installed_skills(args.harness)
if args.json:
print(json.dumps(installed, indent=2))
else:
for hid, skills in installed.items():
harness = HARNESSES[hid]
print(f"\n{harness['name']} ({harness['path']}):")
if skills:
for skill in skills:
print(f" - {skill['name']}")
else:
print(" (no skills installed)")
sys.exit(0)
# Uninstall mode
if args.uninstall:
if not args.harness:
print("Error: --harness required for uninstall", file=sys.stderr)
sys.exit(1)
success, message = uninstall_skill(args.uninstall, args.harness)
if args.json:
print(json.dumps({"success": success, "message": message}))
else:
if success:
print(f"Uninstalled: {args.uninstall}")
print(f" {message}")
else:
print(f"Error: {message}", file=sys.stderr)
sys.exit(0 if success else 1)
# Install mode
if not args.source:
parser.print_help()
sys.exit(1)
# Determine if source is local or catalog
source = args.source
is_catalog = "/" in source and not Path(source).exists()
if is_catalog:
# Catalog source: vendor/skill
parts = source.split("/", 1)
if len(parts) != 2:
print(f"Error: Invalid catalog reference: {source}", file=sys.stderr)
print("Use format: vendor/skill (e.g., anthropic/document-skills)")
sys.exit(1)
vendor_key, skill_key = parts
# Download to temp location
import tempfile
temp_dir = Path(tempfile.mkdtemp()) / skill_key
print(f"Downloading {vendor_key}/{skill_key} from catalog...")
success, message = download_from_catalog(vendor_key, skill_key, temp_dir)
if not success:
print(f"Error: {message}", file=sys.stderr)
sys.exit(1)
source_path = temp_dir
else:
# Local source
source_path = Path(source).resolve()
# Validate
valid, error = validate_skill(source_path)
if not valid:
print(f"Error: {error}", file=sys.stderr)
sys.exit(1)
# Determine harness
harness_id = args.harness
if not harness_id:
detected = detect_harnesses()
if not detected:
print("Error: No harnesses detected. Use --harness to specify.", file=sys.stderr)
print("Supported: " + ", ".join(HARNESSES.keys()))
sys.exit(1)
elif len(detected) == 1:
harness_id = detected[0]
print(f"Auto-detected harness: {HARNESSES[harness_id]['name']}")
else:
print("Multiple harnesses detected. Please specify with --harness:")
for hid in detected:
print(f" {hid} - {HARNESSES[hid]['name']}")
sys.exit(1)
# Install
skill_name = get_skill_name(source_path)
print(f"\nInstalling skill: {skill_name}")
print(f" Source: {source_path}")
print(f" Target: {HARNESSES[harness_id]['path'] / skill_name}")
print()
success, result = install_skill(source_path, harness_id, force=args.force)
if args.json:
print(json.dumps({
"success": success,
"skill": skill_name,
"harness": harness_id,
"path": result if success else None,
"error": result if not success else None,
}))
else:
if success:
print(f" Success! Skill installed to {HARNESSES[harness_id]['name']}.")
print(f" Location: {result}")
print()
if harness_id == "claude-code":
print(" The skill will be available in your next Claude Code session.")
elif harness_id == "goose":
print(" The skill will be available in your next Goose session.")
else:
print(" Restart your agent to use the new skill.")
else:
print(f" Error: {result}", file=sys.stderr)
# Cleanup temp dir if catalog download
if is_catalog and 'temp_dir' in dir():
try:
shutil.rmtree(temp_dir.parent)
except Exception:
pass
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()
Related skills
FAQ
What does skill-installer do?
Skill Installer is a meta utility skill for developers who treat agent skills like dependencies: you want a verified bundle copied into the right folder for Claude Code, Cursor, Goose, or OpenCode without hand-moving files each time.
When should I use skill-installer?
When you need to install curated agent skills from a manifest into Claude Code, Cursor, Goose, OpenCode, and similar harnesses with a repeatable Python installer., or when skill installer is a meta utility skill for developers who treat agent skills like dependencies: you want
What are the main capabilities?
Python install_skill.py script with argparse-driven harness targets; agentskills.io manifest.v1 with per-file SHA-256 integrity entries; Supports Claude Code, Goose, OpenCode, Cursor, and related agents.
Is Skill Installer safe to install?
skills.sh reports 0 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.