What happens
Claude Code keeps entries of its own in ~/.claude/skills/. Skills enabled on claude.ai are downloaded to synced/<account>/<skill>/ and refreshed while Claude Code runs; they move to .trash/ when syncing stops, and downloads are staged in .staging/. The skills docs treat synced as a reserved name, and Claude Code loads these skills as anthropic-skills:<name>.
At global scope dotagents replaces ~/.claude/skills/ with a link to ~/.agents/skills/. Claude Code then writes synced/ into the shared directory, and Codex (recursive scan of ~/.agents/skills) and OpenCode (skills/**/SKILL.md) load the claude.ai skills as ordinary skills. On my machine that put 12 claude.ai skills into Codex, where skill-creator and pdf now appear twice next to Codex's own.
Excluding synced/ during the migration is not enough: Claude Code recreates it inside the shared directory on its next sync, because ~/.claude/skills is the link.
(sync also adopts synced, .trash, and .staging as skills and breaks agents.toml; I'm sending a separate fix for that.)
Proposal
At global scope, keep ~/.claude/skills/ a real directory and link each shared skill into it:
~/.claude/skills/<name> -> ~/.agents/skills/<name>
~/.claude/skills/synced/ (left to Claude Code)
init, install, and sync link every skill in ~/.agents/skills/, including projected plugin skills, and remove links whose skill is gone. remove unlinks right away.
- An existing directory link is replaced, and
synced/, .trash/, and .staging/ move back to ~/.claude/skills/.
sync moves a skill directory created in ~/.claude/skills/ into ~/.agents/skills/, links it back, and declares it; install only links. A name that exists on both sides is left alone, and install and sync warn.
doctor reports a directory link, missing or stale links, and skills not shared yet.
- The bundled
dotagents skill tells agents to create new skills in ~/.agents/skills/ and link them for Claude Code, so a skill created from any agent is shared right away when the guidance is followed. It is not followed every time (see below), and the next sync shares the rest.
Project scope keeps the directory link, since Claude Code does not sync into projects. Cursor uses ~/.claude/skills too, so it gets the same treatment.
What I measured
Claude Code 2.1.283, Codex CLI 0.156.0, OpenCode 1.18.31, macOS.
- Claude Code loads per-skill links in
~/.claude/skills/. A skill written to ~/.agents/skills/ and linked mid-session could be invoked in the same session about 10 seconds later, in 3 of 3 runs. Skills written directly into ~/.claude/skills/ need the same wait.
--add-dir ~/.agents (with ~/.agents/.claude/skills -> ../skills) makes Claude Code read the shared directory directly, but the same directory in permissions.additionalDirectories does not load skills. That would need a flag on every launch, so I did not pursue it.
- Asked to "turn this review procedure into a global skill" (Sonnet), Claude Code wrote to
~/.claude/skills/ in 3 of 3 runs without guidance. With the guidance above in the dotagents skill it wrote to ~/.agents/skills/ and linked it in 3 of 3 runs in a clean profile. In my own profile, with a large CLAUDE.md and requests in Japanese, the English trigger phrases matched only 2 of 5 runs; adding the request phrasing in the user's language raised it to 3 of 3. The sync fallback above covers the misses.
- After switching my own setup: Claude Code loads the 31 shared skills and the 12 claude.ai skills (as
anthropic-skills:*) and keeps refreshing ~/.claude/skills/synced/; Codex no longer sees the claude.ai skills. OpenCode still does, because it reads ~/.claude/skills/ itself; that is OpenCode's own discovery.
I have an implementation of the above with tests, reviewed and run on my machine (pnpm check on Node 20, the CI build and docs steps, and the dotagents-qa Docker checks for init, install, sync, remove, and doctor --fix). Would you take a PR along these lines? In particular:
- Is per-skill linking at global scope acceptable, or would you rather keep the directory link and handle this another way?
- Should Cursor share the per-skill behavior, or keep the directory link?
- Is moving skill directories out of
~/.claude/skills/ during sync acceptable, or should that be opt-in?
What happens
Claude Code keeps entries of its own in
~/.claude/skills/. Skills enabled on claude.ai are downloaded tosynced/<account>/<skill>/and refreshed while Claude Code runs; they move to.trash/when syncing stops, and downloads are staged in.staging/. The skills docs treatsyncedas a reserved name, and Claude Code loads these skills asanthropic-skills:<name>.At global scope dotagents replaces
~/.claude/skills/with a link to~/.agents/skills/. Claude Code then writessynced/into the shared directory, and Codex (recursive scan of~/.agents/skills) and OpenCode (skills/**/SKILL.md) load the claude.ai skills as ordinary skills. On my machine that put 12 claude.ai skills into Codex, whereskill-creatorandpdfnow appear twice next to Codex's own.Excluding
synced/during the migration is not enough: Claude Code recreates it inside the shared directory on its next sync, because~/.claude/skillsis the link.(
syncalso adoptssynced,.trash, and.stagingas skills and breaksagents.toml; I'm sending a separate fix for that.)Proposal
At global scope, keep
~/.claude/skills/a real directory and link each shared skill into it:init,install, andsynclink every skill in~/.agents/skills/, including projected plugin skills, and remove links whose skill is gone.removeunlinks right away.synced/,.trash/, and.staging/move back to~/.claude/skills/.syncmoves a skill directory created in~/.claude/skills/into~/.agents/skills/, links it back, and declares it;installonly links. A name that exists on both sides is left alone, andinstallandsyncwarn.doctorreports a directory link, missing or stale links, and skills not shared yet.dotagentsskill tells agents to create new skills in~/.agents/skills/and link them for Claude Code, so a skill created from any agent is shared right away when the guidance is followed. It is not followed every time (see below), and the nextsyncshares the rest.Project scope keeps the directory link, since Claude Code does not sync into projects. Cursor uses
~/.claude/skillstoo, so it gets the same treatment.What I measured
Claude Code 2.1.283, Codex CLI 0.156.0, OpenCode 1.18.31, macOS.
~/.claude/skills/. A skill written to~/.agents/skills/and linked mid-session could be invoked in the same session about 10 seconds later, in 3 of 3 runs. Skills written directly into~/.claude/skills/need the same wait.--add-dir ~/.agents(with~/.agents/.claude/skills -> ../skills) makes Claude Code read the shared directory directly, but the same directory inpermissions.additionalDirectoriesdoes not load skills. That would need a flag on every launch, so I did not pursue it.~/.claude/skills/in 3 of 3 runs without guidance. With the guidance above in thedotagentsskill it wrote to~/.agents/skills/and linked it in 3 of 3 runs in a clean profile. In my own profile, with a large CLAUDE.md and requests in Japanese, the English trigger phrases matched only 2 of 5 runs; adding the request phrasing in the user's language raised it to 3 of 3. Thesyncfallback above covers the misses.anthropic-skills:*) and keeps refreshing~/.claude/skills/synced/; Codex no longer sees the claude.ai skills. OpenCode still does, because it reads~/.claude/skills/itself; that is OpenCode's own discovery.I have an implementation of the above with tests, reviewed and run on my machine (
pnpm checkon Node 20, the CI build and docs steps, and thedotagents-qaDocker checks forinit,install,sync,remove, anddoctor --fix). Would you take a PR along these lines? In particular:~/.claude/skills/duringsyncacceptable, or should that be opt-in?