plugins/obsidian-development/skills/obsidian-scaffold/SKILL.md
Scaffolds project structure, manifest, tsconfig, esbuild config, and a minimal plugin class that passes ObsidianReviewBot checks. TRIGGER WHEN: the user asks to start, create, bootstrap, or initialize a new Obsidian community plugin DO NOT TRIGGER WHEN: the task is outside the specific scope of this component.
npx skillsauth add acaprino/anvil-toolset obsidian-scaffoldInstall 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.
Scaffold a new Obsidian community plugin project that is bot-compliant from day one.
/obsidian-scaffold -- then answer the prompts for plugin ID, name, author, and description.
my-plugin/
src/
main.ts # Plugin class with onload/onunload
styles.css # Empty, scoped styles
manifest.json # Valid manifest (bot-compliant)
package.json # Dependencies: obsidian, typescript, esbuild, @types/node, builtin-modules
tsconfig.json # strict: true, target ES2018, moduleResolution node
esbuild.config.mjs # CJS bundle, externalizes obsidian + electron
.eslintrc.json # eslint-plugin-obsidianmd recommended config
LICENSE # MIT with current year
README.md # Minimal description
.gitignore # node_modules, main.js, data.json
Ask the user for:
. ? ! ), under 250 chars)Validate inputs against ObsidianReviewBot rules:
/^[a-z0-9-]+$/, not containing "obsidian", not ending with "plugin".?!)Create all files using the templates below.
Run npm install to install dependencies.
Verify npx tsc --noEmit passes with zero errors.
{
"id": "{{ID}}",
"name": "{{NAME}}",
"version": "1.0.0",
"minAppVersion": "1.0.0",
"description": "{{DESCRIPTION}}",
"author": "{{AUTHOR}}",
"authorUrl": "{{AUTHOR_URL}}",
"isDesktopOnly": {{IS_DESKTOP_ONLY}}
}
{
"name": "{{ID}}",
"version": "1.0.0",
"description": "{{DESCRIPTION}}",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"lint": "eslint src/"
},
"devDependencies": {
"@eslint/js": "^9.0.0",
"@types/node": "^22.0.0",
"builtin-modules": "^4.0.0",
"esbuild": "^0.24.0",
"eslint": "^9.0.0",
"eslint-plugin-obsidianmd": "latest",
"obsidian": "latest",
"typescript": "^5.5.0",
"typescript-eslint": "^8.0.0"
}
}
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES2018",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"strict": true,
"lib": ["DOM", "ES2018", "ES2021.String"]
},
"include": ["src/**/*.ts"]
}
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
const prod = process.argv[2] === "production";
esbuild.build({
entryPoints: ["src/main.ts"],
bundle: true,
external: [
"obsidian",
"electron",
"@codemirror/autocomplete",
"@codemirror/collab",
"@codemirror/commands",
"@codemirror/language",
"@codemirror/lint",
"@codemirror/search",
"@codemirror/state",
"@codemirror/view",
"@lezer/common",
"@lezer/highlight",
"@lezer/lr",
...builtins,
],
format: "cjs",
target: "es2018",
logLevel: "info",
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
minify: prod,
}).catch(() => process.exit(1));
import { Plugin } from 'obsidian';
export default class {{CLASS_NAME}} extends Plugin {
onload(): void {
// Plugin initialization here
}
onunload(): void {
// Cleanup here (Obsidian handles leaf detachment automatically)
}
}
node_modules/
main.js
data.json
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import obsidianmd from 'eslint-plugin-obsidianmd';
export default [
js.configs.recommended,
...tseslint.configs.recommended,
...obsidianmd.configs.recommended,
{
languageOptions: {
parserOptions: {
project: './tsconfig.json',
},
},
},
];
After creation, remind the user:
npm run dev for watch mode during developmentnpm run build for production buildnpm run lint to check against ObsidianReviewBot rules locallymain.js, manifest.json, and styles.css as individual assetsv prefix)development
Unified web frontend knowledge base covering CSS architecture, UX psychology, UI components, distinctive aesthetics, and interface design generation. TRIGGER WHEN: working on web styling, design systems, component decisions, responsive strategy, distinctive frontend aesthetics, or exploring multiple interface designs. DO NOT TRIGGER WHEN: the task is purely backend or unrelated to web frontend.
development
Coordinate parallel code reviews across multiple quality dimensions with finding deduplication, severity calibration, and consolidated reporting. Use this skill when organizing multi-reviewer code reviews, calibrating finding severity, or consolidating review results.
tools
Knowledge base for the codebase-mapper plugin. Provides writing guidelines, tone rules, and diagram conventions for generating human-readable project guides. Referenced by all codebase-mapper agents during document generation. TRIGGER WHEN: referenced by codebase-mapper pipeline agents (codebase-explorer, overview-writer, tech-writer, flow-writer, onboarding-writer, ops-writer, config-writer, guide-reviewer) during document generation. DO NOT TRIGGER WHEN: outside the /map-codebase pipeline (general documentation work should use docs:readme-craft or codebase-mapper:docs-create).
tools
Progressive Web App knowledge base for 2025-2026: Web App Manifest, Service Workers (Workbox 7, Serwist), Web Push (VAPID, RFC 8030/8291/8292, Declarative Push for Safari 18.4+), install flows (beforeinstallprompt, Window Controls Overlay), OPFS storage, Project Fugu, Core Web Vitals (INP < 200ms), security (HTTPS, CSP, COOP/COEP), and distribution (Bubblewrap, PWA Builder MSIX, Capacitor). TRIGGER WHEN: building, auditing, or debugging PWAs, including manifest, service worker, Web Push, install flow, OPFS, Background Sync, Wake Lock, vite-plugin-pwa, Next.js Serwist, @angular/pwa, @vite-pwa/nuxt, Bubblewrap, TWA, PWA Builder, or Capacitor wrapping. DO NOT TRIGGER WHEN: the task is generic frontend styling (use frontend), React performance (use react-development:review-react), cross-platform security unrelated to PWA (use platform-engineering), Tauri or Electron wrappers (use tauri-development), or GA4 / analytics (use digital-marketing).