Skip to content

fix(extensions): register commands on enable after an integration change - #5014

Open
yxshee wants to merge 1 commit into
github:mainfrom
yxshee:fix/extension-enable-after-integration-switch
Open

yxshee wants to merge 1 commit into
github:mainfrom
yxshee:fix/extension-enable-after-integration-switch

Conversation

@yxshee

@yxshee yxshee commented Oct 17, 2026

Copy link
Copy Markdown

Description

An extension that is disabled while the project changes integration comes back "enabled" with no commands for the new agent. docs/reference/extensions.md describes disable as temporary ("Re-enable with enable"), but here re-enabling silently restores nothing:

$ specify init p --integration claude --ignore-agent-tools --non-interactive && cd p
$ specify extension add --dev ../jira          # one command: speckit.jira.sync-issues
$ specify extension disable jira
$ specify integration switch gemini
$ specify extension enable jira
✓ Extension 'Jira' enabled
# .specify/extensions/.registry -> jira: enabled=True, registered_commands={}
# ls .gemini/commands | grep jira -> nothing

integration install gemini followed by integration use gemini gives the same result. The only ways back are selecting the integration again or reinstalling the extension.

Root cause:

  • integration switch and integration use register only enabled extensions for the agent they activate (register_enabled_extensions_for_agent skips disabled entries).
  • switch also removes a disabled extension's commands from the previous agent.
  • extension enable (extensions/command_enable.py) then only flips the registry flag and re-enables hooks. Every integration except generic gets no registration at all.

The fix:

  • register_enabled_extensions_for_agent() gains a keyword-only extension_ids filter, so a single extension can be registered.
  • For non-generic agents, enable calls it for this one extension, but only when the registry has no commands recorded for the active agent.
  • A plain disable/enable cycle, where the commands are still registered, leaves the agent's files untouched.
  • Agents that take extension commands as skills (e.g. Copilot with --skills) only get missing skill files written.

With the change, the same steps end with:

$ specify extension enable jira
✓ Extension 'Jira' enabled
# registry -> jira: enabled=True, registered_commands={'gemini': ['speckit.jira.sync-issues']}
# .gemini/commands now contains the jira command

Overlap: your open PRs #4959 and #4883 also edit extensions/command_enable.py. Neither touches this case, but they will conflict textually with this change. If #4959 lands first, this logic belongs in ExtensionManager.enable(), and the PR can be rebased onto that.

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable): the reproduction above, on main and on this branch

New tests in tests/specify_cli/extensions/test_command_enable.py, each parametrized over claude and copilot with --skills:

  • test_enable_registers_commands_for_integration_switched_while_disabled: fails on main (the extension's SKILL.md is missing after enable) and passes with the change
  • test_enable_leaves_commands_still_registered_for_active_integration: the negative case. A hand-edited skill survives a disable/enable cycle and the registry is unchanged. It passes before and after.

The file gives 5 passed with the change (2 failed on main).

  • Focused suites (tests/specify_cli/extensions, test_command_switch, test_command_use, test_extensions, test_extension_skills, test_extension_registration, test_integration_generic): 1095 passed.
  • Full suite (macOS, Python 3.13): 12334 passed, 376 skipped. 11 failures in the tests/test_*_python_parity.py files occur identically on unmodified main on this machine under full-suite load; those files pass when run on their own (257 passed, 112 skipped).
  • uvx ruff@0.15.0 check src tests: clean

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: Claude Code (model: Claude Opus 5.5, max reasoning effort, autonomous agent mode) opened this PR on behalf of @yxshee. A Claude Code subagent (same model, autonomous) found the bug and wrote the fix and tests. The lead agent independently re-ran the new tests against main and the branch, reproduced the behavior above with the real CLI, reviewed the diff, and wrote this description. No human reviewed the change line by line before it was opened.

🤖 Generated with Claude Code

`integration switch` and `integration use` register only enabled
extensions for the agent they activate, and `switch` also removes a
disabled extension's commands from the previous agent. For every
integration except `generic`, `extension enable` only flipped the
registry flag and re-enabled hooks, so an extension disabled across a
switch or use came back "enabled" with no commands for the active
agent: no skill or command file and nothing for that agent in
`registered_commands`, until the integration is selected again or the
extension is reinstalled.

When the registry has no commands for the active agent, `enable` now
registers the extension through register_enabled_extensions_for_agent,
which gains an `extension_ids` filter so only that extension is touched.
A plain disable/enable cycle, where the commands are still registered,
leaves the agent's files alone; agents that take extension commands as
skills (Copilot with --skills) only get missing skill files written.

Assisted-by: Claude Code (model: Claude Opus 5.5, autonomous)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yxshee
yxshee requested a review from mnriem as a code owner October 17, 2026 19:16
@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Oct 18, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-must-have Verdict: high-value, important work for Spec Kit — do first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants