New authoring tooling and a fix for the doc-regeneration defect it exposed. Added: - src/kaizen_agentic/agent_docs.py — render + idempotent upsert of the CLAUDE.md "## Installed Agents" section (shared by installer and CLI) - `kaizen-agentic docs generate [--check]` — idempotent doc refresh / CI gate - `kaizen-agentic create-agent` — scaffold a schema-valid agent - Frontmatter schema validation in `kaizen-agentic validate` (required name/description/category, known category, valid memory/model) - tests: test_agent_docs, test_validate_schema, test_create_agent Fixed: - _update_documentation regex duplicated the Installed Agents block on every run (stopped at the first ### subheading) — now idempotent - declared frontmatter `category` is authoritative (heuristic is fallback) - list_installed_agents reads the frontmatter name, not the filename - renamed agent-project-management.md -> agent-project-assistant.md to satisfy the agent-<name>.md convention (eliminates a name/filename collision that caused install/update to write a divergent duplicate) - test_cli_error_handling no longer installs into the repo root (uses tmp) Version 1.4.0; CHANGELOG, CLI cheat sheet, agency-framework, TODO updated. Workplan KAIZEN-WP-0007 closed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 lines
2.4 KiB
Python
75 lines
2.4 KiB
Python
"""Tests for agent frontmatter schema validation (WP-0007 T03)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from kaizen_agentic.registry import AgentRegistry
|
|
|
|
REPO_AGENTS = Path(__file__).parent.parent / "agents"
|
|
|
|
|
|
def _registry(tmp_path: Path, files: dict) -> AgentRegistry:
|
|
agents = tmp_path / "agents"
|
|
agents.mkdir(parents=True)
|
|
for filename, content in files.items():
|
|
(agents / filename).write_text(content)
|
|
return AgentRegistry(agents)
|
|
|
|
|
|
class TestFrontmatterSchema:
|
|
def test_repo_agents_are_schema_valid(self):
|
|
# The shipped agents/ must always pass the schema.
|
|
assert AgentRegistry(REPO_AGENTS).validate_frontmatter_schema() == {}
|
|
|
|
def test_good_agent_passes(self, tmp_path: Path):
|
|
reg = _registry(
|
|
tmp_path,
|
|
{
|
|
"agent-good.md": (
|
|
"---\nname: good\ndescription: A fine agent\n"
|
|
"category: testing\nmemory: enabled\n---\nbody\n"
|
|
)
|
|
},
|
|
)
|
|
assert reg.validate_frontmatter_schema() == {}
|
|
|
|
def test_missing_required_fields(self, tmp_path: Path):
|
|
reg = _registry(
|
|
tmp_path,
|
|
{"agent-x.md": "---\nname: x\ncategory: testing\n---\nbody\n"},
|
|
)
|
|
errors = reg.validate_frontmatter_schema()["agent-x.md"]
|
|
assert any("description" in e for e in errors)
|
|
|
|
def test_invalid_category(self, tmp_path: Path):
|
|
reg = _registry(
|
|
tmp_path,
|
|
{
|
|
"agent-x.md": (
|
|
"---\nname: x\ndescription: d\ncategory: nonsense\n---\nb\n"
|
|
)
|
|
},
|
|
)
|
|
errors = reg.validate_frontmatter_schema()["agent-x.md"]
|
|
assert any("invalid category" in e for e in errors)
|
|
|
|
def test_invalid_memory(self, tmp_path: Path):
|
|
reg = _registry(
|
|
tmp_path,
|
|
{
|
|
"agent-x.md": (
|
|
"---\nname: x\ndescription: d\ncategory: testing\n"
|
|
"memory: maybe\n---\nb\n"
|
|
)
|
|
},
|
|
)
|
|
errors = reg.validate_frontmatter_schema()["agent-x.md"]
|
|
assert any("invalid memory" in e for e in errors)
|
|
|
|
def test_missing_frontmatter(self, tmp_path: Path):
|
|
reg = _registry(tmp_path, {"agent-x.md": "just text, no frontmatter\n"})
|
|
assert reg.validate_frontmatter_schema()["agent-x.md"] == [
|
|
"missing YAML frontmatter"
|
|
]
|