You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Claude skill discovery re-resolves the same repository root hundreds of times per turn #29754
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
Install several Claude Code plugins at project scope across many projects, so installed_plugins.json holds hundreds of project-scoped install records. Enable some of those plugins.
Open a thread with the Claude provider in a git repository.
Start a turn or steer a running one, and look at the server trace for the turn.
Expected behavior
Skill discovery resolves each distinct project path's repository root at most once per discovery. Discovery adds a few milliseconds to a turn start.
Actual behavior
discoverClaudeSkills runs on every Claude turn start, steer and provider refresh. Inside it, discoverPluginSkillRoots calls findPluginRepositoryRoot(record.projectPath) once for every project-scoped install record of every enabled plugin, with no memoization. Each call walks up the directory tree with one exists check per level, reads .git, commondir and gitdir, and makes two realPath calls. Both helpers are named Effect.fn, so each call also writes a span.
Measured from server traces on one install over 112 minutes:
66 discovery calls produced 20,770 findPluginRepositoryRoot spans and 20,836 findRepositoryRoot spans, about 315 lookups per discovery.
discoverPluginSkillRoots took 93 ms at the median and 230 ms at worst.
That was nearly all of the adapter time for a normal turn. startTurn took 111 ms, of which skill discovery took 110 ms. steerTurn took 143 ms, of which skill discovery took 142 ms.
The install had 480 plugin install records, 461 of them project-scoped, across only 110 distinct project paths, with 19 plugins enabled.
The two span names made up 13% of all trace bytes.
The code is in apps/server/src/provider/Drivers/ClaudeSkills.ts (findRepositoryRoot, findPluginRepositoryRoot, and the per-record filter in discoverPluginSkillRoots). The callers are in apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts.
Activity