Automatically share skills, migrate local skills to code repositories, open source skills, skill version management, configure git remote
Migrate user's locally created temporary skills to a project repository via symlinks, and initialize Git for version tracking.
| Command | Description |
|---------|-------------|
| /share-skill <skill-name> | Migrate specified skill to code repository and initialize git |
| /share-skill config | Configure code_root and other settings |
| /share-skill <skill-name> --remote <url> | Migrate and configure remote URL |
| /share-skill list | List all local skills available for migration |
| /share-skill remote <alias> <endpoint> | Configure Git remote alias |
| /share-skill remote list | List configured remote aliases |
| /share-skill docs | Generate documentation website for the repository |
| /share-skill docs --style <name> | Generate docs with specified design style |
| /share-skill docs --skill <ui-skill> | Use specified UI skill to design docs |
| /share-skill docs config | Configure default design style or UI skill |
| /share-skill allow | One-time authorization for this skill's permissions |
| Natural language | e.g., "Help me open source port-allocator and push to github" |
All settings are stored in ~/.claude/share-skill-config.json:
{
"code_root": "~/Codes",
"skills_repo": "skills",
"github_username": "guo-yu",
"remotes": {
"github": "git@github.com:guo-yu/skills",
"gitlab": "git@gitlab.com:guo-yu/skills"
},
"default_remote": "github",
"auto_detected": true,
"docs": {
"style": "botanical",
"custom_skill": null,
"custom_domain": null
}
}
Configuration Fields:
| Field | Description | Default |
|-------|-------------|---------|
| code_root | Base directory for code repositories | ~/Codes |
| skills_repo | Name of skills repository folder | skills |
| github_username | GitHub username for URLs | Auto-detected |
| remotes | Git remote aliases | Auto-configured |
| docs.custom_domain | Custom domain for docs site | null (use GitHub Pages) |
Path Variables:
Throughout this document, the following variables are used:
{code_root} → Value of code_root config (e.g., ~/Codes){skills_repo} → Value of skills_repo config (e.g., skills){skills_path} → {code_root}/{skills_repo} (e.g., ~/Codes/skills){username} → Value of github_username configshare-skill automatically creates a Claude Code Plugin Marketplace structure, enabling users to install skills via the /plugin command.
Once your skills repository is set up, users can install skills with:
# Add the marketplace (one-time setup)
/plugin marketplace add {username}/{skills_repo}
# Install individual skills
/plugin install port-allocator@{username}-{skills_repo}
/plugin install share-skill@{username}-{skills_repo}
The repository requires two types of manifest files:
1. Root marketplace.json ({skills_path}/.claude-plugin/marketplace.json):
{
"name": "{username}-{skills_repo}",
"owner": {
"name": "{display-name}",
"email": "{username}@users.noreply.github.com"
},
"metadata": {
"description": "A collection of productivity skills for Claude Code",
"version": "1.0.0"
},
"plugins": [
{
"name": "skill-name",
"source": "./skill-name",
"description": "Skill description from SKILL.md frontmatter"
}
]
}
2. Plugin manifest ({skills_path}/<skill-name>/.claude-plugin/plugin.json):
{
"name": "skill-name",
"description": "Skill description",
"version": "1.0.0"
}
{skills_path}/
├── .claude-plugin/
│ └── marketplace.json # Root marketplace config
├── port-allocator/
│ ├── .claude-plugin/
│ │ └── plugin.json # Plugin manifest
│ ├── SKILL.md
│ └── ...
├── share-skill/
│ ├── .claude-plugin/
│ │ └── plugin.json
│ ├── SKILL.md
│ └── ...
└── docs/
└── ...
| Command | Description |
|---------|-------------|
| /plugin marketplace add <repo> | Add a marketplace (GitHub: owner/repo) |
| /plugin marketplace update | Update all marketplace indexes |
| /plugin install <name>@<marketplace> | Install a plugin from marketplace |
| /plugin validate . | Validate marketplace structure |
On first invocation of share-skill, it automatically detects settings:
Auto-detection Logic:
Check if config file exists
if [ ! -f ~/.claude/share-skill-config.json ]; then
# First run, perform auto-detection
fi
Detect code_root directory
# Check common code directory locations in order
for dir in ~/Codes ~/Code ~/Projects ~/Dev ~/Development ~/repos; do
if [ -d "$dir" ]; then
CODE_ROOT="$dir"
break
fi
done
# If none found, default to ~/Codes
CODE_ROOT="${CODE_ROOT:-~/Codes}"
Read Git global config for username
# Try to get username
USERNAME=$(git config --global user.name)
# If username contains spaces, try extracting from GitHub email
if [[ "$USERNAME" == *" "* ]]; then
EMAIL=$(git config --global user.email)
# Extract from xxx@users.noreply.github.com
USERNAME=$(echo "$EMAIL" | grep -oP '^\d+-?\K[^@]+(?=@users\.noreply\.github\.com)')
fi
# If still unable to determine, try extracting from remote URL
if [ -z "$USERNAME" ]; then
USERNAME=$(git config --global --get-regexp "url.*github.com" | grep -oP 'github\.com[:/]\K[^/]+' | head -1)
fi
Generate default config
{
"code_root": "<detected-code-root>",
"skills_repo": "skills",
"github_username": "<detected-username>",
"remotes": {
"github": "git@github.com:<detected-username>/skills"
},
"default_remote": "github",
"auto_detected": true,
"docs": {
"style": "botanical",
"custom_skill": null,
"custom_domain": null
}
}
Output detection result
First run, auto-detecting settings...
Detected settings:
Code root: ~/Codes
GitHub username: guo-yu
Auto-configured:
Skills path: ~/Codes/skills
Remote: git@github.com:guo-yu/skills
Config file: ~/.claude/share-skill-config.json
To modify, use:
/share-skill config
/share-skill configInteractive configuration for share-skill settings:
TUI Interface (AskUserQuestion):
Configure share-skill settings:
Code root directory:
Current: ~/Codes
[ ] ~/Codes
[ ] ~/Code
[ ] ~/Projects
[ ] Other... (enter custom path)
Custom domain for documentation:
Current: (none - using GitHub Pages)
[ ] No custom domain (use {username}.github.io/{repo})
[ ] Enter custom domain...
Implementation:
# Read current config
CONFIG=$(cat ~/.claude/share-skill-config.json 2>/dev/null || echo '{}')
# After user selection, update config
# Example: Update code_root
jq --arg root "$NEW_CODE_ROOT" '.code_root = $root' <<< "$CONFIG" > ~/.claude/share-skill-config.json
If settings cannot be auto-detected, prompt user to configure:
Unable to auto-detect settings
Please configure manually:
/share-skill config
Or specify when migrating:
/share-skill <skill-name> --remote git@github.com:your-username/skills.git
When user invokes via natural language, intelligent analysis is needed:
User might say:
xxxDefault behavior: Use auto-detected username + default repository name skills
User might say:
git@github.com:<username>/skills/<skill-name>.gitImportant rule: Modifying remote path requires explicit specification
If user wants to use non-default remote path, must explicitly specify via:
Explicit command-line specification
/share-skill <skill-name> --remote git@github.com:other-user/other-repo.git
Explicit path in natural language
OK: "Help me push port-allocator to git@github.com:my-org/tools.git"
OK: "Open source to gitlab, address is git@gitlab.com:team/shared-skills.git"
NOT OK: "Help me push to somewhere else" (unclear, will ask for specific address)
NOT OK: "Use another repository" (unclear, will ask for specific address)
Address Resolution Rules:
"Help me open source xxx"
-> Use default config: git@github.com:<auto-detected-user>/skills
-> Final address: git@github.com:<user>/skills/<skill-name>.git
"Push to git@github.com:other-user/repo.git"
-> Detected full address, use directly
"Open source to gitlab" (gitlab not configured)
-> Prompt: Please specify full GitLab address
Skills may exist at the following locations, searched by priority:
# 1. Standard skills directory
~/.claude/skills/<skill-name>/SKILL.md
# 2. User custom skills directory
~/.claude/skills/*/<skill-name>/SKILL.md
# 3. Standalone skill file
~/.claude/skills/<skill-name>.md
# 4. Project-level skills (current working directory)
.claude/skills/<skill-name>/SKILL.md
Search command:
# Search for directories containing SKILL.md under ~/.claude
find ~/.claude -name "SKILL.md" -type f 2>/dev/null | while read f; do
dir=$(dirname "$f")
name=$(basename "$dir")
echo "$name: $dir"
done
# Or search for specific name
find ~/.claude -type d -name "<skill-name>" 2>/dev/null
After finding skill:
/share-skill remote <alias> <endpoint>Configure Git remote alias:
Read existing config
cat ~/.claude/share-skill-config.json 2>/dev/null || echo '{"remotes":{}}'
Update config
{
"remotes": {
"<alias>": "<endpoint>"
}
}
Write config file (preserve existing config)
Output confirmation
Remote alias configured
Alias: github
Address: git@github.com:guo-yu/skills
Usage:
/share-skill <skill-name> --remote github
or: "Help me open source xxx to github"
/share-skill remote listList configured remote aliases:
cat ~/.claude/share-skill-config.json | jq '.remotes'
Output format:
Configured remote aliases:
github -> git@github.com:guo-yu/skills
gitlab -> git@gitlab.com:guo-yu/skills
gitee -> git@gitee.com:guo-yu/skills
Default: github
/share-skill <skill-name> [--remote <url|alias>]Migrate specified skill from ~/.claude/ directory to {skills_path}/:
Search skill location
# First check standard location
if [ -d ~/.claude/skills/<skill-name> ]; then
SKILL_PATH=~/.claude/skills/<skill-name>
else
# Recursive search
SKILL_PATH=$(find ~/.claude -type d -name "<skill-name>" 2>/dev/null | head -1)
fi
Check target directory
ls {skills_path}/<skill-name> 2>/dev/null
Execute migration
# Create target directory (if doesn't exist)
mkdir -p {skills_path}
# Move skill to code directory
mv ~/.claude/skills/<skill-name> {skills_path}/
# Create symlink
ln -s {skills_path}/<skill-name> ~/.claude/skills/<skill-name>
Create .gitignore
cat > {skills_path}/<skill-name>/.gitignore << 'EOF'
# OS
.DS_Store
Thumbs.db
# Editor
.vscode/
.idea/
*.swp
*.swo
# Logs
*.log
# Temp
tmp/
temp/
EOF
Initialize Git
cd {skills_path}/<skill-name>
git init
git add .
git commit -m "Initial commit: <skill-name> skill"
Configure remote (if specified)
If user specified --remote:
# If it's an alias, resolve to full address
if [ "<remote>" is alias ]; then
ENDPOINT=$(read alias's endpoint from config)
REMOTE_URL="${ENDPOINT}/<skill-name>.git"
else
REMOTE_URL="<remote>"
fi
cd {skills_path}/<skill-name>
git remote add origin "$REMOTE_URL"
git push -u origin master
Ask when remote not specified
If user didn't specify remote, ask after migration using AskUserQuestion:
Do you want to configure Git remote address?
Options:
- Use github (git@github.com:guo-yu/skills/<skill-name>.git)
- Use gitlab (git@gitlab.com:guo-yu/skills/<skill-name>.git)
- Enter custom address
- Skip for now
Post-migration automation (automatic, no interaction)
After migration completes, automatically update all related files:
8.1 Update docs/js/main.js SKILLS config
// Add new skill to SKILLS object
const SKILLS = {
// ... existing skills
'<skill-name>': {
name: '<skill-name>',
description: '<extracted from SKILL.md frontmatter>',
path: '<skill-name>'
}
};
8.2 Update docs/js/main.js SKILL_MARKETING config
// Generate marketing content for the new skill
const SKILL_MARKETING = {
// ... existing skills
'<skill-name>': {
en: {
headline: '<generated from skill description>',
why: '<generated explanation>',
painPoints: [
{ icon: '🔥', title: '...', desc: '...' },
{ icon: '🧠', title: '...', desc: '...' },
{ icon: '💥', title: '...', desc: '...' }
],
triggers: [
'<natural language example 1>',
'<natural language example 2>'
]
},
'zh-CN': { /* Chinese translation including triggers */ },
ja: { /* Japanese translation including triggers */ }
}
};
8.3 Update all README files
Add new skill to the skills table in all language versions:
# Files to update:
# - {skills_path}/README.md
# - {skills_path}/README.zh-CN.md
# - {skills_path}/README.ja.md
# Extract description from SKILL.md frontmatter
DESCRIPTION=$(grep -A1 "^description:" {skills_path}/<skill-name>/SKILL.md | tail -1 | sed 's/^description: //')
# Add row to skills table in each README
# English: | [skill-name](./skill-name/) | Description |
# Chinese: | [skill-name](./skill-name/) | 中文描述 |
# Japanese: | [skill-name](./skill-name/) | 日本語説明 |
8.4 (Automatic) Skill lists are dynamically generated
The skill lists in navigation dropdown, mobile menu, and sidebar are
dynamically generated from the SKILLS object in main.js. No manual
HTML editing required - step 8.1 handles this automatically.
Icon SVG path guidelines (for step 8.1):
| Skill Type | SVG Icon Path |
|------------|---------------|
| Port/Network | <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/> |
| Sharing/Export | <circle cx="18" cy="5" r="3"/>...(share icon) |
| Security/Permissions | <rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/> |
| Translation/i18n | <circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3..."/> |
8.5 Generate translations using skill-i18n
Automatically invoke skill-i18n to translate SKILL.md:
# Check if skill-i18n is available
if [ -d ~/.claude/skills/skill-i18n ] || [ -L ~/.claude/skills/skill-i18n ]; then
# Use Skill tool to invoke skill-i18n with integration flags
# Skill: skill-i18n
# Args: --lang zh-CN,ja --files SKILL.md --skill <skill-name> --no-prompt --overwrite
#
# This generates:
# - {skills_path}/<skill-name>/SKILL.zh-CN.md
# - {skills_path}/<skill-name>/SKILL.ja.md
fi
Implementation: Use the Skill tool to invoke skill-i18n:
Skill(skill: "skill-i18n", args: "--lang zh-CN,ja --files SKILL.md --skill <skill-name> --no-prompt --overwrite")
If skill-i18n is not available, skip this step and output:
⚠ skill-i18n not found, skipping translations
Install with: ln -s {skills_path}/skill-i18n ~/.claude/skills/skill-i18n
8.6 Update cache version
# Update version numbers in docs/index.html
VERSION=$(date +%s)
sed -i '' "s/main.js?v=[0-9]*/main.js?v=$VERSION/" {skills_path}/docs/index.html
sed -i '' "s/custom.css?v=[0-9]*/custom.css?v=$VERSION/" {skills_path}/docs/index.html
8.7 Create/Update Plugin Marketplace structure
To enable installation via /plugin marketplace, create the plugin manifest files:
# Create plugin.json for the new skill
mkdir -p {skills_path}/<skill-name>/.claude-plugin
cat > {skills_path}/<skill-name>/.claude-plugin/plugin.json << EOF
{
"name": "<skill-name>",
"description": "<extracted from SKILL.md frontmatter>",
"version": "1.0.0"
}
EOF
Update the root marketplace.json to include the new skill:
# Read existing marketplace.json and add new plugin entry
# File: {skills_path}/.claude-plugin/marketplace.json
# Add to plugins array:
{
"name": "<skill-name>",
"source": "./<skill-name>",
"description": "<extracted from SKILL.md frontmatter>"
}
Marketplace structure after migration:
{skills_path}/
├── .claude-plugin/
│ └── marketplace.json # Root marketplace config
├── <skill-name>/
│ ├── .claude-plugin/
│ │ └── plugin.json # Plugin manifest
│ ├── SKILL.md
│ └── ...
└── ...
8.8 Commit all changes
cd {skills_path}
git add .
git commit -m "Add <skill-name>: update docs, README, translations, and plugin manifest"
git push # If remote is configured
Post-migration output:
Post-migration updates completed:
✓ Updated docs/js/main.js (SKILLS + SKILL_MARKETING)
✓ Updated README.md, README.zh-CN.md, README.ja.md
✓ Generated SKILL.zh-CN.md, SKILL.ja.md
✓ Updated cache version in docs/index.html
✓ Created .claude-plugin/plugin.json
✓ Updated .claude-plugin/marketplace.json
✓ Committed and pushed changes
Note: Skill lists (navbar, mobile menu, sidebar, install commands) are
dynamically generated from SKILLS config - no HTML editing needed.
/share-skill listList all local skills available for migration (excluding symlinks):
# Search for all directories containing SKILL.md under ~/.claude
echo "Discovered skills:"
find ~/.claude -name "SKILL.md" -type f 2>/dev/null | while read f; do
dir=$(dirname "$f")
name=$(basename "$dir")
if [ -L "$dir" ]; then
target=$(readlink "$dir")
echo " $name -> $target (migrated)"
else
echo " $name: $dir (available)"
fi
done
Skill migration successful
skill: <skill-name>
New location: {skills_path}/<skill-name>
Symlink: ~/.claude/skills/<skill-name> -> {skills_path}/<skill-name>
Git: Initialized and committed
Remote: git@github.com:guo-yu/skills/<skill-name>.git
Post-migration updates:
✓ Updated docs/js/main.js (SKILLS + SKILL_MARKETING)
✓ Updated README.md, README.zh-CN.md, README.ja.md
✓ Generated SKILL.zh-CN.md, SKILL.ja.md
✓ Updated cache version in docs/index.html
✓ Committed and pushed changes
Repository URL: https://github.com/guo-yu/skills
Skill migration successful
skill: <skill-name>
New location: {skills_path}/<skill-name>
Symlink: ~/.claude/skills/<skill-name> -> {skills_path}/<skill-name>
Git: Initialized and committed
Post-migration updates:
✓ Updated docs/js/main.js (SKILLS + SKILL_MARKETING)
✓ Updated README.md, README.zh-CN.md, README.ja.md
✓ Generated SKILL.zh-CN.md, SKILL.ja.md
✓ Updated cache version in docs/index.html
✓ Committed changes (not pushed - no remote configured)
Do you want to configure remote address?
Skill already migrated
<skill-name> is already a symlink:
~/.claude/skills/<skill-name> -> {skills_path}/<skill-name>
Local skills available for migration (N):
- art-master
- design-master
- prompt-generator
Migrated skills (M):
- port-allocator -> {skills_path}/port-allocator
- share-skill -> {skills_path}/share-skill
share-skill supports two Git management modes:
| Mode | Trigger | Git Structure | Remote |
|------|---------|---------------|--------|
| Monorepo | Default endpoint | Parent repo managed | guo-yu/skills |
| Standalone | Custom endpoint | Independent .git | User specified |
When using default endpoint, all skills are managed by parent repo {skills_path}/.git:
{skills_path}/
├── .git/ # Parent repo -> guo-yu/skills
├── .gitignore
├── README.md
├── port-allocator/ # No independent .git, managed by parent
│ ├── .gitignore
│ └── SKILL.md
├── share-skill/
│ ├── .gitignore
│ └── SKILL.md
└── skill-permissions/
├── .gitignore
└── SKILL.md
Operations:
# After adding new skill
cd {skills_path}
git add <new-skill>/
git commit -m "Add <new-skill>"
git push
When user specifies custom endpoint, that skill has independent .git:
{skills_path}/
├── .git/ # Parent repo
├── .gitignore # Contains: /custom-skill/
├── custom-skill/ # Independent repo -> user specified address
│ ├── .git/
│ └── SKILL.md
└── port-allocator/ # Managed by parent repo
Parent repo .gitignore auto-updates:
# Skills with custom endpoints
/custom-skill/
Regardless of mode, ~/.claude/skills/ uses symlinks:
~/.claude/skills/
├── port-allocator -> {skills_path}/port-allocator
├── share-skill -> {skills_path}/share-skill
└── skill-permissions -> {skills_path}/skill-permissions
If you encounter permission prompts, first run:
/share-skill allow
/share-skill allowExecute one-time authorization, adding permissions required by this skill to Claude Code config:
~/.claude/settings.jsonpermissions.allow:{
"permissions": {
"allow": [
"Bash(cat ~/.claude/*)",
"Bash(find ~/.claude *)",
"Bash(ls {skills_path}/*)",
"Bash(mkdir -p {skills_path}*)",
"Bash(mv ~/.claude/skills/* *)",
"Bash
<!-- Content truncated for initial SEO render. Open the source file tab for the full file. -->
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer