A Shelf for My Agent Skills

Every coding agent I use keeps its skills in a different drawer. Claude Code reads ~/.claude/skills. Codex reads ~/.codex/skills. Cursor has its own. Then there are the per-project .claude dirs, and a few more stashed in an Obsidian vault. The copies drift. I rewrite skills I already wrote. I forget which ones even exist.
The obvious fix is to dump everything into one folder and point every agent at it. That trades one problem for a worse one: now every session loads hundreds of skill descriptions at once, and you pay for all of them on every turn, whether you use them or not.
So I made myself a tool. It is called skillshelf, and the idea is a package manager for agent skills: one canonical library, loaded on demand, never all at once.
One library, nothing auto-loads
There is exactly one copy of each skill, in a plain git repo. The library is a passive shelf. Nothing in it loads itself. I can search it, read any skill's instructions from the command line, and bundle skills by domain tag. A skill tagged both coding and bioinfo shows up in both bundles from a single copy on disk. The token cost stays near zero until I actually ask for something.

Toggle per agent, not per copy
This is the part I wanted a real interface for. Each skill has a row of toggles, one per agent: Claude, Codex, and the rest. Turning one on symlinks the skill into that agent's directory. A scope switcher at the top lets me do this globally or for just the project I'm in, so a one-off project loadout never leaks into everything else.
The state is read from the filesystem every time, never stored. The UI shows what is actually deployed, so it cannot quietly tell me a skill is on when the link is broken or a stray copy has drifted. When something is wrong it surfaces a resolve step instead of pretending.
Selective updates that never clobber my own work
Here is the reason I built this instead of living with a folder of symlinks: I am always writing new skills, and I did not want an update to ever overwrite one I am in the middle of.
So a library entry is one of two kinds. Either it owns its bytes, a real copy, good for things I downloaded and want to pin, or it is linked to its own git repo. For the skills I actively develop, I shelve a link. The dev repo stays canonical, my edits show up live, and update and outdated skip linked entries entirely. They never reach back into my working repo. For the owned ones, an update re-pulls only the instruction body and leaves my tags and notes alone, since those live in a separate file. The upstream swaps in cleanly without touching anything I added.

Why not just use Vercel's skills CLI?
Fair question. vercel-labs/skills is a good tool, and it solves the other half of the problem. Vercel's skills is a distributor: point it at a repo or the skills.sh registry and it fetches a skill and installs it into your agents in one step, where installed means present and loading. skillshelf is the librarian for the skills I already have, most of them scattered across local dirs and never published anywhere. It keeps one passive shelf, separates owning a skill from loading it, and pulls skills into a project on demand by tag, so no session pays to load the whole collection at once.
They compose, not compete. Both speak the same SKILL.md, so I can vendor something out of Vercel's ecosystem into my library, then bundle and load it like everything else. One is how a skill reaches me; the other is how I keep a hundred of them straight.
Where it is
skillshelf is a Bun CLI (skl) with a Tauri desktop app on top of the same engine. The app reads the real library, and every toggle writes the same symlinks the CLI does, so the two never disagree. It is open source.
给智能体的技能,做了个货架

我用的每个编码智能体,都把技能存在自己的抽屉里。Claude Code 读 ~/.claude/skills,Codex 读 ~/.codex/skills,Cursor 又有自己的一套。再加上一堆项目里的 .claude 目录,还有几个塞在 Obsidian 笔记库里的。副本各自漂移,我会重写早就写过的技能,也会忘了哪些已经存在。
最直接的办法,是把所有东西倒进一个文件夹,让每个智能体都指向它。但这是拿一个问题去换一个更糟的问题:现在每次会话都要一次性加载几百条技能描述,不管用不用,每一轮都得为它们付出 token 成本。
于是我给自己做了个工具,叫 skillshelf。思路是给智能体技能做一个包管理器:一个统一的规范库,按需加载,绝不一次性全装。
一个库,什么都不自动加载
每个技能只有一份副本,放在一个普通的 git 仓库里。这个库是一个被动的货架,里面没有任何东西会自己加载。我可以检索它,在命令行里读任意技能的说明,按领域标签把技能打成包。一个同时标了 coding 和 bioinfo 的技能,靠磁盘上的同一份副本,就能出现在两个包里。在我真正开口要某样东西之前,token 成本几乎为零。

按智能体切换,而不是按副本
这正是我想要一个真正界面的地方。每个技能都有一排开关,每个智能体一个:Claude、Codex,以及其余。打开其中一个,就把这个技能软链接进那个智能体的目录。顶部有一个作用域切换器,让我可以全局地做,也可以只针对当前所在的项目做,这样一次性的项目配置就不会泄漏到所有地方去。
状态每次都从文件系统读取,从不存储。界面显示的是真正部署了什么,所以它不会偷偷告诉我某个技能开着,而其实链接已经断了,或者有个野副本漂移了。出问题时,它会给出一个解决步骤,而不是假装一切正常。
有选择的更新,绝不动我自己在写的东西
我之所以做这个,而不是凑合用一堆软链接,原因就在这里:我一直在写新技能,我不想让任何一次更新覆盖掉我正写到一半的那个。
所以库里的每个条目分两种。要么它拥有自己的字节,也就是一份真正的副本,适合我下载下来、想钉住的东西;要么它链接到它自己的 git 仓库。对于我正在积极开发的技能,我货架上放的是一个链接。开发仓库始终是规范源,我的修改实时生效,而 update 和 outdated 会完全跳过链接条目,它们绝不会反过来动我的工作仓库。对于"拥有"的那一种,更新只重新拉取说明正文,不碰我加的标签和笔记(它们存在单独的文件里)。上游可以干净地替换进来,而不动我添加的任何东西。

为什么不直接用 Vercel 的 skills CLI?
合理的问题。vercel-labs/skills 是个好工具,它解决的是问题的另一半。Vercel 的 skills 是一个分发器:把它指向一个仓库或 skills.sh 注册表,它就把某个技能取下来、一步装进你的智能体里,而装好就意味着它已经在那儿、并且会加载。skillshelf 则是我已有技能的图书管理员,这些技能大多散落在本地各处,从没发布到任何地方。它只维护一个被动的货架,把"拥有一个技能"和"加载它"分开,并按标签把技能按需拉进某个项目,这样任何一次会话都不必一次性加载整个集合。
两者是互补,不是竞争。它们说的是同一种 SKILL.md 格式,所以我可以把 Vercel 生态里的某个东西收进我的库,再像对待其它技能一样给它打包、加载。一个解决技能怎么到我手里,另一个解决我怎么把上百个技能理清楚。
在哪里
skillshelf 是一个 Bun 命令行工具(skl),上面叠了一个基于同一引擎的 Tauri 桌面应用。应用读取的是真实的库,每一次切换写入的也是命令行写的那些软链接,所以两者从不打架。它是开源的。