Create a minimal working Obsidian plugin with commands and settings. Use when building your first plugin feature, testing your setup, or learning basic Obsidian plugin patterns. Trigger with phrases like "obsidian hello world", "first obsidian plugin", "obsidian quick start", "simple obsidian plugin".
From obsidian-packnpx claudepluginhub nickloveinvesting/nick-love-plugins --plugin obsidian-packThis skill is limited to using the following tools:
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides agent creation for Claude Code plugins with file templates, frontmatter specs (name, description, model), triggering examples, system prompts, and best practices.
Build a minimal working Obsidian plugin demonstrating core features: commands, settings, and ribbon icons.
obsidian-install-auth setup// src/main.ts
import { App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
interface MyPluginSettings {
greeting: string;
}
const DEFAULT_SETTINGS: MyPluginSettings = {
greeting: 'Hello, Obsidian!'
}
export default class MyPlugin extends Plugin {
settings: MyPluginSettings;
async onload() {
await this.loadSettings();
// Add ribbon icon
this.addRibbonIcon('dice', 'Greet Me', (evt: MouseEvent) => {
new Notice(this.settings.greeting);
});
// Add command to command palette
this.addCommand({
id: 'show-greeting',
name: 'Show Greeting',
callback: () => {
new Notice(this.settings.greeting);
}
});
// Add command with editor context
this.addCommand({
id: 'insert-greeting',
name: 'Insert Greeting at Cursor',
editorCallback: (editor: Editor, view: MarkdownView) => {
editor.replaceSelection(this.settings.greeting);
}
});
// Add settings tab
this.addSettingTab(new MySettingTab(this.app, this));
}
onunload() {
console.log('Goodbye from My Plugin!');
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
// Add to src/main.ts
class MySettingTab extends PluginSettingTab {
plugin: MyPlugin;
constructor(app: App, plugin: MyPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl('h2', { text: 'My Plugin Settings' });
new Setting(containerEl)
.setName('Greeting')
.setDesc('The message to display when greeting')
.addText(text => text
.setPlaceholder('Enter your greeting')
.setValue(this.plugin.settings.greeting)
.onChange(async (value) => {
this.plugin.settings.greeting = value;
await this.plugin.saveSettings();
}));
}
}
// Add to src/main.ts
class GreetingModal extends Modal {
greeting: string;
constructor(app: App, greeting: string) {
super(app);
this.greeting = greeting;
}
onOpen() {
const { contentEl } = this;
contentEl.createEl('h1', { text: this.greeting });
contentEl.createEl('p', { text: 'Click outside or press Escape to close.' });
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}
// Add to onload():
this.addCommand({
id: 'show-greeting-modal',
name: 'Show Greeting Modal',
callback: () => {
new GreetingModal(this.app, this.settings.greeting).open();
}
});
set -euo pipefail
# Build the plugin
npm run build
# In Obsidian:
# 1. Open Settings > Community plugins
# 2. Enable "My Plugin"
# 3. Click the dice icon in ribbon
# 4. Open command palette (Ctrl/Cmd+P) and search "Show Greeting"
| Error | Cause | Solution |
|---|---|---|
| Plugin not loading | Build errors | Check console for TypeScript errors |
| Settings not saving | Missing loadData/saveData | Verify async/await usage |
| Command not showing | Plugin not enabled | Enable in Community Plugins |
| Ribbon icon missing | Wrong icon name | Use valid Lucide icon name |
Obsidian uses Lucide icons. Common examples:
file-text, folder, search, settingsstar, heart, bookmark, tagedit, trash, copy, clipboardlink, external-link, globedice, bot, sparkles, wand// Add to onload():
const statusBarItem = this.addStatusBarItem();
statusBarItem.setText('Plugin Active');
// Listen to file open
this.registerEvent(
this.app.workspace.on('file-open', (file) => {
if (file) {
console.log('Opened:', file.path);
}
})
);
Proceed to obsidian-local-dev-loop for hot-reload development workflow.