mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix: preserve custom frontmatter fields when updating notes
Fixes #36 by modifying entity_service.update_entity() to read existing frontmatter from files before updating them. Custom metadata fields such as Status, Priority, and Version are now preserved when notes are updated through the write_note MCP tool. Added test case that verifies this behavior by creating a note with custom frontmatter and then updating it. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
@@ -141,10 +141,23 @@ class EntityService(BaseService[EntityModel]):
|
||||
# Convert file path string to Path
|
||||
file_path = Path(entity.file_path)
|
||||
|
||||
# Read existing frontmatter from the file if it exists
|
||||
existing_markdown = await self.entity_parser.parse_file(file_path)
|
||||
|
||||
# Create post with new content from schema
|
||||
post = await schema_to_markdown(schema)
|
||||
|
||||
# Merge new metadata with existing metadata
|
||||
existing_markdown.frontmatter.metadata.update(post.metadata)
|
||||
|
||||
# Create a new post with merged metadata
|
||||
merged_post = frontmatter.Post(
|
||||
post.content,
|
||||
**existing_markdown.frontmatter.metadata
|
||||
)
|
||||
|
||||
# write file
|
||||
final_content = frontmatter.dumps(post, sort_keys=False)
|
||||
final_content = frontmatter.dumps(merged_post, sort_keys=False)
|
||||
checksum = await self.file_service.write_file(file_path, final_content)
|
||||
|
||||
# parse entity from file
|
||||
@@ -309,4 +322,4 @@ class EntityService(BaseService[EntityModel]):
|
||||
)
|
||||
continue
|
||||
|
||||
return await self.repository.get_by_file_path(path)
|
||||
return await self.repository.get_by_file_path(path)
|
||||
@@ -252,3 +252,72 @@ async def test_write_note_verbose(app):
|
||||
""").strip()
|
||||
in result
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_write_note_preserves_custom_metadata(app, test_config):
|
||||
"""Test that updating a note preserves custom metadata fields.
|
||||
|
||||
Reproduces issue #36 where custom frontmatter fields like Status
|
||||
were being lost when updating notes with the write_note tool.
|
||||
|
||||
Should:
|
||||
- Create a note with custom frontmatter
|
||||
- Update the note with new content
|
||||
- Verify custom frontmatter is preserved
|
||||
"""
|
||||
# First, create a note with custom metadata using write_note
|
||||
await write_note(
|
||||
title="Custom Metadata Note",
|
||||
folder="test",
|
||||
content="# Initial content",
|
||||
tags=["test"],
|
||||
)
|
||||
|
||||
# Read the note to get its permalink
|
||||
content = await read_note("test/custom-metadata-note")
|
||||
|
||||
# Now directly update the file with custom frontmatter
|
||||
# We need to use a direct file update to add custom frontmatter
|
||||
from pathlib import Path
|
||||
import frontmatter
|
||||
|
||||
file_path = test_config.home / "test" / "Custom Metadata Note.md"
|
||||
post = frontmatter.load(file_path)
|
||||
|
||||
# Add custom frontmatter
|
||||
post["Status"] = "In Progress"
|
||||
post["Priority"] = "High"
|
||||
post["Version"] = "1.0"
|
||||
|
||||
# Write the file back
|
||||
with open(file_path, "w") as f:
|
||||
f.write(frontmatter.dumps(post))
|
||||
|
||||
# Now update the note using write_note
|
||||
result = await write_note(
|
||||
title="Custom Metadata Note",
|
||||
folder="test",
|
||||
content="# Updated content",
|
||||
tags=["test", "updated"],
|
||||
)
|
||||
|
||||
# Verify the update was successful
|
||||
assert "Updated test/Custom Metadata Note.md" in result
|
||||
|
||||
# Read the note back and check if custom frontmatter is preserved
|
||||
content = await read_note("test/custom-metadata-note")
|
||||
|
||||
# Custom frontmatter should be preserved
|
||||
assert "Status: In Progress" in content
|
||||
assert "Priority: High" in content
|
||||
# Version might be quoted as '1.0' due to YAML serialization
|
||||
assert "Version:" in content # Just check that the field exists
|
||||
assert "1.0" in content # And that the value exists somewhere
|
||||
|
||||
# And new content should be there
|
||||
assert "# Updated content" in content
|
||||
|
||||
# And tags should be updated
|
||||
assert "'#test'" in content
|
||||
assert "'#updated'" in content
|
||||
Reference in New Issue
Block a user