Copilot CLI plugin discovery watches unrelated runtime database writes and republishes unchanged plugins
@pwang347 is already working on this.
Since Sep 18, 2026.
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.7k
- PR merge metrics
- PR metrics pending
Description
- VS Code Version: 1.138.0, commit
7debcd0e2acdea1c52de81bf9ee1620444407dda - Copilot Chat Extension Version: built-in GitHub Copilot 0.66.0
- OS: macOS, Apple silicon
- Feature: Agents window / Copilot CLI installed-plugin discovery
- Selected model: N/A
- Extensions-disabled reproduction: not tested
Problem
I was actively running several sessions concurrently in the GitHub Copilot desktop app while VS Code remained open but unused. VS Code's renderer processes showed substantial CPU usage, and its Agents window repeatedly logged identical customization inventories.
The strongest source-level explanation is that CopilotCliAgentPluginDiscovery watches the parent ~/.copilot directory even when ~/.copilot/installed-plugins already exists. Normal Copilot database writes can therefore cause installed-plugin rediscovery. That rediscovery unconditionally republishes a new array of unchanged plugin objects, which propagates into prompt change events and full customization snapshots.
This appears to be another path to the unchanged-state notification problem previously addressed for MCP servers in #330637 / #330638.
Captured evidence
- At one hot sample, three
Code Helper (Renderer)processes used 74.7%, 46.9%, and 11.1% CPU; anotherCode Helperused 36.3%. These are process CPU percentages, not percentages of total machine capacity. I did not capture renderer CPU profiles or conclusively map each hot PID to its window. - Retained Agents-window logs contain 4,335 snapshot headers over approximately ten hours. Of these, 4,332 identify the same inactive project-session root.
- In one hot interval, 12 consecutive snapshots started within 1.856 seconds. All 12 were identical after removing timestamp/log-level prefixes: each contained 78 records and the same inventory. This is actual duplicate state, not merely similarly sized log output.
- The retained customization logs contain 338,071 lines and occupy approximately 32 MiB.
- The installed plugin skill's modification time predated the incident by several days.
- A top-level
~/.copilot/data.dbmodification time coincides to the second with a duplicate snapshot pair. This is correlation, not a captured filesystem-event trace. - A subsequent 20-second metadata poll while Copilot desktop sessions were active observed 19 changes to
platform-cache.dband one todata.db-wal, both direct children of~/.copilot. This establishes ongoing database churn, not historical attribution of every refresh. - AHP traces during the hot interval showed periodic pings rather than repeated customization protocol messages.
- VS Code shutdown was logged later in the capture. The battery-life estimate improved from about 1:53 to 3:43 over the monitoring period, but other processes also changed activity, so this is not a controlled measurement of VS Code's power consumption.
Raw logs contain private session data and are not attached. Paths and session identifiers have been omitted; only diagnostic aggregates are included.
Source-level analysis
The relevant code is present in the 1.138.0 tag:
CopilotCliAgentPluginDiscovery.start()adds the existing parent ofinstalled-pluginsto its non-recursive watcher set. Normally this includes~/.copilot. Its callback does not filter events to plugin-related paths: it schedules rediscovery and rebuilds watchers on every event.AbstractAgentPluginDiscovery._refreshPlugins()builds a fresh array, reuses existing plugin instances when appropriate, and unconditionally calls_plugins.set(plugins, undefined). Equivalent inventories therefore still publish a changed array reference.PromptsService.watchPluginPromptFilesForType()recomputes the projected prompt files and unconditionally fires a change event, without comparing the inventory with its previous value.CustomizationsDebugLogContributionlistens separately for custom-agent and slash-command changes. Each snapshot makes 24 prompt-storage listing calls, gathers source folders, and logs the inventory. If another event arrives while a snapshot is running, it immediately runs another afterward; it does not suppress identical output.
These behaviors provide a concrete mechanism for unrelated runtime writes to cause repeated discovery and diagnostic work in idle VS Code windows. The paired, identical snapshots are consistent with that mechanism. A live event trace or controlled reproduction is still needed to attribute the captured CPU to this path conclusively; the logs do not identify the originating notification.
Reproduction setup
This describes the observed setup, not a completed minimal reproduction:
- Have a CLI-installed plugin under
~/.copilot/installed-plugins/<marketplace>/<plugin>. - Open an Agents window with a selected project session.
- Leave VS Code idle while running several sessions in the GitHub Copilot desktop app, which shares
~/.copilot. - Monitor renderer CPU and duplicate output in
customizationsDebug.log.
For a focused developer test, emit an event for an unrelated direct child such as ~/.copilot/example-runtime.db while the installed-plugin directory exists and its inventory stays unchanged. Verify whether this schedules discovery, republishes plugins, and fires prompt change events.
Expected behavior / proposed regression coverage
- Unrelated runtime database writes should not refresh installed plugins or rebuild their watchers.
- Preserve detection of first installation when
installed-pluginsis absent, and of directory deletion/recreation, by filtering ancestor events to the relevant path. - Rediscovering the same ordered plugin instances should preserve the existing observable value, following the MCP fix in #330638.
- Real plugin additions, removals, and content changes must still propagate.
- Diagnostic snapshots should coalesce related notifications and avoid repeatedly logging identical state.
Separate error observed during the incident
The host also repeatedly logged:
[SessionCustomizationDiscovery] BUG: customization '.../.copilot/installed-plugins/.../skills/.../SKILL.md' of type 'skill' is outside discovered directories; creating fallback directory '.../skills/...'.
There were 48,483 occurrences across retained agent-host logs. #335500 addresses that SDK-native plugin-skill classification defect, which is still present in the 1.138.0 discovery code. It is a separate problem exposed on repeated discovery, not proof that the plugin itself causes the refresh trigger.
Related: #314805 introduced this installed-plugin discovery watcher; #330638 fixed analogous unchanged-array publications for MCP servers; #335500 addresses the skill classification error.
Drafted by Copilot with GPT-6 Astra.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.