github/spec-kit · error · ValueError

Invalid Copilot prompt name {cmd_name!r}: {name_reason}

Error message

Invalid Copilot prompt name {cmd_name!r}: {name_reason}

What it means

write_copilot_prompt() creates the companion .prompt.md file under .github/prompts/ for a Copilot agent command. Because the file path is built as prompts_dir / f"{cmd_name}.prompt.md", the cmd_name is first checked with relative_extension_path_violation(); an unsafe name (separators, '..', absolute/anchored, empty/whitespace) raises ValueError before any write, and _ensure_inside() then backstops containment.

Source

Thrown at src/specify_cli/agents.py:995

        except (OSError, ValueError):
            # Windows often requires Developer Mode or admin privileges for
            # symlinks, and relpath can fail across drives. Keep dev installs
            # functional by falling back to a copy.
            if dest_file.is_symlink():
                dest_file.unlink()
            dest_file.write_text(content, encoding="utf-8")

    @staticmethod
    def write_copilot_prompt(project_root: Path, cmd_name: str) -> None:
        """Generate a companion .prompt.md file for a Copilot agent command.

        Args:
            project_root: Path to project root
            cmd_name: Command name (e.g. 'speckit.my-ext.example')
        """
        name_reason = relative_extension_path_violation(cmd_name)
        if name_reason:
            raise ValueError(
                f"Invalid Copilot prompt name {cmd_name!r}: {name_reason}"
            )
        prompts_dir = project_root / ".github" / "prompts"
        prompts_dir.mkdir(parents=True, exist_ok=True)
        prompt_file = prompts_dir / f"{cmd_name}.prompt.md"
        CommandRegistrar._ensure_inside(prompt_file, prompts_dir)
        prompt_file.parent.mkdir(parents=True, exist_ok=True)
        prompt_file.write_text(f"---\nagent: {cmd_name}\n---\n", encoding="utf-8")

    @staticmethod
    def _resolve_agent_dir(
        agent_name: str,
        agent_config: dict[str, Any],
        project_root: Path,
    ) -> Path:
        """Return the agent command directory, falling back to legacy_dir.

        Supports project-relative paths (e.g. ``.claude/skills/``),

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Pass a flat command name with no path components: write_copilot_prompt(root, "speckit.my-ext.example").
  2. Sanitize extension-provided names before Copilot registration (reject '/', '\', '..').
  3. Prefer dot-namespacing over slash-namespacing for Copilot command identifiers.

Example fix

# before
CommandRegistrar.write_copilot_prompt(root, "../../evil")
# after
CommandRegistrar.write_copilot_prompt(root, "speckit.example")
Defensive patterns

Strategy: validation

Validate before calling

from specify_cli import relative_extension_path_violation

if relative_extension_path_violation(cmd_name):
    raise SystemExit(f"unsafe Copilot prompt name: {cmd_name!r}")

Type guard

from specify_cli import relative_extension_path_violation

def is_safe_prompt_name(name: str) -> bool:
    """True when the Copilot prompt name passes the path-safety policy."""
    return relative_extension_path_violation(name) is None

Try / catch

try:
    CommandRegistrar.write_copilot_prompt(project_root, cmd_name)
except ValueError as exc:
    if "Invalid Copilot prompt name" in str(exc):
        raise SystemExit(f"rejected unsafe prompt name: {exc}") from exc
    raise

Prevention

When it happens

Trigger: Calling CommandRegistrar.write_copilot_prompt(root, "../evil") or a name containing '/' like "team/plan"; extension command names with traversal segments reaching the Copilot prompt-generation path.

Common situations: Copilot commands namespaced with dots or slashes ('speckit.my-ext.example' is fine; 'my/ext/../x' is not); malformed extension manifests targeting Copilot; names produced by string concatenation that accidentally include '..' or a leading '/'.

Related errors


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