You run Claude Code, Cursor, and a few other AI coding agents. Each one wants its skills in a different directory. So you end up with:
~/.claude/skills/pdf/SKILL.md
~/.agents/skills/pdf/SKILL.md
~/.clawdbot/skills/pdf/SKILL.md
~/.cursor/skills/pdf/SKILL.md
Same skill. Four copies. Every time you tweak the PDF skill, you have to sync four places โ or forget, and they silently diverge.
SkillFS fixes this. It finds all your duplicate skills, migrates them to ~/.skills/, and replaces the copies with symlinks. Each agent still sees its own skills/pdf/ โ but now they all point to the same files.
# 1. Install
npm install -g skillfs
# 2. See what's duplicated
sk doctor
# 3. Fix it
sk dedupeThat's it. Your agents won't notice the difference โ they follow symlinks transparently.
sk doctor Scan all runtimes, find duplicates, estimate savings
sk doctor --json Machine-readable JSON output for automation
sk doctor --snapshot Cargo.lock-style reproducible lockfile
sk dedupe Migrate duplicates to ~/.skills/, replace with symlinks
sk dedupe --dry-run Preview without touching anything
sk install <path> Install a skill to ~/.skills/ and link to runtimes
sk uninstall <name> Remove a skill from ~/.skills/ and clean up symlinks
sk link --all Link all ~/.skills/ back to every runtime
sk list Visual tree of every skill and its link status
sk watch Watch runtime dirs for new skills in real time
Auto-discovers every AI agent on your machine, then scans for duplicates:
- Scans
~/.*/skills/โ finds agents you forgot you even installed - Identical duplicates (same MD5 hash) โ safe to auto-migrate
- Conflicting versions (different content, same name) โ needs your decision
- Disk space savings โ how much you'll reclaim
- Drift detection โ warns if a skill's SKILL.md has changed since last registry update
- Incomplete transactions โ if a previous
dedupewas interrupted, tells you how to recover
$ sk doctor
๐ SkillFS Doctor ๐
ๆซๆ็ฎๅฝ๏ผ
โ ~/.claude/skills (5 skills)
โ ~/.agent/skills (3 skills)
โ ~/.clawdbot/skills (4 skills)
โ ~/.skills (2 skills)
ๅ็ฐ้ๅค Skill๏ผ
pdf ร 3 [ๅ
ๅฎน็ธๅ โ]
code-review ร 2 [ๅ
ๅฎนไธๅ โ ]
ๆฑๆป๏ผ
้ๅค Skill๏ผ2 ไธช๏ผๅ
ฑ 5 ไธชๅฏๆฌ๏ผ
ๅ
ๅฎนๅฒ็ช๏ผ1 ไธช๏ผ้ๆๅจ็กฎ่ฎค๏ผ
ๅฏ่็็ฉบ้ด๏ผ็บฆ 156.3 KB
่ฟ่ก sk dedupe ๅผๅง่ฟ็งป
The main event. Identical skills are migrated automatically. For conflicts, you get an interactive prompt:
- Choose which version to keep
- View a colored line-by-line diff between versions
- Skip and come back later
Every migration follows a transactional safety protocol:
- Copy to
~/.skills/<name>/ - Verify the copy is complete (recursive hash comparison)
- Remove originals and create symlinks
- Update the registry
If anything fails, all changes are rolled back.
sk dedupe # Interactive
sk dedupe --dry-run # See what would happen, no changes madeRe-link centralized skills to your runtimes:
sk link pdf --runtime claude # One skill โ one runtime
sk link pdf --all # One skill โ all runtimes
sk link --all # Everything โ everywhereA tree view of your entire skill ecosystem:
$ sk list
๐ SkillFS List ๐
~/.skills (Source of Truth)
โโโ pdf [claude โ] [agent -] [clawdbot โ]
โโโ code-review [claude โ] [agent โ] [clawdbot โ ]
~/.agent/skills (้ขๅค๏ผๆช่ฟ็งป)
โโโ legacy-formatter (ๆชๅจ ~/.skills ไธญ๏ผ่ฟ่ก sk dedupe ่ฟ็งป)
ๅพไพ: โ ๅทฒ้พๆฅ - ๆช้พๆฅ โ ้พๆฅๆญ่ฃ
Copy a skill directory to ~/.skills/ and create symlinks to runtimes:
sk install ~/projects/my-skill # Install and link to all runtimes
sk install ~/projects/my-skill -r claude # Install and link to one runtime
sk install --all-from claude # Batch-install all unique skills from one runtime
sk install --all-from claude --dry-run # Preview before batch-installingThe source must be a directory containing a SKILL.md file. SkillFS extracts the directory name as the skill name, copies everything to ~/.skills/<name>/, and optionally creates symlinks in each runtime's skills directory.
Remove a skill from ~/.skills/ and clean up symlinks:
sk uninstall my-skill # Remove from ~/.skills/ and all runtimes
sk uninstall my-skill -r claude # Remove from one runtime only, keep ~/.skills/When removing from all runtimes (no --runtime flag), every symlink pointing to ~/.skills/<name> is removed, the central copy is deleted, and the registry entry is cleared. With --runtime, only the specified runtime's symlink is removed.
Monitor runtime skills directories for new skills in real time:
sk watch # Watch all configured runtimes
sk watch --runtime claude # Watch one runtime onlyPolling-based detection (every 2 seconds) โ reliable across all platforms. When a new skill directory containing a SKILL.md appears, prints:
โจ ๅ็ฐๆฐ skill: my-skill โ ไฝฟ็จ sk install ~/.claude/skills/my-skill ๅฎ่ฃ
Runs until Ctrl+C. Graceful shutdown on SIGINT.
sk --help # Show all commands and options
sk --version # Print version numberAuto-discover agents and scan for duplicates, estimate savings.
sk doctor # Human-readable report
sk doctor --json # Machine-readable JSON output
sk doctor --snapshot # Cargo.lock-style lockfile| Option | Alias | Description |
|---|---|---|
--json |
โ | Output analysis results as structured JSON to stdout |
--snapshot |
โ | Output a reproducible lockfile ({ skills: { name: { hash, runtimes } } }) |
Run it anytime โ it's read-only, zero side effects. Automatically finds any ~/.{name}/skills/ directory with valid SKILL.md files.
When --json is passed, the output is a JSON object with runtimes, central, duplicates, totalDuplicatesCount, conflictsCount, savingsBytes, and incompleteTransactions fields โ suitable for piping to jq or consumption by other tools.
Migrate duplicates to ~/.skills/ and replace originals with symlinks.
sk dedupe # Interactive migration
sk dedupe --dry-run # Preview only โ no files are modified| Option | Alias | Description |
|---|---|---|
--dry-run |
โ | Show what would happen without making any changes |
Identical skills (same MD5) are auto-migrated. Conflicting versions offer an interactive prompt to choose, view a diff, or skip.
Create symlinks from ~/.skills/ to runtime skills directories.
sk link <name> --runtime <name> # Link one skill to one runtime
sk link <name> --all (-a) # Link one skill to all runtimes
sk link --all (-a) # Link all skills to every runtime| Option | Alias | Description |
|---|---|---|
--runtime <name> |
-r |
Target runtime (e.g. claude, cursor, gemini) |
--all |
-a |
Link to all configured runtimes |
Display all skills in ~/.skills/ with their symlink status across runtimes.
sk listNo options. Shows โ (linked), - (not linked), โ (broken link) per runtime.
Install skill(s) to ~/.skills/ and link to runtimes.
sk install <path> # Install one skill, link to all runtimes
sk install <path> --runtime <name> # Install one skill, link to one runtime
sk install --all-from <runtime> # Batch-install all unique skills from a runtime
sk install --all-from claude --dry-run # Preview batch install, no changes| Option | Alias | Description |
|---|---|---|
--runtime <name> |
-r |
Target runtime. If omitted, links to all configured runtimes. |
--all-from <name> |
โ | Scan a runtime's skills dir and install every non-symlink skill not yet in ~/.skills/ |
--dry-run |
โ | Preview only โ no files are modified |
For single-skill install, <path> must be a directory containing a SKILL.md file. For batch install with --all-from, no <path> is needed โ the runtime's skills directory is scanned automatically.
Remove a skill from ~/.skills/ and clean up symlinks.
sk uninstall <name> --runtime <name> # Remove from one runtime only
sk uninstall <name> # Remove from all runtimes and ~/.skills/| Option | Alias | Description |
|---|---|---|
--runtime <name> |
-r |
Only remove symlink from the specified runtime. Keeps the skill in ~/.skills/. Without this flag, removes everything: symlinks, central copy, and registry entry. |
Only removes symlinks that actually point to ~/.skills/<name>. Symlinks pointing elsewhere are left untouched.
Monitor runtime skills directories for new skills in real time.
sk watch # Watch all configured runtimes
sk watch --runtime <name> # Watch one runtime only| Option | Alias | Description |
|---|---|---|
--runtime <name> |
-r |
Only watch the specified runtime. Omitting watches all configured runtimes. |
Polls every 2 seconds. Prints a notification when a new skill directory (with SKILL.md) appears. Runs until Ctrl+C.
SkillFS modifies your filesystem. We take that seriously.
| Protection | How it works |
|---|---|
| Dry run | sk dedupe --dry-run shows everything that would happen without touching a single file |
| Transactional migration | Copy โ verify โ remove โ symlink โ registry. Any failure triggers full rollback |
| Atomic file lock | O_CREAT | O_EXCL prevents two sk processes from corrupting the registry |
| Path traversal guard | All paths are validated โ config.json can't trick the scanner into reading /etc |
| Symlink target validation | Symlinks pointing outside your home directory are detected and rejected |
| Incomplete transaction detection | sk doctor flags interrupted dedupe runs and shows recovery steps |
| 127 tests | Full coverage of filesystem operations, scanner, registry, lock, and security edge cases |
npm install -g skillfs
sk doctorAfter global install, all commands are available as sk <command> anywhere.
git clone https://github.com/ares0x/skillfs.git
cd skillfs
pnpm install
pnpm run buildAfter building, use commands via one of these methods:
# Method 1: npm link (makes `sk` available globally)
npm link
sk doctor
# Method 2: pnpm dev script
pnpm run dev doctor
pnpm run dev dedupe --dry-run
pnpm run dev link --all
pnpm run dev list
# Method 3: direct Node execution
node dist/index.js doctor
node dist/index.js dedupe --dry-run
node dist/index.js link --all
node dist/index.js list- Node.js โฅ 18
- macOS or Linux (symlinks are Unix-only)
- pnpm (for development)
Got an agent that isn't in the defaults? Add it to ~/.skills/config.json:
{
"runtimes": [
{
"name": "custom-agent",
"path": "~/my-custom-agent/skills"
}
]
}Auto-discovery โ zero config. SkillFS scans ~/.*/skills/ for any directory with valid SKILL.md files. Install a new agent and sk doctor sees it immediately. No manual config, no hardcoded list to maintain. Use ~/.skills/config.json to exclude specific directories.
If you only use one agent โ you probably don't need this. If you have 27 and didn't even remember half of them, this changes everything.
src/
โโโ index.ts # Commander CLI entry (6 subcommands)
โโโ commands/
โ โโโ doctor.ts # Scan, analyze, report (human + JSON)
โ โโโ dedupe.ts # Migrate with rollback + interactive diff
โ โโโ link.ts # Symlink management
โ โโโ list.ts # Tree visualization
โ โโโ install.ts # Skill installation
โ โโโ uninstall.ts # Skill removal
โ โโโ watch.ts # Real-time directory monitor
โโโ core/
โ โโโ config.ts # Runtime definitions + custom config
โ โโโ registry.ts # ~/.skills/registry.json with atomic locking
โ โโโ scanner.ts # Multi-runtime directory scanner
โ โโโ skill.ts # SKILL.md parser + MD5 identity
โโโ utils/
โโโ fs.ts # Safe filesystem ops + path validation
โโโ lock.ts # Atomic PID-based file lock
โโโ display.ts # Terminal output formatting
Data flow: Config โ Scanner โ Skill Parser โ Registry โ Commands
The central directory ~/.skills/ becomes the single source of truth. Runtimes see symlinks that transparently resolve to it. No agent needs to know SkillFS exists.
- AI agent power users running multiple coding agents simultaneously
- Teams that want shared, version-controlled skill directories
- Anyone who ran
ls ~/.*/skillsand was surprised by the number
SkillFS auto-discovers every agent on your machine โ you don't need to remember which ones you installed. sk doctor tells you.
Bug reports and PRs welcome. Run tests before submitting:
pnpm test # 127 tests, must all pass
pnpm run build # TypeScript compilation, must succeedTests use vitest with isolated temporary directories (os.tmpdir()) โ they never touch your real ~/.skills/.
ISC ยฉ Jace (Sanage)