Obsidian Core Workflow ASAFE
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Overview
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
4f83675ca38aOBSERVED · 2026-10-09Install
Commands as the repository documents them. They are shown, not run.
npm init -y
npm install --save-dev obsidian@latest typescript@latest esbuild@latest \
Host compatibility
What the documentation claims. We have not run a compatibility test.
| Host | Status | Notes |
|---|---|---|
| claude-code | mentioned | |
| cursor | mentioned |
What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
--- name: obsidian-core-workflow-a description: 'Create an Obsidian plugin from scratch with full project scaffolding. Covers Plugin class, ribbon icons, commands, settings tab, esbuild config, manifest.json, and building/testing. Use when starting a new plugin, scaffolding a project, or learning the plugin lifecycle. Trigger with "create obsidian plugin", "scaffold obsidian plugin", "new obsidian plugin", "obsidian plugin from scratch". ' allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(mkdir:*), Bash(ln:*), Glob version: 1.13.0 license: MIT author: Jeremy Longshore <[email protected]> tags: - obsidian - plugin-development - typescript - scaffolding compatibility: Designed for Claude Code --- # Obsidian Core Workflow A: Create a Plugin from Scratch ## Overview Build a complete Obsidian plugin from an empty directory. By the end you will have a working plugin with a ribbon icon, command palette entries, a settings tab, and a production esbuild build. Every file is shown in full -- no stubs. ## Prerequisites - Node.js 18+ installed - Obsidian desktop app installed - A vault to test in (create a fresh vault at `~/ObsidianDev` if needed) ## Instructions ### Step 1: Scaffold the project ```bash set -euo pipefail PLUGIN_NAME="my-obsidian-plugin" mkdir -p "$PLUGIN_NAME/src" cd "$PLUGIN_NAME" # Initialize Node project npm init -y # Install Obsidian types and build tool npm install --save-dev obsidian@latest typescript@latest esbuild@latest \ @types/node@latest tslib@latest # TypeScript config cat > tsconfig.json << 'TSEOF' { "compilerOptions": { "baseUrl": ".", "inlineSourceMap": true, "inlineSources": true, "module": "ESNext", "target": "ES2018", "allowJs": true, "noImplicitAny": true, "moduleResolution": "node", "importHelpers": true, "isolatedModules": true, "strictNullChecks": true, "lib": ["DOM", "ES2018", "ES2021.String"] }, "include": ["src/**/*.ts"] } TSEOF echo "Scaffolding complete." ``` ### Step 2: Create manifest.json Every Obsidian plugin needs a `manifest.json` at the project root. This is what Obsidian reads to register the plugin. ```json { "id": "my-obsidian-plugin", "name": "My Obsidian Plugin", "version": "1.0.0", "minAppVersion": "1.0.0", "description": "A starter Obsidian plugin.", "author": "Your Name", "isDesktopOnly": false } ``` ### Step 3: Write the esbuild config ```javascript // esbuild.config.mjs import esbuild from "esbuild"; import process from "process"; const prod = process.argv[2] === "production"; const context = await esbuild.context({ 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", ], format: "cjs", target: "es2018", logLevel: "info", sourcemap: prod ? false : "inline", treeShaking: true, outfile: "main.js", }); if (prod) { await context.rebuild(); process.exit(0); } else { await context.watch(); } ``` ### Step 4: Write main.ts -- the full plugin This single file contains the Plugin subclass, a settings interface with defaults, a settings tab, and three commands. ```typescript // src/main.ts import { App, Editor, MarkdownView, Notice, Plugin, PluginSettingTab, Setting, } from "obsidian"; // ── Settings ──────────────────────────────────────────────────────── interface MyPluginSettings { greeting: string; showRibbon: boolean; } const DEFAULT_SETTINGS: MyPluginSettings = { greeting: "Hello from My Plugin!", showRibbon: true, }; // ── Plugin ────────────────────────────────────────────────────────── export default class MyPlugin extends Plugin { settings: MyPluginSettings; async onload() { await this.loadSettings(); // Ribbon icon -- shows a Notice when clicked if (this.settings.showRibbon) { this.addRibbonIcon("sparkles", "My Plugin: Greet", () => { new Notice(this.settings.greeting); }); } // Command: show greeting as Notice this.addCommand({ id: "show-greeting", name: "Show greeting", callback: () => { new Notice(this.settings.greeting); }, }); // Command: insert greeting at cursor (only available in editor) this.addCommand({ id: "insert-greeting", name: "Insert greeting at cursor", editorCallback: (editor: Editor, view: MarkdownView) => { editor.replaceSelection(this.settings.greeting); }, }); // Command: count words in current note this.addCommand({ id: "count-words", name: "Count words in current note", editorCallback: (editor: Editor) => { const text = editor.getValue(); const count = text.split(/\s+/).filter(Boolean).length; new Notice(`Word count: ${count}`); }, }); // Status bar item const statusEl = this.addStatusBarItem(); statusEl.setText("Plugin loaded"); // Settings tab this.addSettingTab(new MyPluginSettingTab(this.app, this)); console.log("MyPlugin loaded"); } onunload() { console.log("MyPlugin unloaded"); } async loadSettings() { this.settings = Object.assign( {}, DEFAULT_SETTINGS, await this.loadData() ); } async saveSettings() { await this.saveData(this.settings); } } // ── Settings Tab ──────────────────────────────────────────────────── class MyPluginSettingTab extends PluginSettingTab { plugin: MyPlugin; constructor(app: App, plugin: MyPlugin) { super(app, plugin); this.plugin = plugin; } display(): void { const { containerEl } = this; containerEl.empty(); new Setting(containerEl) .setName("Greeting message") .setDesc("Text shown by the greet command
Trust audit
SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- none-observed
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (1)
The candidate output is a review queue for a human license owner, not an instruction to remove a user.
Gates applied: no_behavioural_pass.
4f83675ca38afull audit observations/trust-audit/skill/jeremylongshore__obsidian-core-workflow-a.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-09 | 4f83675ca38a | SAFE | B | 89 | first audit |
Questions
What does the Obsidian Core Workflow A skill do?
Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.
Is Obsidian Core Workflow A safe to install?
The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.
What can Obsidian Core Workflow A access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
Which assistants does Obsidian Core Workflow A work with?
Its documentation mentions claude-code and cursor. That is what the text claims, not a compatibility test we ran.
How current is this page?
The grade is for one exact copy of the source (4f83675ca38a), read on 2026-10-09. The repository is watched, and a new audit runs when it changes — this is the first audit.