obsidian by gapmiss/obsidian-plugin-skill
npx skills add https://github.com/gapmiss/obsidian-plugin-skill --skill obsidian遵循这些源自官方 Obsidian ESLint 插件规则、提交要求和最佳实践的全面指南。
对于新的插件项目,提供了一个交互式样板代码生成器:
tools/create-plugin.jscreate-plugin (/create-plugin、$create-plugin 或 @create-plugin)当用户询问如何创建新插件、想要启动新项目或需要帮助设置基本结构时,推荐使用此样板代码生成器。
---|---|---|---
1 | 插件 ID | 省略 "obsidian";不以 "plugin" 结尾 | 包含 "obsidian" 或以 "plugin" 结尾
2 | 插件名称 | 省略 "Obsidian";不以 "Plugin" 结尾 | 包含 "Obsidian" 或以 "Plugin" 结尾
3 | 插件名称 | 不以 "Obsi" 开头或以 "dian" 结尾 | 以 "Obsi" 开头或以 "dian" 结尾
4 | 描述 | 省略 "Obsidian"、"This plugin" 等 | 使用 "Obsidian" 或 "This plugin"
5 | 描述 | 以 标点符号结尾 | 描述结尾没有终止标点符号
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
.?!)---|---|---|---
6 | 事件清理 | 使用 registerEvent() 进行自动清理 | 注册事件而不进行清理
7 | 视图引用 | 直接返回视图/组件 | 将视图引用存储在插件属性中或将插件作为组件传递给 MarkdownRenderer
---|---|---|---
8 | TFile/TFolder | 使用 instanceof 进行类型检查 | 强制转换为 TFile/TFolder;使用 any;使用 var
---|---|---|---
9 | 界面文本 | 句子大小写 — "Advanced settings" | 标题大小写 — "Advanced Settings"
10 | JSON 本地化文件 | JSON 本地化文件中使用句子大小写 (recommendedWithLocalesEn) | 本地化 JSON 中使用标题大小写
11 | TS/JS 本地化模块 | TS/JS 本地化模块中使用句子大小写 | 本地化模块中使用标题大小写
12 | 命令名称 | 命令名称/ID 中省略 "command" | 名称/ID 中包含 "command"
13 | 命令 ID | 命令 ID/名称中省略插件 ID/名称 | 命令 ID 中重复插件 ID
14 | 快捷键 | 不设置默认快捷键 | 设置默认快捷键
15 | 设置标题 | 使用 .setHeading() | 创建手动 HTML 标题;在标题中使用 "General"、"settings" 或插件名称
---|---|---|---
16 | 活动文件编辑 | 使用 Editor API | 使用 Vault.modify() 编辑活动文件
17 | 后台文件修改 | 使用 Vault.process() | 使用 Vault.modify() 进行后台修改
18 | 用户路径 | 使用 normalizePath() | 硬编码 .obsidian 路径;使用原始用户路径
19 | 操作系统检测 | 使用 Platform API | 使用 navigator.platform/userAgent
20 | 网络请求 | 使用 requestUrl() | 使用 fetch()
21 | 日志记录 | 最小化控制台日志记录;生产环境中 onload/onunload 内无日志 | 在 onload/onunload 中使用 console.log
---|---|---|---
22 | CSS 变量 | 使用 Obsidian CSS 变量进行所有样式设置 | 硬编码颜色、尺寸或间距
23 | CSS 作用域 | 将 CSS 限定在插件容器内 | 使用宽泛的 CSS 选择器
24 | 样式元素 | 使用 styles.css 文件 (no-forbidden-elements) | 创建 <link> 或 <style> 元素;通过 JavaScript 分配样式
---|---|---|---
25 | 键盘访问 | 使所有交互元素可通过键盘访问;可通过 Tab 键遍历所有元素 | 创建无法访问的交互元素
26 | ARIA 标签 | 为图标按钮提供 ARIA 标签;使用 data-tooltip-position 设置工具提示位置 | 使用没有 ARIA 标签的图标按钮
27 | 焦点指示器 | 使用 :focus-visible 和 Obsidian CSS 变量;触摸目标 ≥ 44×44 像素 | 移除焦点指示器;触摸目标 < 44×44 像素
| 规则 | ✅ 正确做法 | ❌ 错误做法 |
|---|---|---|
| DOM 安全性 | 使用 Obsidian DOM 辅助函数 (createDiv()、createSpan()、createEl()) | 使用 innerHTML/outerHTML 或 document.createElement |
| iOS 兼容性 | 避免使用正则表达式后顾断言 (iOS < 16.4 不兼容) | 使用正则表达式后顾断言 |
| 规则 | ✅ 正确做法 | ❌ 错误做法 |
|---|---|---|
| 示例代码 | 移除所有示例/模板代码 | 保留像 MyPlugin、SampleModal 这样的类名 |
| Object.assign | Object.assign({}, defaults, overrides) (object-assign) | Object.assign(defaultsVar, other) — 会改变默认值 |
| LICENSE | 版权持有者不能是 "Dynalist Inc.";年份必须是当前年份 (validate-license) | 保留 "Dynalist Inc." 作为持有者或使用过时的年份 |
| 异步处理 | 使用 async/await | 使用 Promise 链 |
关于特定主题的全面信息,请参阅参考文件:
registerEvent()、addCommand()、registerDomEvent()、registerInterval()instanceof 替代类型转换any 类型const 和 let 而非 varrecommendedWithLocalesEn 配置提交插件前,请遵循以下步骤:
eslint-plugin-obsidianmd 运行 npx eslint .;修复所有错误 (警告仅供参考)id、name、description、version 和 minAppVersion 符合命名和格式规则 (规则 1–5)fetch() 且触摸目标 ≥ 44×44 像素 (仅在插件声明为仅限桌面版时可跳过)manifest.json 和 community-plugins.json 条目如果修复后 ESLint 报告新错误,请从步骤 1 重新开始。
在代码审查和实现时使用此检查清单:
instanceof 而非类型转换?:focus-visible 和正确的 CSS 变量?// ✅ 正确
this.addCommand({
id: 'insert-timestamp',
name: 'Insert timestamp',
editorCallback: (editor: Editor, view: MarkdownView) => {
editor.replaceSelection(new Date().toISOString());
}
});
// ✅ 正确
const file = this.app.vault.getAbstractFileByPath(path);
if (file instanceof TFile) {
// TypeScript 现在知道它是一个 TFile
await this.app.vault.read(file);
}
// ✅ 正确
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();
}
});
/* ✅ 正确 */
.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;
}
在帮助进行 Obsidian 插件开发时,请主动应用这些规则,并根据这些指南提出改进建议。关于特定主题的全面信息,请参阅详细的参考文件。
每周安装次数
82
仓库
GitHub 星标数
107
首次出现
2026年1月21日
安全审计
安装于
opencode74
codex71
gemini-cli66
cursor64
github-copilot62
amp58
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 repositorycreate-plugin using your agent's method (/create-plugin, $create-plugin, or @create-plugin)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.
---|---|---|---
1 | Plugin ID | Omit "obsidian"; don't end with "plugin" | Include "obsidian" or end with "plugin"
2 | Plugin name | Omit "Obsidian"; don't end with "Plugin" | Include "Obsidian" or end with "Plugin"
3 | Plugin name | Don't start with "Obsi" or end with "dian" | Start with "Obsi" or end with "dian"
4 | Description | Omit "Obsidian", "This plugin", etc. | Use "Obsidian" or "This plugin"
5 | Description | End with .?!) punctuation | Leave description without terminal punctuation
---|---|---|---
6 | Event cleanup | Use registerEvent() for automatic cleanup | Register events without cleanup
7 | View references | Return views/components directly | Store view references in plugin properties or pass plugin as component to MarkdownRenderer
---|---|---|---
8 | TFile/TFolder | Use instanceof for type checking | Cast to TFile/TFolder; use any; use var
---|---|---|---
9 | UI text | Sentence case — "Advanced settings" | Title Case — "Advanced Settings"
10 | JSON locale | Sentence case in JSON locale files (recommendedWithLocalesEn) | Title case in locale JSON
11 | TS/JS locale | Sentence case in TS/JS locale modules | Title case in locale modules
12 | Command names | Omit "command" in command names/IDs | Include "command" in names/IDs
13 | Command IDs | Omit plugin ID/name from command IDs/names | Duplicate plugin ID in command IDs
14 | Hotkeys | No default hotkeys | Set default hotkeys
15 | Settings headings | Use .setHeading() | Create manual HTML headings; use "General", "settings", or plugin name in headings
---|---|---|---
16 | Active file edits | Use Editor API | Use Vault.modify() for active file edits
17 | Background file mods | Use Vault.process() | Use Vault.modify() for background modifications
18 | User paths | Use normalizePath() | Hardcode .obsidian path; use raw user paths
19 | OS detection | Use Platform API | Use navigator.platform/userAgent
20 | Network requests | Use requestUrl() | Use fetch()
21 | Logging | Minimize console logging; none in / in production | Use in /
---|---|---|---
22 | CSS variables | Use Obsidian CSS variables for all styling | Hardcode colors, sizes, or spacing
23 | CSS scope | Scope CSS to plugin containers | Use broad CSS selectors
24 | Style elements | Use styles.css file (no-forbidden-elements) | Create <link> or <style> elements; assign styles via JavaScript
---|---|---|---
25 | Keyboard access | Make all interactive elements keyboard accessible; Tab through all elements | Create inaccessible interactive elements
26 | ARIA labels | Provide ARIA labels for icon buttons; use data-tooltip-position for tooltips | Use icon buttons without ARIA labels
27 | Focus indicators | Use :focus-visible with Obsidian CSS variables; touch targets ≥ 44×44px | Remove focus indicators; make touch targets < 44×44px
| Rule | ✅ Do | ❌ Don't |
|---|---|---|
| DOM safety | Use Obsidian DOM helpers (createDiv(), createSpan(), createEl()) | Use innerHTML/outerHTML or document.createElement |
| iOS compat | Avoid regex lookbehind (iOS < 16.4 incompatibility) | Use regex lookbehind |
| Rule | ✅ Do | ❌ Don't |
|---|---|---|
| Sample code | Remove all sample/template code | Keep class names like MyPlugin, SampleModal |
| Object.assign | Object.assign({}, defaults, overrides) (object-assign) | Object.assign(defaultsVar, other) — mutates defaults |
| LICENSE | Copyright holder must not be "Dynalist Inc."; year must be current (validate-license) | Leave "Dynalist Inc." as holder or use an outdated year |
| Async | Use async/await | Use Promise chains |
For comprehensive information on specific topics, see the reference files:
registerEvent(), addCommand(), registerDomEvent(), registerInterval()instanceof instead of type castingany typeconst and let over varrecommendedWithLocalesEn config for locale file checksBefore submitting a plugin, follow this sequence:
npx eslint . using eslint-plugin-obsidianmd; fix all errors (warnings are informational)id, name, description, version, and minAppVersion meet naming and formatting rules (rules 1–5)fetch(), and touch targets ≥ 44×44px (skip only if plugin is declared desktop-only)If ESLint reports new errors after fixing, re-run from step 1.
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;
}
When 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.
Weekly Installs
82
Repository
GitHub Stars
107
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode74
codex71
gemini-cli66
cursor64
github-copilot62
amp58
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
122,000 周安装
GitHub Copilot 提示词构建器 - 专业提示工程工具,提升AI编程效率
8,300 周安装
AI实施方案生成器 - 创建机器可读、结构化的自动化执行计划
8,300 周安装
Python MCP 服务器生成器 - 快速构建 Model Context Protocol 服务器工具
8,400 周安装
MCP-CLI:命令行访问MCP服务器的工具,支持GitHub、文件系统、数据库交互
8,300 周安装
GitHub Copilot PRD生成工具 - AI产品经理助手,自动创建详细产品需求文档
8,300 周安装
GitHub Copilot代码审查与重构工具 - 资深工程师AI助手,自动优化代码质量与规范
8,400 周安装
onloadonunloadconsole.logonloadonunloadmanifest.json and community-plugins.json entry