Patch Note
vault_patch_noteEdit part of an existing Markdown note by appending, prepending, replacing, or inserting content by heading without overwriting the full body.
Instructions
Surgical edits to a markdown note — append, prepend, replace, or insert content by heading. Properties are kept as written, and body line breaks are saved as LF. A repeated call can write the content again, so after a timeout or lost response, re-read the note before retrying.
Example: vault_patch_note({ path: "Projects/plan.md", operation: "append", heading: "Open questions", content: "- Which region hosts the backup?" }) Example: vault_patch_note({ path: "Notes/Plan.md", operation: "replace", heading: "Status", content: "On track for launch.\n" }) Example: vault_patch_note({ path: "Notes/Plan.md", operation: "insert_before", heading: "Phase 2", content: "## Phase 1\nDone.\n" }) Example: vault_patch_note({ path: "Notes/Plan.md", operation: "prepend", content: "> [!info] Draft\n> Not reviewed yet.\n" }) — adds a leading callout
When to use: Modifying part of an existing note without overwriting the entire body. Prefer vault_write_note for a new note or a full rewrite (overwrite: true); vault_replace_in_note for an in-place text change (a typo, a rename); vault_insert_at_anchor for inserting next to a specific line; vault_replace_span for replacing a run of lines; vault_delete_span for removing lines; vault_update_properties for properties; vault_create_task for adding a task; vault_update_task for a task's status or lane.
Operations:
append: add content at end of section (or end of file if no heading), below any empty lines that end it. So when a blank line follows a table, an appended row starts a new table; to extend the original table, use vault_insert_at_anchor after its last row
prepend: add content after heading line (or at the top of the body, below the properties block, if no heading). To start a new section above the note's current first heading, use insert_before on that heading: a no-heading prepend whose content starts with a heading nests any content above the first heading inside the new section.
replace: replace section body (requires heading); to empty it, use vault_delete_span on its lines
insert_before: insert content above the heading line (requires heading)
Behavior:
Heading-targeted operations keep the matched heading. Every operation inserts content as whole lines and adds no empty lines of its own: content ending in a newline ("Done.\n") leaves an empty line after it, and content without one ("Done.") puts the next line directly below.
A section spans from its heading to the next heading with the same or a smaller level number (or EOF), so it includes its child headings. Empty headings ("##" with no text) act as boundaries but cannot be targeted; edit their content via vault_replace_in_note instead.
To edit a leading callout, read it via vault_read_note(outline: true), then vault_replace_in_note the old block for the new one; a no-heading prepend would stack a second callout above it.
Errors:
"note not found" — path does not exist; check vault_list_notes for valid paths
"path must end in …" — add the .md extension
"heading not found" — the message lists the available headings
"ambiguous heading" — multiple headings match; use heading_level to disambiguate; if they share a level, rename one or use vault_replace_in_note to target by text content
"operation … requires a heading target" — pass heading, or use append or prepend to edit the file body
"heading cannot be empty" — heading is whitespace only; pass the heading's text
"content begins with the heading … which would duplicate it" — content's first line repeats the target heading; omit it
"section … has N child headings …" — the target section contains child headings that replace would destroy; pass include_children: true to confirm, or target the child heading directly
"absolute path blocked" / "path traversal blocked" / "hidden path blocked" — pass a vault-relative path with no dot-prefixed part
"concurrent write in progress" — a write to this note is in flight; re-read it and retry
"content contains a control character" — remove the character the message names
"ENAMETOOLONG: …" or another filesystem error — the message says what to do
"the note would open with a properties block …" — a note without properties would start with --- lines around text that can't be properties; the error says how to avoid it
Obsidian syntax: Content is Obsidian Flavored Markdown (no escaping applied). Watch for: #word = tag, [[ = wikilink, %% = comment block. Table rows: send only the data row ("| cell1 | cell2 |"), not the header or separator — duplicating them splits the table.
Returns: Confirmation message — "Applied to → ", where target is the matched heading (e.g. "## Active") or "file body" for a no-heading append/prepend. A no-heading prepend that nested existing content under an inserted heading adds a sentence naming the content's size and any call that would have avoided it.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"path": "<path>",
"operation": "<operation>",
"content": "<content>"
},
"name": "vault_patch_note"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Vault-relative path to the note, including the ".md" extension (e.g. "TASKS.md", "Projects/plan.md"). Use the exact letter case. | |
| content | Yes | Markdown content to insert, or the section's new body for replace. | |
| heading | No | Target heading text (case-sensitive exact match). Omit for a file-level append or prepend. | |
| operation | Yes | The edit to apply. | |
| heading_level | No | Heading level (1-6) for disambiguation when multiple headings share the same text | |
| include_children | No | When true, allows replace to overwrite a section that contains child headings. |