fix(agent): demote non-coding skill categories to names-only — never hide skills (#44342)

Real-world failure with the original index pruning: under the default auto
posture, an agent-created ops skill in a demoted category vanished from the
prompt's skill index mid-project, and the agent silently fell back to a
stale sibling skill instead. The "discovery-only" premise didn't hold —
models do not reach for skills_list to rediscover what the index stops
showing them, and agent-created skills are the model's accumulated project
memory (runbooks, pitfalls, operating rules).

Gating pruning behind the opt-in focus mode was the wrong fix too: users
opening a worktree don't know the config exists, so the index-noise win
would effectively never ship.

Instead, the coding posture now DEMOTES non-coding categories rather than
hiding them: each demoted category renders as a single names-only line
("gaming [names only]: allthemons10-ops, mc-backup") with a footer note
explaining the omitted descriptions. Every skill name stays in the prompt,
so memory-anchored recall ("load <name>") keeps working in every mode,
while the description noise is still cut. Applies in auto/on/focus alike;
the general posture demotes nothing. Deny-list semantics unchanged —
unknown/custom categories and coding-adjacent ones keep full entries.

API renamed to match the honest semantics: hidden_skill_categories →
compact_skill_categories, build_skills_system_prompt(hidden_categories=) →
compact_categories=.
This commit is contained in:
brooklyn! 2026-06-11 10:25:42 -05:00 committed by GitHub
parent 9c051f57c3
commit ee1a744ace
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 122 additions and 84 deletions

View file

@ -38,9 +38,10 @@ session (deferred), the same contract as ``/skills install`` vs ``--now``.
Activation (config ``agent.coding_context``):
* ``auto`` (default) posture (brief + snapshot) on an interactive coding
surface sitting in a code workspace (git repo or recognised project root).
Prompt-only; toolsets untouched.
* ``auto`` (default) posture (brief + snapshot + names-only demotion of
non-coding skill categories) on an interactive coding surface sitting in
a code workspace (git repo or recognised project root). Prompt-only;
toolsets untouched, no skill is ever hidden.
* ``focus`` like ``auto``, but additionally collapses the toolset to the
``coding`` set + enabled MCP servers. Explicit opt-in for a lean schema.
* ``on`` force the posture anywhere (incl. non-workspaces). Prompt-only.
@ -212,11 +213,13 @@ class ContextProfile:
``model_hint`` routing preference key for smart model routing
(extension seam; not yet consumed by the router).
``memory_policy`` memory namespace/weighting hint (extension seam).
``hidden_skill_categories`` skill categories pruned from the system-prompt
skill index while this posture is active. Discovery-only:
nothing is disabled ``skills_list`` still returns the
full catalog and ``skill_view`` loads anything. Deny-list
semantics so unknown/custom categories stay visible.
``compact_skill_categories`` skill categories DEMOTED to names-only in
the system-prompt skill index while this posture is
active. Never hidden: every skill name stays visible
(so memory-anchored recall keeps working) only the
descriptions are dropped to cut index noise. Deny-list
semantics so unknown/custom categories keep full
entries.
"""
name: str
@ -224,14 +227,14 @@ class ContextProfile:
guidance: str = ""
model_hint: Optional[str] = None
memory_policy: str = "default"
hidden_skill_categories: tuple[str, ...] = ()
compact_skill_categories: tuple[str, ...] = ()
# Skill categories that are clearly not part of a coding workflow. Hidden from
# the prompt's skill index in the coding posture (deny-list — anything not
# listed here, incl. custom user categories, stays visible). Coding-adjacent
# categories (devops, github, mcp, data-science, diagramming, research,
# security, …) are intentionally absent.
# Skill categories that are clearly not part of a coding workflow. Demoted to
# names-only in the prompt's skill index while the coding posture is active
# (deny-list — anything not listed here, incl. custom user categories, keeps
# full entries). Coding-adjacent categories (devops, github, mcp,
# data-science, diagramming, research, security, …) are intentionally absent.
_NON_CODING_SKILL_CATEGORIES = (
"apple", "communication", "cooking", "creative", "email", "finance",
"gaming", "gifs", "health", "media", "music", "note-taking",
@ -247,7 +250,7 @@ CODING_PROFILE = ContextProfile(
guidance=CODING_AGENT_GUIDANCE,
model_hint="coding",
memory_policy="project",
hidden_skill_categories=_NON_CODING_SKILL_CATEGORIES,
compact_skill_categories=_NON_CODING_SKILL_CATEGORIES,
)
_PROFILES: dict[str, ContextProfile] = {
@ -432,9 +435,20 @@ class RuntimeMode:
blocks.append(workspace)
return blocks
def hidden_skill_categories(self) -> frozenset[str]:
"""Skill categories to prune from the prompt's skill index (may be empty)."""
return frozenset(self.profile.hidden_skill_categories)
def compact_skill_categories(self) -> frozenset[str]:
"""Skill categories to demote to names-only in the prompt's skill index.
Demoted never hidden. An earlier revision fully pruned these
categories from the index, which caused silent capability loss in a
real workflow: agent-created skills are the model's accumulated
project memory (server-ops runbooks, learned pitfalls, ), and models
do not reliably reach for ``skills_list`` to rediscover what the
index stopped showing them. Names-only keeps every skill loadable on
recall while still cutting the description noise from the index.
"""
if not self.is_coding:
return frozenset()
return frozenset(self.profile.compact_skill_categories)
def resolve_runtime_mode(
@ -512,20 +526,21 @@ def coding_system_blocks(
).system_blocks()
def coding_hidden_skill_categories(
def coding_compact_skill_categories(
*,
platform: Optional[str] = None,
cwd: Optional[str | Path] = None,
config: Optional[dict[str, Any]] = None,
) -> frozenset[str]:
"""Skill categories the active posture prunes from the prompt's skill index.
"""Skill categories the active posture demotes to names-only in the index.
Empty outside the coding posture. Discovery-only: hidden skills remain
loadable via ``skills_list`` / ``skill_view``.
Empty outside the coding posture. Demoted never hidden: every skill
name stays in the index and remains loadable via ``skill_view`` /
``skills_list``; only descriptions are dropped.
"""
return resolve_runtime_mode(
platform=platform, cwd=cwd, config=config
).hidden_skill_categories()
).compact_skill_categories()
def _enabled_mcp_servers(config: Optional[dict[str, Any]]) -> list[str]: