github/spec-kit · error · ValueError
Integration destination {dest_resolved} escapes project root
Error message
Integration destination {dest_resolved} escapes project root {project_root_resolved} What it means
Raised by CopilotIntegration._setup_commands() (src/specify_cli/integrations/copilot/__init__.py:511) when the resolved commands destination (self.commands_dest(project_root).resolve()) does not lie under the resolved project root — Path.relative_to(project_root_resolved) raised ValueError, which is chained into this guard. It is a containment check preventing the integration from writing command files outside the project.
Source
Thrown at src/specify_cli/integrations/copilot/__init__.py:511
raise ValueError(
f"manifest.project_root ({manifest.project_root}) does not match "
f"project_root ({project_root_resolved})"
)
templates = self.list_command_templates()
if not templates:
return []
from ...presets import PresetResolver
preset_resolver = PresetResolver(project_root_resolved)
dest = self.commands_dest(project_root)
dest_resolved = dest.resolve()
try:
dest_resolved.relative_to(project_root_resolved)
except ValueError as exc:
raise ValueError(
f"Integration destination {dest_resolved} escapes "
f"project root {project_root_resolved}"
) from exc
dest.mkdir(parents=True, exist_ok=True)
created: list[Path] = []
script_type = opts.get("script_type", "sh")
arg_placeholder = self.registrar_config.get("args", "$ARGUMENTS")
# 1. Process and write command files as .agent.md
for src_file in templates:
resolved_template = preset_resolver.resolve(
f"speckit.{src_file.stem}", template_type="command"
)
source_path = resolved_template or src_file
raw = source_path.read_text(encoding="utf-8")
processed = self.process_template(
raw, self.key, script_type, arg_placeholder,View on GitHub (pinned to bf88c9f9a8)
Solutions
- Ensure the destination returned by commands_dest(project_root) resolves under project_root.resolve().
- Remove or repoint any symlinked destination directories (.github, .github/agents) inside the project.
- Pass the same resolved project_root used elsewhere in the call.
- If you subclassed CopilotIntegration, keep the destination relative and in-tree.
Example fix
# before
class MyCopilot(CopilotIntegration):
def commands_dest(self, project_root):
return Path("/opt/shared/agents") # escapes project root
# after
class MyCopilot(CopilotIntegration):
def commands_dest(self, project_root):
return project_root / ".github" / "agents" Defensive patterns
Strategy: validation
Validate before calling
root = project_root.resolve()
dest = integration.commands_dest(project_root).resolve()
try:
dest.relative_to(root)
except ValueError:
raise SystemExit(f"destination {dest} escapes {root}") Try / catch
try:
created = integration.setup(project_root, manifest)
except ValueError as e:
if "escapes project root" in str(e):
fix_symlinked_dest(project_root / ".github")
else:
raise Prevention
- Keep commands_dest() implementations relative to project_root.
- Check for and remove symlinked destination directories (.github, .github/agents).
- Pass one consistently resolved project_root to all setup calls.
When it happens
Trigger: Calling CopilotIntegration.setup(..., --commands mode) where commands_dest() resolves outside project_root — in practice caused by subclassing/overriding commands_dest(), or a symlinked destination directory pointing elsewhere, since the raw config folder (.github/agents) is normally in-tree.
Common situations: Custom integration subclass overriding commands_dest to an absolute or external path; a project directory containing a symlink like .github -> /somewhere/else; passing an inconsistent project_root that differs from the one used to build the destination.
Related errors
- Integration destination {dest} escapes project root {project
- Skills destination {new_skills_dir} contains a symlinked pat
- manifest.project_root ({manifest.project_root}) does not mat
- manifest.project_root ({manifest.project_root}) does not mat
- manifest.project_root ({manifest.project_root}) does not mat
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/b6d0eff3cbcfaf5c.
Report an issue: GitHub.