{"record":{"id":"4266874f73b14528","repo":"bmad-code-org/BMAD-METHOD","slug":"memlog-md-has-no-frontmatter","errorCode":null,"errorMessage":".memlog.md has no frontmatter","messagePattern":"\\.memlog\\.md has no frontmatter","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/scripts/memlog.py","lineNumber":98,"sourceCode":"\ndef now() -> str:\n    return datetime.now().strftime(\"%Y-%m-%dT%H:%M\")\n\n\ndef resolve(args) -> Path:\n    \"\"\"The memlog file, from either addressing mode: {workspace}/.memlog.md or an explicit --path.\"\"\"\n    return Path(args.path) if args.path else Path(args.workspace) / MEMLOG\n\n\ndef split(text: str) -> tuple[dict, str]:\n    \"\"\"Return (frontmatter dict in source order, body str). Frontmatter is plain key: value.\n\n    The closing fence is the first line that is *exactly* `---`, so a `---` inside a\n    field value (topic/goal are free user text) never truncates the frontmatter.\n    \"\"\"\n    lines = text.splitlines()\n    if not lines or lines[0] != \"---\":\n        raise ValueError(\".memlog.md has no frontmatter\")\n    end = next((i for i in range(1, len(lines)) if lines[i] == \"---\"), None)\n    if end is None:\n        raise ValueError(\".memlog.md frontmatter is not terminated\")\n    meta: dict[str, str] = {}\n    for line in lines[1:end]:\n        if \":\" in line:\n            k, v = line.split(\":\", 1)\n            meta[k.strip()] = v.strip()\n    return meta, \"\\n\".join(lines[end + 1:]).lstrip(\"\\n\")\n\n\ndef render(meta: dict, body: str) -> str:\n    # Neutralize newlines in values so a multi-line field can't break the fence on re-read.\n    fm = \"\\n\".join(f\"{k}: {' '.join(str(v).splitlines())}\" for k, v in meta.items())\n    return \"---\\n\" + fm + \"\\n---\\n\\n\" + body.rstrip(\"\\n\") + \"\\n\"\n\n\ndef touch(meta: dict) -> None:","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/src/scripts/memlog.py#L80-L116","documentation":"memlog.py's `split` parses a `.memlog.md` file into frontmatter and body. It requires the very first line to be exactly `---`. This error means the file does not start with an opening fence — either the file is empty, the first line has trailing whitespace or a different dash count, or the file is a plain markdown body with no frontmatter block at all. The contract is documented at the top of the script: every memlog begins with a `---`-delimited header.","triggerScenarios":"Resuming a session against a file that was hand-created without the fence; a file whose first line is `--- ` (trailing space) or `----` (four dashes); an empty file; a body-only log saved by an external editor that stripped the frontmatter.","commonSituations":"Manually seeding a memlog instead of using `init`; a find-replace that altered the fence; a sync tool that normalised line endings and broke the exact-match.","solutions":["Prepend a proper frontmatter block starting with a line that is exactly three dashes.","Use `memlog init --workspace <dir>` to create a correctly shaped file rather than hand-writing it.","Check for trailing whitespace or CRLF on the first line and strip it.","If the file should have no frontmatter, reconsider: memlog requires it; convert the body into entries via `append`."],"exampleFix":"# before (.memlog.md)\n- (note) hello\n\n# after\n---\ntopic: demo\ngoal: show the fix\nupdated: 2026-08-12T10:00\n---\n\n- (note) hello","handlingStrategy":"validation","validationCode":"text = Path('.memlog.md').read_text()\nlines = text.splitlines()\nassert lines and lines[0] == '---', '.memlog.md has no frontmatter'","typeGuard":"def has_opening_fence(text: str) -> bool:\n    lines = text.splitlines()\n    return bool(lines) and lines[0] == '---'","tryCatchPattern":"from memlog import split\ntry:\n    meta, body = split(text)\nexcept ValueError as e:\n    print(f\"error: {e}\", file=sys.stderr); sys.exit(2)","preventionTips":["Always create memlogs with `memlog init`, never by hand.","Ensure the first line is exactly three dashes with no trailing whitespace.","Normalise line endings to LF to keep exact fence matching stable."],"tags":["memlog","frontmatter","validation","filesystem","config"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}