Obsidian Webhooks EventsSAFE
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-webhooks-events description: 'Handle Obsidian events and workspace callbacks for plugin development. Use when implementing reactive features, handling file changes, or responding to user interactions in your plugin. Trigger with phrases like "obsidian events", "obsidian callbacks", "obsidian file change", "obsidian workspace events". ' allowed-tools: Read, Write, Edit version: 1.13.0 license: MIT author: Jeremy Longshore <[email protected]> tags: - saas - obsidian - react compatibility: Designed for Claude Code --- # Obsidian Webhooks & Events ## Overview Complete guide to Obsidian's event system: vault events (create, modify, delete, rename), workspace events (layout, leaf changes, editor state), metadataCache events, DOM events, custom EventRef patterns, and periodic tasks. Every event registration uses `this.registerEvent()` for automatic cleanup on plugin unload. ## Prerequisites - Working Obsidian plugin with `onload()` / `onunload()` lifecycle - Understanding of TypeScript event handler signatures - Familiarity with Obsidian's TFile, TFolder, and WorkspaceLeaf types ## Instructions ### Step 1: Vault Events — File Lifecycle Vault events fire when files and folders are created, modified, deleted, or renamed. ```typescript import { Plugin, TFile, TFolder, TAbstractFile } from 'obsidian'; export default class EventPlugin extends Plugin { async onload() { // File created this.registerEvent( this.app.vault.on('create', (file: TAbstractFile) => { if (file instanceof TFile) { console.log('New file:', file.path); this.onFileCreated(file); } if (file instanceof TFolder) { console.log('New folder:', file.path); } }) ); // File content modified (fires on save and on every sync update) this.registerEvent( this.app.vault.on('modify', (file: TAbstractFile) => { if (file instanceof TFile) { this.onFileModified(file); } }) ); // File deleted this.registerEvent( this.app.vault.on('delete', (file: TAbstractFile) => { if (file instanceof TFile) { this.removeFromIndex(file.path); } }) ); // File renamed or moved (includes folder moves) this.registerEvent( this.app.vault.on('rename', (file: TAbstractFile, oldPath: string) => { if (file instanceof TFile) { this.updatePathReferences(oldPath, file.path); } }) ); } } ``` Note: `modify` fires on every keystroke during live editing in some configurations. Always debounce if your handler does non-trivial work (see `obsidian-rate-limits`). ### Step 2: Workspace Events — UI State Changes Workspace events track what the user is looking at and how the UI layout changes. ```typescript async onload() { // Active file changed (user clicked a different tab/pane) this.registerEvent( this.app.workspace.on('active-leaf-change', (leaf) => { if (leaf) { const view = leaf.view; if (view.getViewType() === 'markdown') { const file = (view as any).file as TFile; if (file) { this.onActiveFileChanged(file); } } } }) ); // File opened in any pane (fires even if already active) this.registerEvent( this.app.workspace.on('file-open', (file: TFile | null) => { if (file) { this.trackRecentFile(file); } }) ); // Layout changed (panes split, closed, rearranged) this.registerEvent( this.app.workspace.on('layout-change', () => { this.updateSidebarState(); }) ); // Editor changed (cursor moved, selection changed, content edited) this.registerEvent( this.app.workspace.on('editor-change', (editor, info) => { // info is MarkdownView — gives you the file context const cursor = editor.getCursor(); this.onCursorMoved(cursor.line, cursor.ch); }) ); // Window/pane resized this.registerEvent( this.app.workspace.on('resize', () => { this.adjustCustomViews(); }) ); // Wait for layout to be fully initialized before accessing panes this.app.workspace.onLayoutReady(() => { this.initializeWithCurrentState(); }); } ``` ### Step 3: MetadataCache Events — Content Indexing The metadataCache parses frontmatter, links, tags, and headings in the background. These events fire when parsing completes. ```typescript async onload() { // Single file's metadata changed (fires after modify, once parsing is done) this.registerEvent( this.app.metadataCache.on('changed', (file: TFile, data: string, cache: CachedMetadata) => { // cache contains parsed frontmatter, links, tags, headings const tags = cache.tags?.map(t => t.tag) ?? []; const links = cache.links?.map(l => l.link) ?? []; this.updateFileIndex(file.path, { tags, links }); }) ); // All files in vault have been indexed (fires once after startup) this.registerEvent( this.app.metadataCache.on('resolved', () => { console.log('Metadata cache fully resolved — safe to query all files'); this.buildFullIndex(); }) ); } private buildFullIndex() { const files = this.app.vault.getMarkdownFiles(); for (const file of files) { const cache = this.app.metadataCache.getFileCache(file); if (cache) { this.updateFileIndex(file.path, { tags: cache.tags?.map(t => t.tag) ?? [], links: cache.links?.map(l => l.link) ?? [], headings: cache.headings?.map(h => h.heading) ?? [], frontmatter: cache.frontmatter, }); } } } ``` The `resolved` event is critical for plugins that build indexes — querying metadataCache before it fires returns incomplete data. ### Step 4: DOM Events with registerDomEvent For custom UI elements, use `registerDomEvent` instead of raw `addEventListener`. Obsidian auto-removes these on plugin unload. ```typescript async onload() { // Reg
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-webhooks-events.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 Webhooks Events 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 Webhooks Events 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 Webhooks Events access on my machine?
The audit observed no filesystem, network or shell use at all in its source.
Which assistants does Obsidian Webhooks Events 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.