blob: b934a710bfb5133c016533cb4e281863923f03c0 [file]
#!/usr/bin/env python3
"""Seed a memory record from Markdown, one entry per section, for a realistic demo corpus.
Usage: seed-corpus.py --root ROOT [--kind KIND] [--min-words N] [--memory AMEM] [--strict] PATH...
Each .md file under PATH is split on second-level headings; each section becomes an entry
titled "<file title>: <section heading>". Files under a directory named decisions become
decisions; everything else the kind given (default fact). Sections shorter than --min-words
are folded into the previous one. Writes go through the amem CLI (--memory, `amem` on PATH
by default), so they land at raw trust under the owner, like any other write.
"""
import argparse, os, re, subprocess, sys
# a directory's index and the form new files are written from: neither is knowledge
SKIP = {"README.MD", "TEMPLATE.MD"}
def sections(text):
text = re.sub(r"^---\n.*?\n---\n", "", text, count=1, flags=re.S) # frontmatter
title = None
for line in text.splitlines():
if line.startswith("# "):
title = line[2:].strip(); break
parts = re.split(r"^## ", text, flags=re.M)
out = []
for i, p in enumerate(parts):
if i == 0:
body = re.sub(r"^# .*\n", "", p, count=1).strip()
if body: out.append((None, body))
else:
head, _, body = p.partition("\n")
out.append((head.strip(), body.strip()))
return title, out
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--root", required=True); ap.add_argument("--kind", default="fact")
ap.add_argument("--min-words", type=int, default=40); ap.add_argument("--memory", default="amem")
# a write that fails is reported and skipped; under --strict it also fails the run,
# for a check that must not pass on a partial record
ap.add_argument("--strict", action="store_true")
ap.add_argument("paths", nargs="+")
a = ap.parse_args()
files = []
for p in a.paths:
if os.path.isdir(p):
for d, _, fs in os.walk(p):
files += [os.path.join(d, f) for f in sorted(fs) if f.endswith(".md") and f.upper() not in SKIP]
elif p.endswith(".md"): files.append(p)
written = failed = 0
for f in files:
kind = "decision" if "/decisions/" in f or f.startswith("decisions/") else a.kind
title, secs = sections(open(f, encoding="utf-8").read())
title = title or os.path.splitext(os.path.basename(f))[0]
merged = []
for head, body in secs:
if merged and len(body.split()) < a.min_words:
h, b = merged[-1]; merged[-1] = (h, b + "\n\n" + (f"### {head}\n\n" if head else "") + body)
else:
merged.append((head, body))
for head, body in merged:
if len(body.split()) < 8: continue
t = f"{title}: {head}" if head else title
r = subprocess.run([a.memory, "--root", a.root, "write", f"--kind={kind}", f"--title={t[:140]}",
f"--body={body[:12000]}"], capture_output=True, text=True)
if r.returncode != 0:
print(f"skip {f} [{head}]: {r.stderr.strip()[:120]}", file=sys.stderr)
failed += 1; continue
written += 1
print(f"wrote {written} entries from {len(files)} files")
if failed and a.strict:
sys.exit(f"{failed} writes failed")
if __name__ == "__main__":
main()