github/spec-kit · error · ValidationError

Extension ID '{manifest.id}' conflicts with core command nam

Error message

Extension ID '{manifest.id}' conflicts with core command namespace '{manifest.id}'

What it means

During command-registration validation, the extension's own ID collided with CORE_COMMAND_NAMES — the set of built-in speckit command names (analyze, checklist, clarify, constitution, converge, implement, plan, specify, tasks, taskstoissues, loaded at extensions/__init__.py:119 with a hardcoded fallback). An extension whose id equals a core command name would let it shadow or collide with core slash-commands, so the whole manifest is rejected before any of its commands are registered.

Source

Thrown at src/specify_cli/extensions/__init__.py:1096

        Performs install-time validation for extension-specific constraints:
        - primary commands must use the canonical `speckit.{extension}.{command}` shape
        - primary commands must use this extension's namespace
        - command namespaces must not shadow core commands
        - duplicate command/alias names inside one manifest are rejected
        - aliases are free-form but must remain safe relative output paths

        Args:
            manifest: Parsed extension manifest

        Returns:
            Mapping of declared command/alias name -> kind ("command"/"alias")

        Raises:
            ValidationError: If any declared name is invalid
        """
        if manifest.id in CORE_COMMAND_NAMES:
            raise ValidationError(
                f"Extension ID '{manifest.id}' conflicts with core command namespace '{manifest.id}'"
            )

        declared_names: Dict[str, str] = {}

        for cmd in manifest.commands:
            primary_name = cmd["name"]
            aliases = cmd.get("aliases", [])

            if aliases is None:
                aliases = []
            if not isinstance(aliases, list):
                raise ValidationError(
                    f"Aliases for command '{primary_name}' must be a list"
                )

            for kind, name in [("command", primary_name)] + [
                ("alias", alias) for alias in aliases

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Rename the extension id to something unique and non-core, e.g. 'plan-enhancer' instead of 'plan', and update all speckit.{id}.{cmd} command names and references to match.
  2. After renaming the id, re-check every command name follows speckit.<new-id>.<cmd>.
  3. If you hit this after a Spec Kit upgrade, check the current core command list and rename the colliding extension.

Example fix

// before (manifest)
{ "id": "plan", "commands": [{ "name": "speckit.plan.run", "file": "commands/run.md" }] }
// after
{ "id": "plan-enhancer", "commands": [{ "name": "speckit.plan-enhancer.run", "file": "commands/run.md" }] }
Defensive patterns

Strategy: validation

Validate before calling

from specify_cli.extensions import CORE_COMMAND_NAMES

if manifest["id"] in CORE_COMMAND_NAMES:
    raise SystemExit(f"id '{manifest['id']}' is reserved; rename the extension")

Type guard

def extension_id_is_safe(ext_id: str) -> bool:
    from specify_cli.extensions import CORE_COMMAND_NAMES
    return ext_id not in CORE_COMMAND_NAMES

Try / catch

try:
    ExtensionManifest.load(path)  # or command registration path
except ValidationError as e:
    if "conflicts with core command namespace" in str(e):
        # rename the extension id and all speckit.<old-id>.* command names, then retry
        ...

Prevention

When it happens

Trigger: An extension manifest with "id": "plan" or "id": "specify". The check runs at the top of the declared-names builder (extensions/__init__.py:1096) during command registration for the extension.

Common situations: Generic extension ids like 'plan', 'tasks', or 'analyze' chosen without checking the reserved list; forks renaming an extension to a short core word; core set grown in a newer Spec Kit version so a previously-acceptable id becomes reserved after upgrade.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/759604524caf8ef9. Report an issue: GitHub.