Files
obsidian-memex-chat/CLAUDE.md
svemagie a5b1ef8158 fresh
2026-03-31 14:20:47 +02:00

9.7 KiB
Raw Blame History

Memex Chat — CLAUDE.md

Obsidian plugin: Chat with your vault using Claude AI. Semantic TF-IDF + local embedding context retrieval, @Notizname mentions, thread history, prompt extension buttons, streaming responses, related notes sidebar.

Build

npm install
npm run build   # production build → main.js
npm run dev     # watch mode with inline sourcemaps

Entry: src/main.ts → bundled to main.js via esbuild (CJS, ES2018 target). obsidian and all @codemirror/* / @lezer/* packages are external (provided by Obsidian).

Architecture

File Role
src/main.ts Plugin entry — MemexChatPlugin extends Plugin. Registers views, commands, settings tab. Wires index rebuild, layout-ready hook, sync wait, and embedding progress notices.
src/ChatView.ts Main UI — ChatView extends ItemView. Thread management, sidebar history, context preview, mode buttons, streaming render, Copy/Save actions. View type: memex-chat-view.
src/VaultSearch.ts TF-IDF search engine. Builds in-memory index over all vault markdown files. Frontmatter property boost (5×). findSimilarByName() for unresolved link hints. Exports SearchResult interface (includes optional linked field).
src/EmbedSearch.ts Local semantic search via @xenova/transformers (ONNX, WASM). Caches per-note .ajson vectors under <vault>/.memex-chat/embeddings/. searchSimilarToFile() boosts scores by frontmatter property links (+0.15) and shared tags (+0.05/tag).
src/RelatedNotesView.ts Sidebar panel — RelatedNotesView extends ItemView. Shows semantically similar notes for the active file; refreshes on file-open. Displays similarity bar and "verknüpft" badge for property-linked notes. View type: memex-related-notes.
src/ClaudeClient.ts Anthropic API client. streamChat() yields ClaudeStreamChunk via async generator using native fetch + SSE. chat() and fetchModels() use Obsidian requestUrl (no SDK).
src/SettingsTab.ts MemexChatSettingsTab + MemexChatSettings interface + DEFAULT_SETTINGS. Exports PromptButton interface. Folder autocomplete via attachFolderDropdown() helper.
styles.css All plugin styles. CSS classes prefixed vc- (e.g. vc-root, vc-msg--assistant, vc-related-*, vc-folder-*).
manifest.json Obsidian plugin manifest. ID: memex-chat. Version: 1.0.1.
main.js Compiled output — do not edit manually, always rebuild.
esbuild.config.mjs Build config with three plugins: stubNativeModules (stubs onnxruntime-node/sharp/canvas), forceOnnxWeb (patches ONNX backend detection), forceOrtWebBrowserMode (patches ort-web for Electron).

Key Patterns

  • Data persistence: this.saveData(this.data) / this.loadData() — single object { settings, threads }. Settings merge on load preserves new fields via per-entry spread for promptButtons.
  • Streaming: ClaudeClient.streamChat() is an async generator using native fetch with stream: true and SSE parsing (content_block_delta events). ChatView iterates it and calls updateLastMessage() per chunk. chat() and fetchModels() use requestUrl (buffered, fine for non-streaming calls).
  • Context flow: Query → VaultSearch.search() or EmbedSearch.search() → context preview → user confirms → sendMessage() injects note content into the Claude prompt. Auto-retrieve skipped when prompt extension buttons are active.
  • Active search engine: plugin.activeSearch returns EmbedSearch when enabled, else VaultSearch.
  • System prompt layering: base system prompt → optional systemContextFile → active promptButtons extension files (each appended with \n\n---\n).
  • @mention syntax: @Notizname — autocomplete triggers after 2 chars, inserts full basename. Parsing in handleSend matches vault filenames directly (handles spaces & special chars).
  • Prompt buttons: activeExtensions: Set<string> tracks active button file paths. Mode hint panel shows helpText above input; hidden after send. Date-search buttons parse month from query and filter files by getFileDate().
  • Thread sidebar: Inline rename (double-click title). Collapsible "Verlauf" section loads vault chat files not in active threads via parseThreadFromVault().
  • Thread storage: Optionally saved as Markdown to threadsFolder (default Calendar/Chat/). Filename: YYYYMMDDHHmmss Title.md. Frontmatter includes id: for dedup on re-import.
  • Message actions: Copy (clipboard) and "Als Notiz" (save to Obsidian's default new-note folder) appear on hover for finished assistant messages.
  • Unresolved links: is-unresolved class + inline "Ähnliche Notiz: X" hint via findSimilarByName().
  • History cap: Last 10 messages sent to API per request.
  • CSS prefix: vc- for all plugin DOM classes. Do not use Obsidian internal class names.
  • Event listeners: Use this.registerDomEvent() for permanent listeners (auto-cleanup on view close). Inline onclick / addEventListener acceptable for dynamic elements that are re-created.
  • TypeScript: strictNullChecks on, moduleResolution: bundler. No tests currently.

EmbedSearch

  • Model: TaylorAI/bge-micro-v2 (default) — 384-dim, quantized ONNX, WASM backend via CDN (cdn.jsdelivr.net/npm/onnxruntime-web@1.14.0/dist/)
  • Cache: <vault>/.memex-chat/embeddings/<note-path>.ajson{ mtime, vec }. Manifest at .manifest.json.
  • Models stored in <vault>/.memex-chat/models/ (env.cacheDir).
  • Incremental flush every 100 embeds; final prune of stale files on completion.
  • Per-embed timeout: 13 s (120 s for first call while WASM/model loads).
  • reembedFile(TFile): debounced 2 s re-embed on vault modify events.
  • searchSimilarToFile(file, topK=10): cosine similarity with property/tag boosting (see below).
  • excludeFolders: string[] — vault folder prefixes skipped during indexing.
  • contextProperties: string[] — frontmatter keys whose wikilink values get +0.15 score boost; shared tags get +0.05 each (max 3). Scores capped at 1.0.
  • Obsidian Sync wait: waitForSyncIdle() monitors vault events (5 s probe, 15 s quiet) before starting buildIndex.
  • esbuild patches required: stubNativeModules, forceOnnxWeb, forceOrtWebBrowserMode. import.meta.url defined as a constant string.

RelatedNotesView

  • Opens in right sidebar leaf via plugin.activateRelatedView() or sparkles ribbon icon.
  • Refreshes on active-leaf-change and file-open (400 ms debounce).
  • onIndexReady() called by plugin after buildIndex completes.
  • Shows: note title, folder path (dimmed), similarity bar + percentage.
  • "verknüpft" badge (accent colour) for notes boosted by a property link.

Settings (MemexChatSettings)

Field Default Description
apiKey "" Anthropic API key
model claude-opus-4-6 Claude model ID
maxTokens 8192 Max output tokens (102416000)
maxContextNotes 6 TF-IDF/embedding context notes per query
maxCharsPerNote 2500 Characters per context note
systemPrompt (German default) Base system instructions
systemContextFile "" Optional vault note appended to system prompt
autoRetrieveContext true Auto-search on send
showContextPreview true Show context confirm step
saveThreadsToVault true Save chats as vault markdown files
threadsFolder Calendar/Chat Folder for saved threads
sendOnEnter false Enter sends (vs. Cmd+Enter)
contextProperties [collection, related, up, tags] Frontmatter props boosted 5× in TF-IDF; also used for +0.15 score boost in EmbedSearch
useEmbeddings false Enable local semantic embeddings
embeddingModel TaylorAI/bge-micro-v2 ONNX embedding model ID
embedExcludeFolders [] Vault folders excluded from embedding
promptButtons Draft Check, Monthly Check Header mode buttons with system prompt extension

Prompt Buttons (PromptButton interface)

interface PromptButton {
  label: string;
  filePath: string;        // vault path to prompt note (without .md)
  searchMode?: "date";     // enables date-based file search
  searchFolders?: string[]; // restrict date search to these folders
  helpText?: string;       // shown above input when button is active
}

Folder Autocomplete

attachFolderDropdown(wrap, input, getExcluded, onPick) helper in SettingsTab.ts applied to:

  • embedExcludeFolders (chip-tag list)
  • prompt button searchFolders (chip-tag list)
  • threadsFolder (single value)

CSS classes: vc-folder-search-wrap, vc-folder-dropdown, vc-folder-item.

Deployment (Manual)

Copy main.js, manifest.json, styles.css into .obsidian/plugins/memex-chat/ in the target vault.

Models (SettingsTab.ts)

Static MODELS array (fallback / initial dropdown population):

ID Label
claude-opus-4-6 Claude Opus 4.6 (Stärkste)
claude-sonnet-4-6 Claude Sonnet 4.6 (Empfohlen)
claude-haiku-4-5-20251001 Claude Haiku 4.5 (Schnell)

Default: claude-opus-4-6.

"Aktualisieren" button: calls ClaudeClient.fetchModels(apiKey) to fetch the live model list from the Anthropic API and repopulate the dropdown dynamically. This supersedes the static array at runtime. Update MODELS and DEFAULT_SETTINGS.model only when changing the compile-time fallback.

Embedding Models (EmbedSearch.ts)

EMBEDDING_MODELS array exported from EmbedSearch.ts and used to populate the embedding model dropdown in settings:

ID Description
TaylorAI/bge-micro-v2 BGE Micro v2 — default, 384-dim, fastest
Xenova/all-MiniLM-L6-v2 MiniLM L6 v2 — 384-dim
Xenova/multilingual-e5-small Multilingual E5 Small — DE/EN
Xenova/paraphrase-multilingual-MiniLM-L12-v2 Multilingual MiniLM L12