Skip to content

feat(obsidian): add Obsidian integration with 15 tools#3455

Merged
waleedlatif1 merged 4 commits intostagingfrom
waleedlatif1/add-obsidian-integration
Mar 7, 2026
Merged

feat(obsidian): add Obsidian integration with 15 tools#3455
waleedlatif1 merged 4 commits intostagingfrom
waleedlatif1/add-obsidian-integration

Conversation

@waleedlatif1
Copy link
Collaborator

Summary

  • Add Obsidian integration with 15 tools covering the full Local REST API
  • Tools: list files, get/create/append/patch/delete notes, search, get/append/patch active file, open file, list/execute commands, get/append periodic notes
  • API key auth with configurable base URL for tunnel support

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link

vercel bot commented Mar 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Mar 7, 2026 7:06am

Request Review

@cursor
Copy link

cursor bot commented Mar 7, 2026

PR Summary

Medium Risk
Adds a new third-party integration with 15 new HTTP tool implementations and a new block wired into the global registries; issues in request/response handling or parameter mapping could cause runtime failures but changes are largely additive and isolated.

Overview
Adds a new Obsidian tool/block integration, including a configurable block UI (operation, baseUrl, API key, note/patch/search parameters) that routes to obsidian_* tools and is registered in the app block registry.

Implements 15 new Obsidian tools under apps/sim/tools/obsidian (notes CRUD, append/patch, active file operations, search, file listing, periodic notes, and command list/execute) and wires them into apps/sim/tools/registry.ts.

Updates docs to include the new obsidian tool page and navigation entry, plus adds ObsidianIcon and maps obsidian to it in the docs icon mapping.

Written by Cursor Bugbot for commit d78eb62. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: encodeURIComponent encodes slashes in vault file paths
    • Fixed by splitting filenames on '/' and encoding each segment individually in all affected tools (get_note, create_note, append_note, patch_note, delete_note, open_file).
  • ✅ Fixed: Params config drops most tool parameters
    • Fixed by spreading all remaining parameters (...rest) in tools.config.params function, ensuring all input parameters are passed through to the tools.

Create PR

Or push these changes by commenting:

@cursor push 2ee16c4ed1
Preview (2ee16c4ed1)
diff --git a/apps/sim/blocks/blocks/obsidian.ts b/apps/sim/blocks/blocks/obsidian.ts
--- a/apps/sim/blocks/blocks/obsidian.ts
+++ b/apps/sim/blocks/blocks/obsidian.ts
@@ -221,12 +221,13 @@
     config: {
       tool: (params) => `obsidian_${params.operation}`,
       params: (params) => {
-        const result: Record<string, unknown> = {}
+        const { patchOperation, ...rest } = params
+        const result: Record<string, unknown> = { ...rest }
         if (params.contextLength) {
           result.contextLength = Number(params.contextLength)
         }
-        if (params.patchOperation) {
-          result.operation = params.patchOperation
+        if (patchOperation) {
+          result.operation = patchOperation
         }
         return result
       },

diff --git a/apps/sim/tools/obsidian/append_note.ts b/apps/sim/tools/obsidian/append_note.ts
--- a/apps/sim/tools/obsidian/append_note.ts
+++ b/apps/sim/tools/obsidian/append_note.ts
@@ -37,7 +37,8 @@
   request: {
     url: (params) => {
       const base = params.baseUrl.replace(/\/$/, '')
-      return `${base}/vault/${encodeURIComponent(params.filename.trim())}`
+      const encodedPath = params.filename.trim().split('/').map(encodeURIComponent).join('/')
+      return `${base}/vault/${encodedPath}`
     },
     method: 'POST',
     headers: (params) => ({

diff --git a/apps/sim/tools/obsidian/create_note.ts b/apps/sim/tools/obsidian/create_note.ts
--- a/apps/sim/tools/obsidian/create_note.ts
+++ b/apps/sim/tools/obsidian/create_note.ts
@@ -37,7 +37,8 @@
   request: {
     url: (params) => {
       const base = params.baseUrl.replace(/\/$/, '')
-      return `${base}/vault/${encodeURIComponent(params.filename.trim())}`
+      const encodedPath = params.filename.trim().split('/').map(encodeURIComponent).join('/')
+      return `${base}/vault/${encodedPath}`
     },
     method: 'PUT',
     headers: (params) => ({

diff --git a/apps/sim/tools/obsidian/delete_note.ts b/apps/sim/tools/obsidian/delete_note.ts
--- a/apps/sim/tools/obsidian/delete_note.ts
+++ b/apps/sim/tools/obsidian/delete_note.ts
@@ -31,7 +31,8 @@
   request: {
     url: (params) => {
       const base = params.baseUrl.replace(/\/$/, '')
-      return `${base}/vault/${encodeURIComponent(params.filename.trim())}`
+      const encodedPath = params.filename.trim().split('/').map(encodeURIComponent).join('/')
+      return `${base}/vault/${encodedPath}`
     },
     method: 'DELETE',
     headers: (params) => ({

diff --git a/apps/sim/tools/obsidian/get_note.ts b/apps/sim/tools/obsidian/get_note.ts
--- a/apps/sim/tools/obsidian/get_note.ts
+++ b/apps/sim/tools/obsidian/get_note.ts
@@ -31,7 +31,8 @@
   request: {
     url: (params) => {
       const base = params.baseUrl.replace(/\/$/, '')
-      return `${base}/vault/${encodeURIComponent(params.filename.trim())}`
+      const encodedPath = params.filename.trim().split('/').map(encodeURIComponent).join('/')
+      return `${base}/vault/${encodedPath}`
     },
     method: 'GET',
     headers: (params) => ({

diff --git a/apps/sim/tools/obsidian/open_file.ts b/apps/sim/tools/obsidian/open_file.ts
--- a/apps/sim/tools/obsidian/open_file.ts
+++ b/apps/sim/tools/obsidian/open_file.ts
@@ -37,8 +37,9 @@
   request: {
     url: (params) => {
       const base = params.baseUrl.replace(/\/$/, '')
+      const encodedPath = params.filename.trim().split('/').map(encodeURIComponent).join('/')
       const leafParam = params.newLeaf ? '?newLeaf=true' : ''
-      return `${base}/open/${encodeURIComponent(params.filename.trim())}${leafParam}`
+      return `${base}/open/${encodedPath}${leafParam}`
     },
     method: 'POST',
     headers: (params) => ({

diff --git a/apps/sim/tools/obsidian/patch_note.ts b/apps/sim/tools/obsidian/patch_note.ts
--- a/apps/sim/tools/obsidian/patch_note.ts
+++ b/apps/sim/tools/obsidian/patch_note.ts
@@ -69,7 +69,8 @@
   request: {
     url: (params) => {
       const base = params.baseUrl.replace(/\/$/, '')
-      return `${base}/vault/${encodeURIComponent(params.filename.trim())}`
+      const encodedPath = params.filename.trim().split('/').map(encodeURIComponent).join('/')
+      return `${base}/vault/${encodedPath}`
     },
     method: 'PATCH',
     headers: (params) => {
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 7, 2026

Greptile Summary

This PR adds a full Obsidian integration (15 tools) covering the Obsidian Local REST API, including vault CRUD, search, periodic notes, commands, and active-file operations. The implementation follows the established pattern for other tool integrations in this codebase — per-segment URL encoding, user-only visibility for credentials, and a single block config with operation-conditional sub-fields.

Two tools are missing the standard response.ok guard that every other tool in the PR includes, causing silent failures:

  • apps/sim/tools/obsidian/get_active.ts — calls response.json() directly without checking response.ok. A 404 (no active file) silently returns success: true with empty content instead of throwing.
  • apps/sim/tools/obsidian/get_periodic_note.ts — calls response.text() directly without checking response.ok. An error response (e.g. Periodic Notes plugin not installed) is returned verbatim as the note's content with success: true.

Both are straightforward one-line fixes but do affect correctness.

Confidence Score: 3/5

  • Two tools have logic bugs causing silent failures on error responses instead of surfacing errors. Straightforward one-line fixes required.
  • The Obsidian integration is well-structured and follows established patterns for tool integrations. However, get_active.ts and get_periodic_note.ts both skip the response.ok guard that all other tools correctly include. This means API errors (no active file, plugin not installed) will silently appear as successful empty responses. These are concrete bugs affecting correctness, but they're straightforward one-line fixes—adding the guard pattern already present in other tools in the same PR.
  • apps/sim/tools/obsidian/get_active.ts and apps/sim/tools/obsidian/get_periodic_note.ts need the response.ok guard added before parsing the response body.

Sequence Diagram

sequenceDiagram
    participant UI as Sim UI (Block)
    participant Engine as Tool Engine
    participant OT as Obsidian Tool
    participant API as Obsidian Local REST API

    UI->>Engine: Run block (operation, apiKey, baseUrl, …)
    Engine->>Engine: Resolve tool via obsidian_${operation}
    Engine->>OT: Call tool with params

    alt Vault file operations (get/create/append/patch/delete)
        OT->>API: GET/PUT/POST/PATCH/DELETE /vault/{encoded-path}
    else Active file operations
        OT->>API: GET/POST/PATCH /active/
    else Search
        OT->>API: POST /search/simple/?query={query}
    else Periodic notes
        OT->>API: GET/POST /periodic/{period}/
    else Commands
        OT->>API: GET /commands/
        OT->>API: POST /commands/{commandId}/
    else Open file
        OT->>API: POST /open/{encoded-path}
    end

    API-->>OT: Response (JSON or text/markdown)
    OT->>OT: transformResponse (check ok, parse body)
    OT-->>Engine: { success, output }
    Engine-->>UI: Block output
Loading

Comments Outside Diff (2)

  1. apps/sim/tools/obsidian/get_active.ts, line 37-46 (link)

    Missing response.ok guard causes silent failure

    Unlike every other tool in this PR, get_active.ts skips the response.ok check before parsing the response. When there is no active file, Obsidian's REST API returns a 404 with a JSON error body. The current code calls response.json() on that error response, then returns success: true with content: '' and filename: null — silently swallowing the error instead of surfacing it to the caller.

  2. apps/sim/tools/obsidian/get_periodic_note.ts, line 46-55 (link)

    Missing response.ok guard returns error body as note content

    Like get_active.ts, this transformResponse calls response.text() without first checking response.ok. If the Periodic Notes plugin isn't enabled, or the requested period doesn't exist yet, the API returns a non-2xx response (e.g. a 404 with an HTML/text error body). That error string will be placed in the content field and returned as success: true, silently treating failure as a successful note read.

    Every other tool in this PR guards with if (!response.ok) { … throw … } first — this one should too.

Last reviewed commit: d78eb62

@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Collaborator Author

@greptile

@waleedlatif1
Copy link
Collaborator Author

@cursor review

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@waleedlatif1 waleedlatif1 merged commit 53fd92a into staging Mar 7, 2026
12 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/add-obsidian-integration branch March 7, 2026 07:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant