find_orphans
Identify notes without incoming or outgoing links to maintain a well-connected knowledge base.
Instructions
Find notes that have no incoming or outgoing links
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| includeOutlinksCheck | No | Also check for notes with no outgoing links | |
| maxResults | No | Maximum results to return |
Implementation Reference
- src/tools/links.ts:288-304 (registration)Registration of the 'find_orphans' tool, including its description and input schema.
server.registerTool( "find_orphans", { description: "Find notes that have no incoming or outgoing links", inputSchema: { includeOutlinksCheck: z .boolean() .optional() .default(true) .describe("Also check for notes with no outgoing links"), maxResults: z .number() .optional() .default(200) .describe("Maximum results to return"), }, }, - src/tools/links.ts:305-373 (handler)The handler implementation for 'find_orphans', which builds a link graph and categorizes notes as orphaned based on their connections.
async ({ includeOutlinksCheck, maxResults }) => { try { const graph = await buildLinkGraph(vaultPath); const noBacklinks: OrphanNote[] = []; const noOutlinks: OrphanNote[] = []; const fullyIsolated: OrphanNote[] = []; for (const notePath of graph.allNotes) { const hasBacklinks = (graph.backlinks.get(notePath)?.size ?? 0) > 0; const hasOutlinks = (graph.outlinks.get(notePath)?.size ?? 0) > 0; if (!hasBacklinks && !hasOutlinks) { fullyIsolated.push({ path: notePath, hasOutlinks: false, hasBacklinks: false }); } else if (!hasBacklinks) { noBacklinks.push({ path: notePath, hasOutlinks, hasBacklinks: false }); } else if (!hasOutlinks && includeOutlinksCheck) { noOutlinks.push({ path: notePath, hasOutlinks: false, hasBacklinks }); } } // Apply maxResults cap across all categories let remaining = maxResults; const cappedIsolated = fullyIsolated.slice(0, remaining); remaining -= cappedIsolated.length; const cappedNoBacklinks = noBacklinks.slice(0, Math.max(0, remaining)); remaining -= cappedNoBacklinks.length; const cappedNoOutlinks = includeOutlinksCheck ? noOutlinks.slice(0, Math.max(0, remaining)) : []; const lines: string[] = [ `Orphan analysis for vault (${graph.allNotes.length} notes total)\n`, ]; lines.push(`Fully isolated (no links in or out): ${fullyIsolated.length}`); for (const note of cappedIsolated) { lines.push(` - ${note.path}`); } if (cappedIsolated.length < fullyIsolated.length) { lines.push(` ... and ${fullyIsolated.length - cappedIsolated.length} more`); } lines.push(`\nNo backlinks (not linked by any note): ${noBacklinks.length}`); for (const note of cappedNoBacklinks) { lines.push(` - ${note.path}`); } if (cappedNoBacklinks.length < noBacklinks.length) { lines.push(` ... and ${noBacklinks.length - cappedNoBacklinks.length} more`); } if (includeOutlinksCheck) { lines.push(`\nNo outlinks (links to no other notes): ${noOutlinks.length}`); for (const note of cappedNoOutlinks) { lines.push(` - ${note.path}`); } if (cappedNoOutlinks.length < noOutlinks.length) { lines.push(` ... and ${noOutlinks.length - cappedNoOutlinks.length} more`); } } const totalOrphans = fullyIsolated.length + noBacklinks.length + (includeOutlinksCheck ? noOutlinks.length : 0); lines.push(`\nTotal orphan entries: ${totalOrphans}`); return { content: [{ type: "text" as const, text: lines.join("\n") }] }; } catch (err) { console.error("find_orphans error:", err); return errorResult(`Error finding orphans: ${err instanceof Error ? err.message : String(err)}`); } },