1633 words
8 minutes
Obsidian Vault Curation at Scale: How We Transformed 1,000+ Notes in Under an Hour
Part 4 of 5 Obsidian Notes Pipeline

1,280 chaotic tags - including a hex color. Three different frontmatter formats. Fixed in 30 minutes for $1.50.

By the Dotzlaw Team


The Mess#

Three years of accumulated entropy -- a chaotic Obsidian graph view with scattered yellow nodes and a tag list showing 1,280 unrelated tags including hex color codes, duplicate AI variations, and inconsistent naming

Figure 1 — Three years of accumulated entropy: the Obsidian graph shows scattered, disconnected clusters while the tag pane reveals 1,280 chaotic tags — including a hex color code (#3498db) and duplicate variations like #AI (118), #aiAgents (5), and #agents (11).

Three years of Obsidian notes. 1,280 tags. Including a hex color code that somehow became a category. We fixed all of it in 30 minutes for $1.50.

Here’s what we were working with:

#ai
#AI
#artificialIntelligence
#agentic-systems
#agenticFrameworks
#3498db <- A hex color somehow became a tag
#5year <- What does this even mean?

The inconsistencies ran deeper than tags. Our YAML frontmatter was a mess of uppercase keys, ISO timestamps that broke tooling, and duplicate entries:

---
Title: Some Note # Should be lowercase
Created: 2024-12-27T07:02:00 # ISO format breaks some tools
tags:
- ai
- AI # Duplicate!
---

Some older notes used Obsidian’s legacy inline property format. About 80 notes had no frontmatter at all — just raw markdown floating in the void.

The manual fix would have taken weeks. We had 1,028 files across three different formats, each needing analysis, tag assignment from a curated taxonomy, and formatting corrections. Nobody was going to do that by hand.


The Result#

After the batch completed and all files were updated, we opened Obsidian.

Before and after comparison of the Obsidian tag pane -- the left shows a flat alphabetical list of 1,280 chaotic tags with random counts, an arrow labeled Claude Code Taxonomy Design points to the right showing a clean nested hierarchy with categories like ai (1348), agents (538), assistants (97), and automation (23)

Figure 4 — From flat chaos to nested hierarchy: Claude Code analyzed 1,280 tags, identified logical categories, and designed a four-level taxonomy. The new structure enables drill-down navigation at every level.

The tag pane, which had been an unusable wall of 1,280 unrelated tags, was now a cleanly nested hierarchy. Claude Code had analyzed the full tag list, identified logical categories, designed a four-level hierarchy, and generated a complete mapping from old tags to new — all in minutes. The 1,280 chaotic tags became 1,040 hierarchical ones:

#ai/ # Level 1: Top-level category
#ai/agents/ # Level 2: Subcategory
#ai/agents/frameworks/ # Level 3: Specific area
#ai/agents/frameworks/crewai # Level 4: Individual item
#ai/agents/frameworks/langgraph
#ai/agents/frameworks/autogen
#trading/ # Another top-level
#trading/patterns/ # Trading patterns
#trading/patterns/abcd # Specific pattern
#trading/patterns/harmonics
#trading/psychology/ # Trading psychology
#trading/psychology/discipline
#infrastructure/ # DevOps & Infrastructure
#infrastructure/docker/ # Container tech
#infrastructure/docker/compose
#infrastructure/kubernetes/
#infrastructure/servers/proxmox

Click #ai/agents/frameworks/ and see exactly the 34 notes about agent frameworks. No more hunting through #ai vs #AI vs #artificialIntelligence. Click #trading/patterns/ and every pattern note is right there. The hierarchy enables drill-down at every level: #ai/ surfaces all 200+ AI-related notes, while #ai/rag/embeddings narrows to exactly the 15 notes about embedding strategies.

Three years of accumulated tag chaos, fixed in under an hour.

KEY INSIGHT: AI-assisted taxonomy design is a force multiplier — what would take days of manual categorization, Claude Code did in minutes, producing a cleaner result than we would have designed ourselves.


The Approach#

We built a three-stage Python pipeline: prepare, submit, and apply. The pipeline scanned every markdown file, built format-specific prompts, sent them through Anthropic’s Batch API, and applied the results back to the source files.

Architecture diagram of the three-stage pipeline -- Input markdown file flows through Stage 1 Analyze (Python Script: Assess State), Stage 2 Prompt (Format-Specific Logic), and Stage 3 Apply (Batch API Execution) to produce the Output processed file

Figure 2 — The three-stage pipeline: each markdown file flows through analysis, format-specific prompting, and Batch API execution to produce a clean, standardized output.

Stage 1: Intelligent File Analysis#

The preparation script analyzed each file and classified what needed fixing. The breakdown was sobering:

Issue TypeCountDescription
missing_title~400No title field
missing_description~600No description
uppercase_property~150Title: instead of title:
iso_date_format~200ISO timestamps
inline_to_yaml~50Legacy format conversion
no_frontmatter~80Needs frontmatter created

Nearly every file had at least one issue. Many had several.

Stage 2: Format-Specific Prompts#

The key insight was that different file formats need different prompts. A file with existing YAML frontmatter needs a cleanup prompt. A file with Obsidian’s legacy inline properties (Type:: #note/seedling) needs a conversion prompt. A file with no metadata at all needs a generation prompt.

Three-panel diagram showing context-aware prompting conditions -- Condition A: Existing YAML (standardize keys, fix dates, clean tags), Condition B: Legacy Inline (convert Type:: #note to YAML, must preserve emojis and wikilinks), and Condition C: No Metadata (generate title, tags, and description from scratch)

Figure 3 — Context-aware prompting: each file format gets a tailored prompt. The legacy inline conversion (Condition B) was the most challenging, requiring preservation of emojis and wikilinks during format transformation.

We wrote three tailored prompts. The most interesting was the inline property conversion, which had to preserve emoji values, wikilinks, and existing relationships while converting the format entirely:

prompt = f"""This file uses OLD Obsidian inline property format.
## Current Inline Properties

{inline_properties}

## Task
Convert to proper YAML frontmatter, preserving:
- Emoji values exactly
- Wikilinks as quoted strings
- ALL existing properties (lowercase keys)
Add: title, created, description, and curated tags from the approved taxonomy.
"""

Each prompt included a sample of approved tags from our curated taxonomy so the model could assign consistent, hierarchical tags based on the note’s content.

KEY INSIGHT: One-size-fits-all prompts produce mediocre results. Tailor prompts to each file format — the conversion accuracy jumped significantly when we stopped treating all 1,028 files the same way.

Stage 3: Batch Processing#

We used Anthropic’s Batch API for 50% cost savings (see Part 2 for the full technical deep-dive on our dual-API architecture, multi-batch indexing, and error handling patterns). The 1,028 files were split across 8 batches of roughly 100 requests each. All completed in about 25 minutes with a 100% success rate.

Our progressive testing approach — scaling from 2 files to 6 to 52 to 782 — caught two critical bugs before the full run (details in Part 2). Progressive testing is not optional when you’re modifying a thousand files.


The Transformation#

Side-by-side comparison of Obsidian note properties before and after processing -- the left shows uppercase keys (Title), ISO date format (2024-12-27T12:45:28), and flat tags (AI, python, pydanticAI); the right shows lowercase keys (title), standardized dates (2024-12-27 12:45), hierarchical tags (ai/agents/frameworks, coding/languages/python), and a comprehensive AI-generated description with auto-linked Related Notes

Figure 5 — Standardized metadata and frontmatter: keys lowercased, dates standardized, wikilinks preserved, descriptions added, and flat tags replaced with a hierarchical taxonomy — all in a single automated pass.

The most dramatic transformations were the inline property conversions, where the entire metadata format changed while preserving every relationship:

Before: Inline Properties

Type:: #note/seedling
Tags:: #area/personal , #area/health
Links:: [[2022-11-23]]
up:: [[Try This Before You Get Angry]]
Content starts here...

After: Clean YAML Frontmatter

---
title: Anger Only Makes Things Worse
created: 2022-11-23 10:30
type: "#note/seedling"
links: "[[2022-11-23]]"
up: "[[Try This Before You Get Angry]]"
tags:
- "personal/health"
- "philosophy/stoicism"
description: A reflection on managing anger and its negative consequences.
---
Content starts here...

Every wikilink preserved. Every emoji intact. Every property key lowercased. And now the note has a proper title, a description for search, and hierarchical tags that connect it to related notes across the vault.

Results Summary#

MetricValue
Total Files Processed1,028
API Success Rate100%
Files Successfully Updated1,023 (5 were renamed during processing)
Tags Curated1,280 -> 1,040 hierarchical
Processing Time~30 minutes
Total Cost~$1.50
Development Time~4 hours

What Clean Data Enabled#

A dense, interconnected knowledge graph visualization with yellow and purple nodes connected by a web of blue lines, with a caption reading: What was once noise is now signal. This structure is the foundation for Semantic Search.

Figure 6 — A structured knowledge graph: after curation, the vault transformed from scattered noise into an interconnected web of signal — the foundation for semantic search and retrieval.

Vault curation was never the end goal — it was the foundation. With clean, consistent metadata across every note, the rest of the system could do its job.

The semantic linking system (covered in Part 3) analyzed each note’s content, found related notes using vector similarity, and added bidirectional wiki links — 2,757 of them across the vault, turning isolated notes into a connected knowledge graph. Clean tags meant the embeddings captured real semantic meaning instead of noise from inconsistent metadata.

And the RAG chatbot (covered in Part 5) could finally deliver accurate answers because every note had a proper title, description, and hierarchical tags for the retrieval system to work with.

KEY INSIGHT: Data curation has compound returns. Clean tags enabled semantic linking, which enabled the chatbot. Each layer depends on the one before it — skip the foundation and everything downstream suffers.

Layered stack diagram showing three ascending tiers -- bottom layer: Clean Metadata (Standardized Tags &#x26; Frontmatter) in gold, middle layer: Semantic Linking (Vector Similarity &#x26; Bidirectional Links, 2,757 created) in purple, top layer: RAG Chatbot (Retrieval &#x26; Answer Generation, 2.5s Latency) in green, with arrows flowing upward between each layer

Figure 7 — Curation was the foundation, not the goal: clean metadata enabled semantic linking (2,757 auto-generated links), which enabled the RAG chatbot (2.5s latency). Each layer depends on the one before it.


The Series#

This is Part 4 of a 5-part series on building an AI-powered knowledge management system:

  1. From YouTube to Knowledge Graph — Turning 1,000+ videos into an interconnected knowledge base for $1.50
  2. Anthropic Batch API in Production — 50% cost savings at scale, and the bug that almost corrupted everything
  3. Building a Semantic Note Network — Vector search turned 1,024 isolated notes into a dense knowledge graph
  4. Obsidian Vault Curation at Scale (this article) — Three years of tag chaos, fixed in 30 minutes for $1.50
  5. Ask Your Vault Anything — A RAG chatbot that answers from your notes in 2.5 seconds

Next: Ask Your Vault Anything — The foundation is clean, the index is built. Now what if you could just ask your notes a question?

Obsidian Vault Curation at Scale: How We Transformed 1,000+ Notes in Under an Hour
https://dotzlaw.com/insights/obsidian-notes-04/
Author
Gary Dotzlaw, Katrina Dotzlaw, Ryan Dotzlaw
Published at
2026-03-13
License
CC BY-NC-SA 4.0
← Back to Insights