Rohan03's picture
Sprint 4D: AGENTS.md parser
c63c002 verified
"""
agents_md.py — Parser for repo-local AGENTS.md instruction files.
Precedence: system_policy > developer_config > AGENTS.md > team_purpose > skill_cards > user_task
"""
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any
logger = logging.getLogger(__name__)
@dataclass
class AgentsConfig:
instructions: list[str] = field(default_factory=list)
capabilities: dict[str, str] = field(default_factory=dict)
constraints: list[str] = field(default_factory=list)
metadata: dict[str, Any] = field(default_factory=dict)
source_path: str = ""
def to_prompt_section(self) -> str:
parts = []
if self.instructions:
parts.append("## Repository Instructions (AGENTS.md)")
for i in self.instructions: parts.append(f"- {i}")
if self.constraints:
parts.append("\n## Constraints")
for c in self.constraints: parts.append(f"- {c}")
return "\n".join(parts)
@property
def has_content(self) -> bool:
return bool(self.instructions or self.capabilities or self.constraints)
def parse_agents_md(content: str, source_path: str = "") -> AgentsConfig:
config = AgentsConfig(source_path=source_path)
if content.startswith("---"):
end = content.find("---", 3)
if end > 0: content = content[end+3:]
current = None
for line in content.split("\n"):
line = line.strip()
if line.startswith("## ") or line.startswith("# "):
h = line.lstrip("#").strip().lower()
if "instruction" in h: current = "instructions"
elif "capabilit" in h: current = "capabilities"
elif "constraint" in h: current = "constraints"
else: current = None
continue
if not line or line.startswith("<!--"): continue
item = line.lstrip("- ").lstrip("* ").strip()
if not item: continue
if current == "instructions": config.instructions.append(item)
elif current == "capabilities":
if ":" in item:
n, d = item.split(":", 1); config.capabilities[n.strip()] = d.strip()
else: config.capabilities[item] = ""
elif current == "constraints": config.constraints.append(item)
return config
def load_agents_md(path: str = "AGENTS.md") -> AgentsConfig | None:
for p in [Path(path), Path(".github/AGENTS.md"), Path("docs/AGENTS.md")]:
if p.exists():
try:
config = parse_agents_md(p.read_text(), str(p))
if config.has_content: return config
except: pass
return None