{"record":{"id":"759604524caf8ef9","repo":"github/spec-kit","slug":"extension-id-manifest-id-conflicts-with-core-c","errorCode":null,"errorMessage":"Extension ID '{manifest.id}' conflicts with core command namespace '{manifest.id}'","messagePattern":"Extension ID '(.+?)' conflicts with core command namespace '(.+?)'","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/extensions/__init__.py","lineNumber":1096,"sourceCode":"\n        Performs install-time validation for extension-specific constraints:\n        - primary commands must use the canonical `speckit.{extension}.{command}` shape\n        - primary commands must use this extension's namespace\n        - command namespaces must not shadow core commands\n        - duplicate command/alias names inside one manifest are rejected\n        - aliases are free-form but must remain safe relative output paths\n\n        Args:\n            manifest: Parsed extension manifest\n\n        Returns:\n            Mapping of declared command/alias name -> kind (\"command\"/\"alias\")\n\n        Raises:\n            ValidationError: If any declared name is invalid\n        \"\"\"\n        if manifest.id in CORE_COMMAND_NAMES:\n            raise ValidationError(\n                f\"Extension ID '{manifest.id}' conflicts with core command namespace '{manifest.id}'\"\n            )\n\n        declared_names: Dict[str, str] = {}\n\n        for cmd in manifest.commands:\n            primary_name = cmd[\"name\"]\n            aliases = cmd.get(\"aliases\", [])\n\n            if aliases is None:\n                aliases = []\n            if not isinstance(aliases, list):\n                raise ValidationError(\n                    f\"Aliases for command '{primary_name}' must be a list\"\n                )\n\n            for kind, name in [(\"command\", primary_name)] + [\n                (\"alias\", alias) for alias in aliases","sourceCodeStart":1078,"sourceCodeEnd":1114,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/extensions/__init__.py#L1078-L1114","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","After renaming the id, re-check every command name follows speckit.<new-id>.<cmd>.","If you hit this after a Spec Kit upgrade, check the current core command list and rename the colliding extension."],"exampleFix":"// before (manifest)\n{ \"id\": \"plan\", \"commands\": [{ \"name\": \"speckit.plan.run\", \"file\": \"commands/run.md\" }] }\n// after\n{ \"id\": \"plan-enhancer\", \"commands\": [{ \"name\": \"speckit.plan-enhancer.run\", \"file\": \"commands/run.md\" }] }","handlingStrategy":"validation","validationCode":"from specify_cli.extensions import CORE_COMMAND_NAMES\n\nif manifest[\"id\"] in CORE_COMMAND_NAMES:\n    raise SystemExit(f\"id '{manifest['id']}' is reserved; rename the extension\")","typeGuard":"def extension_id_is_safe(ext_id: str) -> bool:\n    from specify_cli.extensions import CORE_COMMAND_NAMES\n    return ext_id not in CORE_COMMAND_NAMES","tryCatchPattern":"try:\n    ExtensionManifest.load(path)  # or command registration path\nexcept ValidationError as e:\n    if \"conflicts with core command namespace\" in str(e):\n        # rename the extension id and all speckit.<old-id>.* command names, then retry\n        ...","preventionTips":["Avoid generic ids matching core commands: plan, specify, implement, analyze, clarify, converge, tasks, checklist, constitution, taskstoissues.","Prefix ids with your org/tool name (myorg-plan) to avoid collisions.","After a Spec Kit upgrade, re-check CORE_COMMAND_NAMES for newly reserved names."],"tags":["extensions","manifest","naming-convention","namespace","validation"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}