obsidian_move_note
Move or rename a note in an Obsidian vault, optionally updating all incoming wiki and Markdown links to maintain cross-references.
Instructions
Move or rename a note. Optionally rewrites incoming wiki-links and Markdown links.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| vault | No | Optional configured vault name. Defaults to the server default vault. | |
| from | Yes | Vault-relative path. Absolute paths and traversal are rejected. | |
| to | Yes | ||
| overwrite | No | ||
| updateLinks | No |
Implementation Reference
- src/tools.ts:566-583 (registration)Tool registration for 'obsidian_move_note' including its schema (vault, from, to, overwrite, updateLinks) and the inline handler function. The handler resolves source and destination paths, calls vaults.move() to perform the file rename, and optionally calls rewriteIncomingLinks() to update wiki and Markdown links across the vault.
tool( "obsidian_move_note", "Move or rename a note. Optionally rewrites incoming wiki-links and Markdown links.", { vault: vaultArg, from: pathArg, to: pathArg, overwrite: z.boolean().optional().default(false), updateLinks: z.boolean().optional().default(true), }, async (args) => { const from = vaults.notePath(args.from); const to = vaults.notePath(args.to); const moved = await vaults.move(from, to, args.vault, { overwrite: args.overwrite }); const rewrites = args.updateLinks ? await rewriteIncomingLinks(vaults, args.vault, moved.from, moved.to) : []; return { ...moved, rewrites }; }, ); - src/tools.ts:1382-1412 (helper)The rewriteIncomingLinks() helper function, called by the move_note handler. It scans all markdown files in the vault and rewrites any wiki-links ([[...]]) and Markdown links ([...](...)) from the old path to the new path.
async function rewriteIncomingLinks(vaults: VaultManager, vault: string | undefined, fromPath: string, toPath: string): Promise<Array<{ path: string; changed: number }>> { const files = await vaults.markdownFiles(vault); const rewrites: Array<{ path: string; changed: number }> = []; const fromNoExt = fromPath.replace(/\.md$/i, ""); const fromBase = path.posix.basename(fromNoExt); const toNoExt = toPath.replace(/\.md$/i, ""); for (const file of files) { const read = await vaults.readText(file, vault); let changed = 0; let next = read.text.replace(/(!?)\[\[([^\]\n]+)\]\]/g, (full, embed: string, inner: string) => { const [targetAndSection, display] = inner.split("|", 2); const sectionMatch = /([#^].*)$/.exec(targetAndSection); const section = sectionMatch?.[1] ?? ""; const target = targetAndSection.replace(/[#^].*$/, "").trim().replace(/\.md$/i, ""); if (target !== fromNoExt && target !== fromBase && target !== fromPath) return full; changed += 1; return `${embed}[[${toNoExt}${section}${display ? `|${display}` : ""}]]`; }); next = next.replace(/\[([^\]\n]+)\]\(([^)\n]+)\)/g, (full, label: string, target: string) => { const clean = decodeURIComponent(target).replace(/^\.\//, ""); if (clean !== fromPath && clean !== fromNoExt && clean !== `${fromNoExt}.md`) return full; changed += 1; return `[${label}](${encodeURI(toPath)})`; }); if (changed > 0) { await vaults.writeText(read.path, next, vault, { overwrite: true }); rewrites.push({ path: read.path, changed }); } } return rewrites; } - src/vault.ts:150-165 (helper)VaultManager.move() - the underlying filesystem operation for moving/renaming a note. Used directly by the obsidian_move_note handler. It resolves both paths, checks existence, creates parent directories, and performs fs.rename.
async move( fromPath: string, toPath: string, vaultName?: string | null, options: { overwrite?: boolean } = {}, ): Promise<{ from: string; to: string }> { this.assertWritable(); const from = this.resolvePath(fromPath, vaultName); const to = this.resolvePath(toPath, vaultName); if (!fssync.existsSync(from.absolute)) throw new Error(`Source does not exist: ${from.relative}`); if (!options.overwrite && fssync.existsSync(to.absolute)) throw new Error(`Destination exists: ${to.relative}`); await fs.mkdir(path.dirname(to.absolute), { recursive: true }); await fs.rename(from.absolute, to.absolute); this.onInvalidate?.(from.vault.name); return { from: from.relative, to: to.relative }; }