Comprehensive guidelines for Obsidian.md plugin development including all 34 ESLint rules from eslint-plugin-obsidianmd v0.2.4, TypeScript best practices, memory management, API usage (requestUrl vs fetch), UI/UX standards, locale file sentence-case enforcement, popout window compatibility, and submission requirements. Use when working with Obsidian plugins, main.ts files, manifest.json, Plugin class, MarkdownView, TFile, vault operations, or any Obsidian API development.
name: obsidian
description: Comprehensive guidelines for Obsidian.md plugin development including all 36 ESLint rules from eslint-plugin-obsidianmd v0.2.8, TypeScript best practices, memory management, API usage (requestUrl vs fetch), UI/UX standards, locale file sentence-case enforcement, popout window compatibility, and submission requirements. Use when working with Obsidian plugins, main.ts files, manifest.json, Plugin class, MarkdownView, TFile, vault operations, or any Obsidian API development.
license: MIT
metadata:
version: 1.6.0
Obsidian Plugin Development Guidelines
Follow these comprehensive guidelines derived from the official Obsidian ESLint plugin rules, submission requirements, and best practices.
Getting Started
Quick Start Tool
For new plugin projects, an interactive boilerplate generator is available:
Script: tools/create-plugin.js in the skill repository
Command: Invoke create-plugin using your agent's method (/create-plugin, $create-plugin, or @create-plugin)
Generates minimal, best-practice boilerplate with no sample code
Detects existing projects and only adds missing files
Recommend the boilerplate generator when users ask how to create a new plugin, want to start a new project, or need help setting up the basic structure.
Rules Reference (eslint-plugin-obsidianmd v0.2.8)
Submission & Naming
#
Rule
✅ Do
❌ Don't
1
Plugin ID
Omit "obsidian"; don't end with "plugin"
Include "obsidian" or end with "plugin"
2
Plugin name
Omit "Obsidian"; don't end with "Plugin"
Include "Obsidian" or end with "Plugin"
3
Plugin name
Don't start with "Obsi" or end with "dian"
Start with "Obsi" or end with "dian"
4
Description
Omit "Obsidian", "This plugin", etc.
Use "Obsidian" or "This plugin"
5
Description
End with .?!) punctuation
Leave description without terminal punctuation
Memory & Lifecycle
#
Rule
✅ Do
❌ Don't
6
Event cleanup
Use registerEvent() for automatic cleanup
Register events without cleanup
7
View references
Return views/components directly
Store view references in plugin properties or pass plugin as component to MarkdownRenderer
8
Leaf detachment
Let Obsidian handle leaf cleanup
Call detachLeavesOfType() in onunload
Type Safety
#
Rule
✅ Do
❌ Don't
9
TFile/TFolder
Use instanceof for type checking
Cast to TFile/TFolder; use any; use var
10
DOM instanceof
Use .instanceOf(T) for DOM Nodes/UIEvents
Use instanceof for cross-window DOM checks
UI/UX
#
Rule
✅ Do
❌ Don't
11
UI text
Sentence case — "Advanced settings"
Title Case — "Advanced Settings"
12
JSON locale
Sentence case in JSON locale files (recommendedWithLocalesEn)
Title case in locale JSON
13
TS/JS locale
Sentence case in TS/JS locale modules
Title case in locale modules
14
Command names
Omit "command" in command names/IDs
Include "command" in names/IDs
15
Command IDs
Omit plugin ID/name from command IDs/names
Duplicate plugin ID in command IDs
16
Hotkeys
No default hotkeys
Set default hotkeys
17
Settings headings
Use .setHeading()
Create manual HTML headings; use "General", "settings", or plugin name in headings
API Best Practices
#
Rule
✅ Do
❌ Don't
18
Active file edits
Use Editor API
Use Vault.modify() for active file edits
19
Background file mods
Use Vault.process()
Use Vault.modify() for background modifications
20
File deletion
Use FileManager.trashFile()
Use Vault.trash() or Vault.delete() directly
21
File lookup
Use Vault.getAbstractFileByPath()
Iterate all files with Vault.getFiles().find()
22
User paths
Use normalizePath()
Hardcode .obsidian path; use raw user paths
23
OS detection
Use Platform API
Use navigator.platform/userAgent
24
Network requests
Use requestUrl()
Use fetch()
25
Logging
Minimize console logging; none in onload/onunload in production
Use console.log in onload/onunload
26
Input suggest
Use built-in AbstractInputSuggest
Copy Liam's TextInputSuggest implementation
27
API compatibility
Check minAppVersion for API availability
Use APIs not available in declared minAppVersion
28
Language detection
Use Obsidian's getLanguage()
Use localStorage.getItem('language') or i18next-browser-languagedetector
Popout Window Compatibility
#
Rule
✅ Do
❌ Don't
29
Document/Window
Use activeDocument and activeWindow
Use global document and window
30
Timers
Use activeWindow.setTimeout(), setInterval(), etc.
Use bare setTimeout(), setInterval()
Event Handling
#
Rule
✅ Do
❌ Don't
31
Editor drop/paste
Check evt.defaultPrevented and call evt.preventDefault()
Handle editor-drop/paste without checking defaultPrevented
Styling
#
Rule
✅ Do
❌ Don't
32
CSS variables
Use Obsidian CSS variables for all styling
Hardcode colors, sizes, or spacing
33
CSS scope
Scope CSS to plugin containers
Use broad CSS selectors
34
Style elements
Use styles.css file (no-forbidden-elements)
Create <link> or <style> elements; assign styles via JavaScript
Security & Compatibility
#
Rule
✅ Do
❌ Don't
35
DOM creation
Use Obsidian DOM helpers (createEl(), createDiv(), createSpan(), createSvg(), createFragment()) via prefer-create-el
Use document.createElement(), document.createDocumentFragment(), etc.
36
Node.js modules
Guard Node.js imports with Platform.isDesktop check (no-nodejs-modules)
When helping with Obsidian plugin development, proactively apply these rules and suggest improvements based on these guidelines. Refer to the detailed reference files for comprehensive information on specific topics.