github/spec-kit · error · PresetValidationError

Invalid command name '{tmpl['name']}': must be lowercase alp

Error message

Invalid command name '{tmpl['name']}': must be lowercase alphanumeric with hyphens and dots only

What it means

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.

Source

Thrown at src/specify_cli/presets/__init__.py:476

            # Persist normalized value so downstream code sees lowercase
            if "strategy" in tmpl:
                tmpl["strategy"] = strategy
            if strategy not in VALID_PRESET_STRATEGIES:
                raise PresetValidationError(
                    f"Invalid strategy '{strategy}': "
                    f"must be one of {sorted(VALID_PRESET_STRATEGIES)}"
                )
            if tmpl["type"] == "script" and strategy not in VALID_SCRIPT_STRATEGIES:
                raise PresetValidationError(
                    f"Invalid strategy '{strategy}' for script: "
                    f"scripts only support {sorted(VALID_SCRIPT_STRATEGIES)}"
                )

            # Validate template name format
            if tmpl["type"] == "command":
                # Commands use dot notation (e.g. speckit.specify)
                if not re.match(r'^[a-z0-9.-]+$', tmpl["name"]):
                    raise PresetValidationError(
                        f"Invalid command name '{tmpl['name']}': "
                        "must be lowercase alphanumeric with hyphens and dots only"
                    )
            else:
                if not re.match(r'^[a-z0-9-]+$', tmpl["name"]):
                    raise PresetValidationError(
                        f"Invalid template name '{tmpl['name']}': "
                        "must be lowercase alphanumeric with hyphens only"
                    )

    @property
    def id(self) -> str:
        """Get preset ID."""
        return self.data["preset"]["id"]

    @property
    def name(self) -> str:
        """Get preset name."""

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Rename the command to kebab-case or dot notation: `speckit.build-all`, `speckit.build`.
  2. Replace underscores with hyphens and lowercase everything.
  3. Re-run the preset install after fixing preset.yml.

Example fix

# before
  - name: speckit.build_all
    type: command

# after
  - name: speckit.build-all
    type: command
Defensive patterns

Strategy: validation

Validate before calling

import re
for t in yaml.safe_load(open("preset.yml")).get("templates", []):
    if t.get("type") == "command":
        assert re.fullmatch(r"[a-z0-9.-]+", t["name"]), f"bad command name {t['name']!r}"

Type guard

import re
def is_valid_command_name(name: str) -> bool:
    return bool(re.fullmatch(r"[a-z0-9.-]+", name))

Try / catch

try:
    manager.install_from_directory(src, version)
except PresetValidationError as e:
    if "Invalid command name" in str(e):
        # convert to lowercase kebab/dot notation and retry
        ...

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


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