Map of Content (MOC) Generator
The Map of Content (MOC) Generator automatically groups and indexes notes in your vault. By clustering notes into high-level topic categories using the LLM, it generates structured markdown indexes that act as table of contents files for your vault.
1. Overview
As a note vault grows, it becomes harder to get an overview of what is in it. While folders and tags help, they don't provide a narrative index. A Map of Content (MOC) solves this:
- Clustering: Evaluates all notes in the vault and groups them into 3 to 7 logical topic clusters.
- Narrative Topic Pages: Generates a dedicated markdown file for each topic (e.g.
_moc/artificial-intelligence.md) containing a one-sentence topic description and links to all matching notes. - Central Index: Generates a central
_moc/index.mdlisting all topic clusters and linking to their respective topic files.
2. Under the Hood & Code Walkthrough
2.1 Topic Clustering Prompt
The generator gathers note information and asks the LLM to group them into 3 to 7 clusters. It uses strict JSON response formatting to make it easy to parse:
const prompt = `Group these notes into 3-7 topic clusters based on their content and tags. Return ONLY a JSON array: [{ "topic": "Topic Name", "description": "One sentence description", "noteIndices": [1, 3, 5] }]
Notes:
${noteList}`;
2.2 Writing Topic Files & Index
The extension clears the _moc/ directory, converts topic names into clean slugs, and writes the markdown files:
// Generate topic files
const indexEntries: string[] = [];
for (const cluster of clusters) {
const slug = slugify(cluster.topic);
const noteLinks = cluster.noteIndices
.filter(i => i >= 1 && i <= notes.length)
.map(i => {
const note = notes[i - 1];
const relativePath = path.relative(mocDir, note.filePath);
return `- [${path.basename(note.filePath)}](${relativePath})`;
})
.join('\n');
const topicContent = `# ${cluster.topic}\n\n${cluster.description}\n\n## Notes\n\n${noteLinks}\n`;
await fsp.writeFile(path.join(mocDir, `${slug}.md`), topicContent, 'utf8');
indexEntries.push(`- [${cluster.topic}](${slug}.md) β ${cluster.description}`);
}
// Generate central index
const indexContent = `# Map of Content\n\n${indexEntries.join('\n')}\n`;
const indexPath = path.join(mocDir, 'index.md');
await fsp.writeFile(indexPath, indexContent, 'utf8');