Atlas / Skills / jeremylongshore / Obsidian Rate Limits

Obsidian Rate LimitsSAFE

skills/jeremylongshore/obsidian-rate-limits

Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.

Verdict
SAFE
Grade
B
Trust score
89 /100
Version
1.13.0
Hosts
1 documented
License
MIT
Stars
2,824
01

Overview

Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com.

Read from source at commit 4f83675ca38aOBSERVED · 2026-10-09
02

Host compatibility

What the documentation claims. We have not run a compatibility test.

HostStatusNotes
claude-codementioned
03

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-rate-limits
description: 'Handle Obsidian file system operations and throttling patterns.

  Use when processing many files, handling bulk operations,

  or preventing performance issues from excessive operations.

  Trigger with phrases like "obsidian rate limit", "obsidian bulk operations",

  "obsidian file throttling", "obsidian performance limits".

  '
allowed-tools: Read, Write, Edit
version: 1.13.0
license: MIT
author: Jeremy Longshore <[email protected]>
tags:
- saas
- obsidian
- performance
compatibility: Designed for Claude Code
---
# Obsidian Rate Limits

## Overview

Obsidian has no traditional API rate limits, but it runs on Electron with a single-threaded UI. This skill covers debouncing, batching, throttling, and async queue patterns to keep plugins responsive and prevent UI freezes.

## Prerequisites

- Understanding of JavaScript event loop and `requestAnimationFrame`
- Familiarity with async/await and Promises
- Working Obsidian plugin with file operations

## Instructions

### Step 1: Debounce vault.on('modify') Events

`vault.on('modify')` fires on every keystroke when a user types in a note. Without debouncing, your handler runs hundreds of times per second.

```typescript
import { Plugin, TFile, debounce } from 'obsidian';

export default class ThrottledPlugin extends Plugin {
  async onload() {
    // Obsidian provides a built-in debounce utility
    const debouncedHandler = debounce(
      (file: TFile) => this.handleFileModified(file),
      500,   // wait 500ms after last keystroke
      true   // run on leading edge too (immediate first call)
    );

    this.registerEvent(
      this.app.vault.on('modify', debouncedHandler)
    );
  }

  private async handleFileModified(file: TFile) {
    // This runs at most once per 500ms per burst of edits
    const cache = this.app.metadataCache.getFileCache(file);
    if (cache?.frontmatter?.tracked) {
      await this.updateIndex(file);
    }
  }
}
```

If you need per-file debouncing (common when multiple files change simultaneously):

```typescript
private fileTimers = new Map<string, NodeJS.Timeout>();

private debouncedPerFile(file: TFile, fn: () => void, delay = 500) {
  const existing = this.fileTimers.get(file.path);
  if (existing) clearTimeout(existing);

  const timer = setTimeout(() => {
    this.fileTimers.delete(file.path);
    fn();
  }, delay);

  // Use activeWindow for Obsidian's timeout tracking
  this.fileTimers.set(file.path, timer);
}
```

### Step 2: Batch File Operations with UI Yielding

Processing hundreds of files synchronously locks the UI. Yield back to the main thread between batches.

```typescript
async processAllFiles(): Promise<void> {
  const files = this.app.vault.getMarkdownFiles();
  const BATCH_SIZE = 50;
  const results: ProcessResult[] = [];

  for (let i = 0; i < files.length; i += BATCH_SIZE) {
    const batch = files.slice(i, i + BATCH_SIZE);

    // Process one batch
    for (const file of batch) {
      const content = await this.app.vault.cachedRead(file);
      results.push(this.processContent(file.path, content));
    }

    // Yield to UI thread between batches
    await sleep(0);

    // Update progress if you have a status bar or notice
    const pct = Math.round(((i + batch.length) / files.length) * 100);
    this.statusBar?.setText(`Processing: ${pct}%`);
  }

  this.statusBar?.setText(`Done: ${results.length} files processed`);
}

// Obsidian exports sleep(), or use this:
function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}
```

### Step 3: Throttle UI Updates

Updating DOM elements on every event causes layout thrashing. Throttle to animation frames.

```typescript
class ThrottledStatusView {
  private pendingUpdate = false;
  private el: HTMLElement;
  private data: { count: number; lastFile: string } = { count: 0, lastFile: '' };

  constructor(el: HTMLElement) {
    this.el = el;
  }

  // Call this as often as you want — it coalesces to one paint per frame
  update(count: number, lastFile: string) {
    this.data = { count, lastFile };
    if (!this.pendingUpdate) {
      this.pendingUpdate = true;
      requestAnimationFrame(() => {
        this.render();
        this.pendingUpdate = false;
      });
    }
  }

  private render() {
    this.el.empty();
    this.el.createEl('span', { text: `${this.data.count} files` });
    this.el.createEl('span', { text: this.data.lastFile, cls: 'nav-file-title' });
  }
}
```

### Step 4: Async Queue for Write Operations

Concurrent writes to the same file corrupt data. Queue writes so only one runs at a time.

```typescript
class WriteQueue {
  private queue: Array<() => Promise<void>> = [];
  private running = false;

  async enqueue(fn: () => Promise<void>): Promise<void> {
    return new Promise((resolve, reject) => {
      this.queue.push(async () => {
        try {
          await fn();
          resolve();
        } catch (e) {
          reject(e);
        }
      });
      this.process();
    });
  }

  private async process() {
    if (this.running) return;
    this.running = true;

    while (this.queue.length > 0) {
      const task = this.queue.shift()!;
      await task();
      // Small delay between writes to avoid overwhelming disk I/O
      await sleep(10);
    }

    this.running = false;
  }
}

// Usage in plugin
class MyPlugin extends Plugin {
  private writeQueue = new WriteQueue();

  async safeWrite(file: TFile, content: string) {
    await this.writeQueue.enqueue(async () => {
      await this.app.vault.modify(file, content);
    });
  }
}
```

### Step 5: Progress Notice for Long Operations

Give users feedback during operations that take more than a second.

```typescript
async bulkUpdateFrontmatter(
  files: TFile[],
  updater: (fm: any) => void
): Promise<{ success: number; failed: string[] }> {
  const failed: string[] = [];
  let success = 0;

  // Use Notice with a timeout of 0 to create a persistent notice
  const noti
04

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.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codePASS
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (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.

Audited 2026-10-09 · audit v0.4.1 · source sha 4f83675ca38afull audit observations/trust-audit/skill/jeremylongshore__obsidian-rate-limits.json · Report an issue / request a re-scan
05

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-094f83675ca38aSAFEB89first audit
06

Questions

What does the Obsidian Rate Limits 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 Rate Limits 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 Rate Limits access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

Which assistants does Obsidian Rate Limits work with?

Its documentation mentions claude-code. 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.

Advertisement