Skip to content

Structured section-scoped edits (heading/block-targeted replace/append/delete) with optimistic concurrency #65

Description

@MarcDeVinney

labels:

  • enhancement
  • api

Structured section-scoped edits (heading/block-targeted replace/append/delete) with optimistic concurrency

Summary

NoteMesh's edit surface is strong for whole-note and line-level changes (edit_note, append_to_note, prepend_to_note, set_property/remove_property, update_note), but there's no way to target a specific heading or block and replace, append to, or delete only that node's content the way Obsidian's own Local REST API-style tools (e.g. vault_patch) do. For agent workflows that maintain long-lived structured notes (job trackers, project logs, running checklists), this gap forces workarounds that are either fragile (string-matching across a whole section) or risky (rewriting the whole note).

Gaps found (using NoteMesh as a full replacement for an Obsidian REST API-based tool)

  1. No heading/block-scoped edit. There's no tool to say "replace/append/delete the content under heading X" or "under block ^id" without first fetching the full section text and constructing an exact-match oldString for edit_note. For a section that gets appended to repeatedly (a running log, a checklist), this means every caller needs to re-derive the current full section content just to change one part of it.

    • Requested: an edit_section (or similar) tool taking path, targetType: "heading" | "block" | "frontmatter", target, operation: "replace" | "append" | "prepend" | "delete", and content.
  2. No document map / structure-discovery tool with addressable IDs. get_outline returns headings + line numbers, and read_properties returns frontmatter keys, but there's no single call that returns a full addressable map of a note (heading tree, block reference IDs, frontmatter keys) the way callers need to safely target nodes without re-parsing markdown by hand — especially for notes with duplicate heading text, which today has no disambiguation mechanism at all.

    • Requested: a get_document_map tool returning heading tree (with disambiguation for duplicate headings), block IDs, and frontmatter field names.
  3. No optimistic-concurrency token for edits. edit_note's oldString match gives an implicit "note hasn't changed" check for line-level edits, and update_note's expectedLines guards whole-note overwrites, but there's no explicit version/hash token returned by a read that can be passed back into a scoped edit to guard against a race (two agents, or an agent and a human in the Obsidian UI, editing the same section concurrently).

    • Requested: a version (or content-hash) field on read_note/get_outline, acceptable as an optional ifMatch parameter on write tools, failing the write rather than silently overwriting if the note changed since it was read.
  4. No copy_note. move_note exists and correctly rewrites backlinks, but there's no way to duplicate a note (e.g. cloning a template, or merging near-duplicate notes without losing one copy) without a manual read + create.

    • Requested: copy_note(path, newPath), mirroring move_note's link-handling semantics minus the source deletion.
  5. No structured table-row writes. For notes containing markdown tables tracked programmatically (e.g. a tracked-items table under a heading), there's no way to append/replace specific rows without reconstructing and rewriting the entire table as text via edit_note.

    • Requested: table-aware read/write, e.g. a content-shaped 2D array payload on a block or heading target, matching column count.

Why this matters

Without #1 and #2, every "update one part of a structured note" operation degrades to "read the whole note, string-match a section, write it back" — which is exactly the failure mode that caused data loss in our own workflow before we adopted an explicit read-full-section-before-replace discipline. A native scoped-edit primitive with concurrency protection would remove the need for that discipline entirely, rather than just documenting around the footgun.

Environment

NoteMesh MCP server, used as a vault-access layer for AI-agent-driven note maintenance (Claude via MCP), replacing a device-bridge-dependent Obsidian Local REST API integration.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions