gapmiss/obsidian-plugin-skillMIT11 files

Obsidian

Comprehensive guidelines for Obsidian.md plugin development including ESLint rules from eslint-plugin-obsidianmd v0.4.2, TypeScript best practices, memory management, API usage (requestUrl vs fetch), UI/UX standards, popout window compatibility, community.obsidian.md submission process, and Scorecard optimization. Use when working with Obsidian plugins, main.ts files, manifest.json, Plugin class, MarkdownView, TFile, vault operations, or any Obsidian API development.

Specification
Skill ID
gapmiss/obsidian-plugin-skill/obsidian
Publisher
gapmiss
Repository
obsidian-plugin-skill
Installs
0
Files
11
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

gapmiss/obsidian-plugin-skill/obsidianInstalls these files
  • SKILL.md
  • reference/accessibility.md
  • reference/code-quality.md
  • reference/community-scanner.md
  • reference/css-styling.md
  • reference/eslint-setup.md
  • reference/file-operations.md
  • reference/memory-management.md
  • reference/submission.md
  • reference/type-safety.md
  • reference/ui-ux.md

What this skill tells the agent

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.4.2)

Submission & Naming

#Rule✅ Do❌ Don't
1Plugin IDOmit "obsidian"; don't end with "plugin"Include "obsidian" or end with "plugin"
2Plugin nameOmit "Obsidian"; don't end with "Plugin"Include "Obsidian" or end with "Plugin"
3Plugin nameDon't start with "Obsi" or end with "dian"Start with "Obsi" or end with "dian"
4DescriptionOmit "Obsidian", "This plugin", etc.Use "Obsidian" or "This plugin"
5DescriptionEnd with .?!) punctuationLeave description without terminal punctuation

Memory & Lifecycle

#Rule✅ Do❌ Don't
6Event cleanupUse registerEvent() for automatic cleanupRegister events without cleanup
6aDOM eventsUse registerDomEvent() on the plugin or owning componentPair addEventListener with manual removeEventListener cleanup
7View referencesReturn views/components directlyStore view references in plugin properties or pass plugin as component to MarkdownRenderer
8Leaf detachmentLet Obsidian handle leaf cleanupCall detachLeavesOfType() in onunload

Type Safety

#Rule✅ Do❌ Don't
9TFile/TFolderUse instanceof for type checkingCast to TFile/TFolder; use any; use var
10DOM instanceofUse .instanceOf(T) for DOM Nodes/UIEventsUse instanceof for cross-window DOM checks

UI/UX

#Rule✅ Do❌ Don't
11UI textSentence case — "Advanced settings"; use acronyms/brands options for proper namesTitle Case — "Advanced Settings"
12JSON localeSentence case in JSON locale files (recommendedWithLocalesEn)Title case in locale JSON
13TS/JS localeSentence case in TS/JS locale modulesTitle case in locale modules
Note (v0.4.0): ui/sentence-case is now enabled (warn) and enforced on inline UI strings — it was disabled in v0.3.0. Use the recommendedWithLocalesEn config to also check English locale files (rules 12–13).

| 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 |

Declarative Settings (1.13.0+)

All four settings-tab rules ship as warn in recommended. Rules 17a/17c/17d read minAppVersion from manifest.json; 17b is not version-gated.

#Rule✅ Do❌ Don't
17asettings-tab/require-displayKeep display() when minAppVersion < 1.13.0Ship declarative-only settings that render nothing on older Obsidian
17bsettings-tab/prefer-setting-definitionsImplement getSettingDefinitions() on every PluginSettingTabRely on display() alone — settings won't appear in 1.13+ global search
17csettings-tab/prefer-update-over-displayCall this.update() to re-render declarative settingsCall this.display() — it's bypassed when definitions are non-empty
17dsettings-tab/no-deprecated-displayDelete display() once minAppVersion >= 1.13.0 and definitions existLeave a dead display() behind (auto-fixable)
—Settings dataKeep all persisted data inside plugin.settingsStore sibling keys via saveData() — auto-persist clobbers them
Detection caveat: these rules match a bare extends PluginSettingTab only. extends obsidian.PluginSettingTab is out of scope and won't be flagged — but the underlying guidance still applies.

API Best Practices

#Rule✅ Do❌ Don't
18Active file editsUse Editor APIUse Vault.modify() for active file edits
19Background file modsUse Vault.process()Use Vault.modify() for background modifications
20File deletionUse FileManager.trashFile()Use Vault.trash() or Vault.delete() directly
21File lookupUse Vault.getAbstractFileByPath()Iterate all files with Vault.getFiles().find()
22User pathsUse normalizePath()Hardcode .obsidian path; use raw user paths
23OS detectionUse Platform APIUse navigator.platform/userAgent
24Network requestsUse requestUrl()Use fetch()
25LoggingMinimize console logging; none in onload/onunload in productionUse console.log in onload/onunload
26Input suggestUse built-in AbstractInputSuggestCopy Liam's TextInputSuggest implementation
27API compatibilityCheck minAppVersion for API availability (e.g., getSettingDefinitions() requires 1.13.0)Use APIs not available in declared minAppVersion
28Language detectionUse Obsidian's getLanguage()Use localStorage.getItem('language') or i18next-browser-languagedetector

Popout Window Compatibility

#Rule✅ Do❌ Don't
29Document/WindowUse activeDocument and activeWindowUse global document and window
29aGetter captureCapture activeDocument in a variable when the same document is needed laterCall activeDocument at setup and again at cleanup — it follows focus and may return different documents
30TimersUse activeWindow.setTimeout(), setInterval(), etc.Use bare setTimeout(), setInterval()
31Main workspace UIUse this.app.workspace.containerEl.ownerDocument from settingsUse activeDocument to update main workspace from settings window
Note (v0.4.0): prefer-active-doc remains disabled by default — the only Obsidian rule shipped as off. Enable it manually for popout window support.
Note (v1.13.0): Settings now open in a new window. activeDocument from settings callbacks points to the settings window, not the main vault. Use this.app.workspace.containerEl.ownerDocument to target main workspace UI.
Note: activeDocument/activeWindow are dynamic getters that track the focused window. A listener added via activeDocument.addEventListener() at setup cannot reliably be removed via activeDocument.removeEventListener() at cleanup. Prefer registerDomEvent() (rule 6a), which captures the target at registration.

Event Handling

#Rule✅ Do❌ Don't
31Editor drop/pasteCheck evt.defaultPrevented and call evt.preventDefault()Handle editor-drop/paste without checking defaultPrevented

Styling

#Rule✅ Do❌ Don't
32CSS variablesUse Obsidian CSS variables for all stylingHardcode colors, sizes, or spacing
33CSS scopeScope CSS to plugin containersUse broad CSS selectors
34Style elementsUse styles.css file (no-forbidden-elements)Create <link> or <style> elements; assign styles via JavaScript

Use this skill in a project

Open any RiverX project, search the Skills panel for gapmiss/obsidian-plugin-skill/obsidian, and install it in one click.

Use this skill