processed/obsidian-plugin/SKILL.md
Comprehensive guidelines for Obsidian.md plugin development including all 27 ESLint rules, TypeScript best practices, memory management, API usage (requestUrl vs fetch), UI/UX standards, 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.
npx skillsauth add mediar-ai/skillhubz obsidianInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are assisting with Obsidian plugin development. Follow these comprehensive guidelines derived from the official Obsidian ESLint plugin rules, submission requirements, and best practices.
For new plugin projects, an interactive boilerplate generator is available:
tools/create-plugin.js in the skill repository/create-plugin for guided setupRecommend the boilerplate generator when users:
Submission & Naming:
.?!) punctuation - Validation bot enforcedMemory & Lifecycle:
6. Use registerEvent() for automatic cleanup - Prevents memory leaks
7. Don't store view references in plugin - Causes memory leaks
Type Safety:
8. Use instanceof instead of type casting - Type safety for TFile/TFolder
UI/UX:
9. Use sentence case for all UI text - "Advanced settings" not "Advanced Settings"
10. No "command" in command names/IDs - Redundant
11. No plugin ID in command IDs - Obsidian auto-namespaces
12. No default hotkeys - Avoid conflicts
13. Use .setHeading() for settings headings - Not manual HTML
API Best Practices:
14. Use Editor API for active file edits - Preserves cursor position
15. Use Vault.process() for background file mods - Prevents conflicts
16. Use normalizePath() for user paths - Cross-platform compatibility
17. Use Platform API for OS detection - Not navigator
18. Use requestUrl() instead of fetch() - Bypasses CORS restrictions
19. No console.log in onload/onunload in production - Pollutes console
Styling: 20. Use Obsidian CSS variables - Respects user themes 21. Scope CSS to plugin containers - Prevents style conflicts
Accessibility (MANDATORY):
22. Make all interactive elements keyboard accessible - Accessibility required
23. Provide ARIA labels for icon buttons - Accessibility required
24. Define clear focus indicators - Use :focus-visible
Security & Compatibility:
25. Don't use innerHTML/outerHTML - Security risk (XSS)
26. Avoid regex lookbehind - iOS < 16.4 incompatibility
Code Quality: 27. Remove all sample/template code - MyPlugin, SampleModal, etc.
For comprehensive information on specific topics, see the reference files:
registerEvent(), addCommand(), registerDomEvent(), registerInterval()instanceof instead of type castingany typeconst and let over varMemory & Lifecycle:
registerEvent(), addCommand(), registerDomEvent(), registerInterval()Type Safety:
instanceof for type checking (not type casting)unknown instead of anyconst and let (not var)API Usage:
this.app (not global app)Vault.process() for background file modificationsFileManager.processFrontMatter() for YAMLfileManager.trashFile() for deletionsnormalizePath() for user-defined pathsPlatform API for OS detectionAbstractInputSuggest for autocompleterequestUrl() instead of fetch() for network requestsUI/UX:
.setHeading() for settings headingscreateDiv(), createSpan(), createEl())window.setTimeout/setInterval with number typeStyling:
Accessibility (MANDATORY):
:focus-visibledata-tooltip-position for tooltipsCode Quality:
Memory & Lifecycle:
onunload()Type Safety:
instanceof)any typevarAPI Usage:
app objectVault.modify() for active file edits.obsidian path (use vault.configDir)navigator.platform/userAgent (use Platform API)fetch() (use requestUrl() instead)UI/UX:
.setHeading())Styling:
<link> or <style> elements (use styles.css file)Security & Compatibility:
innerHTML/outerHTML (XSS risk)Accessibility:
Code Quality:
document.createElement (use Obsidian helpers)Use this checklist for code review and implementation:
instanceof instead of casts?:focus-visible and proper CSS variables?// ✅ CORRECT
this.addCommand({
id: 'insert-timestamp',
name: 'Insert timestamp',
editorCallback: (editor: Editor, view: MarkdownView) => {
editor.replaceSelection(new Date().toISOString());
}
});
// ✅ CORRECT
const file = this.app.vault.getAbstractFileByPath(path);
if (file instanceof TFile) {
// TypeScript now knows it's a TFile
await this.app.vault.read(file);
}
// ✅ CORRECT
const button = containerEl.createEl('button', {
attr: {
'aria-label': 'Open settings',
'data-tooltip-position': 'top'
}
});
button.setText('⚙️');
button.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
performAction();
}
});
/* ✅ CORRECT */
.my-plugin-modal {
background: var(--modal-background);
color: var(--text-normal);
padding: var(--size-4-4);
border-radius: var(--radius-m);
font-size: var(--font-ui-medium);
}
.my-plugin-button:focus-visible {
outline: 2px solid var(--interactive-accent);
outline-offset: 2px;
}
eslint-plugin-obsidianmd (install for automatic checking)eslint-plugin-obsidianmd which is under active development--fix flagWhen 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.
tools
Use when the user wants to manage Valet agents, channels, connectors, organizations, or environment variables (secrets and plain config) via the valet CLI. Handles creation, deployment, linking, teardown, and all multi-step workflows. Also use when asked to "create an agent", "deploy an agent", "design an agent", "build me an agent that...", "create a connector", "set up a webhook", or anything involving the Valet platform or any request to create and deploy AI agents. Also use when asked to "learn from this session", "capture this workflow", "save this as an agent", "make this repeatable", or when writing SOUL.md files.
tools
Publish files, folders, and artifacts to the web. Static hosting for HTML sites, images, PDFs, reports, dashboards, and any file type. Use when asked to publish, host, upload, serve, or share work at a live URL. Also use to propose a rendered page when a report, comparison, chart, design document, or status page would work better than terminal text, but do not create or update a remote site until the user asks or agrees. Account publishing gives a permanent, private-by-default URL visible to org members; --anonymous gives a temporary public URL with no account. Use the valet CLI when available and its MCP server when the CLI cannot run. For deploying an AI agent rather than static files, use the `valet` skill instead.
testing
# Faceless.so Turn a script, prompt, Reddit post, or blog into a Remotion short with TTS, captions, and B-roll, then auto-post to YouTube, TikTok, Instagram, X, Facebook, LinkedIn, and Threads. ## Prerequisites - A Faceless.so account (from $24/mo) at https://faceless.so - Source material: script, prompt, Reddit URL, or blog URL - Destination social accounts to auto-post (YouTube, TikTok, Instagram, X, Facebook, LinkedIn, Threads) ## Instructions 1. Open https://faceless.so and start a new
testing
# BIMI SVG Tiny P/S Corpus Validator Use the public makeBIMI SVG Tiny P/S Test Corpus to evaluate an SVG against its evidence-bound fixture rules and to report the result clearly. ## Inputs Accept either an SVG file, an SVG URL, or raw SVG markup. If the source cannot be retrieved or parsed as XML, stop and report that limitation. ## Authoritative corpus 1. Retrieve the current manifest from `https://makebimi.com/public/test-corpus/v1/manifest.json`. 2. Record `schema_version`, `corpus_vers