All skills
gapmiss avatar

/obsidian

@ff97cb0

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.

Use this Skill: https://skilld.dev/gh/gapmiss/obsidian-plugin-skill/obsidian

This session only. Nothing lands on disk.

referencefile-operations.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

File & Vault Operations

Proper file operations are critical for safe and efficient Obsidian plugin development.

Table of Contents


View Access

Use getActiveViewOfType() for View Access

Rule: Official guidelines

❌ INCORRECT:

const view = this.app.workspace.activeLeaf?.view;

✅ CORRECT:

const view = this.app.workspace.getActiveViewOfType(MarkdownView);
if (view) {
  // Work with view
}

Rationale: Use getActiveViewOfType() instead of directly accessing workspace.activeLeaf for safer view access.


Editor vs Vault API

Prefer Editor API over Vault.modify()

Rule: Official guidelines

❌ INCORRECT:

// For active file edits
const activeFile = this.app.workspace.getActiveFile();
await this.app.vault.modify(activeFile, newContent);

✅ CORRECT:

// Use Editor API for active file
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
if (view) {
  const editor = view.editor;
  editor.setValue(newContent);
  // Or use editor methods to preserve cursor
  editor.replaceRange(text, from, to);
}

Rationale: Use Editor API for active file edits to preserve cursor position and selection. Use Vault.modify() only for non-active files.


Atomic File Operations

Use Vault.process() for Background Modifications

Rule: Official guidelines

❌ INCORRECT:

// Direct modification can conflict with other plugins
const content = await this.app.vault.read(file);
const modified = content.replace(/old/g, 'new');
await this.app.vault.modify(file, modified);

✅ CORRECT:

// Vault.process() prevents conflicts
await this.app.vault.process(file, (data) => {
  return data.replace(/old/g, 'new');
});

Rationale: Use Vault.process() for background file modifications—it prevents conflicts with other plugins through atomic operations.


Use FileManager.processFrontMatter() for YAML

Rule: Official guidelines

❌ INCORRECT:

const content = await this.app.vault.read(file);
const updated = content.replace(/tags:.*/, 'tags: [new-tag]');
await this.app.vault.modify(file, updated);

✅ CORRECT:

await this.app.fileManager.processFrontMatter(file, (frontmatter) => {
  frontmatter.tags = ['new-tag'];
  frontmatter.modified = new Date().toISOString();
});

Rationale: Use FileManager.processFrontMatter() for YAML modifications to ensure atomic operations and consistent formatting.


File Management

Prefer Vault API over Adapter API

Rule: Official guidelines

❌ INCORRECT:

// Adapter API bypasses Obsidian's safety mechanisms
const content = await this.app.vault.adapter.read(file.path);
await this.app.vault.adapter.write(file.path, newContent);

✅ CORRECT:

// Vault API provides safety and serialization
const content = await this.app.vault.read(file);
await this.app.vault.modify(file, newContent);

Rationale: Prefer the Vault API over the Adapter API for better performance and safety through serialized operations.


Prefer FileManager for Deletion

Rule: obsidianmd/prefer-file-manager-trash-file

❌ INCORRECT:

await this.app.vault.trash(file, system);

✅ CORRECT:

await this.app.fileManager.trashFile(file);

Rationale: fileManager.trashFile() handles additional cleanup like backlinks.


Avoid Full Vault Iteration

Rule: obsidianmd/vault/iterate

❌ INCORRECT:

// Iterating all files to find one
const files = this.app.vault.getMarkdownFiles();
const target = files.find(f => f.path === targetPath);

✅ CORRECT:

// Direct lookup
const target = this.app.vault.getAbstractFileByPath(targetPath);

Rationale: Use direct lookup methods instead of iterating all files for better performance.


Path Handling

Use normalizePath() for User-Defined Paths

Rule: Official guidelines

❌ INCORRECT:

const file = this.app.vault.getAbstractFileByPath(userPath);

✅ CORRECT:

import { normalizePath } from 'obsidian';

const normalizedPath = normalizePath(userPath);
const file = this.app.vault.getAbstractFileByPath(normalizedPath);

Rationale: Apply normalizePath() to user-defined paths to ensure cross-platform compatibility (handles backslashes, etc.).


Don't Hardcode Config Directory

Rule: obsidianmd/hardcoded-config-path

❌ INCORRECT:

const configPath = '.obsidian/plugins/my-plugin/';
const pluginDir = vault.adapter.basePath + '/.obsidian/plugins/my-plugin';

✅ CORRECT:

// Access the configured directory
const configDir = this.app.vault.configDir;  // Might not be '.obsidian'
const pluginDir = `${configDir}/plugins/${this.manifest.id}`;

// Or better yet, use the data APIs:
await this.loadData();
await this.saveData(data);

Rationale: Obsidian's configuration directory isn't necessarily .obsidian - it can be configured by the user. Access it via Vault#configDir.

Source: SKILL.md on GitHub

No alerts4d5 checks · Risk SAFE
  • Gen Agent Trust Hub5d

    The skill is a comprehensive, high-quality documentation resource for Obsidian.md plugin development. It provides correct security guidance (such as XSS prevention), memory management practices, and accessibility standards. No malicious code, data exfiltration, or obfuscation was detected.

  • Socket4d

    No alerts

  • Snyk5d

    Risk: LOW · No issues

  • Runlayer7mo

    9 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at ff97cb0. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last week.

Activeupdated last week
metadata
{
  "version": "1.11.1"
}

README badge

README badge for gapmiss/obsidian-plugin-skill