Skip to content

Frontmatter fence detection is not line-anchored: inline '---' in single-line content gets parsed as frontmatter and writes garbage YAML keys #972

Description

@groksrc

Summary

has_frontmatter(), parse_frontmatter(), and remove_frontmatter() in src/basic_memory/file_utils.py detect frontmatter by substring/split rather than line-anchored fences. The frontmatter convention requires --- fences on their own lines; the current logic (content.startswith("---") + content.split("---", 2)) accepts inline fences anywhere.

Repro

Send single-line content that starts with --- — e.g. a shell command where \n doesn't expand (a very common agent/CLI input shape):

bm tool write-note --title "Meeting Notes" --folder meetings \
  --content "---\nstatus: active\n---\nDiscussed Q3 roadmap with Anthony."

The CLI receives the literal one-line string ---\nstatus: active\n---\nDiscussed Q3 roadmap with Anthony.

Resulting file on disk:

---
title: Meeting Notes
type: note
permalink: main/meetings/meeting-notes
\nstatus: active\n
tags:
- meeting
---

\nDiscussed Q3 roadmap with Anthony.

Two failures:

  1. A garbage YAML key literally named \nstatus is merged into the note's frontmatter and written to disk.
  2. The body is silently transformed (the inline ---…--- segment is stripped out of the content).

Root cause

src/basic_memory/file_utils.py:305-323 (has_frontmatter) and :326-348 (parse_frontmatter, content.split("---", 2)). remove_frontmatter shares the pattern.

Proposed fix

Require line-anchored fences (^---\s*$ multiline). The repo already depends on python-frontmatter (used by dump_frontmatter in the same module), whose loader is line-anchored — either delegate to it or anchor the split. Single-line content starting with --- should be treated as plain content, never as frontmatter. Apply consistently across all three helpers.

Context

Found during manual QA of the June 11 PR batch; present on main @ v0.22.0, unrelated to the open PRs.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions