Bug Description
Running specify extension add <path> --dev --force where <path> resolves to the extension's own install location (.specify/extensions/<id>) deletes the entire extension directory and does not register the extension. The source files are destroyed and no registration occurs — pure data loss with no successful outcome.
Steps to Reproduce
- Have a local custom extension at
.specify/extensions/code-review/ containing extension.yml and commands/speckit.code-review.md.
- Run: specify extension add .specify/extensions/code-review --dev --force
Expected Behavior
- The extension is registered (appears in
specify extension list), OR
- The command fails fast with a clear error (e.g. "source path is the install destination") without deleting anything.
Actual Behavior
.specify/extensions/code-review/ is deleted entirely (extension.yml and commands/speckit.code-review.md removed).
specify extension list still does not show the extension — registration failed.
- A catalog cache is created at
.specify/extensions/.cache/ as a side effect.
- Files were only recoverable because they happened to be tracked in git (
git checkout -- .specify/extensions/code-review/...).
Specify CLI Version
0.10.2
AI Agent
Claude Code
Operating System
macOS 25.5.0
Python Version
3.12.12
Error Logs
Additional Context
Likely cause (hypothesis)
--dev appears to create a symlink at the install destination (see #2930). With
--force, the existing destination is removed first; when source == destination, this removes the source before the link/copy step, leaving nothing. The destructive removal seems to happen before validating that the operation can complete.
Suggested fix
- Detect and reject
source == install destination before any filesystem mutation.
- Do not remove the destination until the source has been validated/staged.
- On any failure, leave the original directory untouched.
Bug Description
Running
specify extension add <path> --dev --forcewhere<path>resolves to the extension's own install location (.specify/extensions/<id>) deletes the entire extension directory and does not register the extension. The source files are destroyed and no registration occurs — pure data loss with no successful outcome.Steps to Reproduce
.specify/extensions/code-review/containingextension.ymlandcommands/speckit.code-review.md.Expected Behavior
specify extension list), ORActual Behavior
.specify/extensions/code-review/is deleted entirely (extension.ymlandcommands/speckit.code-review.mdremoved).specify extension liststill does not show the extension — registration failed..specify/extensions/.cache/as a side effect.git checkout -- .specify/extensions/code-review/...).Specify CLI Version
0.10.2
AI Agent
Claude Code
Operating System
macOS 25.5.0
Python Version
3.12.12
Error Logs
Additional Context
Likely cause (hypothesis)
--devappears to create a symlink at the install destination (see #2930). With--force, the existing destination is removed first; when source == destination, this removes the source before the link/copy step, leaving nothing. The destructive removal seems to happen before validating that the operation can complete.Suggested fix
source == install destinationbefore any filesystem mutation.