Repository navigation
Cursor skill discovery drops all workspace skills when any user-level skills folder exceeds the scan depth limit #17215
Description
Activity
Note
Grok responding on behalf of Julius.
Thanks for the detailed write-up. Reading the code on
main(12069eefd), the diagnosis looks right.What the code does
- All eight roots share one
CursorSkillScanBudget: project.cursor/.agents/.codex/.claudeskills first, then the same four under home (CursorSkills.ts:225-246). Limits areMAX_SKILL_DEPTH = 10and 10,000 entries (:26-28). - When a directory at depth 10 has a subdirectory, the walk sets
budget.exhausted = trueand stops (:207-210). Running out of entries does the same (:199-202). So hitting a limit in one subtree marks the whole scan as failed, rather than just skipping that subtree. probeCursorSkillsthen throwsCursorSkillsProbeError(scan-budget-exhausted)and discards skills it already found (:264-276).CursorDriver.snapshotForCwdturns that into aProviderDriverError(CursorDriver.ts:267-285). With no workspace snapshot, the composer appears to get no skills.- The walk has no dot-directory or
node_modulesfilter (:198-211). It also keeps going below a directory that already has aSKILL.md(:163-191). That would explain why a stale~/.claude/skills/synced/<id>/.staging/...tree can reach the depth limit.
Why it fails hard
Failing the probe appears to be deliberate. #9180, which added this scanner, says "StrictprobeCursorSkillsfails when scan budgets are exhausted". The same pattern in AntigravitySkills.ts:158 explains it: "Read failures remain typed so workspace snapshots do not cache partial results." That reasoning works for a transient read error. It doesn't work for a depth or entry limit, because the same tree fails the same way on every refresh, so retrying never recovers. A filesystem error in any root (budget.incomplete, :67, :249-253) also fails the whole probe, so an unreadable user-level folder could probably cause the same symptom.The other providers don't walk this deep. Claude reads only the direct children of each root and skips anything it can't read (ClaudeSkills.ts:315-347). Antigravity stops at the first
SKILL.mdand goes at most one level down (AntigravitySkills.ts:206-229). Grok and Codex get their skill lists from the CLI or app-server instead of scanning the filesystem.Possible fix (not yet verified against Cursor's own loader)
- When a subtree hits the depth limit, skip it instead of setting
exhausted. Keep the entry budget as a real hard stop. - Skip dot-directories and
node_modules. If Cursor's loader allows it, also stop descending once a directory has aSKILL.md. - Optionally, give each root its own budget, or return partial results with a flag, so a bad user-level root can't hide project skills.
Related
- [Bug]: Workspace skill catalogs retain failed discovery and discard newer scan results #16866 covers how failed discovery is cached and retried. Fixing that alone probably wouldn't help here, since every new scan would fail the same way.
- [Bug]: Cursor/OpenCode skill discovery returns zero skills despite skills existing on disk (Claude/Codex discover them fine) #2736 is an older issue with a similar symptom, from before the scan budget existed.
- Open PR fix(server): include Cursor plugin skills in the composer picker #16430 rewrites part of
CursorSkills.tsto add plugin skills. The plugin scan reuses the same shared budget and doesn't change the depth behavior. That would use up more of the shared entry budget, so the two changes may conflict. - fix(cursor): discover symlinked skills as package boundaries #9420 and fix(providers): discover workspace skills everywhere #9180 are the earlier Cursor discovery PRs. I didn't find an open PR that fixes this.
Workaround until then: move stale
.stagingor.trashfolders out of~/.claude/skills, as you did, then refresh providers.- All eight roots share one
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.via-triageFiled through npx t3 triageFiled through npx t3 triage
on Oct 8, 2026 Same all-or-nothing failure here, but from the 10,000 entry budget, not the depth limit. #17389 doesn't cover this. It only changes the depth path and keeps the entry-budget failure on purpose (it adds a test that a root with more than 10,000 entries still fails the probe). So this case stays broken after that PR merges.
What happened
In one workspace, Cursor threads only showed
/modeland/usage-limitsin the composer. Other workspaces were fine, so it looked intermittent.Cause
A project skill writes its run output into its own folder,
<workspace>/.cursor/skills/verify-ava/artifacts/<run-id>/(screenshots, videos, transcripts). After a month that folder had 301 runs and 10,651 entries. Max depth was 8, so the depth limit wasn't involved.Project roots are scanned first. The budget ran out inside
<workspace>/.cursor/skills(remainingEntries === 0,CursorSkills.ts:199-202),probeCursorSkillsthrewscan-budget-exhausted, and every skill got dropped, including the ones it had already found.Also,
~/.agents/skillsis a symlink to~/.claude/skillson this machine.discoverSkillsInRootcreates a newvisitedDirectoriesfor each root, and both roots resolve to the same realpath, so the same 871-entry tree is charged to the budget twice. Skills get deduped by name, but the budget doesn't.Per-root scan before the workaround
<workspace>/.cursor/skills 10,911 entries (10,651 in verify-ava/artifacts), depth 8 <workspace>/.claude/skills 8 entries ~/.cursor/skills 1 entry ~/.agents/skills 871 entries (symlink to ~/.claude/skills) ~/.codex/skills 79 entries ~/.claude/skills 871 entriesTrace
{"name":"probeCursorSkills",...,"exit":{"_tag":"Failure","cause":"CursorSkillsProbeError: Cursor skill discovery for '<workspace>' was incomplete (scan-budget-exhausted)..."}} {"name":"refreshWorkspaceSnapshot",...,"cause":"ProviderDriverError: Provider driver 'cursor' failed to create instance 'cursor': Failed to discover Cursor skills for '<workspace>'..."} {"name":"recoverRefreshFailure",...,"provider registry refresh failed; preserving cached providers"}Repro
- Workspace with any skill at
.cursor/skills/<name>/SKILL.md. mkdir -p .cursor/skills/<name>/artifacts && for i in $(seq 1 11000); do touch .cursor/skills/<name>/artifacts/f$i; done- Open a Cursor thread in that workspace and type
/. No skills, and the trace showsscan-budget-exhausted.
Suggestions beyond the triage comment
- Don't fail the probe on entry exhaustion either. Return what was found, or give each root its own budget, so one big project skill can't hide everything else.
- Stop recursing once a directory has a
SKILL.md, if Cursor's loader allows it. Thennode_modules, build output or run artifacts next to aSKILL.mdwouldn't count. - Share
visitedDirectories(or a set of root realpaths) across roots so a symlinked root is only charged once.
Workaround
Deleted the old run folders under
artifacts/and refreshed providers.Environment
T3 Code 0.0.45 (v0.0.45, 6c8fed3), desktop app (Nightly) with local server, macOS 26 arm64 (Darwin 25.5.0), Node v26.8.2.
Posted via
t3 triagewith Claude Code (Claude Opus 5.5, claude-opus-5-5).- Workspace with any skill at
What happened
When using models through the Cursor provider, neither
/slash commands nor$skill mentions show any of the skills in my project. The project has 28 skills under.agents/skillsand.claude/skills, and all of them have validSKILL.mdfiles.Diagnosis
probeCursorSkillsscans eight roots:.cursor/skills,.agents/skills,.codex/skillsand.claude/skills, first under the workspace and then under the user's home. All eight share oneCursorSkillScanBudget(10,000 entries,MAX_SKILL_DEPTH = 10). When any root contains a directory that goes past the depth limit,budget.exhaustedis set (apps/server/src/provider/Drivers/CursorSkills.ts:207-210).probeCursorSkillsthen fails the whole probe withCursorSkillsProbeError(scan-budget-exhausted)(CursorSkills.ts:268-273), even though the project roots were scanned completely first.CursorDriver.snapshotForCwd(CursorDriver.ts:235-247) turns this into aProviderDriverError, and the registry logs "provider registry refresh failed; preserving cached providers". As a result, the composer never gets the workspace skills.On this machine the deep tree is not a skill. It is leftover staging data from Claude's skill sync at
~/.claude/skills/synced/<id>/.staging/<pid>/pptx/pptx/scripts/office/schemas/ecma/fouth-edition, 11 levels below~/.claude/skills. The two staging folders date from 6 days earlier, and their PIDs are no longer running. Without that folder, the deepest path under~/.claude/skillsis 8 levels, and Cursor skill discovery works.Two behaviors make this worse:
.staging,.trash,.git,node_modulesand similar are recursed into like any other folder. Claude's skill sync writes.staging/and.trash/inside~/.claude/skills, so any user who has Claude skill sync and a deep skill package (pptx, docx or xlsx shipscripts/office/schemas/...) can hit this. Skipping dot-directories, or not recursing below a directory that already contains aSKILL.md, would avoid it.CursorSkills.tsonmainis identical to v0.0.45, so this is not fixed upstream yet.Steps to reproduce
<workspace>/.agents/skills/<name>/SKILL.md.~/.claude/skills, for examplemkdir -p ~/.claude/skills/x/.staging/1/a/b/c/d/e/f/g/h/i.$or/in the composer.server.trace.ndjsonshowsCursorSkillsProbeError ... (scan-budget-exhausted).Version
0.0.45 (v0.0.45, 6c8fed3)
Environment
Windows 11 Pro 10.0.26200 x64, Node v26.8.2, T3 Code desktop app with a local server, cursor-agent 2026.09.23-86fc751
Evidence
{"type":"effect-span","name":"probeCursorSkills",...,"exit":{"_tag":"Failure","cause":"CursorSkillsProbeError: Cursor skill discovery for '<workspace>' was incomplete (scan-budget-exhausted).\n at probeCursorSkills (.../server.asar/apps/server/dist/bin.mjs:157608:79)\n at refreshWorkspaceSnapshot (.../bin.mjs:218988:40)\n at ws.rpc.server.refreshProviders (.../bin.mjs:100908:104)"}} {"type":"effect-span","name":"refreshWorkspaceSnapshot",...,"exit":{"_tag":"Failure","cause":"ProviderDriverError: Provider driver 'cursor' failed to create instance 'cursor': Failed to discover Cursor skills for '<workspace>' ... [cause]: CursorSkillsProbeError ..."}} {"type":"effect-span","name":"recoverRefreshFailure",...,"events":[{"name":"[\"provider registry refresh failed; preserving cached providers\", ...]"}]} # Per-root scan (entries / max directory depth below the root): <workspace>/.agents/skills 137 entries, depth 2 <workspace>/.claude/skills 137 entries, depth 2 ~/.cursor/skills 2 entries, depth 1 ~/.agents/skills 2 entries, depth 1 ~/.codex/skills 71 entries, depth 3 ~/.claude/skills 557 entries, depth 11 <- synced/<id>/.staging/<pid>/pptx/pptx/scripts/office/schemas/ecma/fouth-editionRelated issues
#16866: failed workspace discovery is cached and not retried. That is related (it is why the missing skills persist), but it covers retry and caching. This issue is about why the probe fails in the first place: an unrelated over-deep user-level directory aborts all Cursor skill discovery. #2736 (closed) had a similar symptom ("Cursor/OpenCode skill discovery returns zero skills") but predates the scan budget.
Fix applied or workaround
Moved the stale
~/.claude/skills/synced/<id>/.stagingfolder out of the skills tree, then restarted the T3 Code desktop app. The problem will come back whenever Claude's skill sync leaves another stale.stagingfolder.Filed by
Claude Code (Claude Opus 5.5, claude-opus-5-5) via
t3 triage