{"id":32329864,"url":"https://github.com/gapmiss/obsidian-plugin-skill","last_synced_at":"2026-05-14T21:05:22.778Z","repository":{"id":320289569,"uuid":"1081523808","full_name":"gapmiss/obsidian-plugin-skill","owner":"gapmiss","description":"Agent SKILL for Obsidian.md plugin development","archived":false,"fork":false,"pushed_at":"2026-04-20T01:44:24.000Z","size":118,"stargazers_count":121,"open_issues_count":0,"forks_count":10,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-20T03:18:57.898Z","etag":null,"topics":["claude","claude-code","claude-skills","codex","codex-skills","obsidian","obsidian-md","obsidian-plugin","skills"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gapmiss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-22T22:55:17.000Z","updated_at":"2026-04-20T01:44:28.000Z","dependencies_parsed_at":"2025-10-23T01:20:58.065Z","dependency_job_id":"50196697-fa18-4dbf-97b6-446342ac0cba","html_url":"https://github.com/gapmiss/obsidian-plugin-skill","commit_stats":null,"previous_names":["gapmiss/obsidian-plugin-skill"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gapmiss/obsidian-plugin-skill","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gapmiss%2Fobsidian-plugin-skill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gapmiss%2Fobsidian-plugin-skill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gapmiss%2Fobsidian-plugin-skill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gapmiss%2Fobsidian-plugin-skill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gapmiss","download_url":"https://codeload.github.com/gapmiss/obsidian-plugin-skill/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gapmiss%2Fobsidian-plugin-skill/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33043271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude","claude-code","claude-skills","codex","codex-skills","obsidian","obsidian-md","obsidian-plugin","skills"],"created_at":"2025-10-23T18:19:36.798Z","updated_at":"2026-05-14T21:05:22.772Z","avatar_url":"https://github.com/gapmiss.png","language":"JavaScript","funding_links":[],"categories":["Lista de Habilidades","Phase 3: Build and Integrate"],"sub_categories":["Habilidades de la Comunidad","Reference Implementations"],"readme":"# Obsidian Plugin Development - Agent Skill\n\nA comprehensive agent skill for developing high-quality Obsidian plugins that follow best practices, pass code review, and adhere to official submission guidelines.\n\n## Overview\n\nThis skill provides your coding agent with deep knowledge of Obsidian plugin development standards, including:\n\n- All 36 ESLint rules from `eslint-plugin-obsidianmd` v0.2.8\n- Official Plugin Guidelines from Obsidian documentation\n- Submission requirements for the community plugins directory\n- Memory management and lifecycle best practices\n- Security guidelines and XSS prevention\n- Platform compatibility (including iOS considerations)\n- Network request best practices (requestUrl vs fetch)\n\n## Prerequisites\n\n- A coding agent supporting the [Agent Skills standard](https://agentskills.io) (Claude Code, OpenAI Codex, or Windsurf)\n- An Obsidian plugin project (or starting a new one)\n\n## Installation\n\n### Quick Install\n\n```bash\nnpx skills add https://github.com/gapmiss/obsidian-plugin-skill --skill obsidian\n```\n\n### Setup\n\n#### Option 1: Installer Script (Recommended)\n\n1. Clone this repository:\n   ```bash\n   git clone https://github.com/gapmiss/obsidian-plugin-skill.git\n   cd obsidian-plugin-skill\n   ```\n\n2. Run the installer:\n   ```bash\n   ./install-skill.sh\n   ```\n\n3. Select your provider(s):\n   - **All providers** — installs to both `.agents/skills/` and `.claude/skills/`\n   - **Claude Code** — installs to `.claude/skills/` with slash commands\n   - **Codex (OpenAI)** — installs to `.agents/skills/`\n   - **Windsurf** — installs to `.agents/skills/`\n\n4. Choose installation target (current directory or custom path)\n\n#### Option 2: Manual Install\n\n\u003cdetails\u003e\n\u003csummary\u003eClaude Code\u003c/summary\u003e\n\n```bash\ngit clone https://github.com/gapmiss/obsidian-plugin-skill.git\ncd obsidian-plugin-skill\n\n# Copy skill\nmkdir -p your-project/.claude/skills/obsidian\ncp -r .agents/skills/obsidian/* your-project/.claude/skills/obsidian/\n\n# Copy slash commands\nmkdir -p your-project/.claude/commands\ncp .claude/commands/obsidian.md your-project/.claude/commands/\ncp .claude/commands/create-plugin.md your-project/.claude/commands/\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eCodex (OpenAI) / Windsurf\u003c/summary\u003e\n\n```bash\ngit clone https://github.com/gapmiss/obsidian-plugin-skill.git\ncd obsidian-plugin-skill\n\n# Copy skill\nmkdir -p your-project/.agents/skills/obsidian\ncp -r .agents/skills/obsidian/* your-project/.agents/skills/obsidian/\n```\n\u003c/details\u003e\n\n#### Option 3: Use as Standalone\n\nJust open this directory with your coding agent — no installation needed!\n\n### Skill Structure\n\nThe skill uses **progressive disclosure** for optimal performance:\n\n```\n.agents/skills/obsidian/\n├── SKILL.md                          # Main overview (285 lines)\n└── reference/                        # Detailed documentation\n    ├── memory-management.md          # Lifecycle \u0026 cleanup patterns\n    ├── type-safety.md                # Type narrowing \u0026 safety\n    ├── ui-ux.md                      # UI standards \u0026 commands\n    ├── file-operations.md            # Vault \u0026 file API\n    ├── css-styling.md                # Theming \u0026 styling\n    ├── accessibility.md              # A11y requirements (MANDATORY)\n    ├── code-quality.md               # Best practices \u0026 security\n    ├── submission.md                 # Publishing guidelines\n    └── eslint-setup.md               # Complete ESLint config guide\n```\n\nSKILL.md provides a concise overview with all 36 rules, while reference files contain comprehensive details on specific topics.\n\n## Quick Start: Creating a New Plugin\n\n### Interactive Boilerplate Generator\n\nThe fastest way to start a new Obsidian plugin with all best practices built-in:\n\n```bash\nnode /path/to/obsidian-plugin-skill/tools/create-plugin.js\n```\n\n**Features:**\n- Generates clean TypeScript boilerplate with **no sample code**\n- Creates `src/` directory structure with `main.ts` and `settings.ts`\n- **Validates plugin metadata in real-time** against Obsidian's submission bot rules\n- Prompts for target directory to avoid overwriting existing files\n- Detects existing projects and only adds missing files\n- All generated code follows the skill's best practices automatically\n\n**What it creates:**\n```\nyour-plugin/\n├── src/\n│   ├── main.ts           # Plugin class with settings integration\n│   └── settings.ts       # Settings interface, defaults, and tab\n├── manifest.json         # Validated plugin metadata\n├── styles.css           # CSS with Obsidian variables\n├── tsconfig.json        # TypeScript configuration\n├── package.json         # Dependencies\n├── esbuild.config.mjs   # Build configuration\n├── eslint.config.mjs    # ESLint configuration\n├── version-bump.mjs     # Version management script\n├── versions.json        # Version tracking\n├── .gitignore          # Git ignore rules\n└── LICENSE             # MIT license\n```\n\n**Interactive prompts:**\n1. Target directory (default: current directory)\n2. Plugin name (validates: no \"Obsidian\", can't end with \"Plugin\")\n3. Plugin ID (validates: no \"obsidian\", can't end with \"plugin\", lowercase only)\n4. Description (validates: no \"Obsidian\"/\"This plugin\", must end with punctuation)\n5. Author name\n6. GitHub username (optional, auto-generates authorUrl)\n7. Minimum Obsidian version\n\n**Real-time validation catches common mistakes:**\n```\n❌ Validation Errors:\n   • Plugin ID cannot contain \"obsidian\"\n   • Plugin name cannot end with \"Plugin\"\n   • Description must end with punctuation: . ? ! or )\n```\n\n---\n\n## Usage\n\n### Invoking the Skill\n\n| Provider | Load skill | Create plugin |\n|----------|-----------|---------------|\n| Claude Code | `/obsidian` | `/create-plugin` |\n| Codex (OpenAI) | `$obsidian` | — |\n| Windsurf | `@obsidian` | — |\n\nSkills are automatically discovered by your agent when present in the project directory. You can also invoke them explicitly using the commands above.\n\nJust ask your agent naturally:\n\n```\nHelp me implement a new command for my Obsidian plugin\n```\n\nYour agent will automatically use the Obsidian skill guidelines while helping you write code.\n\n### What the Skill Helps With\n\n#### Code Quality\n- Prevents common memory leaks\n- Enforces type safety (no unsafe casts)\n- Ensures proper resource cleanup\n- Follows Obsidian's API patterns\n\n#### UI/UX Standards\n- Enforces sentence case for all UI text\n- Prevents redundant naming patterns\n- Ensures consistent settings UI\n\n#### Accessibility (A11y)\n- **MANDATORY keyboard navigation** for all interactive elements\n- **MANDATORY ARIA labels** for icon buttons and controls\n- **MANDATORY focus indicators** with proper CSS styling\n- Touch target size requirements (44×44px minimum)\n- Screen reader support and announcements\n- Tooltip positioning with `data-tooltip-position`\n\n#### Security\n- Prevents XSS vulnerabilities (no innerHTML/outerHTML)\n- Validates manifest structure\n- Ensures proper path handling\n\n#### Platform Compatibility\n- iOS compatibility checks (no regex lookbehind)\n- Cross-platform path handling\n- Mobile-friendly API usage\n\n#### Submission Ready\n- Removes template/sample code\n- Validates manifest.json\n- Ensures LICENSE compliance\n- Follows submission requirements\n\n## What's Covered\n\n### Most Critical Rules (eslint-plugin-obsidianmd v0.2.8)\n\nThe main SKILL.md file highlights the most important rules organized by category:\n\n**Submission \u0026 Naming:**\n1. Plugin ID: no \"obsidian\", can't end with \"plugin\"\n2. Plugin name: no \"Obsidian\", can't end with \"Plugin\"\n3. Plugin name: can't start with \"Obsi\" or end with \"dian\"\n4. Description: no \"Obsidian\", \"This plugin\", etc.\n5. Description must end with `.?!)` punctuation\n\n**Memory \u0026 Lifecycle:**\n6. Use `registerEvent()` for automatic cleanup\n7. Don't store view references in plugin\n8. Don't call `detachLeavesOfType()` in `onunload`\n\n**Type Safety:**\n9. Use `instanceof` instead of type casting for TFile/TFolder\n10. Use `.instanceOf(T)` for cross-window DOM checks\n\n**UI/UX:**\n11. Use sentence case for all UI text\n12. Sentence case in locale JSON files\n13. Sentence case in TS/JS locale modules\n14. No \"command\" in command names/IDs\n15. No plugin ID/name in command IDs/names\n16. No default hotkeys\n17. Use `.setHeading()` for settings headings\n\n**API Best Practices:**\n18. Use Editor API for active file edits\n19. Use `Vault.process()` for background file mods\n20. Use `FileManager.trashFile()` for file deletion\n21. Use `Vault.getAbstractFileByPath()` instead of iterating files\n22. Use `normalizePath()` for user paths\n23. Use `Platform` API for OS detection\n24. Use `requestUrl()` instead of `fetch()`\n25. No console.log in onload/onunload in production\n26. Use built-in `AbstractInputSuggest`\n27. Check `minAppVersion` for API compatibility\n\n**Popout Window Compatibility:**\n28. Use `activeDocument`/`activeWindow` instead of globals\n29. Use `activeWindow.setTimeout()` for timers\n\n**Event Handling:**\n30. Check `evt.defaultPrevented` in editor-drop/paste handlers\n\n**Styling:**\n31. Use Obsidian CSS variables\n32. Scope CSS to plugin containers\n33. Don't create `\u003clink\u003e` or `\u003cstyle\u003e` elements\n\n**Accessibility (MANDATORY):**\n34. Make all interactive elements keyboard accessible\n35. Provide ARIA labels for icon buttons\n36. Define clear focus indicators\n\n**Security \u0026 Compatibility:**\n- Don't use `innerHTML`/`outerHTML`\n- Avoid regex lookbehind\n\n**Code Quality:**\n- Remove all sample/template code\n- Don't mutate defaults with `Object.assign`\n- Validate LICENSE copyright holder and year\n\n### Detailed Coverage by Topic\n\n**[Memory Management \u0026 Lifecycle](/.agents/skills/obsidian/reference/memory-management.md)**\n- Using `registerEvent()`, `addCommand()`, `registerDomEvent()`, `registerInterval()`\n- Avoiding view references in plugin\n- Not using plugin as component\n- Proper leaf cleanup\n\n**[Type Safety](/.agents/skills/obsidian/reference/type-safety.md)**\n- Using `instanceof` instead of type casting\n- Avoiding `any` type\n- Using `const` and `let` over `var`\n\n**[UI/UX Standards](/.agents/skills/obsidian/reference/ui-ux.md)**\n- Sentence case enforcement\n- Command naming conventions\n- Settings and configuration best practices\n\n**[File \u0026 Vault Operations](/.agents/skills/obsidian/reference/file-operations.md)**\n- View access patterns\n- Editor vs Vault API\n- Atomic file operations (Vault.process, processFrontMatter)\n- File management and path handling\n\n**[CSS Styling Best Practices](/.agents/skills/obsidian/reference/css-styling.md)**\n- Avoiding inline styles\n- Using Obsidian CSS variables\n- Scoping plugin styles\n- Theme support (light/dark)\n- Spacing and layout (4px grid)\n\n**[Accessibility (A11y)](/.agents/skills/obsidian/reference/accessibility.md)** - MANDATORY\n- Keyboard navigation for all interactive elements\n- ARIA labels and roles\n- Tooltips with proper positioning\n- Focus management\n- Focus visible styles (`:focus-visible`)\n- Screen reader support\n- Mobile and touch accessibility (44×44px minimum)\n\n**[Code Quality \u0026 Best Practices](/.agents/skills/obsidian/reference/code-quality.md)**\n- Removing sample code\n- Security best practices (XSS prevention)\n- Platform compatibility (iOS, mobile)\n- API usage patterns\n- Async/await patterns\n- DOM helpers\n\n**[Plugin Submission Requirements](/.agents/skills/obsidian/reference/submission.md)**\n- **Naming and description validation rules** (enforced by Obsidian's release bot)\n- Plugin ID, name, and description requirements\n- Repository structure and manifest synchronization\n- Submission process to obsidianmd/obsidian-releases\n- Semantic versioning\n- Testing checklist\n\n## Examples\n\n### Before (Incorrect)\n```typescript\n// Multiple issues\nclass MyPlugin extends Plugin {\n  view: CustomView;\n\n  async onload() {\n    this.registerView(VIEW_TYPE, (leaf) =\u003e {\n      this.view = new CustomView(leaf);  // Memory leak!\n      return this.view;\n    });\n\n    this.addCommand({\n      id: 'my-plugin-show-command',  // Redundant naming\n      name: 'Show Command',  // Title Case\n      hotkeys: [{ modifiers: ['Mod'], key: 's' }],  // Default hotkey\n    });\n\n    const file = abstractFile as TFile;  // Unsafe cast\n  }\n\n  onunload() {\n    this.app.workspace.detachLeavesOfType(VIEW_TYPE);  // Don't do this\n  }\n}\n```\n\n### After (Correct)\n```typescript\n// Following all guidelines\nclass TodoPlugin extends Plugin {\n  async onload() {\n    this.registerView(VIEW_TYPE, (leaf) =\u003e {\n      return new CustomView(leaf);  // Create and return directly\n    });\n\n    this.addCommand({\n      id: 'show',  // Clean naming\n      name: 'Show todo',  // Sentence case\n      // Let users set their own hotkeys\n      checkCallback: (checking: boolean) =\u003e {\n        const view = this.app.workspace.getActiveViewOfType(MarkdownView);\n        if (view) {\n          if (!checking) {\n            // Perform action\n          }\n          return true;\n        }\n        return false;\n      }\n    });\n\n    if (abstractFile instanceof TFile) {\n      // Safe type narrowing\n      const file = abstractFile;\n    }\n  }\n\n  onunload() {\n    // Let Obsidian handle cleanup\n  }\n}\n```\n\n## Checklist for Plugin Review\n\nUse this checklist before submitting your plugin:\n\n**Submission Validation (will fail bot checks if incorrect):**\n- [ ] Plugin ID: no \"obsidian\", doesn't end with \"plugin\", lowercase only\n- [ ] Plugin name: no \"Obsidian\", doesn't end with \"Plugin\"\n- [ ] Plugin name: doesn't start with \"Obsi\" or end with \"dian\"\n- [ ] Description: no \"Obsidian\" or \"This plugin\" phrases\n- [ ] Description ends with proper punctuation (. ? ! or ))\n- [ ] Description under 250 characters (recommended)\n- [ ] manifest.json ID, name, description match submission entry\n\n**Code Quality:**\n- [ ] No memory leaks (views/components properly managed)\n- [ ] Type safety (using `instanceof` instead of casts)\n- [ ] All UI text in sentence case\n- [ ] No redundant words in command names\n- [ ] Using preferred APIs (Editor API, Vault.process, etc.)\n- [ ] No iOS-incompatible features (regex lookbehind)\n- [ ] All sample code removed (MyPlugin, SampleModal, etc.)\n- [ ] No security issues (innerHTML, XSS vulnerabilities)\n\n**Accessibility (MANDATORY):**\n- [ ] **All interactive elements keyboard accessible (Tab, Enter, Space)**\n- [ ] **ARIA labels on all icon buttons (`aria-label`)**\n- [ ] **Clear focus indicators (`:focus-visible` with proper CSS)**\n- [ ] **Touch targets at least 44×44px (mobile)**\n- [ ] **Tooltips positioned with `data-tooltip-position`**\n\n**Release Requirements:**\n- [ ] manifest.json valid and version correct\n- [ ] LICENSE file included\n- [ ] Mobile tested (if not desktop-only)\n- [ ] Repository has issues enabled\n\n## ESLint Integration\n\nFor automatic checking, install the official ESLint plugin **and** typescript-eslint:\n\n```bash\nnpm install --save-dev eslint typescript-eslint @typescript-eslint/parser eslint-plugin-obsidianmd\n```\n\n**Important:** The community plugin scanner uses **both** `eslint-plugin-obsidianmd` AND `typescript-eslint` type-checked rules. Most submission failures come from missing the typescript-eslint setup.\n\nSee the **[complete ESLint setup guide](/.agents/skills/obsidian/reference/eslint-setup.md)** for:\n- Full `eslint.config.mjs` that matches the community scanner\n- Why `recommendedTypeChecked` is required (not just `recommended`)\n- Common violations and how to fix them\nQuick config example:\n\n```javascript\n// eslint.config.mjs\nimport tsParser from \"@typescript-eslint/parser\";\nimport tseslint from \"typescript-eslint\";\nimport obsidianmd from \"eslint-plugin-obsidianmd\";\n\nexport default [\n  { ignores: [\"node_modules/**\", \"main.js\"] },\n  // Type-checked rules — this is what most people miss\n  ...tseslint.configs.recommendedTypeChecked.map(c =\u003e ({ ...c, files: [\"src/**/*.ts\"] })),\n  // Obsidian-specific rules\n  ...obsidianmd.configs.recommended,\n  {\n    files: [\"src/**/*.ts\"],\n    languageOptions: {\n      parser: tsParser,\n      parserOptions: { project: \"./tsconfig.json\" },\n    },\n  },\n];\n```\n\nMany rules are auto-fixable with:\n```bash\nnpx eslint --fix .\n```\n\n## Resources\n\n- Obsidian API Docs: https://docs.obsidian.md\n- ESLint Plugin: https://github.com/obsidianmd/eslint-plugin\n- Sample Plugin: https://github.com/obsidianmd/obsidian-sample-plugin\n- Plugin Guidelines: https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines\n- Submission Repo: https://github.com/obsidianmd/obsidian-releases\n- Agent Skills Standard: https://agentskills.io\n\n## Contributing\n\nFound a missing guideline or rule? Please contribute!\n\n1. Fork this repository\n2. Add the guideline to the appropriate file:\n   - Main overview: `.agents/skills/obsidian/SKILL.md`\n   - Detailed coverage: `.agents/skills/obsidian/reference/*.md`\n3. Update this README if needed\n4. Submit a pull request\n\n### Adding New Guidelines\n\nWhen adding new content:\n- Keep SKILL.md under 500 lines (progressive disclosure principle)\n- Add detailed content to appropriate reference files\n- Use consistent formatting and examples\n- Include both incorrect and correct examples\n\n## Migration from `.claude/skills/`\n\nIf you previously installed this skill to `.claude/skills/obsidian/`, you can migrate:\n\n```bash\n# Move skill files to the new location\nmv .claude/skills/obsidian .agents/skills/obsidian\n\n# Keep .claude/commands/ as-is (Claude Code only)\n```\n\nThe `.claude/skills/` path still works for Claude Code, but `.agents/skills/` is the standard location recognized by all providers.\n\n## License\n\nMIT License - See LICENSE file for details\n\n## Acknowledgments\n\nThis skill is based on:\n- The official Obsidian Plugin Guidelines\n- The `eslint-plugin-obsidianmd` package (not yet production-ready)\n- Community best practices from plugin developers\n- Agent Skills standard best practices (progressive disclosure pattern)\n\n---\n\n## Design Philosophy\n\nThis skill follows **Agent Skills standard best practices**:\n\n- **Progressive Disclosure**: Main SKILL.md (263 lines) provides overview; reference files contain details\n- **Context Window Efficiency**: \"The context window is a public good\" - optimized token usage\n- **One-Level-Deep References**: All reference files directly under `reference/` (no nesting)\n- **Topic-Based Organization**: Each reference file focuses on a specific domain\n- **Consistent Terminology**: Same terms used throughout for clarity\n\nThis structure allows your coding agent to load the essential information quickly while having access to comprehensive details when needed.\n\n---\n\nNote: Guidelines in this skill are based on `eslint-plugin-obsidianmd` v0.2.8. The plugin is under active development and rules may evolve.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgapmiss%2Fobsidian-plugin-skill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgapmiss%2Fobsidian-plugin-skill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgapmiss%2Fobsidian-plugin-skill/lists"}