Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:57:46 +08:00
commit 0958e2ff2c
17 changed files with 2762 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
---
name: obsidian-vault-manager
description: Expert in managing Obsidian vaults using obsidian-cli workflows for reading, writing, searching, moving, and organizing notes while preserving wiki-link integrity and vault structure. Automatically activates when working with Obsidian vaults, markdown notes with wiki-links, or when internal link integrity needs to be preserved during file operations.
---
# Obsidian Vault Manager
## Prerequisites
Before performing vault operations:
1. **Verify obsidian-cli is installed:**
```bash
obsidian-cli --version
```
2. **If obsidian-cli is unavailable:**
- Install via: `npm install -g @johnlindquist/obsidian-cli`
- Fallback: Standard file operations can be used but will NOT preserve wiki-links
- Warning: Without obsidian-cli, moving notes will break all internal `[[wiki-links]]`
3. **Verify vault is accessible:**
```bash
obsidian-cli print-default
```
## Overview
**Use `obsidian-cli` for all Obsidian vault operations.** Standard file tools (mv, Write, Edit) break internal links and ignore vault structure. The `obsidian-cli` tool automatically preserves `[[wiki-links]]` and maintains vault integrity.
## When to Use
This skill activates when:
- Working with Obsidian vaults (`.md` files with `[[wiki-links]]`)
- Moving/renaming notes (links must stay valid)
- Creating notes with Obsidian-specific syntax (wiki-links, checkboxes, tags)
- Searching vault content or note names
- Organizing multiple notes across folders
**Don't use for:**
- General markdown editing outside Obsidian vaults
- Static documentation (no internal links)
- Single-file markdown operations
## Quick Reference
| Task | Command | Notes |
|------|---------|-------|
| Check vault | `obsidian-cli print-default` | Always run first |
| Read note | `obsidian-cli print "Note Name"` | Reads by name or path |
| Create note | `obsidian-cli create "Name" --content "text"` | Add `--open` to launch Obsidian |
| Update note | `obsidian-cli create "Name" --content "text" --append` | Use `--overwrite` to replace |
| Move note | `obsidian-cli move "old/path" "new/path"` | **Auto-updates all links** |
| Search content | `obsidian-cli search-content "term"` | Searches note contents |
| Search names | `obsidian-cli search` | Fuzzy search (interactive) |
| Daily note | `obsidian-cli daily` | Create/open today's note |
**See also:**
- [Complete obsidian-cli Command Reference](./references/obsidian-cli-reference.md) - All commands with flags and advanced usage
- [Obsidian Syntax Reference](./references/obsidian-syntax.md) - Wiki-links, tags, frontmatter, and markdown syntax
- [Note Templates](./assets/templates/) - Daily note, project, and meeting templates
## Core Workflows
### Always Check Vault First
```bash
# REQUIRED before any operation
obsidian-cli print-default
# Get path for direct file operations if needed
VAULT_PATH=$(obsidian-cli print-default --path-only)
```
**Why:** Paths are vault-relative, not repository-relative. Creating files in wrong location breaks vault structure.
### Moving/Reorganizing Notes
```bash
# ✅ CORRECT: Auto-updates all links
obsidian-cli move "Random Notes/Design" "Projects/Design"
# ❌ WRONG: Breaks all links to this note
mv "vault/Random Notes/Design.md" "vault/Projects/Design.md"
```
**Critical:** `obsidian-cli move` updates every link in the vault automatically. Using `mv` or file operations breaks internal references.
### Creating/Updating Notes
```bash
# Create new note
obsidian-cli create "Projects/Mobile App" --content "# Mobile App\n\n## Tasks\n- [ ] Task 1"
# Append to existing (safe if file exists)
obsidian-cli create "Daily Log" --content "\n## Update\n- New entry" --append
# Replace existing (use cautiously)
obsidian-cli create "Draft" --content "# Fresh content" --overwrite
```
**Obsidian syntax in `--content`:**
- Wiki-links: `[[Note Name]]`
- Tags: `#project`
- Checkboxes: `- [ ] Task`
- Newlines: `\n`
**Templates:** Use provided [note templates](./assets/templates/) as starting points for common note types (daily notes, projects, meetings).
### Searching and Organizing
```bash
# Find notes mentioning topic
obsidian-cli search-content "API design"
# Read found note
obsidian-cli print "Backend/API Design"
# Reorganize (preserves all links)
obsidian-cli move "Backend/API Design" "Projects/Backend/API Design"
```
## Common Mistakes
| Mistake | Why Wrong | Fix |
|---------|-----------|-----|
| Using `mv` to move notes | Breaks all `[[wiki-links]]` to that note | Use `obsidian-cli move` |
| Using `Write` tool for notes | Creates files outside vault or wrong location | Use `obsidian-cli create --content` |
| Using `Read` for vault notes | Misses vault context, no search integration | Use `obsidian-cli print` |
| Not checking vault first | Operations fail or create files in wrong place | Always run `print-default` first |
| Manual link updating with sed | Error-prone, misses bidirectional links | `obsidian-cli move` handles automatically |
| Using absolute paths | Breaks when vault moves | Use vault-relative paths |
## When to Use Standard Tools
**Use `obsidian-cli` first.** Only use standard tools when:
- Bulk editing note contents (use `Edit` after `obsidian-cli print`)
- Complex search patterns (use `Grep` with vault path)
- File pattern matching (use `Glob` on `$VAULT_PATH/**/*.md`)
**Always preserve:**
- Frontmatter (YAML between `---`)
- Obsidian link syntax `[[Note]]`
- Tag syntax `#tag-name`
- Markdown structure
## Integration Pattern
```bash
# 1. Check vault
obsidian-cli print-default
# 2. Use obsidian-cli for vault operations
obsidian-cli search-content "search term"
obsidian-cli print "Found Note"
# 3. Use standard tools ONLY when needed
# (e.g., complex editing after reading with obsidian-cli)
```
## Success Criteria
Vault operations succeed when:
- All `[[wiki-links]]` remain valid after moves
- Notes created in correct vault location
- Markdown and frontmatter preserved
- Search returns accurate results
- No broken links or orphaned notes

View File

@@ -0,0 +1,45 @@
---
date: {{date}}
tags:
- daily-note
---
# {{date}}
## Morning
### Goals
- [ ]
- [ ]
- [ ]
### Schedule
-
## Notes
### Meetings
### Ideas
### Quick Captures
## Evening Review
### Completed
-
### Challenges
### Tomorrow
- [ ]
- [ ]
## Links
- [[{{yesterday}}|Yesterday]]
- [[{{tomorrow}}|Tomorrow]]

View File

@@ -0,0 +1,21 @@
---
date: {{date:YYYY-MM-DD}}
tags: [daily-note]
---
# {{date:YYYY-MM-DD}}
## 📝 Today's Focus
- [ ]
## ✅ Completed
-
## 💭 Notes
## 🔗 Links
- [[Yesterday|{{date-1d:YYYY-MM-DD}}]]
- [[Tomorrow|{{date+1d:YYYY-MM-DD}}]]

View File

@@ -0,0 +1,71 @@
---
title: "{{meeting-title}}"
date: {{date}}
time: {{time}}
tags:
- meeting
- {{tag}}
attendees:
- {{attendee}}
---
# {{meeting-title}}
**Date:** {{date}}
**Time:** {{time}}
**Location:**
## Attendees
- [[{{attendee-1}}]]
- [[{{attendee-2}}]]
## Agenda
1.
2.
3.
## Discussion
### Topic 1
### Topic 2
### Topic 3
## Decisions
-
## Action Items
- [ ] {{person}} - {{action}} - Due: {{date}}
- [ ]
- [ ]
## Parking Lot
-
## Next Steps
## Follow-up
**Next Meeting:** {{date}}
## Links
- [[{{previous-meeting}}|Previous Meeting]]
- [[{{project}}|Project]]
-
---
**Notes by:**
**Distribution:**

View File

@@ -0,0 +1,40 @@
---
date: {{date:YYYY-MM-DD}}
tags: [meeting]
attendees: []
---
# {{title}} - {{date:YYYY-MM-DD}}
## 📅 Meeting Info
- **Date:** {{date:YYYY-MM-DD HH:mm}}
- **Attendees:**
-
- **Location:**
## 📋 Agenda
1.
2.
3.
## 📝 Notes
### Topic 1
### Topic 2
## ✅ Action Items
- [ ] [@person] Action item 1
- [ ] [@person] Action item 2
## 🔗 Related
- [[Previous Meeting|{{date-7d:YYYY-MM-DD}}]]
- [[Project Name]]
## 📄 Attachments
-

View File

@@ -0,0 +1,94 @@
---
title: {{project-name}}
status: planning
start-date: {{date}}
tags:
- project
- {{tag}}
---
# {{project-name}}
## Overview
**Status:** #status/planning
**Owner:**
**Timeline:**
### Goals
### Success Criteria
## Context
### Problem Statement
### Background
## Plan
### Phases
- [ ] Phase 1:
- [ ] Phase 2:
- [ ] Phase 3:
### Milestones
| Milestone | Target Date | Status |
| --------- | ----------- | ------ |
| | | |
## Tasks
### To Do
- [ ]
- [ ]
- [ ]
### In Progress
-
### Completed
- [x]
### Blocked
-
## Resources
### Documents
- [[]]
### References
-
### Team
-
## Notes
### Decisions
### Risks
### Open Questions
- [ ]
## Updates
### {{date}}
## Related
- [[Projects MOC]]
-

View File

@@ -0,0 +1,48 @@
---
title: {{title}}
tags: [project]
status: planning
created: {{date:YYYY-MM-DD}}
---
# {{title}}
## 🎯 Overview
Brief description of the project.
## 📋 Goals
- [ ] Goal 1
- [ ] Goal 2
- [ ] Goal 3
## ✅ Tasks
### To Do
- [ ] Task 1
- [ ] Task 2
### In Progress
-
### Done
-
## 📚 Resources
- [[Link to related note]]
-
## 📝 Notes
### {{date:YYYY-MM-DD}}
Initial project setup.
## 🏷️ Related Projects
- [[Related Project 1]]

View File

@@ -0,0 +1,380 @@
# obsidian-cli Command Reference
Complete reference for `obsidian-cli` commands and advanced usage patterns.
## Installation
```bash
npm install -g @johnlindquist/obsidian-cli
```
Verify installation:
```bash
obsidian-cli --version
```
## Core Commands
### print-default
Display current vault information.
```bash
obsidian-cli print-default
```
**Flags:**
- `--path-only` - Output only the vault path (useful for scripting)
**Output:**
- Vault name
- Vault path
- Vault status
**Usage:**
```bash
# Get vault info
obsidian-cli print-default
# Get path for scripts
VAULT_PATH=$(obsidian-cli print-default --path-only)
echo "Vault location: $VAULT_PATH"
```
### print
Read note contents by name or path.
```bash
obsidian-cli print "Note Name"
obsidian-cli print "folder/Note Name"
```
**Behavior:**
- Searches by note name first (without path)
- Falls back to path-based lookup
- Returns full note contents including frontmatter
- Case-sensitive matching
**Examples:**
```bash
# Read by name
obsidian-cli print "Project Plan"
# Read by path
obsidian-cli print "Work/Projects/Project Plan"
# Pipe to other tools
obsidian-cli print "Note" | grep "TODO"
```
### create
Create new notes or update existing ones.
```bash
obsidian-cli create "Note Name" --content "content"
```
**Required Flags:**
- `--content "text"` - Note content (supports `\n` for newlines)
**Optional Flags:**
- `--append` - Add content to end of existing note (safe for existing files)
- `--overwrite` - Replace entire note (destructive)
- `--open` - Open note in Obsidian after creation
**Content Syntax:**
- Use `\n` for newlines
- Include Obsidian syntax: `[[wiki-links]]`, `#tags`, `- [ ]` checkboxes
- Frontmatter can be included in content
**Examples:**
```bash
# Create new note
obsidian-cli create "Meeting Notes" --content "# Meeting\n\nAttendees: [[John]], [[Sarah]]"
# Append to existing
obsidian-cli create "Daily Log" --content "\n## 3pm Update\n- Completed task" --append
# Replace existing (caution!)
obsidian-cli create "Draft" --content "# New Draft\n\nStarting over" --overwrite
# Create and open in Obsidian
obsidian-cli create "Quick Note" --content "# Note" --open
```
**Frontmatter Example:**
```bash
obsidian-cli create "Book Review" --content "---\ntitle: Book Title\nauthor: Author Name\nrating: 5\n---\n\n# Review\n\nExcellent book about [[Topic]]"
```
### move
Move or rename notes while preserving all wiki-links.
```bash
obsidian-cli move "old/path" "new/path"
```
**Behavior:**
- Automatically updates ALL links to moved note throughout entire vault
- Updates bidirectional links
- Maintains frontmatter and note content
- Creates destination folder if needed
**Path Formats:**
- Vault-relative paths (no leading `/`)
- With or without `.md` extension
- Folder paths for organizing
**Examples:**
```bash
# Move note to different folder
obsidian-cli move "Inbox/Idea" "Projects/New Idea"
# Rename note
obsidian-cli move "Draft Title" "Final Title"
# Reorganize with folders
obsidian-cli move "Random/Design Doc" "Projects/Mobile/Design Doc"
# Move with .md extension (works the same)
obsidian-cli move "note.md" "folder/note.md"
```
**Critical:** This is the ONLY safe way to move notes. Using `mv`, `Write`, or file operations will break all links.
### search-content
Search note contents for text.
```bash
obsidian-cli search-content "search term"
```
**Behavior:**
- Full-text search across all notes
- Returns matching note paths
- Case-insensitive by default
- Searches note content, not just titles
**Examples:**
```bash
# Find notes about a topic
obsidian-cli search-content "API design"
# Find todos
obsidian-cli search-content "- [ ]"
# Find tagged notes
obsidian-cli search-content "#important"
# Combine with other commands
for note in $(obsidian-cli search-content "refactor"); do
echo "Found in: $note"
obsidian-cli print "$note"
done
```
### search
Interactive fuzzy search for note names.
```bash
obsidian-cli search
```
**Behavior:**
- Opens interactive picker
- Fuzzy matching on note names
- Navigate with arrow keys
- Press Enter to select
**Usage:**
- Run command
- Type to filter notes
- Select note with Enter
- Use selected note path in scripts
**Note:** This is interactive and may not work in all automation contexts. Use `search-content` for scripting.
### daily
Create or open daily note.
```bash
obsidian-cli daily
```
**Behavior:**
- Creates note with today's date (YYYY-MM-DD format by default)
- Opens in Obsidian if it already exists
- Uses vault's daily note template if configured
**Examples:**
```bash
# Open today's note
obsidian-cli daily
# Create with custom content
obsidian-cli daily && obsidian-cli create "$(date +%Y-%m-%d)" --content "\n## Evening Review\n- Accomplishments" --append
```
## Advanced Usage Patterns
### Scripting with obsidian-cli
```bash
#!/bin/bash
# Get vault path for reference
VAULT_PATH=$(obsidian-cli print-default --path-only)
# Search and process notes
obsidian-cli search-content "TODO" | while read -r note; do
echo "Processing: $note"
content=$(obsidian-cli print "$note")
# Process content...
done
# Bulk reorganization
for note in $(obsidian-cli search-content "#archive"); do
obsidian-cli move "$note" "Archive/$note"
done
```
### Combining with Standard Tools
```bash
# Use obsidian-cli for vault operations, then standard tools for processing
obsidian-cli print "Note" > /tmp/note.md
# Edit with standard tools
sed -i 's/old/new/g' /tmp/note.md
# Write back to vault
obsidian-cli create "Note" --content "$(cat /tmp/note.md)" --overwrite
```
### Template-Based Note Creation
```bash
# Read template
TEMPLATE=$(cat templates/project-template.md)
# Create note with template
obsidian-cli create "New Project" --content "$TEMPLATE"
# Create with substitutions
TEMPLATE=$(cat templates/meeting-template.md | sed "s/DATE/$(date +%Y-%m-%d)/g")
obsidian-cli create "Meeting - Team Sync" --content "$TEMPLATE"
```
### Batch Operations
```bash
# Rename multiple notes with pattern
for note in Project-*; do
new_name=$(echo "$note" | sed 's/Project-/Archived-Project-/')
obsidian-cli move "$note" "Archive/$new_name"
done
# Add tag to multiple notes
obsidian-cli search-content "machine learning" | while read -r note; do
content=$(obsidian-cli print "$note")
obsidian-cli create "$note" --content "$content\n\n#machine-learning" --append
done
```
### Working with Frontmatter
```bash
# Create note with complex frontmatter
obsidian-cli create "Article" --content "---
title: Article Title
date: $(date +%Y-%m-%d)
tags:
- article
- published
author: John Doe
---
# Article Title
Content here with [[Wiki Links]]"
```
### Link Integrity Verification
```bash
# After bulk operations, verify links
# (obsidian-cli handles this automatically, but for validation:)
VAULT_PATH=$(obsidian-cli print-default --path-only)
# Use standard tools to find broken links
grep -r "\[\[.*\]\]" "$VAULT_PATH" | while read -r line; do
# Check if target exists
# obsidian-cli move ensures this isn't needed
done
```
## Troubleshooting
### Command Not Found
```bash
# Install globally
npm install -g @johnlindquist/obsidian-cli
# Or use npx
npx @johnlindquist/obsidian-cli print-default
```
### No Default Vault
Error: "No default vault set"
**Solution:**
- Open Obsidian application
- Vault must be opened at least once
- obsidian-cli reads from Obsidian's configuration
### Path Issues
**Problem:** Note not found by name
**Solution:**
```bash
# Use full path
obsidian-cli print "folder/subfolder/Note Name"
# Or search first
obsidian-cli search-content "unique phrase in note"
```
### Newlines Not Working
**Problem:** `\n` appears literally in notes
**Solution:**
```bash
# Use echo with -e flag
obsidian-cli create "Note" --content "$(echo -e "Line 1\nLine 2")"
# Or use $'...' syntax
obsidian-cli create "Note" --content $'Line 1\nLine 2'
```
## Best Practices
1. **Always check vault first:** Run `print-default` before operations
2. **Use obsidian-cli move exclusively:** Never use `mv` for notes
3. **Preserve Obsidian syntax:** Maintain `[[links]]`, `#tags`, frontmatter
4. **Test on copies:** For bulk operations, test on duplicate notes first
5. **Use --append safely:** Append is safe for existing files, overwrite is destructive
6. **Script defensively:** Check command success before proceeding
7. **Backup regularly:** obsidian-cli is safe, but backups prevent mistakes
## See Also
- [Obsidian Syntax Reference](./obsidian-syntax.md) - Wiki-link and markdown syntax
- [Note Templates](../assets/templates/) - Ready-to-use note templates

View File

@@ -0,0 +1,567 @@
# Obsidian Markdown Syntax Reference
Complete reference for Obsidian-specific markdown syntax, including wiki-links, tags, frontmatter, and extended markdown features.
## Wiki-Links
Obsidian's primary linking syntax for internal note connections.
### Basic Wiki-Links
```markdown
[[Note Name]]
```
Links to a note named "Note Name.md" anywhere in the vault.
**Characteristics:**
- Case-sensitive
- Extension not required
- Searches entire vault by name
- Creates link even if note doesn't exist (shown in different color in Obsidian)
### Wiki-Links with Aliases
```markdown
[[Actual Note Name|Display Text]]
```
Display custom text while linking to the actual note.
**Examples:**
```markdown
See the [[Project Requirements|requirements]] for details.
Read [[Albert Einstein|Einstein's]] biography.
Check [[2024-01-15|yesterday's notes]].
```
### Wiki-Links to Headings
```markdown
[[Note Name#Heading]]
[[Note Name#Heading|Custom Text]]
```
Link to specific section within a note.
**Examples:**
```markdown
Review [[Meeting Notes#Action Items]]
See [[API Documentation#Authentication|auth docs]]
```
**Heading Link Rules:**
- Heading text must match exactly (case-sensitive)
- Use heading text without the `#` prefix
- Spaces in headings are preserved
- Works with any heading level
### Wiki-Links to Blocks
```markdown
[[Note Name#^block-id]]
```
Link to specific block within a note.
**Block ID Syntax:**
```markdown
This is a paragraph with an ID. ^block-123
- List item with ID ^item-456
```
**Example:**
```markdown
Reference: [[Research#^key-finding]]
```
### Wiki-Links with Paths
```markdown
[[folder/subfolder/Note Name]]
```
Specify path when multiple notes share the same name.
**Examples:**
```markdown
[[Work/Projects/Project Plan]]
[[Personal/Projects/Project Plan]]
```
### Embedding Notes
```markdown
![[Note Name]]
```
Embed the entire content of another note.
**Examples:**
```markdown
![[Meeting Template]]
![[Quote Collection#Favorite Quotes]]
```
### Embedding Images
```markdown
![[image.png]]
![[image.png|200]]
![[image.png|200x100]]
![[folder/image.png|Custom Alt Text|300]]
```
**Size Specifications:**
- `|width` - Set width, maintain aspect ratio
- `|widthxheight` - Set both dimensions
- Add alt text before dimensions
## Tags
Flexible categorization and filtering system.
### Basic Tags
```markdown
#tag
#tag-name
#tag_name
```
**Rules:**
- Start with `#`
- No spaces (use `-` or `_`)
- Alphanumeric characters
- Case-sensitive
- Can appear anywhere in note
**Examples:**
```markdown
#project #work #important
This note is about #machine-learning concepts.
Status: #in-progress
```
### Nested Tags
```markdown
#parent/child
#parent/child/grandchild
```
Creates tag hierarchy.
**Examples:**
```markdown
#project/work/client-a
#project/personal/side-hustle
#status/active
#status/archived
```
**In Obsidian UI:**
- Tags displayed as hierarchy
- Filter by parent shows all children
- Organize tags logically
### Inline Tags
Tags can appear anywhere in text:
```markdown
Discussed #meeting-notes with team about #q1-planning.
#review-required
```
### Multi-Word Tags
```markdown
#multi-word-tag
#multi_word_tag
```
Use hyphens or underscores, not spaces.
## Frontmatter (YAML)
Structured metadata at the start of notes.
### Basic Frontmatter
```markdown
---
title: Note Title
author: Author Name
date: 2024-01-15
---
# Note Content
```
**Rules:**
- Must be at very start of file
- Enclosed in `---` delimiters
- YAML syntax
- Key-value pairs
### Common Fields
```markdown
---
title: Document Title
date: 2024-01-15
tags:
- tag1
- tag2
aliases:
- Alternative Name
- Shorthand
author: John Doe
status: draft
---
```
### Array Values
```markdown
---
tags:
- project
- important
categories: [work, planning]
---
```
Both syntaxes work (YAML list or inline array).
### Nested Objects
```markdown
---
metadata:
created: 2024-01-15
modified: 2024-01-20
version: 1.2
project:
name: Project Alpha
status: active
team:
- Alice
- Bob
---
```
### Obsidian-Specific Fields
```markdown
---
aliases:
- Alt Name 1
- Alt Name 2
tags:
- vault-tag
cssclasses:
- custom-theme
- wide-page
---
```
**Special Fields:**
- `aliases` - Alternative names for wiki-links
- `tags` - Tags (alternative to inline `#tags`)
- `cssclasses` - Custom CSS classes for styling
## Task Lists (Checkboxes)
Extended checkbox syntax beyond standard markdown.
### Standard Checkboxes
```markdown
- [ ] Unchecked task
- [x] Completed task
- [X] Completed task (capital X works too)
```
### Extended Checkbox Types
```markdown
- [ ] To do
- [x] Done
- [>] Forwarded/Rescheduled
- [<] Scheduled
- [-] Cancelled
- [?] Question
- [!] Important
- [*] Star
- ["] Quote
- [l] Location
- [b] Bookmark
- [i] Information
- [S] Amount/Money
- [I] Idea
- [p] Pro
- [c] Con
- [f] Fire
- [k] Key
- [w] Win
- [u] Up
- [d] Down
```
**Note:** Extended types require Obsidian or plugins. Rendered specially in Obsidian UI.
### Nested Tasks
```markdown
- [ ] Parent task
- [ ] Subtask 1
- [x] Subtask 2
- [ ] Subtask 3
- [ ] Sub-subtask
```
## Callouts (Admonitions)
Styled information blocks.
### Basic Callout
```markdown
> [!note]
> This is a note callout.
> [!info]
> This is an info callout.
```
### Callout Types
```markdown
> [!note]
> Note content
> [!abstract] / [!summary] / [!tldr]
> Summary content
> [!info] / [!todo]
> Information
> [!tip] / [!hint] / [!important]
> Helpful tip
> [!success] / [!check] / [!done]
> Success message
> [!question] / [!help] / [!faq]
> Question content
> [!warning] / [!caution] / [!attention]
> Warning message
> [!failure] / [!fail] / [!missing]
> Error message
> [!danger] / [!error]
> Danger warning
> [!bug]
> Bug report
> [!example]
> Example content
> [!quote] / [!cite]
> Quoted text
```
### Callout with Title
```markdown
> [!note] Custom Title
> Content goes here.
> [!warning] Important Warning
> This is critical information.
```
### Foldable Callouts
```markdown
> [!note]- Collapsed by default
> Content hidden initially.
> [!note]+ Expanded by default
> Content visible initially.
```
### Nested Callouts
```markdown
> [!info] Outer callout
> Information here.
>
> > [!warning] Nested callout
> > Nested warning.
```
## Code Blocks
### Basic Code Blocks
````markdown
```
Plain code block
```
```javascript
console.log("JavaScript code");
```
```python
print("Python code")
```
````
### With Line Numbers
Obsidian doesn't natively support line numbers, but some plugins do.
## Tables
### Basic Tables
```markdown
| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| Row 1 | Data | Data |
| Row 2 | Data | Data |
```
### Alignment
```markdown
| Left | Center | Right |
| :--- | :----: | ----: |
| L1 | C1 | R1 |
| L2 | C2 | R2 |
```
### Tables with Links
```markdown
| Project | Status | Notes |
| ------- | ------ | ----- |
| [[Project A]] | #active | See [[Notes]] |
| [[Project B]] | #done | Complete |
```
## Comments
```markdown
%%
This is a comment.
Multi-line comments are supported.
%%
Regular text. %% Inline comment %%
```
**Rules:**
- Enclosed in `%%`
- Not rendered in reading view
- Can be inline or multi-line
## Footnotes
```markdown
Here's a sentence with a footnote[^1].
[^1]: This is the footnote content.
Another reference[^note].
[^note]: Named footnotes work too.
```
## Obsidian URI
Link to open notes in Obsidian app:
```markdown
obsidian://open?vault=VaultName&file=NoteName
[Open Note](obsidian://open?vault=MyVault&file=folder/note)
```
## Combining Syntax
### Complex Examples
```markdown
---
title: Project Plan
tags:
- project
- planning
status: active
---
# [[Projects|Project]]: Mobile App Redesign
## Overview
This project focuses on #ui-ux improvements. See [[Design System]] for details.
## Tasks
- [ ] Review [[Requirements#Functional|functional requirements]]
- [x] Create [[Wireframes]]
- [>] Schedule meeting with #stakeholders
- [ ] Update [[Project Timeline]]
## References
![[Design Principles#Core Values]]
> [!tip] Best Practice
> Always link to [[Style Guide]] when implementing designs.
## Related
- [[Previous Projects#Mobile|Past mobile work]]
- [[Team Members|Team]]
#project/mobile #status/in-progress
```
## Best Practices
1. **Use wiki-links liberally** - Create connections between related notes
2. **Consistent tag hierarchy** - Use nested tags for organization (`#project/work/client`)
3. **Frontmatter for metadata** - Structure data that's queried frequently
4. **Aliases for flexibility** - Add aliases for common alternative names
5. **Descriptive link text** - Use aliases when natural reading flow matters
6. **Block links sparingly** - For specific references within longer notes
7. **Comments for drafts** - Use `%%` for notes to self that shouldn't be published
8. **Callouts for emphasis** - Highlight important information visually
## Compatibility Notes
- Standard markdown works everywhere
- Wiki-links are Obsidian-specific (convert to regular links for export)
- Extended checkboxes may need plugins outside Obsidian
- Callouts are Obsidian-specific (render as blockquotes elsewhere)
- Frontmatter is standard YAML (works in most markdown processors)
- Comments (`%%`) are Obsidian-specific
- Tags work in Obsidian; may be ignored elsewhere
## See Also
- [obsidian-cli Reference](./obsidian-cli-reference.md) - Command-line vault operations
- [Note Templates](../assets/templates/) - Ready-to-use note structures

View File

@@ -0,0 +1,319 @@
---
name: technical-writer
description: Expert in technical documentation (README, API docs, guides, tutorials, quickstarts, specs, release notes) that automatically activates when creating, editing, or reviewing .md files in docs/ directories, README files, or when discussing documentation structure, style guides, or content organization. Follows industry best practices for clear, accessible technical communication across all documentation types.
---
# Technical Documentation Expert
## Overview
Provides expert guidance for creating clear, comprehensive, and user-friendly technical documentation following industry best practices and structured content models.
**Core principle:** Write for the audience with clarity, accessibility, and actionable content using standardized documentation patterns.
## When to Use
Automatically activates when:
- Working with `.md` files in `docs/` directories
- Creating or editing README files
- Editing documentation files or markup
- Discussing documentation structure, information architecture, or style guides
- Creating API documentation with examples and parameter tables
- Writing user guides, tutorials, or quickstarts
- Drafting release notes or change logs
- Structuring specifications or technical proposals
Manual invocation when:
- User explicitly asks about documentation best practices
- User needs guidance on content organization or structure
- User requests help with technical writing style
- User encounters documentation quality issues
## When NOT to Use This Skill
Do not use this skill for:
- Creative writing or marketing copy
- Code implementation (documentation only)
- Project management documentation
- Internal team chat or informal notes
- Academic papers or research documentation
## Core Expertise Areas
### Content Types
1. **Conceptual** - Explains what something is and why it's useful ("About..." articles)
2. **Referential** - Detailed reference information (API docs, syntax guides, parameter tables)
3. **Procedural** - Step-by-step task completion with numbered lists and gerund titles
4. **Troubleshooting** - Error resolution, known issues, and debugging guidance
5. **Quickstart** - Essential setup in 5 minutes/600 words maximum
6. **Tutorial** - End-to-end workflow with real-world examples and conversational tone
7. **Release Notes** - Version changes categorized by type (Features, Fixes, Breaking Changes)
### Documentation Structure
**Standard Article Elements:**
- Titles: Sentence case, gerund for procedures, character limits by level
- Intros: 1-2 sentences explaining content
- Prerequisites and permissions when applicable
- Clear next steps
**Information Architecture:**
- Hierarchical structure with maximum 4 navigation levels
- Content ordering: Conceptual → Referential → Procedural → Troubleshooting
**For detailed structure requirements:** See `./references/style-guide.md` section on Article Structure and Standard Elements.
### Style Guide Principles
Apply formatting and style rules from the comprehensive style guide:
- Language: Clear, simple, active voice, sentence case
- Technical formatting: Code in backticks, UI in bold, placeholders in ALL-CAPS
- Structure: Numbered lists for procedures, bullets for non-sequential info
- Links: Descriptive text, no "click here"
- Alerts: Use Note, Tip, Important, Warning, Caution sparingly
**For detailed formatting rules:** See `./references/style-guide.md` sections on Language and Tone, Technical Writing Conventions, and Structure and Format.
### Procedural Content Ordering
Follow standard procedural sequence: Enabling → Using → Managing → Disabling → Destructive
Within individual steps: Optional info → Reason → Location → Action
**For complete ordering guidelines:** See `./references/style-guide.md` section on Content Ordering Guidelines.
## Development Workflow
### 1. Understand the Audience
- Identify user expertise level (beginner, intermediate, advanced)
- Determine user goals and tasks
- Consider context where documentation will be used
- Plan appropriate content depth and technical level
### 2. Choose Content Type
Select the appropriate content type:
- **Need to explain a concept?** → Conceptual
- **Documenting API or syntax?** → Referential
- **How-to for specific task?** → Procedural
- **Debugging help?** → Troubleshooting
- **Quick setup needed?** → Quickstart (≤5 minutes)
- **End-to-end learning?** → Tutorial
- **Version changes?** → Release Notes
### 3. Structure Content
**Standard content sequence:**
1. Title (sentence case, descriptive, within character limits)
2. Brief intro (1-2 sentences)
3. Prerequisites (if applicable)
4. Permissions statement (if required)
5. Main content (ordered appropriately by type)
6. Troubleshooting (embedded when helpful)
7. Next steps / Further reading
### 4. Apply Style Guide
Follow the comprehensive style guide for:
- Formatting code, UI elements, and placeholders
- Writing clear procedures with proper structure
- Adding accessibility features (alt text, sufficient contrast)
- Ensuring proper link formatting and context
- Using alerts appropriately
For complete style guide details, see: `./references/style-guide.md`
### 5. Content Accuracy
**Critical rule:** Do not invent or assume information not present in source material.
- If gaps exist, ask user for missing information
- Do not create placeholder or speculative content
- Verify technical accuracy with authoritative sources
- Include working examples when possible
## Problem-Solving Approach
### 1. Analysis Phase
- Review existing documentation structure and patterns
- Identify target audience and their needs
- Assess information architecture and navigation
- Check for consistency with project documentation standards
### 2. Solution Design
- Select appropriate content type for the task
- Plan information hierarchy and flow
- Consider accessibility and localization needs
- Design for different user expertise levels
### 3. Implementation
- Write clear, concise content following style guide
- Structure with appropriate headings and sections
- Include concrete examples where helpful
- Add tables for complex reference information
- Ensure proper formatting of code, UI, and placeholders
### 4. Validation
- Verify content accuracy and completeness
- Check that examples work as documented
- Ensure style guide compliance
- Validate accessibility (alt text, structure, contrast)
- Confirm navigation and links work correctly
**Automated validation:** Use `./scripts/validate_markdown.py <file>` to check:
- Proper heading hierarchy (no skipped levels)
- Code block formatting (language tags, closing backticks)
- Link syntax and descriptive link text
- Basic document structure
## Communication Style
**Be Clear and Actionable:**
- Use simple, direct language
- Provide specific examples and code snippets
- Break complex topics into digestible sections
- Include visual aids when they clarify concepts
**Serve Multiple Expertise Levels:**
- Layer content from simple to complex
- Provide quick reference sections
- Link to deeper explanations
- Use prerequisites to set expectations
**Focus on User Goals:**
- Organize by tasks users want to accomplish
- Use gerund titles for procedures ("Creating...", "Configuring...")
- Include "what you'll learn" or "what you'll build" statements
- Provide clear next steps after each article
## Reference Materials
This skill references the comprehensive style guide for detailed guidance on all formatting rules.
**See:** `./references/style-guide.md` for the complete technical writing style guide.
### Quick Discovery: Search Patterns
For specific formatting rules in the large style guide, use grep to search:
- **Alert formatting rules:** Search for `"alert"` in `./references/style-guide.md`
- **Code block formatting:** Search for `"code"` or `"backticks"` in `./references/style-guide.md`
- **Link formatting:** Search for `"link text"` in `./references/style-guide.md`
- **Table formatting:** Search for `"table"` in `./references/style-guide.md`
- **Heading hierarchy:** Search for `"heading"` in `./references/style-guide.md`
- **Procedural step structure:** Search for `"step structure"` or `"Within Procedural"` in `./references/style-guide.md`
- **Alt text requirements:** Search for `"alt text"` in `./references/style-guide.md`
- **Placeholder conventions:** Search for `"placeholder"` or `"ALL-CAPS"` in `./references/style-guide.md`
## Success Criteria
Documentation is successful when:
- Content is accessible to the target audience
- Structure follows the appropriate content type
- Examples clarify complex concepts
- Style guide rules are consistently applied
- Users can complete tasks using the documentation
- Information architecture supports easy navigation
- Content is accurate and up-to-date
## Quick Reference: Common Patterns
### README Structure
```markdown
# Project Title (sentence case)
Brief description in 1-2 sentences.
## Prerequisites
- Item 1
- Item 2
## Installation
1. Step one
2. Step two
## Usage
Basic usage examples with code blocks.
## Documentation
Links to further reading.
```
### API Documentation Pattern
```markdown
## `functionName(param1, param2)`
Brief description of what the function does.
**Parameters:**
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| param1 | string | Description |
| param2 | number | Description |
**Returns:** Description of return value
**Example:**
\`\`\`language
// Working code example
\`\`\`
```
### Release Notes Pattern
```markdown
# Version X.Y.Z
## Features
- New feature description
## Fixes
- Bug fix description
## Breaking Changes
- Breaking change with migration path
## Improvements
- Enhancement description
```
## Remember
- Always consider the audience first
- Choose the right content type for the task
- Follow style guide consistently
- Do not invent information - ask when unclear
- Include working examples
- Make content accessible
- Structure for easy navigation
- Validate before completion

View File

@@ -0,0 +1,609 @@
# Comprehensive Technical Writing Style Guide
This reference provides detailed guidance for creating professional, accessible, and user-friendly technical documentation.
## Content Model
### Content Structure
- **Hierarchical organization**: Top-level doc sets → Categories → Map topics → Articles
- **Category creation threshold**: 10+ articles required for new categories
- **Navigation depth**: Maximum 4 levels deep
- **Consistent content types**: Each with specific purposes and formats
- **Standard elements**: Every article includes titles, intros, permissions, etc.
## Article Structure and Standard Elements
### Titles
**Character limits:**
- Categories: 67 character limit
- Map topics: 63 character limit
- Articles: 80 character limit
**Formatting:**
- Use sentence case (not title case)
- Gerund titles for procedural content ("Creating...", "Configuring...")
- Avoid "How to" prefix unless required by product convention
**Examples:**
✅ Do:
- "Set up OAuth for a single-page app"
- "Creating a service principal" (procedural/gerund)
❌ Don't:
- "Setting Up OAuth for a Single-Page App" (title case)
- "How to set up OAuth" (avoid "How to")
### Intros
**Length requirements:**
- Articles: 1-2 sentences
- Categories/Map topics: 1 sentence
**Content:**
- Must explain what the content covers
- Be specific and actionable
- Avoid vague language
**Examples:**
✅ Do:
"This guide shows you how to enable OAuth for single-page apps using PKCE. You'll configure an app, create secrets, and test the flow."
❌ Don't:
"In this document, we will be covering OAuth for single-page applications in depth." (vague, long-winded)
### Permissions Statements
**Required for:** All tasks requiring specific permissions
**Format options:**
1. **Frontmatter** (preferred):
```yaml
---
required-permissions:
role: Owner
scope: Subscription
---
```
2. **Inline**:
"You need the Owner role at the subscription scope to complete these steps."
**Consistency:** Use the same language patterns across documentation.
### Required Sections
When applicable, include these sections:
**Prerequisites:**
- Use structured list format
- Be specific about versions, tools, access levels
Example:
- An Azure subscription
- The Azure CLI 2.60.0 or later
- Owner role at the subscription scope
**Product callouts:**
"This feature is available on the Enterprise plan only."
**Next steps and Further reading:**
- Provide clear next actions
- Link to related content
- Use descriptive link text
## Content Types Detailed
### 1. Conceptual Content
**Purpose:** Explains what something is and why it's useful
**Characteristics:**
- "About..." article pattern
- Defines concepts and terminology
- Explains when to use and tradeoffs
- Provides context without step-by-step instructions
**Example:**
"About service principals" — defines the concept, when to use it, and tradeoffs.
### 2. Referential Content
**Purpose:** Detailed information for active use
**Characteristics:**
- Syntax guides with complete parameter lists
- Tables for complex data relationships
- Alphabetical or logical organization
- Comprehensive but scannable format
**When to use tables vs. lists:**
- **Tables**: Multiple related properties per item
- **Lists**: Simple, single-dimension information
**Structure headers appropriately:**
- Long reference content benefits from clear section breaks
- Use consistent heading hierarchy
- Enable quick scanning and search
**Example:**
"CLI reference for `az ad sp`" — flags, options, examples.
### 3. Procedural Content
**Purpose:** Step-by-step task completion
**Characteristics:**
- Numbered lists (sequential steps)
- Gerund titles ("Creating...", "Configuring...")
- One action per step
- Clear prerequisites upfront
**Step structure:**
1. Optional information (if applicable)
2. Reason for the step (if not obvious)
3. Location where to perform action
4. Action to take
**Example:**
"Creating a service principal" — numbered steps start-to-finish.
### 4. Troubleshooting Content
**Purpose:** Error resolution and known issues
**Types:**
**Known issues** (separate articles):
- Complex problems requiring detailed explanation
- Multiple potential causes
- Ongoing or unresolved issues
**General troubleshooting** (embedded):
- Common errors for specific tasks
- Quick fixes and workarounds
- Embedded in main task articles
**Structure:**
- Symptom description
- Cause explanation
- Resolution steps
- Prevention guidance
**Example:**
"Fix: AADSTS700016 error" — symptoms, cause, resolution.
### 5. Quickstart Content
**Purpose:** Essential steps for quick setup
**Critical requirements:**
- **Time limit**: 5 minutes / 600 words maximum
- **Specific intro phrasing**: Must clarify audience and scope
- **Audience clarification**: Required for complex products
**Structure:**
1. Before you begin (2-3 prerequisites)
2. Create resources (1-2 commands or clicks)
3. Run and verify (1 command or screenshot)
4. Clean up resources
**Intro pattern:**
"In this quickstart, you [accomplish X]. This guide is for [audience] who want to [goal]."
**Example:**
"Create and deploy your first function app" — 3-5 steps, done in 5 minutes.
### 6. Tutorial Content
**Purpose:** Detailed workflow guidance with real-world examples
**Requirements:**
- **Conversational tone**: Required for engagement
- **Real examples**: Must use actual, working examples (no placeholder code)
- **Conclusion structure**: Specific requirements for wrap-up
**Characteristics:**
- End-to-end scenario
- Explains "why" not just "how"
- Includes best practices
- Shows complete, working solution
**Conclusion must include:**
- Summary of what was accomplished
- Link to related concepts
- Suggested next steps
- Resources for going deeper
**Example:**
"Build a news summarizer with Functions and Cosmos DB" — end-to-end scenario.
### 7. Release Notes
**Purpose:** Version-specific changes and updates
**Requirements:**
- **Comprehensive formatting**: Specific categorization rules
- **Change categorization**: Features, fixes, improvements, breaking changes, etc.
**Categories (in order):**
1. Breaking Changes (if any)
2. Features (new capabilities)
3. Improvements (enhancements to existing features)
4. Fixes (bug fixes)
5. Documentation (doc updates)
6. Dependencies (version updates)
**Format:**
```markdown
## Version X.Y.Z - YYYY-MM-DD
### Breaking Changes
- Change description with migration path
### Features
- New feature description with brief example
### Improvements
- Enhancement description
### Fixes
- Bug fix description (can reference issue numbers)
```
**Example:**
"v1.8.0" — Features, fixes, breaking changes.
### Combining Content Types
**Guidelines:**
- Longer articles can combine multiple content types
- Follow content ordering guidelines
- Use clear transitions between sections
- Include troubleshooting information frequently
**Transition examples:**
- "Now that you understand the key concepts, follow these steps to enable the feature."
- "With the basics covered, let's explore advanced configurations."
## Content Ordering Guidelines
### Standard Content Sequence
1. **Conceptual** - What it is and why it's useful
2. **Referential** - Detailed information for active use
3. **Procedural** (in this specific order):
- **Enabling** - Initial setup/activation
- **Using** - Regular operational tasks
- **Managing** - Administrative/configuration tasks
- **Disabling** - Deactivation procedures
- **Destructive** - Deletion/removal tasks
4. **Troubleshooting** - Error resolution
### Within Procedural Steps
Order information within each step:
1. **Optional information** (if applicable)
- "If you already have X, skip this step."
2. **Reason** for the step (if not obvious)
- "This keeps latency low."
3. **Location** where to perform the action
- "In the Azure portal, go to Resource groups..."
4. **Action** to take
- "...and select Create."
**Example:**
"Create a resource group in the same region as your app. This keeps latency low. In the Azure portal, go to Resource groups and select Create. Name it `my-rg` and select a region."
## Style Guide Key Points
### Language and Tone
**Principles:**
- Clear, simple, approachable language
- Active voice preferred (passive acceptable when appropriate)
- Sentence case for titles and headers
- Avoid jargon, idioms, regional phrases
- Write for global, multilingual audience
**Examples:**
✅ Do:
"Run the command and wait for the confirmation message."
❌ Don't:
"One could conceivably run said command prior to proceeding." (jargon, passive, unclear)
### Technical Writing Conventions
**Code formatting:**
- Use `backticks` for code, file names, commands, parameters
- Keep code blocks to ~60 character line length
- Avoid command prompts in examples (just show commands)
- Use syntax highlighting with proper language tags
**UI elements:**
- Format UI text in **bold** (buttons, menu items, fields)
- Use exact text from the interface
- Use > for navigation paths: **File > Save As**
**Placeholders:**
- ALL-CAPS with dashes: YOUR-PROJECT, YOUR-RESOURCE-GROUP
- Must explain placeholders before or after use
- Be consistent with placeholder naming
**Images:**
- Include alt text for all images (40-150 characters)
- Alt text describes what's shown, not just "screenshot"
- Reference images in text: "as shown in the following image"
**Examples:**
✅ Good:
- "Select **Create** and run `az group create --name MY-RG --location westus`."
- "Replace YOUR-RG with the name of your resource group."
- Alt text: "Screenshot of the Azure portal showing the Create resource group form with fields completed"
### Structure and Format
**Lists:**
**Numbered lists** (procedures):
- Capitalize first word
- Use periods for complete sentences
- One action per step
- Sequential order matters
**Bullet lists** (non-sequential):
- Use asterisks (*) not dashes
- Capitalize first word
- Alphabetize when appropriate
- Parallel structure
**Tables:**
- Use consistent header formatting
- Align content properly (left for text, right for numbers)
- Include header row
- Keep cells concise
**Alert Types** (use sparingly):
- **Note**: Neutral, supplementary information
- "The CLI caches credentials for 1 hour."
- **Tip**: Helpful shortcuts or best practices
- "Use tags to organize resources across subscriptions."
- **Important**: Critical information that affects outcomes
- "Do not share client secrets. Rotate them every 90 days."
- **Warning**: Potential risks or consequences
- "Deleting the resource group removes all resources in it."
- **Caution**: Actions that could cause data loss or damage
- "Export data before disabling the feature to avoid loss."
### Links and References
**Internal links:**
- Use appropriate formatting for your doc system
- Link to specific sections when helpful
- Keep link text descriptive
**Link text:**
- Be descriptive (tell what user will find)
- Never use "click here" or "read more"
- Include context when needed
**External links:**
- Provide full context
- Explain why user should follow the link
- Consider link rot (prefer stable URLs)
**Examples:**
✅ Do:
- "See the authentication overview for background on OAuth 2.0."
- "For the OAuth 2.1 draft, see the IETF working group page."
❌ Don't:
- "Click here for more info."
- "Read more." (no context)
## Process and Workflow Elements
### Topics (Metadata)
**Character limits:**
- Keep topics concise
- Follow selection criteria for your platform
**Forbidden patterns:**
- Avoid duplicating title text
- Don't use as keyword stuffing
### Tool Switchers
**When to use:**
- Multiple interfaces for same task (Portal, CLI, PowerShell, Terraform)
- All methods achieve same outcome
- Each deserves equal treatment
**Format:**
- Use tabbed interface when supported
- Consistent ordering across docs
- Complete examples in each tab
**Example:**
"Portal | CLI | PowerShell | Terraform"
### Call to Action (CTA)
**Requirements:**
- Consistent formatting
- Clear, action-oriented language
- Specific next step
**Examples:**
- Next steps: "Next, secure your API keys with Key Vault."
- CTA button text: "Save", "Create", "Deploy" (not "Click to save")
### Reusables and Variables
**When to use reusables:**
- Content repeated verbatim across multiple articles
- Maintenance efficiency matters
- Content unlikely to need article-specific variations
**When to inline content:**
- Article-specific variations likely
- Better readability in source
- Single-use content
**Variable usage:**
- Define at document start or first use
- Be consistent with variable names
- Match placeholder conventions
**Examples:**
- "Set `YOUR-RG`, `YOUR-LOCATION`, and `YOUR-APP-NAME`."
- Reusable snippet: Common troubleshooting block for network timeouts
## Accessibility Requirements
### Alt Text
**Requirements:**
- 40-150 characters
- Describe what's shown, not "screenshot of..."
- Include relevant text from image
- Convey information, not aesthetics
**Examples:**
✅ "Azure portal showing the Create resource group form with fields completed"
❌ "Screenshot" (too vague)
### Structure
**Heading hierarchy:**
- Use proper heading levels (H1 → H2 → H3)
- Don't skip levels
- One H1 per page (the title)
**Reading order:**
- Content makes sense when read linearly
- Screen reader compatible
**Color and contrast:**
- Don't rely on color alone
- Ensure sufficient contrast
- Use patterns or labels in addition to color
### Links
**Descriptive link text:**
- Tells where link goes
- Makes sense out of context
- Avoid "click here"
### ARIA (when applicable)
- Use ARIA labels for complex interactions
- Ensure keyboard navigation works
- Test with screen readers
## Localization Considerations
**Write for translation:**
- Avoid idioms and colloquialisms
- Use simple sentence structure
- Be explicit (avoid implied information)
- Watch for cultural references
**Date and number formatting:**
- Use international formats
- Provide context for ambiguous formats
- Let localization system handle conversion
**Right-to-left (RTL) languages:**
- Ensure UI accommodates RTL
- Test with RTL languages
- Avoid directional language ("left sidebar")
**String externalization:**
- Use localization keys
- Avoid concatenating strings
- Plan for text expansion (some languages are longer)
## Quality Checklist
Use this checklist before publishing:
**Content:**
- [ ] Accurate and technically correct
- [ ] Appropriate content type for task
- [ ] Complete (no missing steps or information)
- [ ] Examples work as documented
- [ ] Tone appropriate for audience
**Structure:**
- [ ] Clear title (sentence case, within character limits)
- [ ] Brief intro (1-2 sentences)
- [ ] Prerequisites listed when needed
- [ ] Logical flow and organization
- [ ] Clear next steps
**Style:**
- [ ] Sentence case for headers
- [ ] Active voice (mostly)
- [ ] Code formatted correctly
- [ ] Placeholders explained
- [ ] Links descriptive and working
**Accessibility:**
- [ ] Alt text for all images
- [ ] Proper heading hierarchy
- [ ] Sufficient color contrast
- [ ] Keyboard accessible
**Polish:**
- [ ] Spell check passed
- [ ] Grammar correct
- [ ] Consistent terminology
- [ ] No jargon or explained when necessary
## Summary: Quick Decision Tree
**What type of content do I need?**
- Explaining a concept? → **Conceptual**
- Documenting API/syntax? → **Referential**
- How to do a task? → **Procedural**
- Fixing errors? → **Troubleshooting**
- Quick start (< 5 min)? → **Quickstart**
- Learning journey? → **Tutorial**
- Version changes? → **Release Notes**
**How should I structure it?**
1. Title (sentence case, descriptive)
2. Intro (1-2 sentences, specific)
3. Prerequisites (if needed)
4. Main content (type-appropriate)
5. Troubleshooting (when helpful)
6. Next steps
**What voice should I use?**
- Active, direct, clear
- Simple language
- Appropriate for global audience
- Professional but approachable
**Did I make it accessible?**
- Alt text on images
- Proper headings
- Descriptive links
- Sufficient contrast

View File

@@ -0,0 +1,267 @@
#!/usr/bin/env python3
"""
Markdown Documentation Validator
Validates markdown documentation files for common issues:
- Proper heading hierarchy (no skipped levels)
- Code block formatting (language tags, closing backticks)
- Link syntax validation
- Basic structure checks
Usage:
python validate_markdown.py <file_path>
python validate_markdown.py <directory_path>
"""
import re
import sys
from pathlib import Path
from typing import List, Tuple
class ValidationError:
"""Represents a validation error with line number and description."""
def __init__(self, line_num: int, error_type: str, message: str):
self.line_num = line_num
self.error_type = error_type
self.message = message
def __str__(self):
return f"Line {self.line_num}: [{self.error_type}] {self.message}"
class MarkdownValidator:
"""Validates markdown documentation files."""
def __init__(self, file_path: Path):
self.file_path = file_path
self.errors: List[ValidationError] = []
self.lines: List[str] = []
self.heading_levels: List[int] = []
def validate(self) -> List[ValidationError]:
"""Run all validation checks and return list of errors."""
try:
with open(self.file_path, 'r', encoding='utf-8') as f:
self.lines = f.readlines()
except Exception as e:
return [ValidationError(0, "FILE_ERROR", f"Cannot read file: {e}")]
self._check_heading_hierarchy()
self._check_code_blocks()
self._check_links()
self._check_basic_structure()
return sorted(self.errors, key=lambda e: e.line_num)
def _check_heading_hierarchy(self):
"""Check that heading levels don't skip (e.g., h1 -> h3)."""
prev_level = 0
for i, line in enumerate(self.lines, 1):
# Match ATX-style headings (# Heading)
match = re.match(r'^(#{1,6})\s+(.+)', line)
if match:
level = len(match.group(1))
self.heading_levels.append(level)
# Check for skipped levels
if level > prev_level + 1:
self.errors.append(ValidationError(
i,
"HEADING_SKIP",
f"Heading level skipped (h{prev_level} -> h{level}). Use h{prev_level + 1} instead."
))
# Check for title case (common mistake)
title = match.group(2).strip()
if self._is_title_case(title) and level <= 3:
self.errors.append(ValidationError(
i,
"TITLE_CASE",
f"Heading appears to use title case. Use sentence case instead: '{title}'"
))
prev_level = level
def _is_title_case(self, text: str) -> bool:
"""Check if text appears to be in title case."""
# Skip if too short or starts with code
if len(text.split()) < 3 or text.startswith('`'):
return False
words = text.split()
# Articles and short words that should be lowercase in sentence case
small_words = {'a', 'an', 'the', 'and', 'but', 'or', 'for', 'nor', 'on', 'at', 'to', 'from', 'by', 'with'}
capitalized_count = sum(1 for word in words[1:] if word and word[0].isupper() and word.lower() not in small_words)
# If more than 50% of non-first words are capitalized, likely title case
return capitalized_count > len(words[1:]) * 0.5
def _check_code_blocks(self):
"""Check code block formatting."""
in_code_block = False
code_block_start = 0
for i, line in enumerate(self.lines, 1):
# Check for code block fences
if line.strip().startswith('```'):
if not in_code_block:
# Starting a code block
in_code_block = True
code_block_start = i
# Check for language tag
fence_content = line.strip()[3:].strip()
if not fence_content:
self.errors.append(ValidationError(
i,
"CODE_BLOCK_LANG",
"Code block missing language identifier (e.g., ```python, ```bash, ```markdown)"
))
else:
# Ending a code block
in_code_block = False
# Check for unclosed code block
if in_code_block:
self.errors.append(ValidationError(
code_block_start,
"CODE_BLOCK_UNCLOSED",
"Code block opened but never closed"
))
def _check_links(self):
"""Check link syntax."""
for i, line in enumerate(self.lines, 1):
# Find all markdown links [text](url)
links = re.finditer(r'\[([^\]]+)\]\(([^)]+)\)', line)
for match in links:
link_text = match.group(1)
link_url = match.group(2)
# Check for "click here" anti-pattern
if link_text.lower() in ['click here', 'here', 'read more', 'more']:
self.errors.append(ValidationError(
i,
"LINK_TEXT",
f"Non-descriptive link text: '{link_text}'. Use descriptive text that tells where the link goes."
))
# Check for empty link text
if not link_text.strip():
self.errors.append(ValidationError(
i,
"LINK_EMPTY",
"Link has empty text"
))
# Check for empty URL
if not link_url.strip():
self.errors.append(ValidationError(
i,
"LINK_EMPTY_URL",
f"Link '{link_text}' has empty URL"
))
def _check_basic_structure(self):
"""Check basic document structure."""
# Check for at least one H1
if not any(line.startswith('# ') for line in self.lines):
self.errors.append(ValidationError(
1,
"NO_H1",
"Document should have at least one top-level heading (# Title)"
))
# Check for multiple H1s (often unintended)
h1_count = sum(1 for line in self.lines if line.startswith('# '))
if h1_count > 1:
self.errors.append(ValidationError(
1,
"MULTIPLE_H1",
f"Document has {h1_count} top-level headings. Consider using only one H1 as the document title."
))
def validate_file(file_path: Path) -> Tuple[Path, List[ValidationError]]:
"""Validate a single markdown file."""
validator = MarkdownValidator(file_path)
errors = validator.validate()
return file_path, errors
def validate_directory(dir_path: Path) -> List[Tuple[Path, List[ValidationError]]]:
"""Validate all markdown files in a directory."""
results = []
for md_file in dir_path.rglob('*.md'):
file_path, errors = validate_file(md_file)
if errors:
results.append((file_path, errors))
return results
def print_results(results: List[Tuple[Path, List[ValidationError]]]):
"""Print validation results."""
if not results:
print("✓ No validation errors found!")
return
total_errors = sum(len(errors) for _, errors in results)
print(f"\n{'='*70}")
print(f"Found {total_errors} validation error(s) in {len(results)} file(s)")
print(f"{'='*70}\n")
for file_path, errors in results:
print(f"\n{file_path}:")
print("-" * 70)
for error in errors:
print(f" {error}")
print(f"\n{'='*70}")
print(f"Total: {total_errors} error(s)")
print(f"{'='*70}\n")
def main():
"""Main entry point."""
if len(sys.argv) != 2:
print("Usage: python validate_markdown.py <file_or_directory>")
sys.exit(1)
path = Path(sys.argv[1])
if not path.exists():
print(f"Error: Path does not exist: {path}")
sys.exit(1)
results = []
if path.is_file():
if path.suffix == '.md':
file_path, errors = validate_file(path)
if errors:
results.append((file_path, errors))
else:
print(f"Error: Not a markdown file: {path}")
sys.exit(1)
elif path.is_dir():
results = validate_directory(path)
else:
print(f"Error: Invalid path: {path}")
sys.exit(1)
print_results(results)
# Exit with error code if validation errors found
sys.exit(1 if results else 0)
if __name__ == '__main__':
main()