labels:
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)
-
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.
-
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.
-
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.
-
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.
-
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.
labels:
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)
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
oldStringforedit_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.edit_section(or similar) tool takingpath,targetType: "heading" | "block" | "frontmatter",target,operation: "replace" | "append" | "prepend" | "delete", andcontent.No document map / structure-discovery tool with addressable IDs.
get_outlinereturns headings + line numbers, andread_propertiesreturns 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.get_document_maptool returning heading tree (with disambiguation for duplicate headings), block IDs, and frontmatter field names.No optimistic-concurrency token for edits.
edit_note'soldStringmatch gives an implicit "note hasn't changed" check for line-level edits, andupdate_note'sexpectedLinesguards 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).version(or content-hash) field onread_note/get_outline, acceptable as an optionalifMatchparameter on write tools, failing the write rather than silently overwriting if the note changed since it was read.No
copy_note.move_noteexists 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.copy_note(path, newPath), mirroringmove_note's link-handling semantics minus the source deletion.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.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.