Skip to content

[Bug]: extension add --dev --force deletes the extension directory and registers nothing when source path == install path #2990

@jinaparkdev

Description

@jinaparkdev

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

  1. Have a local custom extension at .specify/extensions/code-review/ containing extension.yml and commands/speckit.code-review.md.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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