Skip to content

fix(extensions): do not overwrite pre-existing user skills on install - #5386

Open
sx4im wants to merge 2 commits into
github:mainfrom
sx4im:fix/5380-extension-overwrites-user-skill
Open

sx4im wants to merge 2 commits into
github:mainfrom
sx4im:fix/5380-extension-overwrites-user-skill

Conversation

@sx4im

@sx4im sx4im commented Nov 11, 2026

Copy link
Copy Markdown

What broke

extension add overwrote a user's own pre-existing skill when an extension command landed on the same path, and extension remove then deleted the user's skill. The supplemental route already skipped such files, but native command registration ran first and overwrote them, stamping the extension's marker on the file.

What changed

CommandRegistrar.register_commands now checks whether an existing SKILL.md was created by the extension being installed (native, supplemental, or preset marker, or a dev-cache symlink) and skips it with a warning when it was not. A skipped skill is never registered, so remove never targets it.

How verified

New regression test in tests/test_extension_skills.py: install with a pre-existing user skill leaves the skill and its notes file untouched, and remove leaves them in place. The test fails on main and passes with the fix. Targeted suites pass: extension skills, registration, extensions, command-add, presets, bundles (1699 passed, 1 skipped). ruff check clean.

Fixes #5380

Native command registration wrote extension skills over any existing
SKILL.md at the same path, even when the file was a user's own skill
with no extension marker. The supplemental route already skipped such
files, but it ran after native registration had already overwritten
them. The overwritten file then carried the extension's marker, so
extension remove deleted the user's skill as well.

Registering a /SKILL.md output now checks whether the existing file
was created by this extension (native, supplemental, or preset marker,
or a dev-cache symlink) and skips it with a warning when it was not.
A skipped skill is never added to the registry, so remove never
targets it either.

Adds a regression test: install with a pre-existing user skill leaves
the skill and its notes file untouched, and remove leaves them in
place.

Fixes github#5380
@sx4im
sx4im requested a review from mnriem as a code owner November 11, 2026 09:42
Copilot AI auto review requested due to automatic review settings November 11, 2026 09:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The ownership guards can incorrectly accept another extension’s symlink and read non-regular targets, risking unintended skill replacement, blocked installation, or memory exhaustion.

6 open issues
What changed in this PR

Adds collision protection for user-authored skills to Spec Kit’s shared command registrar, targeting the install/remove data-loss issue in #5380.

Changes:

  • Checks ownership before replacing native SKILL.md command and alias files, warning when registration is skipped.
  • Adds an install/remove regression test verifying that an existing user skill and its notes survive.

Validation used isolated checks; project suites and the before/after regression comparison were not run.

AI-generated review by GitHub Copilot (model unknown; automated; requester identity not provided).

File Description
tests/​test_extension_skills.py Tests user-skill preservation and exclusion from registration across installation and removal.
src/​specify_cli/​agents.py Adds ownership detection and collision guards for native command and alias skills.

Review effort: Max (auto)

Comment thread src/specify_cli/agents.py
Comment on lines +638 to +639
if target is not None and ".specify-dev" in target.parts:
return True
Comment thread src/specify_cli/agents.py
Comment on lines +640 to +643
try:
raw = path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
return False
Comment thread src/specify_cli/agents.py
Comment on lines +645 to +647
source = (
fm.get("metadata", {}).get("source", "") if isinstance(fm, dict) else ""
)
Comment thread src/specify_cli/agents.py Resolved
Comment thread src/specify_cli/agents.py
Comment on lines +934 to +937
# Never overwrite a pre-existing user skill: the supplemental
# skills route already skips unowned directories, and native
# registration must do the same (#5380). The command is left
# unregistered so a later removal cannot delete it either.
Comment thread src/specify_cli/agents.py Outdated
Comment on lines +1032 to +1035
if (
agent_config["extension"] == "/SKILL.md"
and (alias_file.exists() or alias_file.is_symlink())
and not self._skill_file_owned_by_source(alias_file, source_id)
@mnriem

mnriem commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Nov 11, 2026
… routes

The github#5380 ownership guard in CommandRegistrar treated any SKILL.md not
created by the registering source as a user file and skipped it. That
broke preset registration: the preset override of speckit.specify lands
on a file init created (metadata.source templates/commands/specify.md),
so the preset was never recorded and two integration tests failed.

Judge ownership tooling-wide instead: a file is ours when its
metadata.source matches a route the tooling itself writes (extension:,
preset:, native <source_id>:<file>, or templates/commands/*.md).
User-authored files (no recognized source) are still skipped, so the
github#5380 protection is unchanged.
Copilot AI auto review requested due to automatic review settings November 11, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/specify_cli/agents.py
Comment on lines +666 to +667
and tail
and ("/" in tail or tail.endswith(".md"))
@mnriem

mnriem commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback

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.

[Bug]: extension add overwrites a pre-existing user skill; extension remove then deletes it

3 participants