obedding 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,229 @@
1
+ # Architecture
2
+
3
+ ## System Overview
4
+
5
+ obedding follows a modular pipeline architecture with pluggable embedding backends:
6
+
7
+ ```
8
+ ┌────────────────────────────────────────┐
9
+ │ obedding CLI │
10
+ │ ┌──────────────────────────────────┐ │
11
+ │ │ Indexer │ Scanner │ Search │ │
12
+ │ └──────────────────────────────────┘ │
13
+ └───────────────┬────────────────────────┘
14
+
15
+ ┌───────────────┴────────────────────────┐
16
+ │ Storage Manager │
17
+ │ (JSON File Storage) │
18
+ └───────────────┬────────────────────────┘
19
+
20
+ ┌───────────────────────┼───────────────────────┐
21
+ │ │ │
22
+ ┌───────▼───────┐ ┌────────▼────────┐ ┌───────▼───────┐
23
+ │ LM Studio │ │ Ollama │ │ MLX │
24
+ │ (DEFAULT) │ │ │ │ (NOT REC.) │
25
+ │ localhost: │ │ localhost: │ │ localhost: │
26
+ │ :1234 │ │ :11434 │ │ :28100 │
27
+ │ GGUF models │ │ Native models │ │ MLX models │
28
+ │ 1024 dims │ │ 768 dims │ │ 2048 dims │
29
+ └───────────────┘ └─────────────────┘ └───────────────┘
30
+ ```
31
+
32
+ ## Core Components
33
+
34
+ ### 1. Scanner (`src/scanner.ts`)
35
+
36
+ **Responsibilities:**
37
+ - Recursively discover markdown files in vault
38
+ - Parse YAML frontmatter for metadata
39
+ - Extract metadata from directory structure (`Projects/{type}/{repo}/{context}/`)
40
+ - Generate SHA-256 content hashes for incremental updates
41
+
42
+ **Key Functions:**
43
+ - `scanObsidianVault()` - Discover all .md files
44
+ - `extractMetadata()` - Parse frontmatter and path structure
45
+ - `getNoteHash()` - Generate content hash for change detection
46
+
47
+ ### 2. Preprocessor (`src/preprocessor.ts`)
48
+
49
+ **Responsibilities:**
50
+ - Remove markdown structural elements (# ## ###, bullets, dividers)
51
+ - Extract metadata as keywords (title, tags, repo, context)
52
+ - Normalize text for better embedding quality
53
+
54
+ **Why Preprocessing Matters:**
55
+ Embedding models can be overly sensitive to text STRUCTURE rather than semantic content. By removing markdown formatting, we help the model focus on actual meaning.
56
+
57
+ **Key Functions:**
58
+ - `preprocessNote()` - Clean and normalize note content
59
+ - `checkEmbeddingVariance()` - Detect low-quality embeddings
60
+
61
+ ### 3. Backend Clients
62
+
63
+ All backends implement a consistent interface:
64
+
65
+ ```typescript
66
+ interface EmbeddingBackend {
67
+ checkConnection(): Promise<boolean>
68
+ generateEmbedding(text: string, model?: string): Promise<number[]>
69
+ generateEmbeddings(texts: string[], model?: string, onProgress?: Function): Promise<number[][]>
70
+ getModelInfo(model?: string): Promise<ModelInfo | null>
71
+ }
72
+ ```
73
+
74
+ #### LM Studio (`src/lmstudio.ts`) - **DEFAULT**
75
+ - **API:** OpenAI-compatible at `http://localhost:1234`
76
+ - **Model:** `text-embedding-qwen3-embedding-0.6b`
77
+ - **Dimensions:** 1024
78
+ - **Format:** GGUF models
79
+
80
+ #### Ollama (`src/ollama.ts`)
81
+ - **API:** Ollama API at `http://localhost:11434`
82
+ - **Model:** `qwen3-embedding:0.6b`
83
+ - **Dimensions:** 768
84
+ - **Format:** Native Ollama models
85
+
86
+ #### MLX (`src/mlx.ts`) - **NOT RECOMMENDED**
87
+ - **API:** Swama MLX at `http://localhost:28100`
88
+ - **Model:** `mlx-community/Qwen3-Embedding-0.6B-4bit-DWQ`
89
+ - **Dimensions:** 2048
90
+ - **Known Issue:** Produces identical embeddings for similar content
91
+
92
+ ### 4. Storage Manager (`src/storage.ts`)
93
+
94
+ **Responsibilities:**
95
+ - JSON file storage at `~/.claude/data/obsidian-embeddings.json`
96
+ - Content-based change detection via hash comparison
97
+ - Upsert operations for note updates
98
+ - Metadata tracking (model, dimensions, indexed_at)
99
+
100
+ **Storage Schema:**
101
+ ```typescript
102
+ interface EmbeddingStore {
103
+ version: string; // Storage format version
104
+ model: string; // Which model generated embeddings
105
+ dimensions: number; // Embedding vector size
106
+ indexed_at: string; // Last index timestamp
107
+ notes: NoteEmbedding[];
108
+ }
109
+
110
+ interface NoteEmbedding {
111
+ path: string; // Relative path from vault root
112
+ vault_path: string; // Absolute path
113
+ embedding: number[]; // Vector embedding
114
+ metadata: {
115
+ type?: string; // Project type
116
+ repo?: string; // Repository name
117
+ context?: string; // Context/feature
118
+ tags?: string[]; // Tags from frontmatter
119
+ title?: string; // Note title
120
+ };
121
+ excerpt: string; // First 200 chars
122
+ indexed_at: string; // When this note was indexed
123
+ hash: string; // SHA-256 for change detection
124
+ }
125
+ ```
126
+
127
+ ### 5. Search Engine (`src/search.ts`)
128
+
129
+ **Algorithm:** Cosine Similarity
130
+
131
+ ```
132
+ similarity(A, B) = (A · B) / (||A|| × ||B||)
133
+
134
+ Where:
135
+ - A, B are embedding vectors
136
+ - · is dot product
137
+ - || || is vector magnitude (L2 norm)
138
+ ```
139
+
140
+ **Process:**
141
+ 1. Preprocess query (same as notes)
142
+ 2. Generate query embedding
143
+ 3. Calculate cosine similarity against all stored embeddings
144
+ 4. Filter by minimum score
145
+ 5. Sort by similarity (descending)
146
+ 6. Return top-K results
147
+
148
+ ### 6. CLI Interface (`src/cli.ts`)
149
+
150
+ **Commands:**
151
+ - `index` - Generate embeddings for notes
152
+ - `search` - Semantic search query
153
+ - `stats` - Show storage statistics
154
+ - `clear` - Delete all embeddings
155
+
156
+ ## Data Flow
157
+
158
+ ### Indexing Flow
159
+ ```
160
+ 1. Scan Vault
161
+ └─▶ Discover *.md files
162
+ └─▶ Parse frontmatter
163
+ └─▶ Generate content hashes
164
+
165
+ 2. Filter (if incremental)
166
+ └─▶ Compare hashes with stored
167
+ └─▶ Skip unchanged notes
168
+
169
+ 3. Preprocess
170
+ └─▶ Remove markdown structure
171
+ └─▶ Extract metadata keywords
172
+
173
+ 4. Generate Embeddings
174
+ └─▶ Send to backend (LM Studio/Ollama/MLX)
175
+ └─▶ Receive vector arrays
176
+
177
+ 5. Validate
178
+ └─▶ Check embedding variance
179
+ └─▶ Warn if too low
180
+
181
+ 6. Store
182
+ └─▶ Update metadata (model, dimensions)
183
+ └─▶ Save to JSON file
184
+ ```
185
+
186
+ ### Search Flow
187
+ ```
188
+ 1. Load Storage
189
+ └─▶ Read JSON file
190
+ └─▶ Parse stored embeddings
191
+
192
+ 2. Preprocess Query
193
+ └─▶ Same as note preprocessing
194
+
195
+ 3. Generate Query Embedding
196
+ └─▶ Send to backend
197
+ └─▶ Receive query vector
198
+
199
+ 4. Calculate Similarities
200
+ └─▶ Cosine similarity vs all notes
201
+ └─▶ Skip dimension mismatches
202
+
203
+ 5. Filter & Sort
204
+ └─▶ Apply min-score threshold
205
+ └─▶ Sort by score descending
206
+
207
+ 6. Return Top-K
208
+ └─▶ Format with excerpts/metadata
209
+ ```
210
+
211
+ ## Design Decisions
212
+
213
+ ### Why JSON Storage?
214
+ - **Simplicity:** No database dependencies
215
+ - **Portability:** Single file, easy backup
216
+ - **Debuggability:** Human-readable
217
+ - **Scale:** Handles 1000s of notes efficiently
218
+
219
+ ### Why Content Hashing?
220
+ SHA-256 hashes of note content detect changes more reliably than modification timestamps.
221
+
222
+ ### Why Preprocessing?
223
+ Embedding models can be distracted by markdown formatting. Removing headers, bullets, and dividers helps focus on semantic content.
224
+
225
+ ### Why Multiple Backends?
226
+ Different users have different setups:
227
+ - LM Studio: Easy GUI, GGUF models
228
+ - Ollama: Simple CLI, wide model support
229
+ - MLX: Apple Silicon optimized (but has bugs)
@@ -0,0 +1,230 @@
1
+ # Embedding Backends
2
+
3
+ obedding supports three embedding backends. LM Studio is the default.
4
+
5
+ ## Quick Comparison
6
+
7
+ | Feature | LM Studio (Default) | Ollama | MLX |
8
+ |---------|---------------------|--------|-----|
9
+ | **Server** | `http://localhost:1234` | `http://localhost:11434` | `http://localhost:28100` |
10
+ | **Default Model** | `text-embedding-qwen3-embedding-0.6b` | `qwen3-embedding:0.6b` | `mlx-community/Qwen3-Embedding-0.6B-4bit-DWQ` |
11
+ | **Dimensions** | 1024 | 768 | 2048 |
12
+ | **Model Format** | GGUF | Native | MLX |
13
+ | **Reliability** | ✅ Stable | ✅ Stable | ⚠️ Known Issues |
14
+ | **Performance** | ~1.7s for 3 notes | ~6s for 27 notes | ~11s for 27 notes |
15
+ | **Storage** | ~4KB/note | ~3KB/note | ~8KB/note |
16
+
17
+ ## LM Studio (Recommended)
18
+
19
+ ### Setup
20
+
21
+ 1. **Install LM Studio** from [lmstudio.ai](https://lmstudio.ai/)
22
+
23
+ 2. **Download an embedding model:**
24
+ - Search for `Qwen3-Embedding-0.6B-GGUF`
25
+ - Or use any GGUF embedding model
26
+
27
+ 3. **Load the model and start the server:**
28
+ - Click the "Server" button in LM Studio
29
+ - Ensure it's running on `http://localhost:1234`
30
+
31
+ ### Usage
32
+
33
+ ```bash
34
+ # Explicit backend selection
35
+ npx obedding index --vault ~/.obsidian/Projects --backend lmstudio
36
+ npx obedding search "query" --backend lmstudio
37
+
38
+ # Or use default (lmstudio is now default)
39
+ npx obedding index --vault ~/.obsidian/Projects
40
+ npx obedding search "query"
41
+ ```
42
+
43
+ ### API Details
44
+
45
+ - **Endpoint:** `http://localhost:1234/v1/embeddings`
46
+ - **Format:** OpenAI-compatible
47
+ - **Request:**
48
+ ```json
49
+ {
50
+ "model": "text-embedding-qwen3-embedding-0.6b",
51
+ "input": "your text here"
52
+ }
53
+ ```
54
+ - **Response:**
55
+ ```json
56
+ {
57
+ "object": "list",
58
+ "data": [{
59
+ "object": "embedding",
60
+ "index": 0,
61
+ "embedding": [0.0123, -0.0456, ...]
62
+ }],
63
+ "model": "text-embedding-qwen3-embedding-0.6b"
64
+ }
65
+ ```
66
+
67
+ ### Available Models
68
+
69
+ Check available models in LM Studio:
70
+ ```bash
71
+ curl http://localhost:1234/v1/models
72
+ ```
73
+
74
+ ### Custom Model
75
+
76
+ ```bash
77
+ npx obedding index --backend lmstudio --model "your-custom-model-name"
78
+ ```
79
+
80
+ ## Ollama
81
+
82
+ ### Setup
83
+
84
+ ```bash
85
+ # Install Ollama
86
+ curl -fsSL https://ollama.ai/install.sh | sh
87
+
88
+ # Pull embedding model
89
+ ollama pull qwen3-embedding:0.6b
90
+
91
+ # Start server
92
+ ollama serve
93
+ ```
94
+
95
+ ### Usage
96
+
97
+ ```bash
98
+ npx obedding index --vault ~/.obsidian/Projects --backend ollama
99
+ npx obedding search "query" --backend ollama
100
+ ```
101
+
102
+ ### API Details
103
+
104
+ - **Endpoint:** `http://localhost:11434/api/embeddings`
105
+ - **Format:** Ollama native
106
+ - **Request:**
107
+ ```json
108
+ {
109
+ "model": "qwen3-embedding:0.6b",
110
+ "prompt": "your text here"
111
+ }
112
+ ```
113
+ - **Response:**
114
+ ```json
115
+ {
116
+ "embedding": [0.0123, -0.0456, ...]
117
+ }
118
+ ```
119
+
120
+ ### Available Models
121
+
122
+ ```bash
123
+ ollama list
124
+ ```
125
+
126
+ ### Custom Model
127
+
128
+ ```bash
129
+ npx obedding index --backend ollama --model "mxbai-embed-large"
130
+ ```
131
+
132
+ ## MLX (Not Recommended)
133
+
134
+ ### Known Issues
135
+
136
+ ⚠️ **The MLX backend has a critical bug:** It produces **identical embeddings for different content** when the text has similar structure (e.g., same frontmatter, similar length).
137
+
138
+ **Example:**
139
+ - Content 1: "tags:cli,telegram... Telegram newline fix..." (6416 chars)
140
+ - Content 2: "tags:cli,glm5... GLM-5 MCP search..." (3493 chars)
141
+ - Result: Cosine similarity = 1.0000 (IDENTICAL embeddings)
142
+
143
+ **Root Cause:** Swama batch processing regression. See [Swama issue #93](https://github.com/Trans-N-ai/swama/issues/93)
144
+
145
+ ### Setup (If You Must)
146
+
147
+ ```bash
148
+ # Install Swama
149
+ npm install -g swama
150
+
151
+ # Start MLX embedding server
152
+ swama serve
153
+ ```
154
+
155
+ ### Usage
156
+
157
+ ```bash
158
+ npx obedding index --vault ~/.obsidian/Projects --backend mlx
159
+ npx obedding search "query" --backend mlx
160
+ ```
161
+
162
+ ### API Details
163
+
164
+ - **Endpoint:** `http://localhost:28100/v1/embeddings`
165
+ - **Format:** OpenAI-compatible (with bugs)
166
+ - **Workaround:** Client truncates embeddings to 2048 dimensions
167
+
168
+ ## Switching Backends
169
+
170
+ You can switch backends, but you'll need to re-index:
171
+
172
+ ```bash
173
+ # Clear existing embeddings
174
+ npx obedding clear --force
175
+
176
+ # Index with new backend
177
+ npx obedding index --vault ~/.obsidian/Projects --backend ollama
178
+ ```
179
+
180
+ **Why?** Different backends produce different embedding dimensions, making them incompatible.
181
+
182
+ ## Environment Variables
183
+
184
+ Override default server URLs:
185
+
186
+ ```bash
187
+ # LM Studio
188
+ export LMSTUDIO_BASE_URL="http://localhost:1234"
189
+
190
+ # Ollama
191
+ export OLLAMA_BASE_URL="http://localhost:11434"
192
+ ```
193
+
194
+ ## Troubleshooting
195
+
196
+ ### LM Studio
197
+
198
+ ```bash
199
+ # Check if server is running
200
+ curl http://localhost:1234/v1/models
201
+
202
+ # Test embeddings
203
+ curl -X POST http://localhost:1234/v1/embeddings \
204
+ -H "Content-Type: application/json" \
205
+ -d '{"model": "text-embedding-qwen3-embedding-0.6b", "input": "test"}'
206
+ ```
207
+
208
+ ### Ollama
209
+
210
+ ```bash
211
+ # Check if server is running
212
+ curl http://localhost:11434/api/tags
213
+
214
+ # Test embeddings
215
+ curl -X POST http://localhost:11434/api/embeddings \
216
+ -H "Content-Type: application/json" \
217
+ -d '{"model": "qwen3-embedding:0.6b", "prompt": "test"}'
218
+ ```
219
+
220
+ ### MLX
221
+
222
+ ```bash
223
+ # Check if server is running
224
+ curl http://localhost:28100/
225
+
226
+ # Test embeddings
227
+ curl -X POST http://localhost:28100/v1/embeddings \
228
+ -H "Content-Type: application/json" \
229
+ -d '{"input": ["test"], "model": "mlx-community/Qwen3-Embedding-0.6B-4bit-DWQ"}'
230
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "obedding",
3
- "version": "1.0.1",
4
- "description": "Semantic search for Obsidian notes using local MLX embeddings",
3
+ "version": "1.0.2",
4
+ "description": "Semantic search for Obsidian notes using local embeddings (Ollama, LM Studio, MLX)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {
@@ -17,6 +17,8 @@
17
17
  "obsidian",
18
18
  "semantic-search",
19
19
  "embeddings",
20
+ "lmstudio",
21
+ "ollama",
20
22
  "mlx",
21
23
  "local",
22
24
  "privacy",
@@ -39,6 +41,7 @@
39
41
  },
40
42
  "files": [
41
43
  "dist",
44
+ "docs",
42
45
  "README.md",
43
46
  "LICENSE"
44
47
  ],