| 1 | #!/usr/bin/env python3 |
| 2 | """Initialize per-topic learning state directories with seeded wisdom.""" |
| 3 | |
| 4 | import argparse |
| 5 | import sys |
| 6 | from pathlib import Path |
| 7 | |
| 8 | import yaml |
| 9 | |
| 10 | SQUAD_DIR = Path(".squad") |
| 11 | |
| 12 | SEEDED_WISDOM = { |
| 13 | "ai-ml": """\ |
| 14 | # AI & Machine Learning Topic Wisdom |
| 15 | |
| 16 | ## Signal Patterns |
| 17 | - Papers with code implementations gain rapid adoption |
| 18 | - Framework-adjacent tools (PyTorch/TensorFlow ecosystem) show sustained growth |
| 19 | - LLM-related repos have high initial stars but variable retention |
| 20 | - Research reproducibility repos (paper implementations) peak early then plateau |
| 21 | |
| 22 | ## Noise Patterns |
| 23 | - Tutorial/course repos with high stars but low forks are often one-time views |
| 24 | - Wrapper libraries around APIs tend to be ephemeral |
| 25 | - Repos that only add a README without substantial code are often hype-driven |
| 26 | |
| 27 | ## Scoring Adjustments |
| 28 | - Weight Python and Jupyter Notebook repos higher |
| 29 | - Look for arXiv references as quality signals |
| 30 | - Multi-language repos (Python + C++) often indicate serious frameworks |
| 31 | """, |
| 32 | "rust": """\ |
| 33 | # Rust Topic Wisdom |
| 34 | |
| 35 | ## Signal Patterns |
| 36 | - CLI tools that replace existing Unix utilities gain rapid adoption |
| 37 | - Async runtime ecosystem tools show sustained growth |
| 38 | - WebAssembly-targeting Rust projects are emerging strongly |
| 39 | - Safety-focused alternatives to C/C++ libraries gain institutional backing |
| 40 | |
| 41 | ## Noise Patterns |
| 42 | - "Rewrite in Rust" repos without clear improvements over originals |
| 43 | - Learning projects with "rust-" prefix but minimal functionality |
| 44 | - Abandoned experimental repos from Rust newcomers |
| 45 | |
| 46 | ## Scoring Adjustments |
| 47 | - Weight Rust language repos exclusively |
| 48 | - Cross-compilation and no_std support indicate maturity |
| 49 | - Cargo ecosystem integration (published crate) is a strong signal |
| 50 | """, |
| 51 | } |
| 52 | |
| 53 | |
| 54 | def init_topic(topic_id: str, *, force: bool = False, base_dir: Path | None = None) -> Path: |
| 55 | """Create learning state directory structure for a topic. |
| 56 | |
| 57 | Returns the created topic directory path. |
| 58 | """ |
| 59 | root = (base_dir or SQUAD_DIR) / "topics" / topic_id |
| 60 | skills_dir = root / "skills" |
| 61 | scorecards_dir = root / "scorecards" |
| 62 | wisdom_file = root / "wisdom.md" |
| 63 | |
| 64 | # Create directories |
| 65 | skills_dir.mkdir(parents=True, exist_ok=True) |
| 66 | scorecards_dir.mkdir(parents=True, exist_ok=True) |
| 67 | |
| 68 | # Seed wisdom |
| 69 | if force or not wisdom_file.exists(): |
| 70 | content = SEEDED_WISDOM.get(topic_id, f"# {topic_id} Topic Wisdom\n") |
| 71 | wisdom_file.write_text(content) |
| 72 | |
| 73 | return root |
| 74 | |
| 75 | |
| 76 | def topic_id_from_config(config_path: str) -> str: |
| 77 | """Read topic.id from a YAML config file.""" |
| 78 | with open(config_path) as f: |
| 79 | data = yaml.safe_load(f) |
| 80 | return data["topic"]["id"] |
| 81 | |
| 82 | |
| 83 | def main(argv: list[str] | None = None) -> None: |
| 84 | parser = argparse.ArgumentParser(description="Initialize per-topic learning state") |
| 85 | parser.add_argument("--topic", help="Topic ID to initialize") |
| 86 | parser.add_argument("--config", help="Path to topic YAML config (reads topic.id)") |
| 87 | parser.add_argument("--force", action="store_true", help="Overwrite existing wisdom") |
| 88 | |
| 89 | args = parser.parse_args(argv) |
| 90 | |
| 91 | if not args.topic and not args.config: |
| 92 | parser.error("Provide --topic or --config") |
| 93 | |
| 94 | topic_id = args.topic or topic_id_from_config(args.config) |
| 95 | root = init_topic(topic_id, force=args.force) |
| 96 | print(f"Initialized learning state: {root}") |
| 97 | |
| 98 | |
| 99 | if __name__ == "__main__": |
| 100 | main() |