obsidian-plugin
ALIAS — merged into the unified `obsidian` skill (v2.0). Use the `obsidian` skill instead. Build, validate, and publish Obsidian plugins. Redirects to obsidian skill for plugin development, ESLint rules, boilerplate generation, accessibility, and submission validation.
How do I install this agent skill?
npx skills add https://github.com/akillness/jeo-skills --skill obsidian-pluginIs this agent skill safe to install?
- Gen Agent Trust Hubpass
This skill provides a comprehensive toolkit for developing Obsidian plugins, including a boilerplate generator, setup scripts, and extensive documentation on best practices like accessibility, memory management, and security. The tool chain and dependencies are standard for the developer use-case, and the code includes sanitization for project metadata.
- Socketwarn
1 alert: gptSecurity
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
obsidian-plugin — Obsidian Plugin Development Skill
Keyword:
obsidian plugin·create obsidian plugin·obsidian eslint·obsidian submissionBuild high-quality Obsidian plugins that pass community review on first attempt. Covers all 27 rules from
eslint-plugin-obsidianmdv0.1.9, boilerplate generation, vault API patterns, accessibility requirements, and submission validation.
When to use this skill
- Generate a new Obsidian plugin project with clean boilerplate (no sample code bloat)
- Review and fix ESLint violations from
eslint-plugin-obsidianmd - Prepare a plugin for Obsidian community directory submission
- Apply memory-safe lifecycle patterns (
registerEvent, no view reference storage) - Implement proper type safety (no unsafe
as TFilecasts, noany) - Enforce accessibility requirements (keyboard navigation, ARIA labels, focus management)
- Apply Obsidian CSS variables for theme-compatible styling
- Validate plugin metadata (manifest.json, plugin ID/name/description rules)
Instructions
Step 1: Generate a new plugin project
# Interactive boilerplate generator — validates metadata against submission rules
node scripts/create-plugin.js
# Or use npx directly from the source repo
npx github:gapmiss/obsidian-plugin-skill create-plugin
The generator produces:
src/main.ts— Plugin class with settings integrationsrc/settings.ts— Settings interface and PluginSettingTabmanifest.json— Validated plugin metadatastyles.css— CSS scaffold with Obsidian variables commenttsconfig.json,package.json,esbuild.config.mjs— Build toolchainversion-bump.mjs,versions.json— Version managementLICENSE— MIT with auto-populated year/author
Step 2: Install ESLint validation
npm install --save-dev eslint eslint-plugin-obsidianmd
// eslint.config.mjs
import pluginObsidianmd from "eslint-plugin-obsidianmd";
export default [
pluginObsidianmd.configs.recommended,
// For locale string checking:
// pluginObsidianmd.configs.recommendedWithLocalesEn,
];
Run validation:
npx eslint src/
npx eslint src/ --fix # auto-fix where possible
Step 3: Follow the submission validation workflow
- Run
bash scripts/install.shto set up the development environment - Validate plugin ID and name against naming rules (see below)
- Run ESLint — all 27 rules must pass
- Complete the Code Review Checklist (see References)
- Submit PR to obsidianmd/obsidian-releases
Plugin Naming Rules
| Field | Rule |
|---|---|
| Plugin ID | Lowercase, alphanumeric + dashes/underscores; no "obsidian"; no "plugin" suffix |
| Plugin Name | No "Obsidian" word; no "Plugin" suffix; no "Obsi" prefix or "dian" suffix |
| Description | No "Obsidian" word; no "This plugin"; must end with ., ?, !, or ) |
# Validate your manifest.json
node scripts/create-plugin.js --validate-only
ESLint Rules Summary (27 rules)
Submission & Naming
| Rule | Auto-fix | Description |
|---|---|---|
no-obsidian-in-id | No | Plugin ID must not contain "obsidian" |
no-plugin-suffix-in-id | No | Plugin ID must not end with "-plugin" |
no-obsidian-in-name | No | Plugin name must not contain "Obsidian" |
no-plugin-suffix-in-name | No | Plugin name must not end with "Plugin" |
valid-description | No | Description format validation |
Memory & Lifecycle
| Rule | Auto-fix | Description |
|---|---|---|
prefer-register-event | No | Use this.registerEvent() for automatic cleanup |
no-view-reference | No | Never store direct view references (causes memory leaks) |
Type Safety
| Rule | Auto-fix | Description |
|---|---|---|
no-tfile-cast | No | Avoid as TFile / as TFolder (use instanceof) |
UI/UX (sentence-case rules — mostly auto-fixable)
| Rule | Auto-fix | Description |
|---|---|---|
sentence-case | Yes | All UI text in sentence case |
no-plugin-name-in-command | No | Commands must not repeat plugin name |
no-command-in-command | No | Commands must not include the word "command" |
no-default-hotkey | No | Do not define default hotkeys |
no-manual-headings | No | Settings UI: use setHeading(), not manual HTML |
API Best Practices
| Rule | Auto-fix | Description |
|---|---|---|
no-global-app | No | Use this.app, not global app |
prefer-request-url | No | Use requestUrl(), not fetch() |
no-console-log | No | Remove console.log before submission |
prefer-abstract-input-suggest | No | Use AbstractInputSuggest for suggestions |
Styling
| Rule | Auto-fix | Description |
|---|---|---|
no-inline-styles | No | Use CSS classes; no inline style attributes |
prefer-css-variables | No | Use Obsidian CSS variables, not hardcoded colors |
scope-plugin-styles | No | Scope all CSS to plugin ID selector |
Accessibility (MANDATORY)
| Rule | Auto-fix | Description |
|---|---|---|
require-aria-label | No | Icon buttons must have aria-label |
require-keyboard-nav | No | All interactions must be keyboard accessible |
require-focus-visible | No | Use :focus-visible CSS for focus indicators |
Key Code Patterns
Memory-safe event registration
// ✅ Correct — auto-cleaned on plugin unload
this.registerEvent(
this.app.vault.on('create', (file) => this.handleCreate(file))
);
// ❌ Wrong — leaks memory
this.app.vault.on('create', (file) => this.handleCreate(file));
Type-safe file access
// ✅ Correct — instanceof narrowing
const file = this.app.workspace.getActiveFile();
if (file instanceof TFile) {
await this.app.vault.read(file);
}
// ❌ Wrong — unsafe cast
const file = this.app.workspace.getActiveFile() as TFile;
Accessibility — ARIA on icon buttons
// ✅ Correct
const btn = containerEl.createEl('button', { cls: 'clickable-icon' });
btn.setAttribute('aria-label', 'Delete note');
setIcon(btn, 'trash');
// ❌ Wrong — no aria-label
const btn = containerEl.createEl('button', { cls: 'clickable-icon' });
setIcon(btn, 'trash');
CSS with Obsidian variables
/* ✅ Correct — theme-compatible */
.my-plugin-button {
background-color: var(--interactive-accent);
color: var(--text-on-accent);
border-radius: var(--radius-m);
}
/* ❌ Wrong — hardcoded colors */
.my-plugin-button {
background-color: #7c3aed;
color: white;
}
Quick Reference
| Task | Command |
|---|---|
| Generate boilerplate | node scripts/create-plugin.js |
| Install ESLint | npm install --save-dev eslint eslint-plugin-obsidianmd |
| Run ESLint | npx eslint src/ |
| Auto-fix ESLint | npx eslint src/ --fix |
| Build plugin | npm run build |
| Dev watch mode | npm run dev |
| Bump version | npm run version |
References
- Accessibility Guide — Keyboard nav, ARIA, focus management (MANDATORY)
- Code Quality Guide — Security, platform compat, API usage
- CSS Styling Guide — Obsidian variables, scoped styles, dark/light mode
- File Operations Guide — Vault API, editor vs vault, atomic ops
- Memory Management Guide — registerEvent, lifecycle patterns
- Submission Guide — Repository structure, naming, submission process
- Type Safety Guide — instanceof narrowing, no
any, const/let - UI/UX Guide — Sentence case, commands, settings structure
- eslint-plugin-obsidianmd — Official ESLint rules
- Obsidian Plugin Developer Docs
- Source Skill Repository — MIT License
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/akillness/jeo-skills/obsidian-plugin">View obsidian-plugin on skillZs</a>