Skip to content

feat(skills): /skills picker dialog — browse, search, toggle, pick #4532

@callmeYe

Description

@callmeYe

What would you like to be added?

A skills picker dialog opened by bare /skills that combines four jobs in one panel:

  • Browse — see every skill loaded from project / user / extension / bundled scopes.
  • Search — type to fuzzy-filter the visible list.
  • Toggle — Space enables/disables a skill at workspace scope; Esc auto-saves and exits.
  • Pick — Enter on a row drops /<skill-name> into the input buffer (no auto-submit) so the user can review/edit before sending.

A new skills.disabled: string[] setting (UNION-merged across systemDefaults / user / workspace / system scopes) drives both the model-facing <available_skills> block and the /<skill-name> slash-command surface. Skills disabled at a higher scope show in a separate "locked" section in the dialog and are not toggleable from a lower scope.

Why is this needed?

Today /skills only lists skills. There's no first-class way to:

  1. Hide noise from the model. Long skill catalogs eat tokens in <available_skills>. Codex (the sibling reference at https://github.com/openai/codex) ships exactly this picker — I built feature parity here.
  2. Discover & launch quickly. Tab-completion shows skill names but not their descriptions. The dialog renders name + description + scope side-by-side, with search.
  3. Reason about visibility across scopes. When an admin disables a skill at user/system scope, the user has no visual feedback inside the workspace today — they just don't see it. The locked section makes scope precedence explicit.

Issue #3696 ("comprehensive hot-reload system") is adjacent but doesn't cover skill-level enable/disable; this is a focused, smaller addition that doesn't depend on it.

Additional context

Implementation already on a branch + PR. Highlights:

  • Live refresh, no restartConfig.disabledSkillNamesProvider is a closure over LoadedSettings attached at construction time (so the first <available_skills> build at cold-start honors persisted disables in interactive, non-interactive, AND ACP sessions). On toggle: await reloadCommands(); await skillManager.notifyConfigChanged(); — strict serialization, since notifyConfigChanged reads modelInvocableCommandsProvider which is re-registered inside the reloadCommands effect.
  • Single entry/skills opens the dialog directly. Typing /skil<Enter> from the auto-completion popup also opens the dialog (one keystroke), via a new SlashCommand.submitOnAccept opt-in flag that InputPrompt honors.
  • Same-name MCP prompt safetySkillTool.refreshSkills excludes disabled skills from fileBasedSkillNames so a same-named MCP prompt resurfaces. validateToolParams and SkillToolInvocation.execute mirror the same commandExists → disabled-branch ordering so a disabled skill never shadows an MCP prompt during validation OR execution.
  • Filter inside skill loaders only (SkillCommandLoader, BundledSkillLoader) — never via the global disabledSlashCommands denylist, which would also hide a same-named built-in command.
  • Untrusted workspace — refuses with a clear error rather than silently no-op'ing (workspace settings are dropped from the merged config when untrusted).
  • i18n — all 9 supported locales (en / zh / zh-TW / ja / fr / de / pt / ru / ca) updated; key strings added to MUST_TRANSLATE_KEYS to enforce parity going forward.
  • Tests — 31+ regression tests covering refresh order, same-name MCP prompt protection (validate + execute), execute-side guard, listing/completion/filter, untrusted workspace, UNION-blocked behavior, locked-row semantics.

PR will link to this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    category/cliCommand line interface and interactioncategory/uiUser interface and displayscope/interactiveInteractive CLI featurestype/feature-requestNew feature or enhancement request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions