skill-link
SKILL.md
skill-link — Manage Extensions for Claude Code & Codex CLI
Install, list, health-check, and uninstall skills, commands, and agents via symlinks.
Requires environment variables (set in shell profile):
export CLAUDE_HOME="${CLAUDE_HOME:-$HOME/.claude}"
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
Subcommands
| Subcommand | Trigger | Description |
|---|---|---|
| (default) | /skill-link |
Install extensions from source directory |
| list | /skill-link list |
List all installed extensions |
| check | /skill-link check |
Health-check: find broken/stale symlinks |
| uninstall | /skill-link uninstall <name> |
Remove symlinks for specified extensions |
If no subcommand is given, defaults to install.
Extension Types
| Type | Source pattern | Claude Code target | Codex CLI target |
|---|---|---|---|
| Skills | skills/{name}/ (has SKILL.md) |
$CLAUDE_HOME/skills/{name} → dir symlink |
$CODEX_HOME/skills/{name} → dir symlink |
| Commands | commands/{name}.md |
$CLAUDE_HOME/commands/{name}.md → file symlink |
N/A (Codex has no commands) |
| Agents | agents/{name}/agent.md |
$CLAUDE_HOME/agents/{name}.md → file symlink to agent.md |
N/A (Codex has no agents) |
Subcommand: install (default)
Workflow
- Get source directory from user (default: current project root)
- Scan for:
skills/*/SKILL.md→ skill directoriescommands/*.md→ command filesagents/*/agent.md→ agent files
- Show discovered extensions with current status, AskUserQuestion to confirm
- Create symlinks per the table above
- Report results
Linking Logic
src="$(realpath "/path/to/source")"
dst="$CLAUDE_HOME/skills/{name}"
# Check target type before linking
if [ -d "$dst" ] && [ ! -L "$dst" ]; then
# Target is a real directory, not a symlink — warn user
echo "WARNING: $dst is a real directory, skipping (use --force to replace)"
else
ln -sfn "$src" "$dst"
fi
Rules
- Always resolve source to absolute path with
realpath - Quote all paths to handle spaces
- Create target directories if missing
- If target is a real directory (not a symlink): skip and warn
- If target is a symlink:
ln -sfnsafely overwrites it - Show status:
new/updated/already linked/skipped (real dir) - For agents: symlink points to the
agent.mdfile, not the directory
Example
User: /skill-link
Agent: Scanning /Users/me/claude-code-addons/ ...
Skills (3):
✓ continuous-learning → not installed
- skill-link → already linked
✓ eval-harness → not installed
Commands (2):
✓ peer-review.md → not installed
- cr.md → already linked
Agents (2):
- code-reviewer.md → already linked
✓ architect.md → not installed
Install 3 extensions?
User: Yes
Agent:
Skills: 2 installed to claude + codex
Commands: 1 installed to claude
Agents: 0 (all linked)
Done.
Subcommand: list
Scan $CLAUDE_HOME and $CODEX_HOME for all installed symlinks. Shows every extension regardless of whether it came from the current project.
Workflow
- Scan these directories for symlinks:
$CLAUDE_HOME/skills/— directory symlinks$CLAUDE_HOME/commands/— file symlinks$CLAUDE_HOME/agents/— file symlinks$CODEX_HOME/skills/— directory symlinks
- For each symlink, resolve target with
readlink - Display as table with name, type, target path, and health status
Output Format
Installed extensions:
Skills (Claude + Codex):
roadmap → /path/to/source/skills/roadmap ✓ ok
tech-interview → /path/to/source/skills/tech-interview ✓ ok
cr → /path/to/source/skills/cr ✓ ok
Commands (Claude only):
architect.md → /path/to/source/commands/architect.md ✓ ok
code-invs.md → /path/to/source/commands/code-invs.md ✓ ok
Agents (Claude only):
architect.md → /path/to/source/agents/architect/agent.md ✓ ok
code-reviewer.md → /path/to/source/agents/code-reviewer/agent.md ✓ ok
Total: 7 extensions installed
Example
User: /skill-link list
Agent: [displays table above]
Subcommand: check
Health-check all installed symlinks. Detects:
| Problem | Description | How to detect |
|---|---|---|
| broken | Symlink target no longer exists | [ -L "$link" ] && [ ! -e "$link" ] |
| stale | Target exists but is not the expected type (e.g., no SKILL.md in skill dir) | Symlink resolves but content is wrong |
| orphaned | Installed in one location but not the other (Claude has it, Codex doesn't) | Cross-check Claude vs Codex for skills |
| duplicate | Same name installed from different source directories | Compare resolved targets |
Workflow
- Scan all symlinks in
$CLAUDE_HOME/{skills,commands,agents}and$CODEX_HOME/skills - For each symlink, check:
- Does the target exist? (
brokenif not) - For skills: does target contain
SKILL.md? (staleif not) - For commands: is target a
.mdfile? (staleif not) - For agents: is target a
.mdfile? (staleif not) - Is this skill installed in both Claude and Codex? (
orphanedif not)
- Does the target exist? (
- Report problems, suggest fixes
- If problems found, AskUserQuestion: "Fix N issues?" with options to auto-fix
Auto-fix Actions
| Problem | Fix |
|---|---|
| broken | Remove the dead symlink |
| orphaned | Create the missing symlink in the other location |
| stale | Remove + warn user |
| duplicate | Show both, let user choose |
Output Format
Health check:
✗ exec-plan BROKEN → /path/to/skills/exec-plan (target removed)
✗ tech-design BROKEN → /path/to/skills/tech-design (target removed)
! my-skill ORPHAN → installed in Claude but not Codex
✓ 22 extensions OK
Found 3 issues. Fix them?
Example
User: /skill-link check
Agent:
✗ exec-plan BROKEN → target directory no longer exists
✗ tech-design BROKEN → target directory no longer exists
✓ 29 extensions OK
Remove 2 broken symlinks?
User: Yes
Agent:
Removed: exec-plan (claude + codex)
Removed: tech-design (claude + codex)
Done.
Subcommand: uninstall
Remove symlinks for specified extensions. Never deletes source files — only removes symlinks from $CLAUDE_HOME and $CODEX_HOME.
Workflow
- Parse extension names from arguments
- For each name, find matching symlinks in:
$CLAUDE_HOME/skills/{name}$CODEX_HOME/skills/{name}$CLAUDE_HOME/commands/{name}.md$CLAUDE_HOME/agents/{name}.md
- Show what will be removed, AskUserQuestion to confirm
- Remove symlinks (only if they ARE symlinks, never
rm -rfa real directory) - Report results
Safety Rules
- Only remove symlinks, never real files or directories
- Check with
[ -L "$path" ]before removing - If target is a real directory/file, refuse and warn
- Always confirm with user before removing
Output Format
Will uninstall:
skill exec-plan → claude + codex (2 symlinks)
skill tech-design → claude + codex (2 symlinks)
Remove 4 symlinks? Source files are NOT affected.
User: Yes
Agent:
Removed: exec-plan (claude, codex)
Removed: tech-design (claude, codex)
Done. Source files in /path/to/skills/ are untouched.
Example
User: /skill-link uninstall exec-plan tech-design
Agent:
Will remove:
~/.claude/skills/exec-plan (symlink)
~/.codex/skills/exec-plan (symlink)
~/.claude/skills/tech-design (symlink)
~/.codex/skills/tech-design (symlink)
Remove 4 symlinks?
User: Yes
Agent: Removed 4 symlinks. Source files untouched.
Weekly Installs
1
Repository
fancive/claude-skillsFirst Seen
12 days ago
Security Audits
Installed on
codex1