Write markdown documents and mermaid diagrams to Obsidian vaults.
Writes markdown documents and mermaid diagrams to Obsidian vaults. Use when creating research notes, documentation, or diagrams that need to be saved to an Obsidian vault.
/plugin marketplace add mindmorass/reflex/plugin install reflex@mindmorass-reflexThis skill inherits all available tools. When active, it can use any tool Claude has access to.
Write markdown documents and mermaid diagrams to Obsidian vaults.
Obsidian uses plain markdown files in folder-based vaults. Publishing is simply writing .md files to the correct directory.
vault-path/
├── folder/
│ ├── note.md
│ └── subfolder/
│ └── nested-note.md
├── attachments/ # Optional: for images
└── templates/ # Optional: note templates
The vault path is passed per-request. Validate it exists:
from pathlib import Path
def validate_vault(vault_path: str) -> Path:
path = Path(vault_path).expanduser().resolve()
if not path.exists():
raise ValueError(f"Vault not found: {vault_path}")
if not path.is_dir():
raise ValueError(f"Vault path is not a directory: {vault_path}")
return path
def create_note(
vault_path: str,
folder: str,
filename: str,
content: str,
frontmatter: dict = None
) -> Path:
"""
Create a note in an Obsidian vault.
Args:
vault_path: Path to Obsidian vault
folder: Subfolder within vault (can be nested like "projects/2024")
filename: Note filename (without .md extension)
content: Markdown content
frontmatter: Optional YAML frontmatter dict
Returns:
Path to created file
"""
vault = validate_vault(vault_path)
target_dir = vault / folder
target_dir.mkdir(parents=True, exist_ok=True)
# Sanitize filename
safe_filename = sanitize_filename(filename)
file_path = target_dir / f"{safe_filename}.md"
# Build content with optional frontmatter
full_content = build_content(content, frontmatter)
file_path.write_text(full_content, encoding='utf-8')
return file_path
def build_content(content: str, frontmatter: dict = None) -> str:
"""Build markdown content with optional YAML frontmatter."""
if frontmatter:
import yaml
fm_str = yaml.dump(frontmatter, default_flow_style=False)
return f"---
{fm_str}---
{content}"
return content
def sanitize_filename(name: str) -> str:
"""Remove or replace invalid filename characters."""
invalid_chars = '<>:"/\|?*'
for char in invalid_chars:
name = name.replace(char, '-')
return name.strip()
# Title
Content goes here.
## Section
More content.
# My Note
Content here.
# System Architecture
## Overview
This document describes the system architecture.
## Diagram
```mermaid
flowchart TD
A[Client] --> B[API Gateway]
B --> C[Service]
C --> D[(Database)]
Handles routing and authentication.
### Note with Internal Links
```markdown
# Project Overview
This project uses [[Architecture|the architecture]] defined elsewhere.
Related:
- [[API Design]]
- [[Database Schema]]
See also: [[projects/2024/related-project|Related Project]]
vault/
├── notes/
├── research/
├── diagrams/
├── meetings/
└── projects/
vault/
├── 2024/
│ ├── 01-january/
│ └── 02-february/
└── archive/
vault/
├── project-alpha/
│ ├── research/
│ ├── design/
│ └── notes/
└── project-beta/
create_note(
vault_path="~/Documents/Obsidian/MyVault",
folder="research",
filename="API Design Patterns",
content="""
# API Design Patterns
## REST Best Practices
Key findings from research...
## GraphQL Considerations
...
""",
frontmatter={
"title": "API Design Patterns",
"date": "2024-01-15",
"tags": ["api", "research"],
"status": "draft"
}
)
create_note(
vault_path="~/Documents/Obsidian/MyVault",
folder="diagrams/architecture",
filename="System Overview",
content="""
# System Overview
```mermaid
flowchart TB
subgraph Frontend
A[Web App]
B[Mobile App]
end
subgraph Backend
C[API Server]
D[Worker]
end
A --> C
B --> C
C --> D
## Integration with Mermaid
Obsidian renders mermaid diagrams natively. Use `documentation-generator:mermaid-expert` for diagram syntax, then embed directly:
```markdown
```mermaid
sequenceDiagram
Client->>Server: Request
Server-->>Client: Response
## Obsidian-Specific Features
### Callouts
```markdown
> [!note]
> This is a note callout
> [!warning]
> This is a warning
> [!tip]
> This is a tip
#tag-name
Or in frontmatter:
tags:
- tag1
- tag2
[[Note Name]]
[[folder/Note Name]]
[[Note Name|Display Text]]
[[Note Name#Heading]]
![[Note to embed]]
![[image.png]]
![[Note#Section]]
class ObsidianPublishError(Exception):
"""Base exception for Obsidian publishing errors."""
pass
class VaultNotFoundError(ObsidianPublishError):
"""Vault path does not exist."""
pass
class InvalidFilenameError(ObsidianPublishError):
"""Filename contains invalid characters."""
pass
Before publishing:
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.