anthropics / anthropics/claude-code
Account skills sync moves locally-installed skills out of ~/.claude/skills/ into skills/.trash, though the docs scope the sweep to skills/synced/
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
## Summary
Across seven separate events, Claude Code moved **83 skill directories that live flat at `~/.claude/skills//`** into `~/.claude/skills/.trash/`. 69 of them are a third-party skill pack installed locally two months ago by copying directories into `~/.claude/skills/` — they were never uploaded to, or enabled on, claude.ai.
`~/.claude/skills/synced/` **has never existed on this machine** — not on disk, and not in any commit of the git repository that versions `~/.claude` (checked with `git log --diff-filter=A -- 'skills/synced*'` → 0 commits).
The docs scope this mechanism to `synced/` only, so the observed behaviour appears to be a bug rather than the documented opt-out.
## Environment
- Claude Code 2.1.276 (the waves also occurred under 2.1.273 and 2.1.274)
- macOS 24.6.0, arm64
- `~/.claude/settings.json`: `"syncClaudeAiSkills": false`, `"syncClaudeAiPlugins": false`
- No `settings.local.json`, no managed settings file present
- `~/.claude` is a git repository, so every moved file is provably tracked and restorable — which is how the loss was measured precisely
## What happened
Each wave creates one `~/.claude/skills/.trash/--//` entry per skill, all sharing one timestamp, each wave under a different pid.
| # | UTC | entries |
|---|---|---|
| 1 | 2026-09-16 18:30:27 | 69 |
| 2 | 2026-09-17 07:40:47 | 69 |
| 3 | 2026-09-17 15:30:30 | 69 |
| 4 | 2026-09-17 17:28:03 | 69 |
| 5 | 2026-09-17 17:33:18 | 84 |
| 6 | 2026-09-17 20:33:11 | 69 |
| 7 | 2026-09-18 13:03:19 | 69 |
Between waves the directories were restored from git, which is why the same skills were moved repeatedly. Wave 7 happened 48 minutes after a restore, with no session started in between that I could correlate — consistent with the documented background check "about every 10 minutes" rather than with "at the next launch".
`~/.claude/plugins/synced/.bucket-_` was created at 2026-09-16 18:30:25 UTC — two seconds before wave 1 — and is empty. No `skills/synced` was ever created.
## What was moved
- **69 directories from a third-party skill pack**, installed locally on 2026-08-10 by copying them into `~/.claude/skills/`, committed to my own repo, never touched by claude.ai.
- **14 account-provisioned skills** (`xlsx`, `pptx`, `pdf`, `docx`, `docs`, `morning`, `theme-factory`, `slack-gif-creator`, `canvas-design`, `brand-guidelines`, `algorithmic-art`, `mcp-builder`, `internal-comms`, `import-memory`) — these I would expect to be in scope.
Not moved: 62 other flat directories in the same parent (my own authored skills). So the selection is not "everything under `skills/`" — but it does include locally-installed directories that were never synced.
## Why this looks like a bug
From the docs:
- `en/skills`: "Claude Code downloads your account's skills into `~/.claude/skills/synced/` in the background, then checks claude.ai for changes about every 10 minutes."
- `en/skills`: "To stop syncing on a machine, set `syncClaudeAiSkills` to `false` in your user settings. Claude Code stops downloading, and the next time it starts it moves **the skills it already synced** to `~/.claude/skills/.trash/` and no longer loads them."
- `en/skills`: personal skills live at `~/.claude/skills//SKILL.md` and are described as a separate location from claude.ai account skills.
- `en/claude-directory`: `skills/.trash/` is "synced skills that Claude Code removed".
Nothing in the docs describes a path by which a flat `~/.claude/skills//` directory that was never synced is treated as synced or swept. On this machine, directories in exactly that location, with no `synced/` present at all, are being moved.
## Reproduction
I have not reproduced this on a clean machine — it is reproducing continuously on mine, and I can run any diagnostic you would like. The shape appears to be:
1. Sign in to a claude.ai account that has account skills enabled.
2. Install a skill pack locally by copying directories into `~/.claude/skills//` (no `synced/` directory, no upload to claude.ai).
3. Set `"syncClaudeAiSkills": false` in `~/.claude/settings.json` (the waves began before I set this, so it may not be required).
4. Leave a session running, or start one, and wait.
Expected: only skills under `~/.claude/skills/synced/` are ever moved to `.trash`. Actual: flat, never-synced directories under `~/.claude/skills/` are moved.
## Impact
Every skill in the pack stops loading, silently. There is no message at the time of the move, and nothing in a session says why a skill vanished — the first wave went unnoticed for about 24 hours. Users whose `~/.claude` is not version-controlled would be relying on `.trash` alone, which the retention sweep deletes after `cleanupPeriodDays` (default 30).
## Questions
1. Is the sweep supposed to consider anything outside `~/.claude/skills/synced/`?
2. When `synced/` does not exist, does the sweep fall back to treating `~/.claude/skills/` as the synced root?
3. Is there a supported way to mark a locally-installed directory as out of scope? I could not find one in `en/skills`, `en/claude-directory`, or the settings reference.
Happy to attach the full list of moved directory names, the per-wave pids, or anything else useful.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the behavior and scope described in en/skills and en/claude-directory, then locate the background skill-sync check and any related tests. Trace how it selects directories when skills/synced/ is absent. Done means locally installed flat skills remain in place while only documented synced skills are moved to .trash.
Written by the indexing model from the issue text.
Assessment
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100