obsidian_patch_active
Modify the active note by appending, prepending, or replacing content at a heading, block reference, or frontmatter key using the Local REST API.
Instructions
Patch the active note by heading, block reference, or frontmatter key through Local REST API.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| targetType | Yes | ||
| target | Yes | ||
| operation | Yes | ||
| content | Yes |
Implementation Reference
- src/tools.ts:1244-1244 (registration)The registration of 'obsidian_patch_active' tool within the registerObsidianTools function.
); - src/tools.ts:1233-1238 (schema)Input schema for obsidian_patch_active: targetType (heading/block/frontmatter), target, operation (append/prepend/replace), and content.
{ targetType: z.enum(["heading", "block", "frontmatter"]), target: z.string(), operation: z.enum(["append", "prepend", "replace"]), content: z.string(), }, - src/tools.ts:1239-1243 (handler)Handler that fetches the active note via REST API, patches the specified section using patchSection, and writes it back via PUT.
async (args) => { const current = await getRestText(config, "/active/"); const next = patchSection(current, selectorFrom(args.targetType, args.target), args.operation, args.content); return obsidianRestRequest(config, { method: "PUT", path: "/active/", body: next, contentType: "text/markdown" }); }, - src/tools.ts:1360-1363 (helper)The selectorFrom helper function that converts targetType/target values to a SectionSelector object used by patchSection.
function selectorFrom(type: "heading" | "block" | "frontmatter", value: string): SectionSelector { if (type === "heading") return { type, heading: value }; if (type === "block") return { type, block: value.replace(/^\^/, "") }; return { type, key: value }; - src/markdown.ts:214-1363 (helper)The patchSection function imported from markdown.ts that does the actual section patching.
export function patchSection( markdown: string, selector: SectionSelector, operation: "append" | "prepend" | "replace", content: string, ): string { if (selector.type === "frontmatter") { const parsed = parseFrontmatter(markdown); const data = { ...parsed.data }; if (operation === "replace") data[selector.key] = content; if (operation === "append") data[selector.key] = `${data[selector.key] ?? ""}${content}`; if (operation === "prepend") data[selector.key] = `${content}${data[selector.key] ?? ""}`; return stringifyFrontmatter(data, parsed.body); } const range = findSectionRange(markdown, selector); if (!range) throw new Error(`Section not found: ${JSON.stringify(selector)}`); if (operation === "replace") { return `${markdown.slice(0, range.start)}${content}${markdown.slice(range.end)}`; } if (operation === "prepend") { return `${markdown.slice(0, range.start)}${content}\n${markdown.slice(range.start)}`; } return `${markdown.slice(0, range.end).replace(/\s*$/, "\n")}${content}\n${markdown.slice(range.end).replace(/^\n?/, "")}`; } export function replaceTaskLine( markdown: string, lineNumber: number, update: { checked?: boolean; status?: string; text?: string }, ): string { const lines = markdown.replace(/\r\n/g, "\n").split("\n"); const idx = lineNumber - 1; const line = lines[idx]; if (!line) throw new Error(`Line ${lineNumber} does not exist`); const match = /^(\s*[-*]\s+\[)([^\]])(\]\s+)(.*)$/.exec(line); if (!match) throw new Error(`Line ${lineNumber} is not a Markdown task`); const status = update.status ?? (update.checked === undefined ? match[2] : update.checked ? "x" : " "); const text = update.text ?? match[4]; lines[idx] = `${match[1]}${status}${match[3]}${text}`; return lines.join("\n"); } export function normalizeNoteTarget(target: string): string { const decoded = decodeURIComponent(target.trim()); return decoded .replace(/\\/g, "/") .replace(/^\/+/, "") .replace(/\.md$/i, ""); } export function noteStem(notePath: string): string { return path.posix.basename(notePath).replace(/\.md$/i, ""); } export function escapeRegExp(value: string): string { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function offsetForLine(lines: string[], lineIndex: number): number { let offset = 0; for (let i = 0; i < lineIndex; i += 1) offset += (lines[i]?.length ?? 0) + 1; return offset; }