Install command templates as agent skills. Creates ``speckit- /SKILL.md`` for each shared command template. Each SKILL.md has normalised frontmatter containing ``name``, ``description``, ``compatibility``, and ``metadata``.
(
self,
project_root: Path,
manifest: IntegrationManifest,
parsed_options: dict[str, Any] | None = None,
**opts: Any,
)
| 1375 | return self._inject_hook_command_note(content) |
| 1376 | |
| 1377 | def setup( |
| 1378 | self, |
| 1379 | project_root: Path, |
| 1380 | manifest: IntegrationManifest, |
| 1381 | parsed_options: dict[str, Any] | None = None, |
| 1382 | **opts: Any, |
| 1383 | ) -> list[Path]: |
| 1384 | """Install command templates as agent skills. |
| 1385 | |
| 1386 | Creates ``speckit-<name>/SKILL.md`` for each shared command |
| 1387 | template. Each SKILL.md has normalised frontmatter containing |
| 1388 | ``name``, ``description``, ``compatibility``, and ``metadata``. |
| 1389 | """ |
| 1390 | |
| 1391 | templates = self.list_command_templates() |
| 1392 | if not templates: |
| 1393 | return [] |
| 1394 | |
| 1395 | project_root_resolved = project_root.resolve() |
| 1396 | if manifest.project_root != project_root_resolved: |
| 1397 | raise ValueError( |
| 1398 | f"manifest.project_root ({manifest.project_root}) does not match " |
| 1399 | f"project_root ({project_root_resolved})" |
| 1400 | ) |
| 1401 | |
| 1402 | skills_dir = self.skills_dest(project_root).resolve() |
| 1403 | try: |
| 1404 | skills_dir.relative_to(project_root_resolved) |
| 1405 | except ValueError as exc: |
| 1406 | raise ValueError( |
| 1407 | f"Skills destination {skills_dir} escapes " |
| 1408 | f"project root {project_root_resolved}" |
| 1409 | ) from exc |
| 1410 | |
| 1411 | script_type = opts.get("script_type", "sh") |
| 1412 | arg_placeholder = ( |
| 1413 | self.registrar_config.get("args", "$ARGUMENTS") |
| 1414 | if self.registrar_config |
| 1415 | else "$ARGUMENTS" |
| 1416 | ) |
| 1417 | created: list[Path] = [] |
| 1418 | |
| 1419 | for src_file in templates: |
| 1420 | raw = src_file.read_text(encoding="utf-8") |
| 1421 | |
| 1422 | # Derive the skill name from the template stem |
| 1423 | command_name = src_file.stem # e.g. "plan" |
| 1424 | skill_name = f"speckit-{command_name.replace('.', '-')}" |
| 1425 | |
| 1426 | # Parse frontmatter for description |
| 1427 | frontmatter: dict[str, Any] = {} |
| 1428 | if raw.startswith("---"): |
| 1429 | parts = raw.split("---", 2) |
| 1430 | if len(parts) >= 3: |
| 1431 | try: |
| 1432 | fm = yaml.safe_load(parts[1]) |
| 1433 | if isinstance(fm, dict): |
| 1434 | frontmatter = fm |
nothing calls this directly
no test coverage detected