← back to Knowledge Layer Skill

knowledge-layer/scripts/kl_init.py

120 lines

#!/usr/bin/env python3
"""
kl_init.py — scaffold a new Knowledge Layer instance.

A Knowledge Layer is a plain-directory, LLM-compiled wiki (the Karpathy /
gBrain pattern): raw sources go in `sources/`, the LLM compiles them into
typed entry folders, and agents read the wiki FIRST before any task. No RAG,
no vector DB — the structure IS the index.

Usage:
    kl_init.py [<path>] [--force] [--folders people,companies,concepts,...]

Defaults:
    <path>    ./knowledge-layer
    folders   people,companies,concepts,ideas,projects,operations,media

Creates:
    <path>/
      SCHEMA.md  INDEX.md  CONTRADICTIONS.md  SOURCES.md
      .kl/manifest.json          (source content-hash state; do not edit by hand)
      sources/                    (drop raw material here)
      <each typed folder>/_about.md

Exit codes: 0 ok, 1 refused (exists, no --force), 2 bad args.
"""
import argparse
import json
import shutil
import sys
from datetime import date
from pathlib import Path

DEFAULT_FOLDERS = ["people", "companies", "concepts", "ideas",
                   "projects", "operations", "media"]

FOLDER_ABOUT = {
    "people":     "One entry per person. Aliases, role, affiliations, quotes, decisions they made.",
    "companies":  "One entry per organization/vendor. What they do, our relationship, key facts.",
    "concepts":   "One entry per idea/term/framework worth a durable definition.",
    "ideas":      "Proposals and hypotheses (not yet decided). Link to the project once acted on.",
    "projects":   "One entry per initiative. Goal, status, decisions, open questions.",
    "operations": "How-we-do-it: workflows, playbooks, standing rules, gotchas.",
    "media":      "Notes on assets/links/videos/threads — the durable takeaway, not the raw file.",
}


def template_dir() -> Path:
    return Path(__file__).resolve().parent.parent / "assets" / "template"


def main() -> int:
    ap = argparse.ArgumentParser(description="Scaffold a Knowledge Layer instance.")
    ap.add_argument("path", nargs="?", default="knowledge-layer",
                    help="target directory (default: ./knowledge-layer)")
    ap.add_argument("--force", action="store_true",
                    help="proceed even if the directory already exists")
    ap.add_argument("--folders", default=",".join(DEFAULT_FOLDERS),
                    help="comma-separated typed folder names")
    args = ap.parse_args()

    root = Path(args.path).resolve()
    folders = [f.strip() for f in args.folders.split(",") if f.strip()]

    if root.exists() and any(root.iterdir()) and not args.force:
        print(f"REFUSED: {root} exists and is not empty. Re-run with --force to add "
              f"missing scaffolding without overwriting your entries.")
        return 1

    tdir = template_dir()
    if not tdir.is_dir():
        print(f"ERROR: template dir missing at {tdir}", file=sys.stderr)
        return 2

    root.mkdir(parents=True, exist_ok=True)
    (root / ".kl").mkdir(exist_ok=True)
    (root / "sources").mkdir(exist_ok=True)

    today = date.today().isoformat()

    # Seed the four root docs (never clobber an existing one).
    for name in ("SCHEMA.md", "INDEX.md", "CONTRADICTIONS.md", "SOURCES.md"):
        dst = root / name
        if dst.exists():
            print(f"kept   {name} (already present)")
            continue
        text = (tdir / name).read_text()
        text = text.replace("{{DATE}}", today).replace(
            "{{FOLDERS}}", ", ".join(folders))
        dst.write_text(text)
        print(f"create {name}")

    # Typed folders, each with an _about.md so git tracks the empty folder and
    # the compile agent knows what belongs where.
    for f in folders:
        d = root / f
        d.mkdir(exist_ok=True)
        about = d / "_about.md"
        if not about.exists():
            desc = FOLDER_ABOUT.get(f, "One entry per item in this category.")
            about.write_text(f"# {f}/\n\n{desc}\n\n"
                             f"Entry files here are `<slug>.md` with YAML "
                             f"frontmatter (see ../SCHEMA.md).\n")
        print(f"folder {f}/")

    # Fresh manifest if none.
    manifest = root / ".kl" / "manifest.json"
    if not manifest.exists():
        manifest.write_text(json.dumps(
            {"version": 1, "compiled_at": None, "sources": {}}, indent=2) + "\n")
        print("create .kl/manifest.json")

    print(f"\nKnowledge Layer ready at: {root}")
    print("Next: drop raw material into sources/, then run kl_scan.py to see the "
          "compile work-list, then follow references/compile-protocol.md.")
    return 0


if __name__ == "__main__":
    sys.exit(main())