Validate Copilot agent, skill, and command markdown files under WORKTREE/.copilot. Checks that generated agent, skill, and command markdown files have valid frontmatter and the minimum metadata Copilot needs to discover them.
(report: Report)
| 606 | |
| 607 | |
| 608 | def validate_copilot(report: Report) -> None: |
| 609 | """Validate Copilot agent, skill, and command markdown files under WORKTREE/.copilot. |
| 610 | |
| 611 | Checks that generated agent, skill, and command markdown files have valid |
| 612 | frontmatter and the minimum metadata Copilot needs to discover them. |
| 613 | """ |
| 614 | candidate_roots = [WORKTREE / ".copilot"] |
| 615 | found_any = False |
| 616 | for root in candidate_roots: |
| 617 | agents_dir = root / "agents" |
| 618 | if not agents_dir.is_dir(): |
| 619 | continue |
| 620 | found_any = True |
| 621 | for agent_md in agents_dir.glob("*.agent.md"): |
| 622 | content = agent_md.read_text(encoding="utf-8") |
| 623 | fm, _ = parse_frontmatter(content) |
| 624 | if not fm: |
| 625 | report.add( |
| 626 | severity="error", |
| 627 | harness="copilot", |
| 628 | path=agent_md, |
| 629 | message="missing or invalid frontmatter", |
| 630 | remediation="Regenerate via `make generate HARNESS=copilot`.", |
| 631 | ) |
| 632 | continue |
| 633 | _check_nonempty_str_field(report, fm, "name", "copilot", agent_md, label="agent") |
| 634 | _check_nonempty_str_field(report, fm, "description", "copilot", agent_md, label="agent") |
| 635 | # 3. Skills: validate .copilot/skills/*/SKILL.md exists and has valid frontmatter. |
| 636 | skills_dir = WORKTREE / ".copilot" / "skills" |
| 637 | if skills_dir.is_dir(): |
| 638 | found_any = True |
| 639 | for skill_md in skills_dir.glob("*/SKILL.md"): |
| 640 | content = skill_md.read_text(encoding="utf-8") |
| 641 | fm, _ = parse_frontmatter(content) |
| 642 | if not fm: |
| 643 | report.add( |
| 644 | severity="error", |
| 645 | harness="copilot", |
| 646 | path=skill_md, |
| 647 | message="missing or invalid frontmatter", |
| 648 | remediation="Regenerate via `make generate HARNESS=copilot`.", |
| 649 | ) |
| 650 | continue |
| 651 | _check_nonempty_str_field(report, fm, "name", "copilot", skill_md, label="skill") |
| 652 | _check_nonempty_str_field(report, fm, "description", "copilot", skill_md, label="skill") |
| 653 | |
| 654 | commands_dir = WORKTREE / ".copilot" / "commands" |
| 655 | if commands_dir.is_dir(): |
| 656 | found_any = True |
| 657 | for command_md in commands_dir.rglob("*.md"): |
| 658 | content = command_md.read_text(encoding="utf-8") |
| 659 | fm, body = parse_frontmatter(content) |
| 660 | if not fm: |
| 661 | report.add( |
| 662 | severity="error", |
| 663 | harness="copilot", |
| 664 | path=command_md, |
| 665 | message="missing or invalid frontmatter", |