plugins/obsidian-development/skills/obsidian-scaffold/SKILL.md
Scaffolds project structure, manifest, tsconfig, esbuild config, and a minimal plugin class that passes Obsidian's automated plugin review. 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/alfio-claude-plugins 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 review-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 (review-compliant)
package.json # Dependencies: obsidian, typescript, esbuild, @types/node
tsconfig.json # strict: true, target ES2018, moduleResolution node
esbuild.config.mjs # CJS bundle, externalizes obsidian + electron
eslint.config.mjs # eslint-plugin-obsidianmd + eslint-comments flat 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 Obsidian automated review 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/ package.json"
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "^4.0.0",
"@eslint/js": "^9.0.0",
"@types/node": "^22.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 { builtinModules as builtins } from "node:module";
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
The eslint-comments block mirrors checks that Obsidian's review platform adds on top of the obsidianmd recommended config.
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import obsidianmd from 'eslint-plugin-obsidianmd';
import comments from '@eslint-community/eslint-plugin-eslint-comments/configs';
export default [
js.configs.recommended,
...tseslint.configs.recommended,
...obsidianmd.configs.recommended,
comments.recommended,
{
rules: {
'@eslint-community/eslint-comments/require-description': 'error',
'@eslint-community/eslint-comments/no-restricted-disable': [
'error',
'obsidianmd/no-static-styles-assignment',
'obsidianmd/ui/sentence-case',
],
},
},
{
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 the automated review rules locallymain.js, manifest.json, and styles.css as individual assetsv prefix)obsidianmd/obsidian-releases was retired in May 2026development
Quality gates for multi-reviewer code review pipelines: adversarial verification panel, completeness critic, reviewer pipeline conventions, and the context sharing pattern for parallel reviewers. TRIGGER WHEN: running /senior-review:team-review quality gates; running /senior-review:code-review Steps 4b/4c (adversarial verification and completeness check); consolidating or deduplicating findings from multiple parallel reviewers. DO NOT TRIGGER WHEN: single-reviewer style review without a consolidation phase, or generic team coordination (the upstream agent-teams skills cover that).
development
Knowledge base for pure-architecture decisions on when to unify duplicated logic into a shared abstraction versus leave it duplicated. Covers the canonical theory (Rule of Three, DRY/WET/AHA, Wrong Abstraction, Locality of Behaviour, Bounded Contexts, Tidy First options framing, CUPID vs SOLID), 12 essential-duplication patterns that justify unification, 12 wrong-abstraction patterns that justify inlining or decomposition, an operational decision frame, and a verified reading list. TRIGGER WHEN: the user is making an architectural decision about whether to centralize, extract, or remove a layer; reviewing an abstraction for premature generality; auditing scattered cross-cutting concerns; spawned by the abstraction-architect agent during /abstraction-architect:audit or as the Abstraction dimension of /senior-review:team-review or /senior-review:code-review; the user asks "should I extract this into a service" / "is this DRY enough" / "is this wrong abstraction". DO NOT TRIGGER WHEN: the task is code formatting and readability cleanup (use clean-code:clean-code), Python-specific refactoring with metrics (use python-development:python-refactor), generic dead-code removal (use senior-review:cleanup-dead-code), security review (use senior-review:security-auditor), or pure pattern-consistency review without an architecture lens (use senior-review:code-auditor).
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
Stripe payments knowledge base - API patterns, checkout optimization, subscription lifecycle, pricing strategies, webhook reliability, Firebase integration, cost analysis, and revenue modeling. Loaded by stripe-integrator and revenue-optimizer agents; also consumable directly when the user asks for Stripe-specific patterns without needing an agent. TRIGGER WHEN: working with Stripe API (Payment Intents, Customers, Subscriptions, Checkout Sessions, Connect, webhooks, tax, usage-based billing), pricing strategy, or revenue modeling. DO NOT TRIGGER WHEN: payment work is non-Stripe (PayPal, Square, crypto) or the task is generic e-commerce unrelated to payments.