#!/usr/bin/env python3 """Build script: Generate .yaml and .json from persona .md files.""" import json import os import re import sys from pathlib import Path try: import yaml except ImportError: print("PyYAML required: pip install pyyaml") sys.exit(1) def parse_persona_md(filepath: Path) -> dict: """Parse a persona markdown file into structured data.""" content = filepath.read_text(encoding="utf-8") # Extract YAML frontmatter fm_match = re.match(r"^---\n(.*?)\n---\n(.*)$", content, re.DOTALL) if not fm_match: print(f" WARN: No frontmatter in {filepath}") return {} frontmatter = yaml.safe_load(fm_match.group(1)) body = fm_match.group(2).strip() # Extract sections from body sections = {} current_section = None current_content = [] for line in body.split("\n"): if line.startswith("## "): if current_section: sections[current_section] = "\n".join(current_content).strip() current_section = line[3:].strip().lower().replace(" ", "_").replace("&", "and") current_content = [] else: current_content.append(line) if current_section: sections[current_section] = "\n".join(current_content).strip() return { "metadata": frontmatter, "sections": sections, "raw_body": body, } def build_persona(persona_dir: Path, output_dir: Path): """Build all variants for a persona directory.""" md_files = sorted(persona_dir.glob("*.md")) if not md_files: return persona_name = persona_dir.name out_path = output_dir / persona_name out_path.mkdir(parents=True, exist_ok=True) # Load _meta.yaml if exists meta_file = persona_dir / "_meta.yaml" meta = {} if meta_file.exists(): meta = yaml.safe_load(meta_file.read_text(encoding="utf-8")) or {} for md_file in md_files: if md_file.name.startswith("_"): continue variant = md_file.stem parsed = parse_persona_md(md_file) if not parsed: continue # Merge meta into parsed data output = {**meta, **parsed["metadata"], "variant": variant, "sections": parsed["sections"]} # Write YAML yaml_out = out_path / f"{variant}.yaml" yaml_out.write_text( yaml.dump(output, allow_unicode=True, default_flow_style=False, sort_keys=False), encoding="utf-8", ) # Write JSON json_out = out_path / f"{variant}.json" json_out.write_text(json.dumps(output, ensure_ascii=False, indent=2), encoding="utf-8") # Write plain system prompt (just the body) prompt_out = out_path / f"{variant}.prompt.md" prompt_out.write_text(parsed["raw_body"], encoding="utf-8") print(f" Built: {persona_name}/{variant} -> .yaml .json .prompt.md") def build_catalog(personas_dir: Path, output_dir: Path): """Generate CATALOG.md from all personas.""" catalog_lines = ["# Persona Catalog\n", "_Auto-generated by build.py_\n"] for persona_dir in sorted(personas_dir.iterdir()): if not persona_dir.is_dir() or persona_dir.name.startswith((".", "_")): continue meta_file = persona_dir / "_meta.yaml" if not meta_file.exists(): continue meta = yaml.safe_load(meta_file.read_text(encoding="utf-8")) or {} variants = [f.stem for f in sorted(persona_dir.glob("*.md")) if not f.name.startswith("_")] catalog_lines.append(f"## {meta.get('codename', persona_dir.name)} — {meta.get('role', 'Unknown')}") catalog_lines.append(f"- **Domain:** {meta.get('domain', 'N/A')}") catalog_lines.append(f"- **Hitap:** {meta.get('address_to', 'N/A')}") catalog_lines.append(f"- **Variants:** {', '.join(variants)}") catalog_lines.append("") catalog_path = personas_dir / "CATALOG.md" catalog_path.write_text("\n".join(catalog_lines), encoding="utf-8") print(f" Catalog: {catalog_path}") def main(): root = Path(__file__).parent personas_dir = root / "personas" if not personas_dir.exists(): print("No personas/ directory found.") sys.exit(1) output_dir = root / ".generated" # Find all persona directories persona_dirs = [ d for d in sorted(personas_dir.iterdir()) if d.is_dir() and not d.name.startswith((".", "_")) ] if not persona_dirs: print("No persona directories found.") sys.exit(1) output_dir.mkdir(parents=True, exist_ok=True) print(f"Building {len(persona_dirs)} personas -> {output_dir}\n") for pdir in persona_dirs: build_persona(pdir, output_dir) build_catalog(personas_dir, output_dir) print(f"\nDone. {len(persona_dirs)} personas built.") if __name__ == "__main__": main()