Stable URLs and Sidebar Strategy 2026
Problem: File moves break links, cause 404s, hurt SEO, disrupt sidebar order
Solution: Stable slugs + metadata-based ordering + LLM-assisted migration
Current State Analysis
What You Have Now
URL Structure:
- ❌ Path-based:
https://deepaksood619.github.io/ai/llm/fundamentals/intro - ❌ Moves create 404s: Rename folder → broken links
- ❌ Poor SEO: URL changes lose search ranking
Links:
- ❌ Relative paths:
[Transformers](../architectures/transformers.md) - ❌ Break on moves: Move file → update all referencing files
Sidebar Ordering:
- ❌ Alphabetical:
sidebars.jsuses{type: 'autogenerated', dirName: '.'} - ⚠️ Some numbered prefixes:
01-intro.md,02-getting-started.md - ❌ Inconsistent: Only in some folders (databricks, concepts)
Slug Usage:
- ❌ Only 1 file:
readme.mdhasslug: / - ❌ No systematic slugs
Problems This Causes
-
Link Rot
- Refactor folder structure → all internal links break
- External links (Google, social media) become 404s
- Wastes SEO value accumulated over time
-
Sidebar Chaos
- Alphabetical order ≠ logical learning order
- "Introduction" appears after "Advanced Topics"
- Numbered prefixes ugly and manual
-
Obsidian ≠ Docusaurus
- Obsidian sorts alphabetically by filename
- Docusaurus sorts alphabetically by sidebar config
- No shared ordering mechanism
-
Maintenance Burden
- Move file → manually update all referencing links
- Reorder topics → rename files with new numbers
- Can't let LLM reorganize (too risky)
Solution Architecture
Three-Part System
┌─────────────────────────────────────────────────────┐
│ 1. STABLE SLUGS (Docusaurus URLs) │
│ Fixed forever, independent of file location │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 2. FRONTMATTER ORDERING (Both tools) │
│ sidebar_position, sidebar_label metadata │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 3. OBSIDIAN METADATA (Custom sort) │
│ Obsidian Dataview + custom CSS for visual order │
└─────────────────────────────────────────────────────┘
Part 1: Stable Slugs
Slug Design Principles
Good slugs are:
- ✅ Permanent: Never change, even if file moves
- ✅ Semantic: Describe content, not location
- ✅ SEO-friendly: Keywords, hyphens, lowercase
- ✅ Hierarchical: Show topic relationships
- ✅ Human-readable: Make sense in URL bar
Examples:
| File Path | Bad Slug | Good Slug |
|---|---|---|
ai/llm/fundamentals/intro.md | /ai/llm/fundamentals/intro | /llm-introduction |
databases/clickhouse/architecture.md | /databases/clickhouse/architecture | /clickhouse-architecture |
book-summaries/atomic-habits.md | /book-summaries/atomic-habits | /atomic-habits-summary |
Why flatten hierarchy in slugs?
- ✅ Shorter URLs (better for sharing)
- ✅ Survives reorganization (move file, slug stays)
- ✅ SEO boost (focus keywords in URL)
Slug Naming Convention
Format: /{domain}-{topic}-{specificity}
Templates by note type:
# Concepts
/{concept-name}
Examples: /transformers, /self-attention, /rag
# Tools/Technologies
/{tool-name}-{aspect}
Examples: /clickhouse-architecture, /kafka-streams, /airflow-operators
# Comparisons
/{x}-vs-{y}
Examples: /postgres-vs-mysql, /rest-vs-graphql
# Guides/Tutorials
/{action}-{object}
Examples: /deploy-kubernetes, /optimize-queries, /debug-llm
# Book Summaries
/{book-title}-summary
Examples: /atomic-habits-summary, /deep-work-summary
# Interview Prep
/{topic}-interview-questions
Examples: /llm-interview-questions, /system-design-interview
# People/Companies
/{name}
Examples: /sam-altman, /openai
# Frameworks/Methodologies
/{framework-name}
Examples: /zettelkasten, /gtd-getting-things-done
Frontmatter Slug Implementation
Every note gets:
---
id: stable-unique-id-2024-03-15
title: "Transformer Architecture in LLMs"
slug: /transformer-architecture # ← THE STABLE URL
sidebar_position: 3
sidebar_label: "Transformers"
description: "Deep dive into transformer architecture and self-attention mechanisms"
keywords: [transformers, self-attention, neural networks, llm]
---
Slug rules:
- Unique across entire vault (LLM checks for collisions)
- Never changes (set once, frozen forever)
- Short (2-4 words max)
- No nested paths (unless absolutely needed for disambiguation)
Exception - Hierarchical slugs when needed:
# Use nested slugs for:
# - Large subsystems (Kafka has 50+ pages)
# - Disambiguation (multiple "architecture" pages)
slug: /kafka/streams/architecture
slug: /clickhouse/architecture
slug: /kubernetes/architecture
Migration Strategy for Slugs
Phase 1: Generate slugs for all notes
def generate_slug(note_path, note_content):
"""LLM generates SEO-friendly slug from note content"""
# Extract context
domain = extract_domain_from_path(note_path) # ai/llm
title = extract_title(note_content)
keywords = extract_keywords(note_content)
note_type = classify_note_type(note_content)
# LLM prompt
prompt = f"""
Generate a permanent, SEO-friendly URL slug for this note.
Note context:
- Domain: {domain}
- Title: {title}
- Type: {note_type}
- Keywords: {keywords}
Rules:
1. 2-4 words max, separated by hyphens
2. Lowercase only
3. Focus on main concept, not file location
4. SEO-friendly (include searchable keywords)
5. No year/date (timeless)
6. Check uniqueness against existing slugs
Examples:
- "Introduction to LLMs" → /llm-introduction
- "ClickHouse Architecture Deep Dive" → /clickhouse-architecture
- "GPT vs BERT Comparison" → /gpt-vs-bert
Output format:
slug: /your-slug-here
reasoning: Why this slug is optimal
"""
response = call_llm(prompt)
slug = extract_slug(response)
# Check for collisions
if slug_exists(slug):
# Try variations
slug = f"{slug}-{domain}"
return slug
Phase 2: Update all notes with slugs
# LLM script
python scripts/add_slugs_to_frontmatter.py
# Output:
# ✓ Generated 3,074 slugs
# ✓ 0 collisions (auto-resolved)
# ✓ Updated frontmatter
# ✓ Created slug registry (slugs.json)
Phase 3: Update internal links
Options:
Option A: Keep relative paths, add slug metadata
---
slug: /transformer-architecture
---
# Transformers
See [Self-Attention](self-attention.md) for details.
<!-- LLM adds: target_slug: /self-attention -->
Option B: Convert to slug-based links (RECOMMENDED)
See [Self-Attention](/self-attention) for details.
Benefits:
- ✅ Works in both Obsidian and Docusaurus
- ✅ Survives file moves
- ✅ Cleaner (no relative path hell)
Phase 4: Set up redirects
// docusaurus.config.js
module.exports = {
plugins: [
[
'@docusaurus/plugin-client-redirects',
{
redirects: [
// Old path → New slug
{
from: '/ai/llm/fundamentals/intro',
to: '/llm-introduction',
},
{
from: '/databases/clickhouse/architecture',
to: '/clickhouse-architecture',
},
],
createRedirects(existingPath) {
// Auto-generate redirects from file path to slug
// LLM generates this mapping
return generateRedirectsFromSlugRegistry(existingPath);
},
},
],
],
};
Slug Registry
Create: docs/.slugs/registry.json
{
"slugs": [
{
"slug": "/transformer-architecture",
"file": "ai/llm/architectures/transformers.md",
"title": "Transformer Architecture",
"created": "2024-03-15",
"last_verified": "2026-06-19",
"old_paths": [
"/ai/llm/fundamentals/transformers",
"/ai/transformers"
]
},
{
"slug": "/clickhouse-architecture",
"file": "databases/clickhouse/architecture.md",
"title": "ClickHouse Architecture",
"created": "2023-05-10",
"old_paths": [
"/databases/clickhouse/architecture"
]
}
],
"collisions": [],
"reserved": ["/", "/about-deepak-sood", "/ai", "/databases"]
}
LLM uses registry to:
- Detect slug collisions before creating
- Generate redirects automatically
- Validate links (ensure target slug exists)
- Track slug history for analytics
Part 2: Sidebar Ordering
Current Problem
Docusaurus autogenerated sidebar:
// sidebars.js
const sidebars = {
tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
};
Result: Alphabetical order (not learning order)
❌ Current sidebar (alphabetical):
- Advanced Topics
- Applications
- Fundamentals
- Introduction
Desired sidebar (logical order):
✅ Desired:
1. Introduction
2. Fundamentals
3. Applications
4. Advanced Topics
Solution: Frontmatter-Based Ordering
Every note gets sidebar_position:
---
slug: /llm-introduction
sidebar_position: 1
sidebar_label: "Introduction"
---
Docusaurus automatically sorts by sidebar_position (built-in feature).
Numbering Convention
Use gap numbering for flexibility:
# Allow insertions without renumbering everything
sidebar_position: 10 # Introduction
sidebar_position: 20 # Fundamentals
sidebar_position: 30 # Intermediate
sidebar_position: 40 # Advanced
sidebar_position: 50 # References
# Insert new page between Fundamentals and Intermediate:
sidebar_position: 25 # New section (no renumbering needed)
Per-folder numbering:
docs/ai/llm/
├── intro.md (sidebar_position: 10)
├── fundamentals/
│ ├── models.md (sidebar_position: 10)
│ ├── training.md (sidebar_position: 20)
│ └── inference.md (sidebar_position: 30)
├── applications/
│ ├── chatbots.md (sidebar_position: 10)
│ └── summarization.md (sidebar_position: 20)
Category ordering with _category_.json:
// docs/ai/llm/_category_.json
{
"label": "Large Language Models",
"position": 20,
"link": {
"type": "doc",
"id": "ai/llm/readme"
},
"collapsible": true,
"collapsed": false
}
Remove Number Prefixes from Filenames
Migrate from:
01-intro.md
02-getting-started.md
03-advanced.md
To:
# intro.md
---
sidebar_position: 10
---
# getting-started.md
---
sidebar_position: 20
---
# advanced.md
---
sidebar_position: 30
---
Benefits:
- ✅ Clean filenames
- ✅ Easier to reference
- ✅ Works in both Obsidian and Docusaurus
- ✅ Reordering doesn't require file renames
LLM Migration Script:
def remove_number_prefixes():
numbered_files = find_files_with_pattern(r'^\d{2,3}-.*\.md$')
for file in numbered_files:
# Extract number
number = extract_leading_number(file.name) # "01-intro.md" → 1
# Remove prefix from filename
new_name = remove_prefix(file.name) # "01-intro.md" → "intro.md"
# Add sidebar_position to frontmatter
add_frontmatter(file, sidebar_position=number * 10)
# Rename file
rename_file(file, new_name)
# Update all links to this file
update_links_in_vault(old_name=file.name, new_name=new_name)
Part 3: Obsidian Ordering
Challenge: Obsidian Doesn't Read Frontmatter for Sorting
Obsidian file browser sorts by:
- ❌ Filename (alphabetically or by number prefix)
- ❌ Created date
- ❌ Modified date
Not by:
- ❌ Frontmatter
sidebar_position
Solution: Obsidian Plugins + Visual Indicators
Option A: Custom File Explorer Order (Plugin)
Use Obsidian Custom File Explorer plugin:
- Install plugin:
obsidian42-custom-file-explorer - Configure sort by frontmatter:
// .obsidian/plugins/custom-file-explorer/data.json
{
"sortBy": "frontmatter",
"frontmatterKey": "sidebar_position",
"fallbackSort": "alphabetical"
}
Option B: Numbered Emoji Prefixes (Visual Only)
Add visual indicators without changing filenames:
---
title: "📍 1. Introduction to LLMs"
sidebar_position: 10
sidebar_label: "Introduction"
slug: /llm-introduction
---
Obsidian displays: 📍 1. Introduction to LLMs
Docusaurus displays: Introduction (uses sidebar_label)
Option C: Dataview Dynamic Index (RECOMMENDED)
Create _index.md in each folder:
<!-- docs/ai/llm/_index.md -->
# LLM Knowledge Base
> Ordered index of all LLM notes (auto-generated)
```dataview
TABLE
sidebar_position as "#",
file.link as "Note",
description as "Description"
FROM "ai/llm"
WHERE file.name != "_index" AND file.name != "readme"
SORT sidebar_position ASC
```
Result in Obsidian:
| # | Note | Description |
|---|---|---|
| 10 | [[intro]] | Introduction to LLMs |
| 20 | [[fundamentals/models]] | LLM architectures and models |
| 30 | [[applications/chatbots]] | Building chatbots with LLMs |
Option D: Folder Notes Plugin
Use Folder Note plugin to make readme.md the folder note:
- Install:
alx-folder-note - Configure: Treat
readme.mdas folder overview - Add ordered navigation section to each
readme.md:
<!-- ai/llm/readme.md -->
# LLM
## Learning Path (In Order)
1. [Introduction](fundamentals/intro.md) - Start here
2. [Models](fundamentals/models.md) - Core architectures
3. [Training](fundamentals/training.md) - How LLMs learn
4. [Applications](applications/readme.md) - Real-world use
5. [Advanced Topics](advanced/readme.md) - Deep dives
<!-- Auto-generated from sidebar_position -->
Recommended: Combine B + C + D
- Visual emoji prefixes for quick scanning
- Dataview tables for structured navigation
- Folder notes for curated learning paths
Comprehensive Frontmatter Schema
Complete Template
---
# Identity (stable, never changes)
id: transformer-architecture-2024-03-15
slug: /transformer-architecture
# Display
title: "Transformer Architecture in LLMs"
sidebar_label: "Transformers" # Short label for sidebar
description: "Deep dive into transformer architecture, self-attention mechanisms, and positional encoding"
# Ordering
sidebar_position: 25
# SEO
keywords:
- transformers
- self-attention
- neural networks
- llm architecture
- attention mechanism
# Content metadata (from previous recommendations)
type: concept
domain: ai/llm/architectures
status: evergreen
confidence: high
created: 2024-03-15
updated: 2026-06-19
last_verified: 2026-06-19
review_by: 2027-06-19
decay_rate: medium
# Relationships
related:
- id: self-attention
type: prerequisite
slug: /self-attention
- id: bert-architecture
type: implements
slug: /bert-architecture
- id: gpt-architecture
type: sibling
slug: /gpt-architecture
# Flashcards
has_flashcards: true
flashcard_file: ai/llm/architectures/flashcards.md
flashcard_count: 12
# Learning
tags:
- domain/ai/ml/deep-learning/architectures/transformers
- application/nlp/text-generation
- technique/attention-mechanisms
# Obsidian-specific (visual ordering)
aliases:
- "📍 2.5 Transformers"
- "attention-is-all-you-need"
---
Minimal Required Fields
For new notes, minimum:
---
slug: /your-permanent-slug
sidebar_position: 10
title: "Note Title"
---
LLM auto-generates rest.
Migration Playbook
Phase 1: Slug Generation (Week 1-2)
Goal: Every note gets a permanent slug
Steps:
-
LLM Script: Generate slugs
python scripts/generate_slugs.pyFor each note:
- Analyze title, content, domain
- Generate SEO-friendly slug
- Check uniqueness
- Add to frontmatter
- Update slug registry
-
Human Review: Sample check
- Review 100 random slugs
- Check for collisions
- Verify SEO quality
- Approve or regenerate
-
Commit: Slug additions
git commit -m "feat: add permanent slugs to all notes"
Estimated:
- LLM time: 3-4 hours (3,074 notes × 4 sec each)
- Human review: 2 hours
- Cost: $15-25 (Claude API)
Phase 2: Sidebar Positions (Week 3-4)
Goal: Every note gets logical ordering
Steps:
-
LLM Script: Assign positions
def assign_sidebar_positions():for folder in get_all_folders():notes = get_notes_in_folder(folder)# LLM determines logical orderprompt = f"""Order these notes from beginner to advanced:{[note.title for note in notes]}Consider:- Prerequisites first- Concepts before applications- Simple before complexOutput: Ordered list with gap numbering (10, 20, 30...)"""ordered = call_llm(prompt)for note, position in zip(notes, ordered):add_frontmatter(note, sidebar_position=position) -
Category files: Create
_category_.json- LLM generates for each folder
- Sets position relative to sibling folders
- Adds labels and descriptions
-
Validate: Build Docusaurus
npm run build# Check sidebar order in output
Estimated:
- LLM time: 2-3 hours
- Human review: 3 hours (verify learning paths)
- Cost: $10-20
Phase 3: Remove Number Prefixes (Week 5)
Goal: Clean filenames, migrate to frontmatter
Steps:
-
Find numbered files:
find . -name "[0-9][0-9]-*.md" -
LLM Script: Migrate
- Extract number → sidebar_position
- Remove prefix from filename
- Update all internal links
- Update git history (preserve)
-
Test: Verify no broken links
npm run build # Docusaurus will catch broken links
Estimated:
- LLM time: 1 hour (only ~50 numbered files based on find results)
- Cost: $5
Phase 4: Convert Links to Slugs (Week 6-8)
Goal: All internal links use slugs, not relative paths
Options:
Option A: Gradual migration
- Keep relative paths
- LLM adds slug metadata in comments
- Convert to slugs when notes move
Option B: Full migration (RECOMMENDED)
- LLM converts all links to slugs
- One-time pain, permanent benefit
Script:
def convert_links_to_slugs():
slug_registry = load_slug_registry()
for note in get_all_notes():
content = read(note)
# Find all markdown links
links = find_markdown_links(content)
for link in links:
target_file = resolve_relative_path(link.path, note.path)
if target_file in slug_registry:
target_slug = slug_registry[target_file].slug
# Replace: [Text](../path/to/file.md) → [Text](/slug)
content = content.replace(
f"[{link.text}]({link.path})",
f"[{link.text}]({target_slug})"
)
write(note, content)
Risk mitigation:
- Backup entire vault first
- Test on 10 notes
- Build Docusaurus after each batch
- Commit in small batches (100 notes at a time)
Estimated:
- LLM time: 4-6 hours (link parsing + conversion)
- Human review: 5 hours (verify critical links)
- Cost: $20-30
Phase 5: Obsidian Visual Ordering (Week 9)
Goal: Make ordering visible in Obsidian
Steps:
-
Install plugins:
- Custom File Explorer
- Dataview
- Folder Note
-
Create
_index.mdin each folder:- LLM generates Dataview queries
- Links to ordered notes
- Auto-updates on change
-
Add emoji prefixes (optional):
aliases: ["📍 1.5 Transformers"] -
Configure Obsidian:
- Set File Explorer to sort by frontmatter
- Enable Folder Note for readme.md
Estimated:
- Setup: 2 hours
- LLM generation of index files: 1 hour
- Cost: $5
Phase 6: Redirects & SEO (Week 10)
Goal: Preserve existing SEO, prevent 404s
Steps:
-
Install redirect plugin:
npm install @docusaurus/plugin-client-redirects -
LLM generates redirect rules:
- Read slug registry
- Map old paths → new slugs
- Generate redirect config
-
Submit to Google Search Console:
- Upload new sitemap
- Request recrawl
- Monitor 404s
Estimated:
- Setup: 3 hours
- Monitoring: Ongoing
Obsidian-Specific Solutions
Dataview Queries for Navigation
Master index with ordering:
<!-- docs/_master-index.md -->
# Complete Knowledge Base (Ordered)
```dataview
TABLE
domain as "Domain",
sidebar_position as "#",
file.link as "Note",
status as "Status",
updated as "Last Updated"
FROM ""
WHERE type = "concept" AND status = "evergreen"
SORT domain ASC, sidebar_position ASC
```
Domain-specific ordered views:
<!-- docs/ai/llm/_navigation.md -->
# LLM Learning Path
```dataview
LIST
FROM "ai/llm"
WHERE sidebar_position != null
SORT sidebar_position ASC
```
## By Topic
```dataview
TABLE
sidebar_position as "#",
description as "What You'll Learn"
FROM "ai/llm"
GROUP BY type
SORT sidebar_position ASC
```
Custom CSS for Visual Ordering
Add to .obsidian/snippets/ordered-files.css:
/* Show sidebar_position in file explorer */
.nav-file-title::before {
content: attr(data-position) ". ";
color: var(--text-muted);
font-size: 0.9em;
}
/* Highlight notes with no position */
.nav-file[data-position=""] .nav-file-title {
opacity: 0.6;
font-style: italic;
}
Enable via plugin or Templater:
// Add data-position attribute to file elements
const files = document.querySelectorAll('.nav-file');
files.forEach(file => {
const position = getFileMetadata(file, 'sidebar_position');
file.setAttribute('data-position', position || '');
});
Integration with Previous Recommendations
Enhanced Frontmatter (Combined Schema)
---
# IDENTITY (Stable URLs - this doc)
id: transformer-architecture-2024-03-15
slug: /transformer-architecture
# DISPLAY (Stable URLs - this doc)
title: "Transformer Architecture in LLMs"
sidebar_label: "Transformers"
sidebar_position: 25
description: "Deep dive into transformer architecture and self-attention"
keywords: [transformers, self-attention, llm architecture]
# CONTENT (PKM Scaling recommendations)
type: concept
domain: ai/llm/architectures
status: evergreen
confidence: high
created: 2024-03-15
updated: 2026-06-19
last_verified: 2026-06-19
review_by: 2027-06-19
decay_rate: medium
# RELATIONSHIPS (PKM Scaling)
related:
- id: self-attention
type: prerequisite
slug: /self-attention
- id: bert
type: implements
slug: /bert-architecture
# FLASHCARDS (Flashcard Integration)
has_flashcards: true
flashcard_file: ai/llm/architectures/flashcards.md
flashcard_count: 12
# LEARNING (PKM Scaling + Flashcards)
tags:
- domain/ai/ml/deep-learning/architectures/transformers
- application/nlp/text-generation
# OBSIDIAN (Stable URLs - this doc)
aliases: ["📍 2.5 Transformers", "attention-is-all-you-need"]
# PERSONAL (PKM Scaling)
personal_experience:
- Implemented transformers at OpsTree for NLP pipeline
- Debugged attention memory issues at scale
learning_date: 2023-08-15
mastery_level: expert
---
LLM Workflows Updated
Daily workflow adds:
- Generate slug for new notes
- Assign sidebar_position based on folder context
- Update slug registry
- Validate no slug collisions
Weekly workflow adds:
- Detect moved files (path changed, slug preserved)
- Update slug registry
- Generate redirects for old paths
- Validate all slug-based links
Monthly workflow adds:
- Audit sidebar_position gaps/overlaps
- Rebalance positions if needed
- Update category ordering
- Check for 404s in published site
Best Practices
1. Slug Immutability
Once set, slugs NEVER change.
# ✅ Good: Set once, frozen forever
slug: /transformer-architecture
# ❌ Bad: Changing slug
# Old: slug: /transformers
# New: slug: /transformer-architecture-guide # NEVER DO THIS
If you must change a slug:
- Create new note with new slug
- Add redirect from old → new
- Mark old note as deprecated
- Update all internal links
- Monitor analytics for old slug usage
2. Sidebar Position Gaps
Always use gap numbering:
# ✅ Good: Room for insertions
sidebar_position: 10
sidebar_position: 20
sidebar_position: 30
# ❌ Bad: No room to insert
sidebar_position: 1
sidebar_position: 2
sidebar_position: 3
# Need to insert between 2 and 3?
# Must renumber everything after
Rebalancing trigger:
- If gaps < 5, LLM script rebalances folder
- Auto-renumber to 10, 20, 30 spacing
- Happens monthly
3. Slug vs Relative Path
When to use each:
# ✅ Internal wiki links: Use slugs
See [Transformers](/transformer-architecture) for details.
# ✅ Same-folder references: Relative paths OK
In this section, we cover [basics](basics.md) and [advanced](advanced.md).
# ⚠️ Cross-domain links: Prefer slugs
From databases note: See [LLM concepts](/llm-introduction)
# ❌ Never use full paths
Bad: [Link](../../ai/llm/fundamentals/intro.md)
Good: [Link](/llm-introduction)
4. Obsidian Compatibility
Test both tools:
# After link changes:
1. Build Docusaurus → check for errors
npm run build
2. Open Obsidian → check links resolve
(Click through 20 random links)
3. Check slug registry → no duplicates
python scripts/validate_slugs.py
5. SEO Optimization
Good slug SEO:
# ✅ Good: Keywords, readable
slug: /clickhouse-materialized-views
slug: /react-hooks-useeffect
slug: /system-design-interview-prep
# ❌ Bad: Generic, not searchable
slug: /page-1
slug: /note
slug: /document-123
Use keywords from:
- Note title
- Primary tag
- Most common search queries (Google Search Console)
Potential Issues & Solutions
Issue 1: Slug Collisions
Problem: Two notes want same slug
Solution:
# LLM auto-resolves
if slug_exists("/transformers"):
# Try variations
suggestions = [
"/transformer-architecture",
"/llm-transformers",
"/transformers-neural-network"
]
# Or add domain prefix
slug = f"/{domain}-{base_slug}" # /ai-transformers
Issue 2: Obsidian Link Autocomplete
Problem: Obsidian autocomplete suggests filename, not slug
Solution:
# Add filename as alias
aliases:
- "transformers.md" # For autocomplete
- "📍 2.5 Transformers" # For visual ordering
Obsidian: Type [[transform]] → suggests transformers.md → resolves to note
Docusaurus: Renders as /transformer-architecture
Issue 3: Git History After File Moves
Problem: Moving file loses git history
Solution:
# Use git mv instead of rename
git mv old-path/file.md new-path/file.md
# Git preserves history with proper similarity detection
git log --follow new-path/file.md
Issue 4: External Links to Old URLs
Problem: Blog posts, social media links to old URLs
Solution:
// Comprehensive redirects
{
// Old path → slug
from: '/ai/llm/fundamentals/intro',
to: '/llm-introduction',
},
{
// With and without trailing slash
from: '/ai/llm/fundamentals/intro/',
to: '/llm-introduction',
},
{
// Old numbered versions
from: '/ai/llm/01-intro',
to: '/llm-introduction',
}
Issue 5: Performance with 50K Notes
Problem: Slug registry becomes huge
Solution:
// Shard slug registry
slugs/
├── a-c.json // Slugs starting with a, b, c
├── d-f.json
├── g-i.json
...
// Fast lookup
function get_slug(note_id) {
first_letter = note_id[0].lower();
shard = load_shard(first_letter);
return shard[note_id];
}
Summary
Three-pillar solution:
-
Stable Slugs
- Permanent URLs independent of file location
- SEO-friendly, hierarchical where needed
- LLM-generated, collision-free
- Slug registry tracks all mappings
-
Frontmatter Ordering
sidebar_positionfor both tools- Gap numbering (10, 20, 30) for flexibility
- Category files for folder ordering
- Remove ugly number prefixes from filenames
-
Obsidian Visual Ordering
- Dataview queries show ordered navigation
- Custom File Explorer plugin reads frontmatter
- Emoji aliases for quick visual scanning
- Folder notes for curated learning paths
Migration timeline:
- Week 1-2: Generate slugs
- Week 3-4: Assign sidebar positions
- Week 5: Remove number prefixes
- Week 6-8: Convert links to slugs
- Week 9: Obsidian visual setup
- Week 10: Redirects & SEO
Investment:
- Time: 40-50 hours (mostly LLM automated)
- Cost: $50-80 (Claude API)
- Risk: Low (incremental, reversible)
Payoff:
- ✅ Zero 404s from file moves
- ✅ Preserved SEO value
- ✅ Clean, logical sidebar ordering
- ✅ Obsidian + Docusaurus harmony
- ✅ LLM can safely reorganize structure
Next Steps:
- ✅ Read this document
- ⬜ Backup vault (git commit)
- ⬜ Run Phase 1: Generate slugs (week 1)
- ⬜ Test build, verify no errors
- ⬜ Run Phase 2: Sidebar positions (week 3)
- ⬜ Gradual rollout over 10 weeks
- ⬜ Monitor analytics for 404s
- ⬜ Celebrate stable URLs! 🎉
Remember: URLs are forever. File paths are temporary. Invest in permanent slugs now, reorganize freely forever.