skill-profiles
v0.7.2
Published
Maintain many AI agent skills across profiles without bloat.
Maintainers
Readme
skill-profiles
Maintain many AI agent skills across profiles without bloating every session, since every skill's description eats context in the agent's prompt.
You keep every skill in one vault. At session start you load exactly one profile (plus an always-on set) into the agent that asked. Each session sees only the skills that matter for the work at hand.
Works with Claude Code, Cursor, Codex, and the shared ~/.agents/skills folder. Other agents: register their skills path with sp agent-folder add.
Think of a wardrobe. A skill is a garment; a profile is a whole outfit on one hanger — the dinner suit is jacket, trousers, shirt and shoes. The vault is the wardrobe, and the agent's skills folder is what you're wearing. You dress for one occasion at a time, and what comes off goes back on the rail, not in the bin.
Install
npm install -g skill-profiles
sp setup # deploy the trigger skill + /sp-install (Claude Code)
sp init # stand up the vault; import existing skillsThe CLI is available as skill-profiles and the short alias sp.
Mental model
- Vault — real skill files live in
~/.skill-profiles/vault/<profile>/<skill>/. Profiles are physical folders you can inspect and hand-edit. __must-use__— a special profile whose skills are always linked on every load (includes the trigger skill).__unsorted__— fallback for imports when no profile is chosen. You can also attach individual skills from it beside a loaded profile (--skill/ interactive pick); those addons do not survive the next full load.- Load is replace, not merge —
sp loadclears managed links in the agent's skills folder, then symlinks the chosen profile +__must-use__(plus any unsorted addons for this load only). - Multi-copy — the same skill name may exist in several profiles as independent copies. Names must be unique within a profile (they flatten into one agent folder on load).
- Load / scan scope — only folders listed in the archive's
agent-folders.json(four global defaults, plus any you add). Not the current project's directory; project-cwd.agents/skillsis not scanned.
Commands
Archive
init [--dry-run] Stand up the vault; import existing skills
setup Deploy trigger skill + /sp-install command
seed Create starter profiles (idempotent)
Skills
install <source> [--profile p] [--name n] [--force] [--all]
Clone a skill from git into a profile
source: owner/repo · owner/repo@skill · URL · local path
update <skill|--all> Re-fetch skill copies from recorded source
adopt [--agent id] Import stray skills from agent folders
Load
load [profile] [--agent id] [--skill name ...] [--list-unsorted]
Clear managed links; link profile + __must-use__
Optionally attach skill(s) from __unsorted__ beside it
agents: claude-code · agents · codex · cursor
Agent folders
agent-folder ls List registered skills folders
agent-folder add <path> [--name id] [--label "..."]
Register another skills folder to scan/load
agent-folder rm <id> Unregister a skills folder
Profiles
profile ls [--category c] (--category "" lists uncategorized)
profile categories
profile show <name>
profile new <name> [--desc "..."] [--category c]
profile set <name> [--desc "..."] [--category c]
profile rm <name>
profile add <name> <skill> Copy skill into profile
profile mv <skill> <from> <to> Move skill between profiles
help · --versionQuick start
sp setup
sp init
sp profile new a11y-web --desc "WCAG checks for web apps" --category compliance
sp install vercel-labs/skills@pdf --profile a11y-web
sp profile ls --category compliance
sp load a11y-web --agent claude-codeCategories
Each profile may set an optional category in profile.json (also via
--category on profile new / profile set). Categories are lowercase
labels used to filter when the vault grows large — e.g. engineering,
compliance, design.
sp profile ls --category engineering
sp profile categoriesAgent folders
A fresh archive knows four global skills folders:
| id | path |
| ------------- | ------------------ |
| claude-code | ~/.claude/skills |
| agents | ~/.agents/skills |
| codex | ~/.codex/skills |
| cursor | ~/.cursor/skills |
These are persisted in ~/.skill-profiles/agent-folders.json. Use sp agent-folder ls|add|rm to inspect or extend the list. --agent on load / adopt must be one of those ids (or an id you chose when adding a path).
init, adopt, and load only touch folders in that record — never process.cwd() project trees.
init — first-run migration
sp init creates the archive layout, scans every registered agent folder that exists on disk, prints a plan, and (after confirmation, with a backup first) triages each entry:
- dangling symlink → removed
- symlink into the vault → leave (already managed)
- external symlink / git clone → skip for now, or import a copy into the vault
- real skill (
SKILL.md) → moved into the vault (pick a profile, or__unsorted__)
Non-interactive runs send real skills to __unsorted__ and leave external links/clones alone.
Load
sp load a11y-web --agent claude-code
sp load a11y-web --agent claude-code --skill pdf --skill notes
sp load --list-unsortedsp load replaces managed links in the agent folder with the chosen profile plus __must-use__. Name collisions: __must-use__ wins over the profile.
You can attach zero-or-more skills from __unsorted__ beside that load (not instead of a profile). Use repeatable --skill <name>, or pick interactively when the TTY offers it. Collision priority is __must-use__ > active profile > unsorted addons (addon skipped with a warning). Addons are managed links, so the next plain sp load drops them.
sp load --list-unsorted prints skill names in __unsorted__ without loading.
How agents trigger it
setup writes an always-on skill-profiles skill into __must-use__ and links it into each registered agent's skills folder. Its guidance tells the agent: at session start, ask which profile to load and run sp load, always passing --agent <its-own-id> (e.g. claude-code, cursor).
Claude Code also gets a /sp-install slash command for installs.
Layout
~/.skill-profiles/ # override with SKILL_PROFILES_HOME
├── config.json # settings + derived profile index
├── agent-folders.json # registered skills folders (scan/load targets)
├── backups/<timestamp>.json # snapshot written before each destructive op
└── vault/
├── __must-use__/ # always loaded, alongside the chosen profile
│ ├── profile.json
│ └── skill-profiles/ # the trigger skill, written by `sp setup`
│ └── SKILL.md
├── __unsorted__/ # fallback when no profile is chosen
│ └── profile.json
├── <profile>/
├── profile.json # description, optional category, usage stats
└── <skill>/
├── SKILL.md
└── .skill-source.json # git origin, if installed via `sp install`Every profile directory carries a profile.json, the two seeded ones included; sp recreates them on any run if they go missing.
config.json settings:
adoptExternal—ask|auto|ignore(stray skills in agent folders)onDirtyLoad—ask|auto-import|abort(real files at load time)defaultProfile— preselected whensp loadis run without a namepreserveUnmanaged—true|false(defaultfalse). Whentrue, load leaves unmanaged entries alone (no adopt / dirty import) and skips linking a profile skill whose name is already occupied by one; whenfalse, vault-authoritative adopt/onDirtyLoadbehavior applies.
Develop
npm install
npm run build # tsc → dist/
npm run dev # watch
SKILL_PROFILES_HOME=/tmp/sp-test node dist/cli.js profile lsSee DESIGN.md for the full design and open questions.
