Skip to content

[FEATURE] Add insert_before_section and insert_after_section operations to edit_note #646

@Brennall

Description

@Brennall

Feature Description

Add two new operations to edit_note: insert_before_section and insert_after_section. These insert content relative to a markdown section heading without consuming or modifying any existing content. The heading is used purely as a positional anchor.

Problem This Feature Solves

When using find_replace to insert content near a section heading, AI models (Claude, and likely others) consistently consume the heading itself. The str_replace pattern, which is trained extensively across all coding workflows, reinforces not including boundary text in replacements. Despite documentation warning against this, every Claude instance we've tested makes the same mistake repeatedly.

Example of the problem:

# Using find_replace to add content before ## Observations
find_text: "## Observations"  
content: "New content here\n## Observations"  # Must re-include the heading

# But trained str_replace behaviour produces:
find_text: "## Observations"
content: "New content here"  # Heading consumed, it's gone

This is a structural problem, not a documentation problem. Advisory warnings don't fix trained behaviour. The solution is operations that make the error impossible.

Proposed Solution

Two new operations that use section headings as positional anchors:

  • insert_before_section: Insert content immediately before a section heading
  • insert_after_section: Insert content immediately after a section heading line

Both use the existing section parameter (same interface as replace_section). The heading is never in the find/replace path, it cannot be consumed.

Implementation

entity_service.py — New method insert_relative_to_section:

  • Finds the section heading (same logic as replace_section_content)
  • Inserts content before or after the heading line
  • Raises ValueError if section not found (unlike replace_section which appends — insert operations require a target)
  • Raises ValueError if multiple matching sections found

mcp/tools/edit_note.py — Updated validation and response formatting:

  • Added to valid_operations list
  • Section validation covers all three section operations
  • Response formatting reports lines inserted and target section

schemas/request.py — Updated Pydantic schema:

  • Added to Literal type constraint on operation field
  • Updated section validator to cover new operations

User workflow

# Insert a new paragraph before the Observations section
edit_note("my-note", "insert_before_section", 
          "## New Section\nContent here", 
          section="## Observations")

# Insert content after a section heading
edit_note("my-note", "insert_after_section",
          "First line under this heading",
          section="## Implementation")

Alternative Solutions

  • Better documentation: We tried this. Every Claude instance reads the warning and makes the mistake anyway. The error is trained, not knowledge-based.
  • Auto-include heading in find_replace: Would change existing behaviour and break other use cases where consuming text is intentional.
  • Use replace_section for everything: Works but replaces content rather than inserting alongside it. Different semantics.

Additional Context

Relationship to existing Anthropic tools: Anthropic's own str_replace tool (used in Claude Code and computer use) is the root cause of the trained behaviour it replaces matched text, consuming the match. Anthropic's text_editor tool has an insert operation, but it works by line number, not by section heading. Line numbers are fragile in markdown notes where content shifts frequently. Our insert_before_section and insert_after_section use section headings as semantic anchors, stable positional references that work regardless of which line the section is on. This is a new approach specifically designed for markdown-structured notes.

Track record since implementation: Since deploying these operations to our fork, we have had zero instances of heading consumption. Prior to this change, every Claude instance (across multiple sessions, multiple model versions including Opus 4.5 and Opus 4.6, and both thinking-enabled and standard modes) made the heading consumption error despite explicit documentation warning against it. The structural fix eliminated the error class entirely, not reduced frequency, eliminated.

We've been using Basic Memory extensively with Claude for a knowledge base of 270+ notes. We implemented and tested these operations in our fork (Brennall/basic-memory) and have been using them in production for two days across multiple sessions.

The implementation follows existing patterns in the codebase — same section-finding logic as replace_section_content, same error handling, same parameter interface.

Impact

This would benefit any AI model using edit_note with find_replace near section headings. The problem is not Claude-specific it's a consequence of how all LLMs are trained on text replacement patterns. Providing section-aware insert operations eliminates the error class structurally rather than relying on each model to override its training.

Three files changed, ~60 lines of new code. Backward compatible, no changes to existing operations.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions