mcpbeat Sign in

Obsidian Dev Rules Skill for Cursor

Authoritative reference and rules for developing for Obsidian — building TypeScript plugins (Plugin lifecycle, manifest.json, commands, settings, modals, views, ribbon/status bar), the Vault and Editor APIs, the event system, Markdown post-processing & code-block processors, CodeMirror 6 editor extensions, building CSS themes (CSS variables, theme.css/manifest), and submitting plugins/themes to the community directory. Use whenever the user asks to build, debug, or review an Obsidian plugin or theme, work with the Obsidian API (Vault/Editor/Workspace/Plugin), register commands/views/events, process Markdown, or release/submit to the Obsidian community.

1.5k tokens
context cost
SKILL.md, read when the skill is used
5
files
plus reference files
0
copies elsewhere
how many repositories repackaged it
100
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/Agents365-ai/365-skills --skill obsidian-dev-rules

What comes with it

18 531 bytes besides the instruction
references/plugin-basics.md
references/themes-and-release.md
references/ui.md
references/vault-and-editor.md

The instruction itself

5 sections, as written by the author

Obsidian Dev Rules

Obsidian is extended two ways: plugins (TypeScript against the Obsidian API) and themes/snippets

(CSS). This skill mirrors the official developer docs at https://docs.obsidian.md so you can build and

review Obsidian plugins/themes without re-fetching. The API ships as the obsidian npm package; the

canonical starting point is the obsidian-sample-plugin.

When to use this skill

  • Building, debugging, or reviewing an Obsidian plugin (lifecycle, commands, settings, UI, views).
  • Reading/writing notes via the Vault API; manipulating the active note via the Editor API.
  • Subscribing to events, registering Markdown post-processors / code-block processors, or

CodeMirror 6 editor extensions.

  • Building a theme (CSS variables, theme.css, manifest) or snippets.
  • Releasing/submitting a plugin or theme to the community directory.

Reference index — load the file you need

| File | Covers |

|------|--------|

| references/plugin-basics.md | Project setup, manifest.json, Plugin lifecycle (onload/onunload), resource registration & cleanup, events, dev workflow / hot reload, debugging |

| references/vault-and-editor.md | Vault API (read/cachedRead/create/modify/process/delete, TFile/TFolder, adapter, normalizePath), Editor API, Markdown post-processing & code-block processors, CodeMirror 6 editor extensions |

| references/ui.md | Commands (callback variants, hotkeys), Settings (PluginSettingTab, load/saveData, Setting controls), Modals (Modal/SuggestModal/FuzzySuggestModal), Views (ItemView, registerView, workspace leaves), ribbon/status bar |

| references/themes-and-release.md | Themes (CSS variables, theme.css/manifest, body classes, snippets), submitting plugins & themes, developer policies & guidelines |

Cheat sheet

import { Plugin, Notice, MarkdownView, TFile, normalizePath } from 'obsidian';

export default class MyPlugin extends Plugin {
  async onload() {
    await this.loadSettings();
    this.addRibbonIcon('dice', 'Greet', () => new Notice('Hello!'));
    this.addCommand({ id: 'do-x', name: 'Do X', callback: () => {/* ... */} });
    this.addSettingTab(new MySettingTab(this.app, this));
    // Auto-cleaned on unload — always register through these:
    this.registerEvent(this.app.vault.on('modify', (f) => {/* ... */}));
    this.registerInterval(window.setInterval(() => {/* ... */}, 1000));
    this.registerDomEvent(document, 'click', () => {/* ... */});
  }
  onunload() { /* release anything NOT registered via register*/ }
}
// Vault: prefer process() over read()+modify(); use cachedRead() for display only.
const file = this.app.vault.getFileByPath('Notes/x.md');
await this.app.vault.process(file, (data) => data.replace('foo', 'bar'));
// Editor of the active note (preserves cursor/selection):
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
view?.editor.replaceSelection(view.editor.getSelection().toUpperCase());

Plugin files: manifest.json + main.js (+ optional styles.css) in <vault>/.obsidian/plugins/<id>/.

Theme files: manifest.json + theme.css in <vault>/.obsidian/themes/<name>/.

Hard rules

  • Use this.app, never the global app (global exists for debugging only and may be removed).
  • Register everything that needs teardown via registerEvent / registerInterval /

registerDomEvent / addCommand / registerView / registerMarkdownPostProcessor — Obsidian

auto-cleans those on unload. Manually release anything else in onunload(). Leaked listeners/

intervals degrade Obsidian after the plugin is disabled.

  • Never use innerHTML / outerHTML / insertAdjacentHTML with dynamic content — build DOM with

createEl() / createDiv() / createSpan().

  • Prefer the Vault API over the Adapter API; use getFileByPath() (not iterate-all); always

normalizePath() user-supplied paths. Use process() (atomic) instead of sequential

read()+modify() to avoid data loss; cachedRead() only when you won't write it back.

  • For the active note, edit via the Editor interface, not Vault.modify — it preserves the

cursor and selection.

  • Don't store references to view instances; Obsidian may recreate them — fetch with

getLeavesOfType() / getActiveViewOfType().

  • Don't set default hotkeys for distributed plugins (OS-dependent, conflict-prone). UI text is

sentence case. Use CSS classes + Obsidian CSS variables, not hardcoded inline styles.

  • manifest.json required fields: id, name, version (semver x.y.z), minAppVersion,

description, author, isDesktopOnly. id must not contain "obsidian"; name is Basic-Latin,

no emoji/punctuation except hyphens.

  • Release: GitHub release whose tag equals the manifest version, with main.js,

manifest.json, and optional styles.css attached as individual binary assets (not zipped).

  • Use async/await (not Promise chains); const/let (not var).

How to use it

Copy the folder

Take agents365-ai/obsidian-dev-rules from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.