{"record":{"id":"dbefca010c90d98a","repo":"github/spec-kit","slug":"invalid-command-name-tmpl-name-must-be-low","errorCode":null,"errorMessage":"Invalid command name '{tmpl['name']}': must be lowercase alphanumeric with hyphens and dots only","messagePattern":"Invalid command name '(.+?)': must be lowercase alphanumeric with hyphens and dots only","errorType":"validation","errorClass":"PresetValidationError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/presets/__init__.py","lineNumber":476,"sourceCode":"            # Persist normalized value so downstream code sees lowercase\n            if \"strategy\" in tmpl:\n                tmpl[\"strategy\"] = strategy\n            if strategy not in VALID_PRESET_STRATEGIES:\n                raise PresetValidationError(\n                    f\"Invalid strategy '{strategy}': \"\n                    f\"must be one of {sorted(VALID_PRESET_STRATEGIES)}\"\n                )\n            if tmpl[\"type\"] == \"script\" and strategy not in VALID_SCRIPT_STRATEGIES:\n                raise PresetValidationError(\n                    f\"Invalid strategy '{strategy}' for script: \"\n                    f\"scripts only support {sorted(VALID_SCRIPT_STRATEGIES)}\"\n                )\n\n            # Validate template name format\n            if tmpl[\"type\"] == \"command\":\n                # Commands use dot notation (e.g. speckit.specify)\n                if not re.match(r'^[a-z0-9.-]+$', tmpl[\"name\"]):\n                    raise PresetValidationError(\n                        f\"Invalid command name '{tmpl['name']}': \"\n                        \"must be lowercase alphanumeric with hyphens and dots only\"\n                    )\n            else:\n                if not re.match(r'^[a-z0-9-]+$', tmpl[\"name\"]):\n                    raise PresetValidationError(\n                        f\"Invalid template name '{tmpl['name']}': \"\n                        \"must be lowercase alphanumeric with hyphens only\"\n                    )\n\n    @property\n    def id(self) -> str:\n        \"\"\"Get preset ID.\"\"\"\n        return self.data[\"preset\"][\"id\"]\n\n    @property\n    def name(self) -> str:\n        \"\"\"Get preset name.\"\"\"","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/presets/__init__.py#L458-L494","documentation":"Template entries with `type: command` must have a `name` matching ^[a-z0-9.-]+$ — lowercase letters, digits, hyphens, and dots (dot notation like `speckit.build`). Any uppercase letter, underscore, space, or other character fails this regex check during manifest validation.","triggerScenarios":"A preset.yml command template named `speckit.build_all`, `Speckit.Build`, or `speckit build` (space). The check runs on every command-type template during PresetManifest validation, i.e. at install time.","commonSituations":"Using snake_case command names (common in other CLI conventions), capitalized names, or names copied from filenames with spaces. The dot is allowed specifically because commands use dot notation (e.g. speckit.specify).","solutions":["Rename the command to kebab-case or dot notation: `speckit.build-all`, `speckit.build`.","Replace underscores with hyphens and lowercase everything.","Re-run the preset install after fixing preset.yml."],"exampleFix":"# before\n  - name: speckit.build_all\n    type: command\n\n# after\n  - name: speckit.build-all\n    type: command","handlingStrategy":"validation","validationCode":"import re\nfor t in yaml.safe_load(open(\"preset.yml\")).get(\"templates\", []):\n    if t.get(\"type\") == \"command\":\n        assert re.fullmatch(r\"[a-z0-9.-]+\", t[\"name\"]), f\"bad command name {t['name']!r}\"","typeGuard":"import re\ndef is_valid_command_name(name: str) -> bool:\n    return bool(re.fullmatch(r\"[a-z0-9.-]+\", name))","tryCatchPattern":"try:\n    manager.install_from_directory(src, version)\nexcept PresetValidationError as e:\n    if \"Invalid command name\" in str(e):\n        # convert to lowercase kebab/dot notation and retry\n        ...","preventionTips":["Command names: lowercase letters, digits, hyphens, dots only (dot notation like speckit.build).","No underscores or uppercase — convert snake_case to kebab-case.","Add a preset.yml lint step to your preset's CI."],"tags":["preset","validation","naming","command"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}