Obsidian Core Workflow BSAFE
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-09Host 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-b description: 'Build advanced Obsidian plugin features: custom views (ItemView), modals, editor commands with selection manipulation, status bar, context menus, and Vault API file creation/modification. Use when adding UI components to a plugin, building sidebar views, or creating modal dialogs. Trigger with "obsidian modal", "obsidian custom view", "obsidian sidebar", "obsidian context menu", "obsidian editor command", "obsidian UI". ' allowed-tools: Read, Write, Edit, Bash(npm:*), Grep version: 1.13.0 license: MIT author: Jeremy Longshore <[email protected]> tags: - obsidian - ui-components - views - modals - editor compatibility: Designed for Claude Code --- # Obsidian Core Workflow B: Advanced Plugin Features ## Overview Add production UI to an existing Obsidian plugin: custom sidebar views, modal dialogs with forms, fuzzy-search suggestion popups, editor commands that manipulate selections, status bar widgets, context menus, and programmatic file creation via the Vault API. Every snippet is a complete, copy-pasteable class. ## Prerequisites - A working plugin built with `obsidian-core-workflow-a` (or equivalent) - `npm install --save-dev obsidian` already done - Familiarity with the Plugin lifecycle (`onload` / `onunload`) ## Instructions ### Step 1: Custom sidebar view (ItemView) A custom view registers a new panel type that can live in the left or right sidebar. ```typescript // src/views/StatsView.ts import { ItemView, WorkspaceLeaf, TFile } from "obsidian"; export const STATS_VIEW_TYPE = "vault-stats-view"; export class StatsView extends ItemView { constructor(leaf: WorkspaceLeaf) { super(leaf); } getViewType(): string { return STATS_VIEW_TYPE; } getDisplayText(): string { return "Vault Stats"; } getIcon(): string { return "bar-chart-2"; } async onOpen() { const container = this.containerEl.children[1]; container.empty(); container.addClass("stats-view"); container.createEl("h4", { text: "Vault Statistics" }); const listEl = container.createEl("ul"); const files = this.app.vault.getMarkdownFiles(); let totalWords = 0; for (const file of files) { const content = await this.app.vault.cachedRead(file); totalWords += content.split(/\s+/).filter(Boolean).length; } listEl.createEl("li", { text: `Notes: ${files.length}` }); listEl.createEl("li", { text: `Total words: ${totalWords.toLocaleString()}` }); listEl.createEl("li", { text: `Avg words/note: ${files.length ? Math.round(totalWords / files.length) : 0}`, }); // Refresh button const btn = container.createEl("button", { text: "Refresh" }); btn.addEventListener("click", () => this.onOpen()); } async onClose() { // cleanup if needed } } ``` Register and open it from your main plugin: ```typescript // In your Plugin's onload(): import { StatsView, STATS_VIEW_TYPE } from "./views/StatsView"; this.registerView(STATS_VIEW_TYPE, (leaf) => new StatsView(leaf)); this.addCommand({ id: "open-stats-view", name: "Open vault stats", callback: () => this.activateStatsView(), }); this.addRibbonIcon("bar-chart-2", "Vault Stats", () => this.activateStatsView()); // Helper to open or reveal the view async activateStatsView() { const { workspace } = this.app; let leaf = workspace.getLeavesOfType(STATS_VIEW_TYPE)[0]; if (!leaf) { const rightLeaf = workspace.getRightLeaf(false); if (rightLeaf) { await rightLeaf.setViewState({ type: STATS_VIEW_TYPE, active: true }); leaf = rightLeaf; } } if (leaf) workspace.revealLeaf(leaf); } // In onunload(): this.app.workspace.detachLeavesOfType(STATS_VIEW_TYPE); ``` ### Step 2: Modal dialogs **Confirmation modal** -- returns a boolean via callback: ```typescript // src/modals/ConfirmModal.ts import { App, Modal, Setting } from "obsidian"; export class ConfirmModal extends Modal { private resolved = false; constructor( app: App, private message: string, private onResult: (confirmed: boolean) => void ) { super(app); } onOpen() { const { contentEl } = this; contentEl.createEl("h3", { text: "Confirm" }); contentEl.createEl("p", { text: this.message }); new Setting(contentEl) .addButton((btn) => btn.setButtonText("Cancel").onClick(() => this.close()) ) .addButton((btn) => btn .setButtonText("Confirm") .setCta() .onClick(() => { this.resolved = true; this.close(); }) ); } onClose() { this.onResult(this.resolved); this.contentEl.empty(); } } ``` **Text input modal** -- collects a single string: ```typescript // src/modals/InputModal.ts import { App, Modal, Setting } from "obsidian"; export class InputModal extends Modal { private value = ""; constructor( app: App, private title: string, private placeholder: string, private onSubmit: (value: string | null) => void ) { super(app); } onOpen() { const { contentEl } = this; contentEl.createEl("h3", { text: this.title }); new Setting(contentEl).addText((text) => text .setPlaceholder(this.placeholder) .onChange((v) => (this.value = v)) ); new Setting(contentEl) .addButton((btn) => btn.setButtonText("Cancel").onClick(() => { this.onSubmit(null); this.close(); }) ) .addButton((btn) => btn .setButtonText("OK") .setCta() .onClick(() => { this.onSubmit(this.value); this.close(); }) ); } onClose() { this.contentEl.empty(); } } ``` ### Step 3: Fuzzy suggestion modal (SuggestModal) Opens a searchable list. Users type to filter, then pick an item. ```typescript // src/modals/NotePicker.ts import { App, FuzzySuggestModal, TFile } from "obsidian"; export clas
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 (0)
No findings outside the package's declared scope.
Gates applied: no_behavioural_pass.
4f83675ca38afull audit observations/trust-audit/skill/jeremylongshore__obsidian-core-workflow-b.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 B 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 B 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 B access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
Which assistants does Obsidian Core Workflow B 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.