[FEATURE] Sync Skills between Claude Desktop and Claude Code CLI
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Problem
Skills added in the Claude Desktop app (under Settings → Features → Skills) are stored in a different location than skills for Claude Code CLI (~/.claude/skills/).
This means:
Skills created in Desktop are not available in CLI
Skills created in CLI are not available in Desktop
Users have to add the same skill twice
Expected Behavior
Skills should be stored in a shared location (~/.claude/skills/) so they work in both:
Claude Desktop (with integrated Claude Code)
Claude Code CLI
Current Workaround
Manually copy skills to both locations.
Why This Matters
Claude Desktop now includes Claude Code functionality. Having a unified skill storage would provide a seamless experience across both interfaces.
Proposed Solution
Proposed Solution
Ideal User Experience:
Single storage location for all skills: ~/.claude/skills/
Both Claude Desktop and Claude Code CLI read from this location
Skills created in either interface are immediately available in both
Desktop UI syncs to filesystem
When adding a skill in Desktop Settings → Features → Skills, it creates/updates the corresponding file in ~/.claude/skills/
When editing a skill file manually, Desktop picks up the changes
Seamless workflow:
User adds skill in Desktop UI
↓
File created: ~/.claude/skills/my-skill/SKILL.md
↓
Skill available in CLI via /my-skill
And vice versa:
User creates ~/.claude/skills/project-init/SKILL.md
↓
Skill appears in Desktop Settings
↓
Skill available in Desktop via /project-init
Optional: A "Refresh Skills" button in Desktop to manually sync if needed
This would make skills truly portable and shareable, matching how other Claude Code settings (like ~/.claude/settings.json) already work across interfaces.
Alternative Solutions
_No response_
Priority
Critical - Blocking my work
Feature Category
CLI commands and flags
Use Case Example
_No response_
Additional Context
_No response_
51 Comments
+1
+1
Skill portability across Claude surfaces is a top priority for a lot of people. Having to recreate skills separately in Desktop and CLI is a real workflow killer.
claude-brain solves the cross-machine part for CLI skills — keeping your skills directory synced via git hooks. But the Desktop ↔ CLI bridge really needs native support. Would be great to see a unified skill store that works everywhere.
+1
A simple cloud backup of all skills and pulldown of the skills when needed is an absolutely necessary. There is otherwise no tracking of what version is available on which device (if at all available)
I put my support behind this too!
but, it would need to sync Web, Desktop, and CLI. So
~/.claude/skills/isn't the best place for it.Was just looking at how I can do this, glad I found this. +1
This is definitely a huge +1. I switch between coding tasks (~30% of work) and business/workflow tasks, the latter of which I tend to use the desktop app for. I don't want to keep in sync manually skills that apply in both cases.
We had a similar discussion forever ago with MCPs - but the thing was that not everyone wanted the same list of MCPs on one service/app as they did in another. You're going to use different services for different purposes and different tools (eg. MCPs) for each one.
But, skills is a little different. But there are some skills that work in claude code that won't work in Claude desktop (eg. ones that make api requests to blocked URLs or ones that can't run CLI commands in Claude desktop's sandbox)
Claude Desktop > Code tab, I believe already pulls from ~/.claude/skills/ so that's not the issue we're talking about.
For now, manually copying/downloading the skills you want from ~/.claude/skills or Claude Desktop > Cowork tab > Customize and pasting/uploading them into the other doesn't take that long really...
+1
+1
+1
This is purportedly a tool to do this: https://github.com/kcchien/skills-cli
+1
+1
+1
+1
I Added a comment to an similar issue about why the skills/connectors/plugins settings in the "customize" window of the desktop app needs to be exposed and available to interact with programatically.
#Feature Request: API for syncing skills between Claude Code and Claude Chat/Projects #47968
My comment Text:
Related Issues - For Visibility:
All open as of 2026-04-11:
(Figured I'd pull from this recent mention so that we can have this listed in thread for tracking. Thank you Kevin Deldycke)
+1
+1
+1
+1 or claude API to claude desktop app or cowork. We have a repo of internal skills that we have to upload as zip files for each change which is not optimal.
Skills are one dimension of a broader gap — connectors, memory, files, and chat history all suffer the same surface-silo problem. Filed an umbrella issue at #55842 proposing a unified user state across Cowork and chat. Skills sync is load-bearing for that.
+1
+1
+1
+1
+1
+1
+1
+1
Anthropic please, for the love of god, just implement this already! The amount of threads I see begging for this feature on social media/discord/forums without any acknowledgement from your team is ridiculous. Everyday there are new issues opened related to being able to even just programmatically access skills/plugins, let alone asking for some sort of native sync.
You don't even have to give us a native sync feature with ui/ux. Just allow us to access stored skills/sync through the api or various configuration surfaces. Thousands of creative solutions have been offered to remedy this and nothing has been accepted or listened to. The corpses of these many issues filed now pile at your feat, a monument to corporate obstinance. The collective hours wasted engineering/maintaining workarounds to this problem are a catastrophic failure of product management and engineering management.
Just pick ONE option from the many or at least offer some explanation on why this is not something being prioritized.
+1
+1
Without a solution like the one proposed here, not only does the user have to add the same skill twice, but extra work is is required to maintain them.
This can lead to clumsy workarounds like:
Yes. I can build automation to help with these items. But often this defeats the purpose of having skills in the first place!
It would be great to have full two-way synchronization of both skills in the cloud and skills in the local directory (~/.claude/skills/), and for all types of systems: Claude Chat, Claude CoWork, Claude code.
Sure. This only means the config needs a way to specify which tools are exposed to the skill / MCP.
Even better, since Claude is great but not the whole world: A tool-agnostic location for both MCP config and skills. E.g. on Linux
~/.config/agents/skillsetc.Agreed. And if Antropic feels we still need a set of desktop-only skills, then we could have a different location for those non-shared skills.
I would also really like to have this!
Adding support, with one note on scope that may be worth separating out.
The proposal here is a single shared local location read by every surface. That closes the CLI/Desktop gap, but it cannot close the cloud one: a cloud sandbox has no access to the local filesystem, so scheduled routines and Cowork still resolve skills from the account-level claude.ai deployment store regardless of what lives locally. @marr00n raised the same point earlier in this thread. #76724 confirms the resolution model with a concrete failure.
The part that bites hardest in the cloud case is that drift is silent. If a skill is edited locally and never re-uploaded, the scheduled run completes successfully against the older deployed version, with no error and no version mismatch surfaced anywhere. There is currently no way for local tooling to even ask what version is deployed.
I have filed #84611 for that narrower piece: a programmatic publish path, and a way to list deployed skills with a version or content hash so local tooling can diff local against deployed. Complementary to this issue rather than a replacement. Also relevant: #47968 asked for the API previously and was auto-closed as stale, then locked.
Until this lands natively, here's a workaround pattern I've been running daily across Claude Code CLI and Claude Desktop/Cowork on the same skills:
~/.claude/skills/<plugin>is a symlink into the repo working copy — every edit is live in the next CLI session, nothing to sync..pluginfile for upload. Two gotchas that cost me time: the filename must not contain the version (Cowork derives the plugin name from the filename, so a versioned name creates a duplicate plugin instead of updating it), and the local session cache underlocal-agent-mode-sessions/is session-scoped — don't build tooling on that path.Repo with the scripts, the skills (sanitized) and a longer write-up: https://github.com/tkkrixi/claude-docs-sync
Native support would still be much better — the manual desktop upload is the remaining friction this can't remove.
@jmaxzh Happy to clarify. My main pain point was Desktop ↔ CLI sync on a single machine: the same skills maintained once, available in both. Version conflicts and multi-user reuse were secondary for me.
Also, a correction to my earlier comment: I wrote that one manual upload per version was the lower bound. That turned out to be wrong — a git-based marketplace repo solves it, including auto-updates. The working recipe, since none of this is documented:
marketplace.jsongoes in the repo root under.claude-plugin/....menu next to the marketplace name (next to "Synced commit" and "Check for updates").versionfield in the marketplace.json plugin entry is mandatory for update detection — bumpingplugin.jsonalone leaves the "Update" button greyed out, because detection reads the marketplace manifest.Full working example (MIT): https://github.com/tkkrixi/claude-docs-sync
What's still unsolved for me: this only covers distribution. True two-way sync (edit a skill on either side, both update) still needs the git repo as the single source of truth and manual pushes.
Hey Anthropic, this "Sounds like a skill issue"!
I too would love to see first class support, for the general case of dotfile sync'ing, from Anthropic.
I have found DIY (but hacky) ways to make this work for myself using a yadm ("yet another dotfile manager"), but I don't exactly love it. There are also convoluted workarounds for the case of ephemeral sessions --which sorta work but haven't always worked right. My current method of syncing for ephemeral sessions could easily have more pitfalls I still don't know about. It feels like a potentially dangerous attack surface from a security perspective also. All compelling reasons to prefer a "blessed" solution from Anthropic.
My current solution lives in my personal (public) dotfiles repo, but I'm filing an issue against my own solution for the ephemeral case because it just doesn't feel robust enough: https://github.com/mark-brannan/dotfiles/issues/17
--Can Claude solve me problems with Claude? (skill issue)
<html><head></head><body><h1>Keeping 44 skills in sync across Cowork and Claude Code — a field report</h1>
<p><strong>Date:</strong> 2026-09-01 · <strong>Setup:</strong> macOS desktop app (Cowork) + Claude Code CLI · 44 custom skills
version-controlled in a connected folder · 7 scheduled tasks that invoke them.</p>
<p>Filing this because the existing threads
(<a href="https://github.com/anthropics/claude-code/issues/20697">#20697</a>,
<a href="https://github.com/anthropics/claude-code/issues/65928">#65928</a>,
<a href="https://github.com/anthropics/claude-code/issues/65693">#65693</a>)
describe the mechanics but not the cost. Here is the cost, measured.</p>
<hr>
<h2>The setup</h2>
<p>I maintain a Product Owner system: 44 skills that live as <code>SKILL.md</code> files in a git-tracked folder
(<code>PO-Workspace/skills/</code>), including five orchestrators that chain other skills. Seven scheduled tasks
invoke them on a weekday cadence. I work in both Cowork and Claude Code, editing the same files.</p>
<p>That is the whole ambition: <strong>one folder of skills, two surfaces, stay in sync.</strong></p>
<hr>
<h2>What it actually took</h2>
<h3>Phase 1 — Figuring out where skills even live (multiple sessions, two environments)</h3>
<p>Cowork reported <strong>40</strong> skills. Claude Code reported <strong>44</strong>. Neither number matched the <strong>44</strong> files on
disk. Reconciling that required running a session in each environment and comparing them against each
other, because no single surface can see the whole picture.</p>
<p>What I eventually had to derive empirically, because it is not documented anywhere:</p>
<ol>
<li>There is <strong>one account registry</strong> — the installed list, shared by both surfaces.</li>
<li>Each surface keeps <strong>its own file cache</strong>, and the caches can differ <em>while the registry entry is
byte-identical</em>, because the timestamp comes from the registry and the files come from a bundle
packaged at a different moment.</li>
<li><strong>Files in a folder are not installed.</strong> Writing <code>SKILL.md</code> anywhere on disk installs nothing.
There is no name-based resolution from a connected folder.</li>
<li>Entries with <code>updatedAt: null</code> are surface bundles, not installed skills — which is the entire
explanation for 44 vs 40. (<code>40 + 4 bundles = 44</code>, no drift.)</li>
</ol>
<p>None of that is in the docs. It came out of comparing two manifests by hand.</p>
<h3>Phase 2 — Detecting what was actually stale</h3>
<p><strong>The obvious test is wrong.</strong> Comparing file modification times flagged <strong>28 of 33</strong> skills as
outdated. The real number was <strong>21</strong>. Seven false positives, because a bulk backup copy on 2026-06-10
had touched mtimes on files that were byte-identical to what was installed.</p>
<p>The mirror's mtime is no better: the zip preserves the original mtime, so it reflects when the file
was written, not when it was installed. <strong>The only trustworthy signal is <code>updatedAt</code> in the
manifest.</strong></p>
<p>Then a second trap, on the content comparison itself. Normalized comparison flagged two more skills as
drifted that were in fact identical. Cause: on upload, <code>description: ></code> (folded block) is rewritten as
a quoted string, and in the process it</p>
<ul>
<li><strong>escapes internal quotes</strong> — <code>\"like this\"</code> adds one character per quote, and</li>
<li><strong>preserves multiple spaces</strong> the folded block used to collapse — two characters per gap.</li>
</ul>
<p>A normalizer that only strips wrapping quotes and trailing whitespace reports drift on files that are
the same. You must also unescape <code>\"</code> / <code>\'</code> and collapse <code>\s+</code>. Two more false positives.</p>
<p>So before comparing anything, I had to write and debug a normalizer. That is not a user-level task.</p>
<h3>Phase 3 — Installing: 6 rounds, ~40 manual uploads, 1 hard failure</h3>
<p>Every install goes through <strong>Settings → Capabilities</strong>, one file at a time, by hand. There is no bulk
import, no folder sync, no CLI path to the account registry.</p>
Round | What went up | Result
-- | -- | --
1 | 21 outdated skills | ok — registry 40
2 | 5 of the 11 missing | ok — registry 45
3 | 5 orchestrators (run-*) | ok — registry 50
4 | report | ❌ rejected
5 | po-report + run-weekly (after rename) | ok — registry 51
6 | 6 skills whose text referenced the renamed skill | ok — drift 0
<p><strong>Round 4 is the one worth reading.</strong> Uploading a skill named <code>report</code> failed with:</p>
<pre><code>A plugin named 'report' already exists.
</code></pre>
<ul>
<li>No <code>report</code> skill exists in my account. Settings → Skills, filtered by "report", shows only
<code>partner-report</code> and <code>eligibility-report</code>.</li>
<li>No <code>report</code> plugin exists in my plugin catalog or in the marketplace.</li>
<li>The colliding registration is <strong>server-side and invisible from every client surface</strong>. It cannot be
inspected and it cannot be removed.</li>
<li>The other ten skills in the same batch — <code>blast-radius</code>, <code>run-midday</code>, <code>product-refresh</code> — installed
without complaint. They have invented names. <code>report</code> is a common English word.</li>
</ul>
<p>This matches <a href="https://github.com/anthropics/claude-code/issues/65693">#65693</a> exactly, which was
closed as <em>not planned</em>.</p>
<p>The workaround is renaming, and renaming is not free. <code>report</code> → <code>po-report</code> cascaded to <strong>9 files</strong>:
the skill itself, the orchestrator that invokes it, three other orchestrators, three skills that
mention it in prose, and one scheduled task definition. Six of those then had to be <strong>reinstalled</strong>,
which is round 6 above.</p>
<h3>Phase 4 — Verification</h3>
<p>Confirming the end state meant writing a script that hashes normalized content on both sides and
diffs them. Final state: <strong>51 in the manifest, 44 of 44 PO skills installed, drift 0.</strong></p>
<p>Total span of the install phase alone: <strong>01:58 → 02:38 UTC</strong>, 40 minutes of pure clicking, on top of
the investigation that preceded it.</p>
<hr>
<h2>The worst part: neither assistant knew how it worked — or how the other one did</h2>
<p>This is the finding I did not expect, and it is the one that cost the most time.</p>
<p>Throughout this, I was working with two Claude sessions — one in Cowork, one in Claude Code — and
<strong>both were confidently wrong about their own mechanics.</strong> Not vague. Specifically, verifiably wrong,
in ways that only surfaced when something failed.</p>
<p>A partial list, all from this one day:</p>
<ul>
<li><strong>Cowork claimed it only syncs the account skill set at session start</strong>, and told me I would probably
need to reopen the session to verify an install. False. The mirror refreshed live, mid-session. It
only found out because I installed something and it re-read the manifest.</li>
<li><strong>Cowork said it had no way to hand me a save-skill button</strong>, so I spent the entire session uploading
~40 files by hand through Settings. It had a tool that renders exactly that card. It had not checked
its own tool inventory.</li>
<li><strong>Neither session could describe the other.</strong> To find out whether Claude Code can install account
skills, or whether it auto-loads from <code>~/.claude/skills/</code>, the Cowork session had to dispatch a
documentation-lookup agent. From inside one surface, the other is opaque.</li>
<li><strong>Both produced different drift lists</strong> for the same 44 files, because each was measuring against a
different copy without knowing a different copy existed.</li>
<li>The drift detection itself was <strong>wrong twice</strong> — first by trusting file dates (7 false positives),
then by under-normalizing (2 more).</li>
</ul>
<h3>And then they corrected each other, and I wrote it down as fact</h3>
<p>Because neither had ground truth, they reconciled against <em>each other</em>. One session would assert
something, the other would accept the correction, and the merged version got written into my own
project doctrine as settled.</p>
<p>At least one of those corrections was simply false. My documentation stated, as a hard rule, that all
five orchestrators "are invoked by name from the triggers." Checking the actual trigger files today:
<strong>two of them invoke by file path, not by name</strong> — meaning those two kept working the whole time the
skill was missing from the registry, while the doctrine said they were broken. I had been reasoning
about severity from a claim that no one had verified against the files.</p>
<p>That is the real failure mode, and it is worse than any single bug in this report. When the product's
internal model is undocumented, the assistants fill the gap by <em>guessing plausibly and agreeing with
each other</em> — and the user, who has no independent way to check, promotes that agreement to
documentation. I ended up as the arbiter between two Claudes, on a subject where I was the least
qualified of the three, adjudicating claims none of us could verify.</p>
<p>Everything in this report that turned out to be true, I know only because something failed loudly
enough to force a measurement.</p>
<hr>
<h2>The part that stings</h2>
<p>While writing this up I learned that Claude Code auto-loads skills from <code>~/.claude/skills/</code> and
<code>.claude/skills/</code>, by name, with live change detection — <strong>no install step at all</strong>.</p>
<p>That directory does not exist on my machine. Nobody surfaced it. I had been paying the Settings toll
for every iteration, including one-line edits, because the fast path was never visible from where I
was working. And it would not have solved the real problem anyway: Cowork does not read that
directory, and my seven scheduled tasks run in Cowork.</p>
<hr>
<h2>What would have prevented all of this</h2>
<ol>
<li><strong>Bulk/folder install.</strong> Point at a directory, install or update everything in it. ~40 individual
uploads for one library is not a workflow.</li>
<li><strong>A visible name registry.</strong> If a name is taken, let me see what holds it and release it. A
server-side registration invisible to every client is a dead end for the user.</li>
<li><strong>Namespacing</strong> — as requested in
<a href="https://github.com/anthropics/claude-code/issues/50486">#50486</a>. <code>walter/report</code> would never have
collided.</li>
<li><strong>A drift indicator.</strong> The surface knows what it installed and when. It could say "3 of your skills
differ from their source" instead of leaving users to write hash comparators.</li>
<li><strong>Document the model.</strong> Three levels — registry, per-surface cache, files on disk — and the fact
that only one of them makes a skill invocable. Four sentences in the docs would have saved a day.</li>
<li><strong>Let the assistants read their own plumbing.</strong> If a Cowork or Claude Code session could answer
"where do my skills come from, when did they last sync, and what does the other surface see"
from an actual source rather than inference, none of the guessing above would have happened.
Undocumented internals do not produce "I don't know" — they produce confident, mutually
reinforcing invention.</li>
</ol>
<h2>What I would tell another user today</h2>
<ul>
<li>Your folder is where you <strong>write</strong> skills. Settings is where you <strong>install</strong> them. Those are two
different actions and nothing warns you when you have only done the first.</li>
<li>Never trust file dates to tell you what is stale. <code>updatedAt</code> in the manifest is the only signal.</li>
<li><strong>Never name a skill with a bare common word.</strong> <code>report</code>, <code>sync</code>, <code>build</code>, <code>status</code>, <code>search</code> are
landmines. Prefix with a domain from day one — it is free at creation and expensive later.</li>
<li>If you are iterating rather than shipping, put the skill in <code>~/.claude/skills/</code> and use Claude Code.
No install step. Just know that Cowork will not see it.</li>
</ul></body></html># Keeping 44 skills in sync across Cowork and Claude Code — a field report
Date: 2026-09-01 · Setup: macOS desktop app (Cowork) + Claude Code CLI · 44 custom skills
version-controlled in a connected folder · 7 scheduled tasks that invoke them.
Filing this because the existing threads
([#20697](https://github.com/anthropics/claude-code/issues/20697),
[#65928](https://github.com/anthropics/claude-code/issues/65928),
[#65693](https://github.com/anthropics/claude-code/issues/65693))
describe the mechanics but not the cost. Here is the cost, measured.
---
The setup
I maintain a Product Owner system: 44 skills that live as
SKILL.mdfiles in a git-tracked folder(
PO-Workspace/skills/), including five orchestrators that chain other skills. Seven scheduled tasksinvoke them on a weekday cadence. I work in both Cowork and Claude Code, editing the same files.
That is the whole ambition: one folder of skills, two surfaces, stay in sync.
---
What it actually took
Phase 1 — Figuring out where skills even live (multiple sessions, two environments)
Cowork reported 40 skills. Claude Code reported 44. Neither number matched the 44 files on
disk. Reconciling that required running a session in each environment and comparing them against each
other, because no single surface can see the whole picture.
What I eventually had to derive empirically, because it is not documented anywhere:
byte-identical*, because the timestamp comes from the registry and the files come from a bundle
packaged at a different moment.
SKILL.mdanywhere on disk installs nothing.There is no name-based resolution from a connected folder.
updatedAt: nullare surface bundles, not installed skills — which is the entireexplanation for 44 vs 40. (
40 + 4 bundles = 44, no drift.)None of that is in the docs. It came out of comparing two manifests by hand.
Phase 2 — Detecting what was actually stale
The obvious test is wrong. Comparing file modification times flagged 28 of 33 skills as
outdated. The real number was 21. Seven false positives, because a bulk backup copy on 2026-06-10
had touched mtimes on files that were byte-identical to what was installed.
The mirror's mtime is no better: the zip preserves the original mtime, so it reflects when the file
was written, not when it was installed. The only trustworthy signal is
updatedAtin themanifest.
Then a second trap, on the content comparison itself. Normalized comparison flagged two more skills as
drifted that were in fact identical. Cause: on upload,
description: >(folded block) is rewritten asa quoted string, and in the process it
\"like this\"adds one character per quote, andA normalizer that only strips wrapping quotes and trailing whitespace reports drift on files that are
the same. You must also unescape
\"/\'and collapse\s+. Two more false positives.So before comparing anything, I had to write and debug a normalizer. That is not a user-level task.
Phase 3 — Installing: 6 rounds, ~40 manual uploads, 1 hard failure
Every install goes through Settings → Capabilities, one file at a time, by hand. There is no bulk
import, no folder sync, no CLI path to the account registry.
| Round | What went up | Result |
|---|---|---|
| 1 | 21 outdated skills | ok — registry 40 |
| 2 | 5 of the 11 missing | ok — registry 45 |
| 3 | 5 orchestrators (
run-*) | ok — registry 50 || 4 |
report| ❌ rejected || 5 |
po-report+run-weekly(after rename) | ok — registry 51 || 6 | 6 skills whose text referenced the renamed skill | ok — drift 0 |
Round 4 is the one worth reading. Uploading a skill named
reportfailed with:reportskill exists in my account. Settings → Skills, filtered by "report", shows onlypartner-reportandeligibility-report.reportplugin exists in my plugin catalog or in the marketplace.inspected and it cannot be removed.
blast-radius,run-midday,product-refresh— installedwithout complaint. They have invented names.
reportis a common English word.This matches [#65693](https://github.com/anthropics/claude-code/issues/65693) exactly, which was
closed as not planned.
The workaround is renaming, and renaming is not free.
report→po-reportcascaded to 9 files:the skill itself, the orchestrator that invokes it, three other orchestrators, three skills that
mention it in prose, and one scheduled task definition. Six of those then had to be reinstalled,
which is round 6 above.
Phase 4 — Verification
Confirming the end state meant writing a script that hashes normalized content on both sides and
diffs them. Final state: 51 in the manifest, 44 of 44 PO skills installed, drift 0.
Total span of the install phase alone: 01:58 → 02:38 UTC, 40 minutes of pure clicking, on top of
the investigation that preceded it.
---
The worst part: neither assistant knew how it worked — or how the other one did
This is the finding I did not expect, and it is the one that cost the most time.
Throughout this, I was working with two Claude sessions — one in Cowork, one in Claude Code — and
both were confidently wrong about their own mechanics. Not vague. Specifically, verifiably wrong,
in ways that only surfaced when something failed.
A partial list, all from this one day:
need to reopen the session to verify an install. False. The mirror refreshed live, mid-session. It
only found out because I installed something and it re-read the manifest.
~40 files by hand through Settings. It had a tool that renders exactly that card. It had not checked
its own tool inventory.
skills, or whether it auto-loads from
~/.claude/skills/, the Cowork session had to dispatch adocumentation-lookup agent. From inside one surface, the other is opaque.
different copy without knowing a different copy existed.
then by under-normalizing (2 more).
And then they corrected each other, and I wrote it down as fact
Because neither had ground truth, they reconciled against each other. One session would assert
something, the other would accept the correction, and the merged version got written into my own
project doctrine as settled.
At least one of those corrections was simply false. My documentation stated, as a hard rule, that all
five orchestrators "are invoked by name from the triggers." Checking the actual trigger files today:
two of them invoke by file path, not by name — meaning those two kept working the whole time the
skill was missing from the registry, while the doctrine said they were broken. I had been reasoning
about severity from a claim that no one had verified against the files.
That is the real failure mode, and it is worse than any single bug in this report. When the product's
internal model is undocumented, the assistants fill the gap by *guessing plausibly and agreeing with
each other* — and the user, who has no independent way to check, promotes that agreement to
documentation. I ended up as the arbiter between two Claudes, on a subject where I was the least
qualified of the three, adjudicating claims none of us could verify.
Everything in this report that turned out to be true, I know only because something failed loudly
enough to force a measurement.
---
The part that stings
While writing this up I learned that Claude Code auto-loads skills from
~/.claude/skills/and.claude/skills/, by name, with live change detection — no install step at all.That directory does not exist on my machine. Nobody surfaced it. I had been paying the Settings toll
for every iteration, including one-line edits, because the fast path was never visible from where I
was working. And it would not have solved the real problem anyway: Cowork does not read that
directory, and my seven scheduled tasks run in Cowork.
---
What would have prevented all of this
uploads for one library is not a workflow.
server-side registration invisible to every client is a dead end for the user.
[#50486](https://github.com/anthropics/claude-code/issues/50486).
walter/reportwould never havecollided.
differ from their source" instead of leaving users to write hash comparators.
that only one of them makes a skill invocable. Four sentences in the docs would have saved a day.
"where do my skills come from, when did they last sync, and what does the other surface see"
from an actual source rather than inference, none of the guessing above would have happened.
Undocumented internals do not produce "I don't know" — they produce confident, mutually
reinforcing invention.
What I would tell another user today
different actions and nothing warns you when you have only done the first.
updatedAtin the manifest is the only signal.report,sync,build,status,searcharelandmines. Prefix with a domain from day one — it is free at creation and expensive later.
~/.claude/skills/and use Claude Code.No install step. Just know that Cowork will not see it.
+1
A data point on current builds, since part of this issue may have changed.
A skill uploaded in the desktop app (Customize → Skills → + Add → Upload skill) became available in the Claude Code CLI as well as in local and cloud Cowork, within about a minute, each time with its full instructions, scripts and reference files. I measured this on one account on 2026-09-27, so it's worth confirming on yours.
So for Desktop → CLI, one upload may now be enough. Two limits:
~/.claude/skillsstill isn't seen by Cowork. For that, @tkkrixi's git-marketplace recipe above is the route I'd use.Zip tip: put the skill's folder at the top level (
my-skill/SKILL.md…), and leave out.claude-plugin/plugin.json. The uploader refuses a zip that contains a plugin manifest.Evidence and caveats:
https://ccinternals.dev/cowork/plugins-and-plugin-root/?ref=gh-issue#fact-plugins-upload-a-personal-skill
Disclosure: that's an unofficial reference I maintain, based on reverse-engineering the shipped binaries and testing live sessions. It is not affiliated with Anthropic. Measured on Desktop 2.9939.2 / agent 2.1.281; behaviour served from Anthropic's side can change without a version bump.
there should be NO upload. Simply chatting and having Claude modify the
skill should suffice, cross app or cross access method. When Claude says,
"I have updated the skill so now it does this and that...", it should make
it available in full. This is AI, not sharing XLS files in 1998.
On Mon, Sep 28, 2026 at 7:26 PM Yaniv Golan @.***>
wrote:
This has been fixed with skill and plugin sync
@wpilimon-arg you're mostly right, and most of it already exists. I checked live on 2026-09-29 (Desktop 2.9939.4):
The gaps:
So in practice: upload once if the skill has scripts, then edit by chatting.
https://ccinternals.dev/cowork/plugins-and-plugin-root/?ref=gh-issue#fact-plugins-edit-a-skill-in-chat
(Same unofficial reference as my comment above; measured on one account.)
But if you use claude code app, e.g. in Mac Os, and you edit skills by
chatting, it will prepare and pack the updated skill, but it will refuse to
show you the Update Skill button. It should be as easy as showing the
button in both flavors of the app. Ridiculous.
On Mon, Sep 28, 2026 at 8:12 PM Yaniv Golan @.***>
wrote:
I use the same skill in Claude Code, Cowork and on my claude.ai account, and it ends up as three separate copies: ~/.claude/skills, the Cowork app folder, and the account. An edit in one does not reach the others. Today I had to update a Cowork skill via the "Update skill" card in a Cowork chat, because Claude Code could not push it to the account. A single shared skill store, or at least a visible sync from Claude Code, would save me a lot of work.
+1, with a concrete case from today (Claude Max, Windows 11).
I keep one skill library and install it to two places: Cowork (server-side, via
save_skill) and Claude Code (.claude/skills/). Neither surface can see or write the other's copy. Today I updated a skill in Claude Code, and the only way to get the same change into Cowork was to leave a note in a file asking a Cowork session to runsave_skillby hand.It's sold as one product, but in practice:
save_skillexists only in Cowork.Artifact,Agent(with a model choice), hooks and native file paths exist only in Claude Code. A skill written for one surface behaves differently on the other.What would fix it: one account-level skill store that every surface reads and writes, or at least a
save_skillequivalent in Claude Code. A per-skill flag saying which surfaces it's meant for would also help.Related: #53414 (siloed across tabs, closed), #77503, #83704, #31422.