feat: extend ToolSearch deferral to plugin skills
Summary
Plugin skills inject their name and description into an <available_skills> XML block in the system prompt on every turn. There is no deferral mechanism equivalent to what built-in tools received in v2.1.69 (#31002) or what MCP tools support via defer_loading: true. The result is a fixed per-turn token cost that scales linearly with the number of installed plugins regardless of whether any of those skills are relevant to the current task.
The Numbers
A user with 14 enabled plugins has approximately 152 skills and 35 agents listed every turn. At roughly 200 characters per entry, that is ~37,400 characters (~9,350 tokens) of skill descriptions baked into every system prompt. The SLASH_COMMAND_TOOL_CHAR_BUDGET caps injection at ~1% of the context window, which on a 200K-token model still permits 8,000–16,000 characters of skill descriptions per turn as a floor.
On Opus with the 5-hour rate limit, this overhead accumulates across every session. Users who install plugins for occasional use — image generation, marketing copy, PDF export — pay the full per-turn cost even when those skills will never be invoked.
What Already Works (And Doesn't Apply Here)
Built-in tools moved behind ToolSearch deferral in v2.1.69 (#31002). The partial reversion in v2.1.72 kept 9 core tools pre-loaded and deferred the rest — a "keep essential, defer the rest" pattern that is exactly what plugin skills need. MCP tools support defer_loading: true at the API level.
Plugin skills have no equivalent. Every enabled plugin, every turn.
Current Workarounds
None of the existing options are workable:
- Disable plugins entirely — loses access to agents and bundled tools, not just skills
disable-model-invocation: truein SKILL.md — removes from context but makes it undiscoverable by Claude; manual-only invocation- Lower
SLASH_COMMAND_TOOL_CHAR_BUDGET— truncates all descriptions, degrading Claude's ability to match any skill to any task - Permission deny rules — may still inject descriptions even when invocation is blocked
Proposed Solution
Extend ToolSearch deferral to plugin skills using the existing architecture.
- Register each plugin skill as a deferred entry in the ToolSearch index, keyed on name and description, rather than injecting into
<available_skills>every turn - Claude discovers skills via ToolSearch when it encounters a relevant task — same as deferred built-in tools
- The
Skilltool itself remains pre-loaded. Only the per-skill description injection is deferred - Skills with
user-invocable: truecontinue to appear in the/command menu regardless of deferral state
| | Current | Proposed |
|---|---|---|
| Per-turn skill cost | O(n) — all installed skills | O(1) base + O(k) on query |
| Prompt cache efficiency | Low — prefix changes with skill count | Higher — stable prefix |
| Discoverability | Full descriptions always present | ToolSearch-indexed, on demand |
Related Issues
- #31002 — Built-in tools deferred behind ToolSearch
- #39686 — Cloud-synced skills silently consuming ~6K tokens with no opt-out
- #14549 — marketplace.json duplication inflating skill count
- #12836 — Original ToolSearch feature request
- #32485 — Custom agents undiscoverable via ToolSearch
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗