Back to home@Daseanle

dsh-obsidian-bridge

Bidirectional knowledge bridge between DeepSeek Harness and Obsidian Vault — FTS5 search, draft writing, session linking

Stars
0
Language
JavaScript
Created
Aug 18, 2026
Updated
Aug 18, 2026

Introduction

dsh-obsidian-bridge

Bidirectional knowledge bridge between DeepSeek Harness (DSH) and Obsidian Vault.

What It Does

Gives DSH agents direct read/write access to your Obsidian Vault. The agent can search notes via SQLite FTS5 full-text search, read full content by path or wiki-link, write draft notes back to the vault, and create bidirectional links between DSH sessions and notes.

Unlike existing one-way export tools or MCP-based bridges, this plugin runs natively inside the DSH Cordis framework — no external server, no need for Obsidian to be running.

Status: v0.2.0 — Open Source Alpha

Verified Capabilities

CapabilityStatusTest
Read note by file pathPasstest/spike.mjs
Read note by wiki-link namePasstest/spike.mjs
Read note with spaces in namePasstest/spike.mjs
SQLite FTS5 full-text searchPasstest/phase2-spike.mjs
BM25 relevance rankingPasstest/phase2-spike.mjs
Chinese text search (CJK tokenization)Passtest/phase2-spike.mjs
Incremental sync (mtime-based)Passtest/phase2-spike.mjs
500-note search performancePass (34ms)test/spike.mjs
Path traversal protectionPasstest/spike.mjs
Plugin loads in Cordis contextPasstest/integration.mjs
Tool registration via defineToolPasstest/integration.mjs
Tool execute + render pipelinePasstest/integration.mjs
System prompt section injectionPasstest/integration.mjs
Write draft note to vaultPasstest/phase1-spike.mjs
Write draft with Unicode titlePasstest/phase1-spike.mjs
Link session to vault notePasstest/phase1-spike.mjs
Link multiple notes to same sessionPasstest/phase1-spike.mjs
Keyword extraction (EN + CN)Passtest/phase1-spike.mjs
Auto-context hook (agent/pre-step)Passtest/phase1-integration.mjs
Auto-capture hook (tools/result)Passtest/phase1-integration.mjs
Auto-capture skips obsidian_* toolsPasstest/phase1-integration.mjs
Zod config schema validationPasstest/phase2-spike.mjs
Plugin config via cordis.patch.ymlPasstest/phase2-integration.mjs
Env var fallback compatibilityPasstest/phase2-integration.mjs
Plugin disabled without vault pathPasstest/phase2-integration.mjs
Hook disposer cleanupPasstest/phase2-integration.mjs
Plugin lifecycle cleanup (ctx.effect)Passtest/phase2-integration.mjs

Test Results

Phase 0 Spike:        25 passed, 0 failed
Phase 0 Integration:  49 passed, 0 failed
Phase 1 Spike:        35 passed, 0 failed
Phase 1 Integration:  45 passed, 0 failed
Phase 2 Spike:        35 passed, 0 failed
Phase 2 Integration:  23 passed, 0 failed
Total:               212 passed, 0 failed

Architecture

DSH Agent (Node.js process)
  └─ Cordis Framework
       └─ dsh-obsidian-bridge plugin (apply(ctx, config))
            ├─ Config Schema (zod: vaultPath, autoContext, autoCapture, draftFolder, sessionId)
            ├─ System Prompt: "obsidian-vault-aware" (tools + workflow guide)
            ├─ Tool: obsidian_search (FTS5 BM25 search across vault notes)
            ├─ Tool: obsidian_read_note (read full note by path or wiki-link)
            ├─ Tool: obsidian_write_draft (write draft to dsh-drafts/ folder)
            ├─ Tool: obsidian_link_session (bidirectional session-note linking)
            ├─ Hook: agent/pre-step (auto-inject vault context, opt-in)
            ├─ Hook: tools/result (auto-capture tool results, opt-in)
            ├─ ctx.effect() cleanup (closes SQLite, disposes tools/hooks)
            └─ VaultManager (file system access, caching, wiki-link resolution)
                 ├─ NoteIndex (SQLite FTS5 full-text index)
                 │    ├─ Incremental sync (mtime-based, throttled)
                 │    ├─ BM25 relevance ranking
                 │    ├─ Chinese CJK tokenization
                 │    └─ .dsh/index.db (WAL mode, 16MB cache)
                 └─ Obsidian Vault (plain Markdown files on disk)

Single process. No external server. Direct file system access.

Installation

Prerequisites

  • Node.js >= 22.19 (or >= 24)
  • DSH installed: npm install -g @deepseek-ai/dsh
  • An Obsidian Vault directory

Build

cd dsh-obsidian-bridge
npm install
npm run build

Install into DSH

Option A: From GitHub (recommended — no npm account needed)

# Install directly from GitHub
dsh plugin --profile web add github:Daseanle/dsh-obsidian-bridge

# Configure via cordis.patch.yml
dsh web

Option B: From npm (when published)

dsh plugin --profile web add dsh-obsidian-bridge
dsh web

Option C: From local clone

git clone https://github.com/Daseanle/dsh-obsidian-bridge.git
cd dsh-obsidian-bridge && npm install && npm run build
dsh plugin --profile web add file:./dsh-obsidian-bridge
dsh web

Configuration

Create or edit cordis.patch.yml in your DSH config directory:

- id: dsh-obsidian-bridge
  config:
    vaultPath: /path/to/your/vault
    autoContext: false        # auto-inject vault context before each model step
    autoCapture: false        # auto-capture non-Obsidian tool results as drafts
    draftFolder: dsh-drafts   # folder for draft notes
    sessionId: ""             # optional: link drafts to a specific session

Or use environment variables (legacy, used as fallback when config values are not provided):

export OBSIDIAN_VAULT_PATH="/path/to/your/vault"
export DSH_OBSIDIAN_AUTO_CONTEXT=true   # optional
export DSH_OBSIDIAN_AUTO_CAPTURE=true   # optional
export DSH_SESSION_ID="my-session"      # optional

Verify

In the DSH agent, ask it to search your vault:

Search my Obsidian vault for notes about "architecture"

Project Structure

dsh-obsidian-bridge/
├── src/
│   ├── index.ts              # Plugin entry: apply(ctx, config) with zod schema
│   ├── vault-manager.ts      # Core: path resolution, note reading, search, write, link
│   ├── note-index.ts         # SQLite FTS5 full-text index with incremental sync
│   ├── hooks.ts              # Event hooks: auto-context, auto-capture (returns disposer)
│   └── tools/
│       ├── read-note.ts      # obsidian_read_note tool definition
│       ├── search.ts          # obsidian_search tool definition
│       ├── write-draft.ts    # obsidian_write_draft tool definition
│       └── link-session.ts   # obsidian_link_session tool definition
├── dist/                      # Compiled JavaScript (tsc output)
├── test/
│   ├── vault/                 # Test Obsidian Vault (4 sample notes)
│   ├── spike.mjs              # Phase 0 core logic tests (25 tests)
│   ├── integration.mjs        # Phase 0 plugin lifecycle tests (49 tests)
│   ├── phase1-spike.mjs       # Phase 1 write/link tests (35 tests)
│   ├── phase1-integration.mjs # Phase 1 tools+hooks tests (45 tests)
│   ├── phase2-spike.mjs       # Phase 2 FTS5+config tests (35 tests)
│   └── phase2-integration.mjs # Phase 2 config+cleanup tests (23 tests)
├── cordis.patch.yml          # Example plugin configuration
├── package.json
├── tsconfig.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
└── .npmignore

Configuration

Config Schema (zod)

FieldTypeDefaultDescription
vaultPathstring""Absolute path to your Obsidian Vault
autoContextbooleanfalseAuto-inject vault context before each model step
autoCapturebooleanfalseAuto-capture non-Obsidian tool results as drafts
draftFolderstring"dsh-drafts"Folder name for draft notes
sessionIdstring""Session ID for draft frontmatter and session linking

Config is validated via zod Standard Schema V1. Values can be provided through cordis.patch.yml or environment variables (as fallback).

Environment Variables

VariableFallback ForDefault
OBSIDIAN_VAULT_PATHvaultPath
DSH_OBSIDIAN_AUTO_CONTEXTautoContextfalse
DSH_OBSIDIAN_AUTO_CAPTUREautoCapturefalse
DSH_SESSION_IDsessionId""

SQLite FTS5 Index

The plugin creates a .dsh/index.db SQLite database inside your vault directory:

  • FTS5 virtual table with unicode61 tokenizer
  • UNINDEXED columns for metadata (path, frontmatter, mtime, etc.)
  • BM25 relevance ranking for search results
  • Incremental sync: only re-reads notes whose mtime changed
  • Throttled sync: skips re-sync within 2s of last sync (unless invalidated)
  • Chinese support: CJK characters are split for unicode61 tokenization
  • WAL mode with 16MB cache for performance

Roadmap

PhaseScopeStatus
Phase 0 — Spikeread_note + search, in-memory index, path traversal guardComplete
Phase 1 — Self-use MVPwrite_draft + link_session tools, hooks (auto-context, auto-capture)Complete
Phase 2 — Open Source AlphaSQLite FTS5, cordis.patch.yml config, npm publish, documentationComplete

License

MIT