nano-brain 2026.1.0
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.
- package/AGENTS_SNIPPET.md +36 -0
- package/CHANGELOG.md +68 -0
- package/README.md +281 -0
- package/SKILL.md +153 -0
- package/bin/cli.js +18 -0
- package/index.html +929 -0
- package/nano-brain +4 -0
- package/opencode-mcp.json +9 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/design.md +68 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/proposal.md +27 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/specs/mcp-integration-testing/spec.md +50 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/specs/mcp-server/spec.md +40 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/specs/search-pipeline/spec.md +29 -0
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/tasks.md +37 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/design.md +111 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/proposal.md +30 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/specs/mcp-server/spec.md +33 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/specs/storage-limits/spec.md +90 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/specs/workspace-scoping/spec.md +66 -0
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/tasks.md +199 -0
- package/openspec/changes/codebase-indexing/.openspec.yaml +2 -0
- package/openspec/changes/codebase-indexing/design.md +169 -0
- package/openspec/changes/codebase-indexing/proposal.md +30 -0
- package/openspec/changes/codebase-indexing/specs/codebase-collection/spec.md +187 -0
- package/openspec/changes/codebase-indexing/specs/mcp-server/spec.md +36 -0
- package/openspec/changes/codebase-indexing/tasks.md +56 -0
- package/openspec/specs/mcp-integration-testing/spec.md +50 -0
- package/openspec/specs/mcp-server/spec.md +75 -0
- package/openspec/specs/search-pipeline/spec.md +29 -0
- package/openspec/specs/storage-limits/spec.md +94 -0
- package/openspec/specs/workspace-scoping/spec.md +70 -0
- package/package.json +34 -0
- package/site/build.js +66 -0
- package/site/partials/_api.html +83 -0
- package/site/partials/_compare.html +100 -0
- package/site/partials/_config.html +23 -0
- package/site/partials/_features.html +43 -0
- package/site/partials/_footer.html +6 -0
- package/site/partials/_hero.html +9 -0
- package/site/partials/_how-it-works.html +26 -0
- package/site/partials/_models.html +18 -0
- package/site/partials/_quick-start.html +15 -0
- package/site/partials/_stats.html +1 -0
- package/site/partials/_tech-stack.html +13 -0
- package/site/script.js +12 -0
- package/site/shell.html +44 -0
- package/site/styles.css +548 -0
- package/src/chunker.ts +427 -0
- package/src/codebase.ts +331 -0
- package/src/collections.ts +192 -0
- package/src/embeddings.ts +293 -0
- package/src/expansion.ts +79 -0
- package/src/harvester.ts +306 -0
- package/src/index.ts +503 -0
- package/src/reranker.ts +103 -0
- package/src/search.ts +294 -0
- package/src/server.ts +664 -0
- package/src/storage.ts +221 -0
- package/src/store.ts +623 -0
- package/src/types.ts +202 -0
- package/src/watcher.ts +384 -0
- package/test/chunker.test.ts +479 -0
- package/test/cli.test.ts +309 -0
- package/test/codebase-chunker.test.ts +446 -0
- package/test/codebase.test.ts +678 -0
- package/test/collections.test.ts +571 -0
- package/test/harvester.test.ts +636 -0
- package/test/integration.test.ts +150 -0
- package/test/llm.test.ts +322 -0
- package/test/search.test.ts +572 -0
- package/test/server.test.ts +541 -0
- package/test/storage.test.ts +302 -0
- package/test/store.test.ts +465 -0
- package/test/watcher.test.ts +656 -0
- package/test/workspace.test.ts +239 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +16 -0
package/index.html
ADDED
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>nano-brain · MCP Server</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
color-scheme: dark;
|
|
10
|
+
--bg: #0b1220;
|
|
11
|
+
--bg-2: #0f172a;
|
|
12
|
+
--bg-3: #121b2f;
|
|
13
|
+
--card: rgba(15, 23, 42, 0.7);
|
|
14
|
+
--glass: rgba(17, 25, 40, 0.6);
|
|
15
|
+
--border: rgba(148, 163, 184, 0.18);
|
|
16
|
+
--text: #e2e8f0;
|
|
17
|
+
--muted: #94a3b8;
|
|
18
|
+
--accent: #3b82f6;
|
|
19
|
+
--accent-2: #06b6d4;
|
|
20
|
+
--shadow: 0 30px 80px rgba(2, 6, 23, 0.6);
|
|
21
|
+
--radius-lg: 22px;
|
|
22
|
+
--radius-md: 16px;
|
|
23
|
+
--radius-sm: 12px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
* {
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
html {
|
|
31
|
+
scroll-behavior: smooth;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
body {
|
|
35
|
+
margin: 0;
|
|
36
|
+
font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
37
|
+
background: radial-gradient(circle at 20% 20%, rgba(59, 130, 246, 0.18), transparent 45%),
|
|
38
|
+
radial-gradient(circle at 80% 0%, rgba(6, 182, 212, 0.16), transparent 40%),
|
|
39
|
+
linear-gradient(180deg, #0a1020 0%, #0b1220 45%, #0c1224 100%);
|
|
40
|
+
color: var(--text);
|
|
41
|
+
min-height: 100vh;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
a {
|
|
45
|
+
color: inherit;
|
|
46
|
+
text-decoration: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.page {
|
|
50
|
+
max-width: 1180px;
|
|
51
|
+
margin: 0 auto;
|
|
52
|
+
padding: 0 20px 80px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.nav {
|
|
56
|
+
position: sticky;
|
|
57
|
+
top: 0;
|
|
58
|
+
z-index: 20;
|
|
59
|
+
backdrop-filter: blur(14px);
|
|
60
|
+
background: rgba(10, 16, 32, 0.75);
|
|
61
|
+
border-bottom: 1px solid var(--border);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.nav-inner {
|
|
65
|
+
max-width: 1180px;
|
|
66
|
+
margin: 0 auto;
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: space-between;
|
|
70
|
+
padding: 16px 20px;
|
|
71
|
+
gap: 16px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.brand {
|
|
75
|
+
display: flex;
|
|
76
|
+
align-items: center;
|
|
77
|
+
gap: 12px;
|
|
78
|
+
font-weight: 700;
|
|
79
|
+
letter-spacing: 0.02em;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.brand-dot {
|
|
83
|
+
width: 10px;
|
|
84
|
+
height: 10px;
|
|
85
|
+
border-radius: 50%;
|
|
86
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
87
|
+
box-shadow: 0 0 18px rgba(59, 130, 246, 0.8);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.nav-links {
|
|
91
|
+
display: flex;
|
|
92
|
+
gap: 12px;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.nav-links a {
|
|
97
|
+
padding: 8px 12px;
|
|
98
|
+
border-radius: 999px;
|
|
99
|
+
border: 1px solid transparent;
|
|
100
|
+
color: var(--muted);
|
|
101
|
+
font-size: 0.9rem;
|
|
102
|
+
transition: color 200ms ease, background 200ms ease, border-color 200ms ease;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.nav-links a:hover {
|
|
106
|
+
color: var(--text);
|
|
107
|
+
background: rgba(59, 130, 246, 0.12);
|
|
108
|
+
border-color: rgba(59, 130, 246, 0.4);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.hero {
|
|
112
|
+
margin-top: 40px;
|
|
113
|
+
padding: 52px;
|
|
114
|
+
border-radius: var(--radius-lg);
|
|
115
|
+
background: linear-gradient(140deg, rgba(17, 24, 39, 0.85), rgba(2, 6, 23, 0.95));
|
|
116
|
+
border: 1px solid var(--border);
|
|
117
|
+
box-shadow: var(--shadow);
|
|
118
|
+
position: relative;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.hero::after {
|
|
123
|
+
content: '';
|
|
124
|
+
position: absolute;
|
|
125
|
+
inset: 0;
|
|
126
|
+
background: radial-gradient(circle at 80% 20%, rgba(59, 130, 246, 0.25), transparent 40%);
|
|
127
|
+
pointer-events: none;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.badge {
|
|
131
|
+
display: inline-flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 8px;
|
|
134
|
+
padding: 6px 12px;
|
|
135
|
+
border-radius: 999px;
|
|
136
|
+
font-size: 0.8rem;
|
|
137
|
+
font-weight: 600;
|
|
138
|
+
background: rgba(59, 130, 246, 0.15);
|
|
139
|
+
border: 1px solid rgba(59, 130, 246, 0.4);
|
|
140
|
+
color: #bfdbfe;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.hero h1 {
|
|
144
|
+
font-size: clamp(2.6rem, 4.5vw, 3.8rem);
|
|
145
|
+
margin: 16px 0 12px;
|
|
146
|
+
letter-spacing: -0.02em;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.hero p {
|
|
150
|
+
font-size: 1.05rem;
|
|
151
|
+
color: var(--muted);
|
|
152
|
+
max-width: 700px;
|
|
153
|
+
line-height: 1.7;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.hero-actions {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
gap: 14px;
|
|
160
|
+
margin-top: 26px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.button {
|
|
164
|
+
display: inline-flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 10px;
|
|
167
|
+
padding: 12px 18px;
|
|
168
|
+
border-radius: 12px;
|
|
169
|
+
font-weight: 600;
|
|
170
|
+
border: 1px solid transparent;
|
|
171
|
+
transition: transform 200ms ease, box-shadow 200ms ease, background 200ms ease;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.button.primary {
|
|
175
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
176
|
+
color: #0b1220;
|
|
177
|
+
box-shadow: 0 18px 36px rgba(59, 130, 246, 0.35);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.button.secondary {
|
|
181
|
+
background: rgba(15, 23, 42, 0.7);
|
|
182
|
+
border-color: var(--border);
|
|
183
|
+
color: var(--text);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.button:hover {
|
|
187
|
+
transform: translateY(-2px);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
section {
|
|
191
|
+
margin-top: 72px;
|
|
192
|
+
scroll-margin-top: 100px;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.section-title {
|
|
196
|
+
font-size: clamp(1.6rem, 2.4vw, 2.2rem);
|
|
197
|
+
margin-bottom: 12px;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.section-subtitle {
|
|
201
|
+
margin-bottom: 26px;
|
|
202
|
+
color: var(--muted);
|
|
203
|
+
max-width: 720px;
|
|
204
|
+
line-height: 1.7;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.grid {
|
|
208
|
+
display: grid;
|
|
209
|
+
gap: 18px;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.features {
|
|
213
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.card {
|
|
217
|
+
background: var(--card);
|
|
218
|
+
border-radius: var(--radius-md);
|
|
219
|
+
border: 1px solid var(--border);
|
|
220
|
+
padding: 20px;
|
|
221
|
+
backdrop-filter: blur(12px);
|
|
222
|
+
transition: border-color 200ms ease, transform 200ms ease, box-shadow 200ms ease;
|
|
223
|
+
min-height: 160px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.card:hover {
|
|
227
|
+
border-color: rgba(59, 130, 246, 0.5);
|
|
228
|
+
transform: translateY(-3px);
|
|
229
|
+
box-shadow: 0 20px 45px rgba(15, 23, 42, 0.6);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.icon {
|
|
233
|
+
width: 40px;
|
|
234
|
+
height: 40px;
|
|
235
|
+
border-radius: 12px;
|
|
236
|
+
display: grid;
|
|
237
|
+
place-items: center;
|
|
238
|
+
background: rgba(59, 130, 246, 0.16);
|
|
239
|
+
color: #93c5fd;
|
|
240
|
+
margin-bottom: 14px;
|
|
241
|
+
font-weight: 700;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.card h3 {
|
|
245
|
+
margin: 0 0 10px;
|
|
246
|
+
font-size: 1.05rem;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.card p {
|
|
250
|
+
margin: 0;
|
|
251
|
+
color: var(--muted);
|
|
252
|
+
line-height: 1.6;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.pipeline {
|
|
256
|
+
background: var(--glass);
|
|
257
|
+
border-radius: var(--radius-lg);
|
|
258
|
+
border: 1px solid var(--border);
|
|
259
|
+
padding: 28px;
|
|
260
|
+
display: grid;
|
|
261
|
+
gap: 18px;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.pipeline-row {
|
|
265
|
+
display: flex;
|
|
266
|
+
align-items: center;
|
|
267
|
+
justify-content: center;
|
|
268
|
+
gap: 14px;
|
|
269
|
+
flex-wrap: wrap;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.node {
|
|
273
|
+
padding: 12px 16px;
|
|
274
|
+
border-radius: var(--radius-sm);
|
|
275
|
+
border: 1px solid rgba(59, 130, 246, 0.45);
|
|
276
|
+
background: rgba(10, 16, 32, 0.9);
|
|
277
|
+
font-weight: 600;
|
|
278
|
+
min-width: 150px;
|
|
279
|
+
text-align: center;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.connector {
|
|
283
|
+
width: 52px;
|
|
284
|
+
height: 2px;
|
|
285
|
+
background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.7), transparent);
|
|
286
|
+
position: relative;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.connector::after {
|
|
290
|
+
content: '';
|
|
291
|
+
position: absolute;
|
|
292
|
+
right: -6px;
|
|
293
|
+
top: 50%;
|
|
294
|
+
width: 8px;
|
|
295
|
+
height: 8px;
|
|
296
|
+
border-right: 2px solid rgba(59, 130, 246, 0.7);
|
|
297
|
+
border-top: 2px solid rgba(59, 130, 246, 0.7);
|
|
298
|
+
transform: translateY(-50%) rotate(45deg);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.split {
|
|
302
|
+
display: grid;
|
|
303
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
304
|
+
gap: 14px;
|
|
305
|
+
width: 100%;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.merge {
|
|
309
|
+
width: 2px;
|
|
310
|
+
height: 36px;
|
|
311
|
+
background: rgba(59, 130, 246, 0.7);
|
|
312
|
+
margin: 0 auto;
|
|
313
|
+
position: relative;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
.merge::after {
|
|
317
|
+
content: '';
|
|
318
|
+
position: absolute;
|
|
319
|
+
bottom: -6px;
|
|
320
|
+
left: 50%;
|
|
321
|
+
width: 10px;
|
|
322
|
+
height: 10px;
|
|
323
|
+
border-right: 2px solid rgba(59, 130, 246, 0.7);
|
|
324
|
+
border-bottom: 2px solid rgba(59, 130, 246, 0.7);
|
|
325
|
+
transform: translateX(-50%) rotate(45deg);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.api-grid {
|
|
329
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.api-card {
|
|
333
|
+
padding: 18px;
|
|
334
|
+
border-radius: var(--radius-md);
|
|
335
|
+
border: 1px solid var(--border);
|
|
336
|
+
background: rgba(12, 19, 35, 0.8);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.api-card h4 {
|
|
340
|
+
margin: 0 0 8px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.api-card p {
|
|
344
|
+
margin: 0 0 10px;
|
|
345
|
+
color: var(--muted);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.params {
|
|
349
|
+
display: flex;
|
|
350
|
+
flex-wrap: wrap;
|
|
351
|
+
gap: 8px;
|
|
352
|
+
color: var(--muted);
|
|
353
|
+
font-size: 0.85rem;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.chip {
|
|
357
|
+
padding: 4px 8px;
|
|
358
|
+
border-radius: 999px;
|
|
359
|
+
background: rgba(59, 130, 246, 0.12);
|
|
360
|
+
border: 1px solid rgba(59, 130, 246, 0.35);
|
|
361
|
+
color: #c7d2fe;
|
|
362
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.code-pill {
|
|
366
|
+
padding: 8px 12px;
|
|
367
|
+
border-radius: 999px;
|
|
368
|
+
background: rgba(15, 23, 42, 0.75);
|
|
369
|
+
border: 1px solid rgba(148, 163, 184, 0.3);
|
|
370
|
+
color: #cbd5f5;
|
|
371
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
372
|
+
font-weight: 600;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.codeblock {
|
|
376
|
+
background: #0b1220;
|
|
377
|
+
border-radius: var(--radius-md);
|
|
378
|
+
padding: 20px;
|
|
379
|
+
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
380
|
+
overflow-x: auto;
|
|
381
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
382
|
+
font-size: 0.9rem;
|
|
383
|
+
line-height: 1.7;
|
|
384
|
+
color: #e2e8f0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.token-key {
|
|
388
|
+
color: #93c5fd;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.token-string {
|
|
392
|
+
color: #fca5a5;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.token-boolean {
|
|
396
|
+
color: #facc15;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.token-comment {
|
|
400
|
+
color: #94a3b8;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.models {
|
|
404
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.model-card {
|
|
408
|
+
padding: 16px;
|
|
409
|
+
border-radius: var(--radius-md);
|
|
410
|
+
border: 1px solid var(--border);
|
|
411
|
+
background: rgba(12, 19, 35, 0.75);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.model-card h4 {
|
|
415
|
+
margin: 0 0 6px;
|
|
416
|
+
font-size: 1rem;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.model-card p {
|
|
420
|
+
margin: 0;
|
|
421
|
+
color: var(--muted);
|
|
422
|
+
font-size: 0.9rem;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.tech-stack {
|
|
426
|
+
display: flex;
|
|
427
|
+
flex-wrap: wrap;
|
|
428
|
+
gap: 10px;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.tech-pill {
|
|
432
|
+
padding: 6px 12px;
|
|
433
|
+
border-radius: 999px;
|
|
434
|
+
background: rgba(15, 23, 42, 0.8);
|
|
435
|
+
border: 1px solid rgba(148, 163, 184, 0.2);
|
|
436
|
+
color: var(--muted);
|
|
437
|
+
font-size: 0.85rem;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.stats {
|
|
441
|
+
margin-top: 48px;
|
|
442
|
+
padding: 16px 20px;
|
|
443
|
+
border-radius: var(--radius-md);
|
|
444
|
+
border: 1px solid var(--border);
|
|
445
|
+
background: rgba(15, 23, 42, 0.7);
|
|
446
|
+
text-align: center;
|
|
447
|
+
color: #cbd5f5;
|
|
448
|
+
font-weight: 600;
|
|
449
|
+
letter-spacing: 0.01em;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
footer {
|
|
453
|
+
margin-top: 72px;
|
|
454
|
+
padding-top: 24px;
|
|
455
|
+
border-top: 1px solid var(--border);
|
|
456
|
+
display: flex;
|
|
457
|
+
align-items: center;
|
|
458
|
+
justify-content: space-between;
|
|
459
|
+
gap: 12px;
|
|
460
|
+
color: var(--muted);
|
|
461
|
+
flex-wrap: wrap;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.fade-in {
|
|
465
|
+
opacity: 0;
|
|
466
|
+
transform: translateY(16px);
|
|
467
|
+
transition: opacity 600ms ease, transform 600ms ease;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.fade-in.visible {
|
|
471
|
+
opacity: 1;
|
|
472
|
+
transform: translateY(0);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
@media (max-width: 900px) {
|
|
476
|
+
.features,
|
|
477
|
+
.api-grid,
|
|
478
|
+
.models {
|
|
479
|
+
grid-template-columns: 1fr;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.hero {
|
|
483
|
+
padding: 36px 24px;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.nav-inner {
|
|
487
|
+
flex-direction: column;
|
|
488
|
+
align-items: flex-start;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
@media (max-width: 640px) {
|
|
493
|
+
.hero-actions {
|
|
494
|
+
flex-direction: column;
|
|
495
|
+
align-items: stretch;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.pipeline-row {
|
|
499
|
+
flex-direction: column;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.connector {
|
|
503
|
+
width: 2px;
|
|
504
|
+
height: 28px;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.connector::after {
|
|
508
|
+
right: 50%;
|
|
509
|
+
top: auto;
|
|
510
|
+
bottom: -6px;
|
|
511
|
+
transform: translateX(50%) rotate(135deg);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
/* Comparison table */
|
|
517
|
+
.compare-table-wrap {
|
|
518
|
+
overflow-x: auto;
|
|
519
|
+
margin: 2rem 0;
|
|
520
|
+
border-radius: 12px;
|
|
521
|
+
border: 1px solid rgba(255,255,255,0.08);
|
|
522
|
+
}
|
|
523
|
+
.compare-table {
|
|
524
|
+
width: 100%;
|
|
525
|
+
border-collapse: collapse;
|
|
526
|
+
font-size: 0.85rem;
|
|
527
|
+
min-width: 700px;
|
|
528
|
+
}
|
|
529
|
+
.compare-table th,
|
|
530
|
+
.compare-table td {
|
|
531
|
+
padding: 0.75rem 1rem;
|
|
532
|
+
text-align: left;
|
|
533
|
+
border-bottom: 1px solid rgba(255,255,255,0.06);
|
|
534
|
+
}
|
|
535
|
+
.compare-table thead th {
|
|
536
|
+
background: rgba(255,255,255,0.04);
|
|
537
|
+
font-weight: 600;
|
|
538
|
+
font-size: 0.8rem;
|
|
539
|
+
text-transform: uppercase;
|
|
540
|
+
letter-spacing: 0.05em;
|
|
541
|
+
color: #aaa;
|
|
542
|
+
}
|
|
543
|
+
.compare-table th.highlight,
|
|
544
|
+
.compare-table td.highlight {
|
|
545
|
+
background: rgba(99,102,241,0.08);
|
|
546
|
+
color: #a5b4fc;
|
|
547
|
+
font-weight: 500;
|
|
548
|
+
}
|
|
549
|
+
.compare-table thead th.highlight {
|
|
550
|
+
color: #a5b4fc;
|
|
551
|
+
font-weight: 700;
|
|
552
|
+
}
|
|
553
|
+
.compare-table tbody tr:hover {
|
|
554
|
+
background: rgba(255,255,255,0.02);
|
|
555
|
+
}
|
|
556
|
+
</style>
|
|
557
|
+
</head>
|
|
558
|
+
<body>
|
|
559
|
+
<header class="nav">
|
|
560
|
+
<div class="nav-inner">
|
|
561
|
+
<div class="brand"><span class="brand-dot"></span>nano-brain</div>
|
|
562
|
+
<nav class="nav-links">
|
|
563
|
+
<a href="#features">Features</a>
|
|
564
|
+
<a href="#compare">Compare</a>
|
|
565
|
+
<a href="#how">How It Works</a>
|
|
566
|
+
<a href="#api">API</a>
|
|
567
|
+
<a href="#config">Config</a>
|
|
568
|
+
<a href="#models">Models</a>
|
|
569
|
+
</nav>
|
|
570
|
+
</div>
|
|
571
|
+
</header>
|
|
572
|
+
|
|
573
|
+
<div class="page">
|
|
574
|
+
<section class="hero fade-in" id="hero">
|
|
575
|
+
<span class="badge">v2026.1.0</span>
|
|
576
|
+
<h1>nano-brain</h1>
|
|
577
|
+
<p>Persistent hybrid search memory for AI coding agents.</p>
|
|
578
|
+
<div class="hero-actions">
|
|
579
|
+
<a class="button primary" href="https://github.com/kokorolx/nano-brain">GitHub</a>
|
|
580
|
+
<span class="code-pill">npm i nano-brain</span>
|
|
581
|
+
</div>
|
|
582
|
+
</section>
|
|
583
|
+
<section id="features" class="fade-in">
|
|
584
|
+
<h2 class="section-title">Features</h2>
|
|
585
|
+
<p class="section-subtitle">
|
|
586
|
+
Premium local memory with a hybrid search pipeline, SQLite foundations, codebase indexing, and MCP-first ergonomics.
|
|
587
|
+
</p>
|
|
588
|
+
<div class="grid features">
|
|
589
|
+
<div class="card">
|
|
590
|
+
<div class="icon">🔍</div>
|
|
591
|
+
<h3>Hybrid Search Pipeline</h3>
|
|
592
|
+
<p>Query expansion → parallel BM25 + vector search → RRF fusion → LLM reranking</p>
|
|
593
|
+
</div>
|
|
594
|
+
<div class="card">
|
|
595
|
+
<div class="icon">🧠</div>
|
|
596
|
+
<h3>Local AI Models</h3>
|
|
597
|
+
<p>nomic-embed-text-v1.5, bge-reranker-v2-m3, qmd-query-expansion-1.7B — all GGUF, fully offline</p>
|
|
598
|
+
</div>
|
|
599
|
+
<div class="card">
|
|
600
|
+
<div class="icon">🗄️</div>
|
|
601
|
+
<h3>SQLite + sqlite-vec</h3>
|
|
602
|
+
<p>FTS5 for BM25 keyword search, sqlite-vec for vector similarity — single-file database</p>
|
|
603
|
+
</div>
|
|
604
|
+
<div class="card">
|
|
605
|
+
<div class="icon">🔌</div>
|
|
606
|
+
<h3>MCP Server</h3>
|
|
607
|
+
<p>10 tools via stdio transport, integrates with any MCP-compatible AI agent</p>
|
|
608
|
+
</div>
|
|
609
|
+
<div class="card">
|
|
610
|
+
<div class="icon">📚</div>
|
|
611
|
+
<h3>Multi-Collection</h3>
|
|
612
|
+
<p>Sessions, daily logs, curated memory — all indexed and searchable</p>
|
|
613
|
+
</div>
|
|
614
|
+
<div class="card">
|
|
615
|
+
<div class="icon">🔒</div>
|
|
616
|
+
<h3>Privacy First</h3>
|
|
617
|
+
<p>100% local processing, no cloud dependencies, your data stays on your machine</p>
|
|
618
|
+
</div>
|
|
619
|
+
<div class="card">
|
|
620
|
+
<div class="icon">🧬</div>
|
|
621
|
+
<h3>Codebase Indexing</h3>
|
|
622
|
+
<p>Index source files with structural boundary detection. Workspace-scoped search across sessions and code.</p>
|
|
623
|
+
</div>
|
|
624
|
+
</div>
|
|
625
|
+
</section>
|
|
626
|
+
<section id="compare" class="fade-in">
|
|
627
|
+
<h2 class="section-title">How nano-brain Compares</h2>
|
|
628
|
+
<p class="section-subtitle">The only MCP memory server with a full hybrid search pipeline — BM25 + vector + query expansion + LLM reranking. All local.</p>
|
|
629
|
+
<div class="compare-table-wrap">
|
|
630
|
+
<table class="compare-table">
|
|
631
|
+
<thead>
|
|
632
|
+
<tr>
|
|
633
|
+
<th>Feature</th>
|
|
634
|
+
<th class="highlight">nano-brain</th>
|
|
635
|
+
<th>Mem0</th>
|
|
636
|
+
<th>Zep</th>
|
|
637
|
+
<th>OMEGA</th>
|
|
638
|
+
<th>Letta</th>
|
|
639
|
+
</tr>
|
|
640
|
+
</thead>
|
|
641
|
+
<tbody>
|
|
642
|
+
<tr>
|
|
643
|
+
<td>Search</td>
|
|
644
|
+
<td class="highlight">BM25 + Vector + Reranking</td>
|
|
645
|
+
<td>Vector only</td>
|
|
646
|
+
<td>Graph + Vector</td>
|
|
647
|
+
<td>Semantic + BM25</td>
|
|
648
|
+
<td>Agent-managed</td>
|
|
649
|
+
</tr>
|
|
650
|
+
<tr>
|
|
651
|
+
<td>Storage</td>
|
|
652
|
+
<td class="highlight">SQLite (single file)</td>
|
|
653
|
+
<td>PostgreSQL + Qdrant</td>
|
|
654
|
+
<td>Neo4j</td>
|
|
655
|
+
<td>SQLite</td>
|
|
656
|
+
<td>PostgreSQL</td>
|
|
657
|
+
</tr>
|
|
658
|
+
<tr>
|
|
659
|
+
<td>Local AI Models</td>
|
|
660
|
+
<td class="highlight">GGUF (nomic + bge)</td>
|
|
661
|
+
<td>Cloud API</td>
|
|
662
|
+
<td>Cloud API</td>
|
|
663
|
+
<td>ONNX</td>
|
|
664
|
+
<td>Cloud API</td>
|
|
665
|
+
</tr>
|
|
666
|
+
<tr>
|
|
667
|
+
<td>Codebase Indexing</td>
|
|
668
|
+
<td class="highlight">✓</td>
|
|
669
|
+
<td>✗</td>
|
|
670
|
+
<td>✗</td>
|
|
671
|
+
<td>✗</td>
|
|
672
|
+
<td>✗</td>
|
|
673
|
+
</tr>
|
|
674
|
+
<tr>
|
|
675
|
+
<td>Session Recall</td>
|
|
676
|
+
<td class="highlight">✓</td>
|
|
677
|
+
<td>✗</td>
|
|
678
|
+
<td>✗</td>
|
|
679
|
+
<td>✗</td>
|
|
680
|
+
<td>✗</td>
|
|
681
|
+
</tr>
|
|
682
|
+
<tr>
|
|
683
|
+
<td>Query Expansion</td>
|
|
684
|
+
<td class="highlight">✓</td>
|
|
685
|
+
<td>✗</td>
|
|
686
|
+
<td>✗</td>
|
|
687
|
+
<td>✗</td>
|
|
688
|
+
<td>✗</td>
|
|
689
|
+
</tr>
|
|
690
|
+
<tr>
|
|
691
|
+
<td>LLM Reranking</td>
|
|
692
|
+
<td class="highlight">✓</td>
|
|
693
|
+
<td>✗</td>
|
|
694
|
+
<td>✗</td>
|
|
695
|
+
<td>✗</td>
|
|
696
|
+
<td>✗</td>
|
|
697
|
+
</tr>
|
|
698
|
+
<tr>
|
|
699
|
+
<td>Privacy</td>
|
|
700
|
+
<td class="highlight">100% local</td>
|
|
701
|
+
<td>Cloud API calls</td>
|
|
702
|
+
<td>Cloud / self-host</td>
|
|
703
|
+
<td>100% local</td>
|
|
704
|
+
<td>Self-host / cloud</td>
|
|
705
|
+
</tr>
|
|
706
|
+
<tr>
|
|
707
|
+
<td>External Deps</td>
|
|
708
|
+
<td class="highlight">None</td>
|
|
709
|
+
<td>Docker + PG + Qdrant</td>
|
|
710
|
+
<td>Docker + Neo4j</td>
|
|
711
|
+
<td>None</td>
|
|
712
|
+
<td>PostgreSQL</td>
|
|
713
|
+
</tr>
|
|
714
|
+
<tr>
|
|
715
|
+
<td>Pricing</td>
|
|
716
|
+
<td class="highlight">Free (MIT)</td>
|
|
717
|
+
<td>Free / $249/mo</td>
|
|
718
|
+
<td>Free / $25-475/mo</td>
|
|
719
|
+
<td>Free (Apache-2.0)</td>
|
|
720
|
+
<td>Free (Apache-2.0)</td>
|
|
721
|
+
</tr>
|
|
722
|
+
</tbody>
|
|
723
|
+
</table>
|
|
724
|
+
</div>
|
|
725
|
+
</section>
|
|
726
|
+
<section id="how" class="fade-in">
|
|
727
|
+
<h2 class="section-title">How It Works</h2>
|
|
728
|
+
<p class="section-subtitle">
|
|
729
|
+
Query expansion and dual retrieval streams converge through RRF fusion (k=60), then a reranker refines the final ordering.
|
|
730
|
+
</p>
|
|
731
|
+
<div class="pipeline">
|
|
732
|
+
<div class="pipeline-row">
|
|
733
|
+
<div class="node">Query</div>
|
|
734
|
+
<div class="connector"></div>
|
|
735
|
+
<div class="node">Query Expansion</div>
|
|
736
|
+
</div>
|
|
737
|
+
<div class="merge"></div>
|
|
738
|
+
<div class="pipeline-row split">
|
|
739
|
+
<div class="node">BM25 Search</div>
|
|
740
|
+
<div class="node">Vector Search</div>
|
|
741
|
+
</div>
|
|
742
|
+
<div class="merge"></div>
|
|
743
|
+
<div class="pipeline-row">
|
|
744
|
+
<div class="node">RRF Fusion (k=60)</div>
|
|
745
|
+
<div class="connector"></div>
|
|
746
|
+
<div class="node">LLM Reranking</div>
|
|
747
|
+
<div class="connector"></div>
|
|
748
|
+
<div class="node">Results</div>
|
|
749
|
+
</div>
|
|
750
|
+
</div>
|
|
751
|
+
</section>
|
|
752
|
+
<section id="api" class="fade-in">
|
|
753
|
+
<h2 class="section-title">API Reference</h2>
|
|
754
|
+
<p class="section-subtitle">MCP tools for hybrid search, retrieval, and maintenance.</p>
|
|
755
|
+
<div class="grid api-grid">
|
|
756
|
+
<div class="api-card">
|
|
757
|
+
<h4><span class="chip">memory_search</span></h4>
|
|
758
|
+
<p>BM25 keyword search.</p>
|
|
759
|
+
<div class="params">
|
|
760
|
+
<span class="chip">query (required)</span>
|
|
761
|
+
<span class="chip">limit (default 10)</span>
|
|
762
|
+
<span class="chip">collection</span>
|
|
763
|
+
<span class="chip">workspace</span>
|
|
764
|
+
</div>
|
|
765
|
+
</div>
|
|
766
|
+
<div class="api-card">
|
|
767
|
+
<h4><span class="chip">memory_vsearch</span></h4>
|
|
768
|
+
<p>Semantic vector search using embeddings.</p>
|
|
769
|
+
<div class="params">
|
|
770
|
+
<span class="chip">query (required)</span>
|
|
771
|
+
<span class="chip">limit (default 10)</span>
|
|
772
|
+
<span class="chip">collection</span>
|
|
773
|
+
<span class="chip">workspace</span>
|
|
774
|
+
</div>
|
|
775
|
+
</div>
|
|
776
|
+
<div class="api-card">
|
|
777
|
+
<h4><span class="chip">memory_query</span></h4>
|
|
778
|
+
<p>Full hybrid search with query expansion, RRF fusion, and LLM reranking.</p>
|
|
779
|
+
<div class="params">
|
|
780
|
+
<span class="chip">query (required)</span>
|
|
781
|
+
<span class="chip">limit (default 10)</span>
|
|
782
|
+
<span class="chip">collection</span>
|
|
783
|
+
<span class="chip">minScore</span>
|
|
784
|
+
<span class="chip">workspace</span>
|
|
785
|
+
</div>
|
|
786
|
+
</div>
|
|
787
|
+
<div class="api-card">
|
|
788
|
+
<h4><span class="chip">memory_get</span></h4>
|
|
789
|
+
<p>Retrieve document by path or docid (#abc123).</p>
|
|
790
|
+
<div class="params">
|
|
791
|
+
<span class="chip">id (required)</span>
|
|
792
|
+
<span class="chip">fromLine</span>
|
|
793
|
+
<span class="chip">maxLines</span>
|
|
794
|
+
</div>
|
|
795
|
+
</div>
|
|
796
|
+
<div class="api-card">
|
|
797
|
+
<h4><span class="chip">memory_multi_get</span></h4>
|
|
798
|
+
<p>Batch retrieve by glob pattern.</p>
|
|
799
|
+
<div class="params">
|
|
800
|
+
<span class="chip">pattern (required)</span>
|
|
801
|
+
<span class="chip">maxBytes (default 50000)</span>
|
|
802
|
+
</div>
|
|
803
|
+
</div>
|
|
804
|
+
<div class="api-card">
|
|
805
|
+
<h4><span class="chip">memory_write</span></h4>
|
|
806
|
+
<p>Write to daily log or MEMORY.md.</p>
|
|
807
|
+
<div class="params">
|
|
808
|
+
<span class="chip">content (required)</span>
|
|
809
|
+
<span class="chip">target ("daily" or "memory")</span>
|
|
810
|
+
</div>
|
|
811
|
+
</div>
|
|
812
|
+
<div class="api-card">
|
|
813
|
+
<h4><span class="chip">memory_status</span></h4>
|
|
814
|
+
<p>Show index health, collections, model status.</p>
|
|
815
|
+
<div class="params">
|
|
816
|
+
<span class="chip">no params</span>
|
|
817
|
+
</div>
|
|
818
|
+
</div>
|
|
819
|
+
<div class="api-card">
|
|
820
|
+
<h4><span class="chip">memory_update</span></h4>
|
|
821
|
+
<p>Trigger immediate reindex of all collections.</p>
|
|
822
|
+
<div class="params">
|
|
823
|
+
<span class="chip">no params</span>
|
|
824
|
+
</div>
|
|
825
|
+
<div class="api-card">
|
|
826
|
+
<h4><span class="chip">memory_index_codebase</span></h4>
|
|
827
|
+
<p>Index source files in the current workspace.</p>
|
|
828
|
+
<div class="params">
|
|
829
|
+
<span class="chip">root (optional)</span>
|
|
830
|
+
</div>
|
|
831
|
+
</div>
|
|
832
|
+
</div>
|
|
833
|
+
</div>
|
|
834
|
+
</section>
|
|
835
|
+
<section id="config" class="fade-in">
|
|
836
|
+
<h2 class="section-title">Configuration</h2>
|
|
837
|
+
<p class="section-subtitle">Drop this MCP config into your OpenCode settings.</p>
|
|
838
|
+
<pre class="codeblock"><code>{
|
|
839
|
+
<span class="token-string">"mcp"</span>: {
|
|
840
|
+
<span class="token-string">"nano-brain"</span>: {
|
|
841
|
+
<span class="token-string">"type"</span>: <span class="token-string">"local"</span>,
|
|
842
|
+
<span class="token-string">"command"</span>: [<span class="token-string">"node"</span>, <span class="token-string">"path/to/nano-brain/bin/cli.js"</span>, <span class="token-string">"mcp"</span>],
|
|
843
|
+
<span class="token-string">"enabled"</span>: <span class="token-boolean">true</span>
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}</code></pre>
|
|
847
|
+
<pre class="codeblock"><code><span class="token-comment"># ~/.config/nano-brain/config.yml</span>
|
|
848
|
+
<span class="token-key">collections</span>:
|
|
849
|
+
<span class="token-key">memory</span>:
|
|
850
|
+
<span class="token-key">path</span>: <span class="token-string">~/.nano-brain</span>
|
|
851
|
+
<span class="token-key">pattern</span>: <span class="token-string">"**/*.md"</span>
|
|
852
|
+
<span class="token-key">update</span>: <span class="token-string">auto</span>
|
|
853
|
+
<span class="token-key">sessions</span>:
|
|
854
|
+
<span class="token-key">path</span>: <span class="token-string">~/.local/share/opencode/sessions</span>
|
|
855
|
+
<span class="token-key">pattern</span>: <span class="token-string">"**/*.json"</span>
|
|
856
|
+
<span class="token-key">update</span>: <span class="token-string">auto</span></code></pre>
|
|
857
|
+
</section>
|
|
858
|
+
<section id="quick-start" class="fade-in">
|
|
859
|
+
<h2 class="section-title">Quick Start</h2>
|
|
860
|
+
<p class="section-subtitle">CLI workflows for MCP, search, and indexing.</p>
|
|
861
|
+
<pre class="codeblock"><code><span class="token-comment"># MCP server</span>
|
|
862
|
+
nano-brain mcp <span class="token-comment"># Start MCP server (stdio)</span>
|
|
863
|
+
nano-brain mcp --http <span class="token-comment"># Start MCP server (HTTP)</span>
|
|
864
|
+
|
|
865
|
+
<span class="token-comment"># Search</span>
|
|
866
|
+
nano-brain search "query" <span class="token-comment"># BM25 search</span>
|
|
867
|
+
nano-brain query "query" <span class="token-comment"># Hybrid search</span>
|
|
868
|
+
|
|
869
|
+
<span class="token-comment"># Index management</span>
|
|
870
|
+
nano-brain status <span class="token-comment"># Show index health</span>
|
|
871
|
+
nano-brain update <span class="token-comment"># Reindex all collections</span></code></pre>
|
|
872
|
+
</section>
|
|
873
|
+
<section id="models" class="fade-in">
|
|
874
|
+
<h2 class="section-title">Models</h2>
|
|
875
|
+
<p class="section-subtitle">Local GGUF models sized for efficient offline retrieval.</p>
|
|
876
|
+
<div class="grid models">
|
|
877
|
+
<div class="model-card">
|
|
878
|
+
<h4>nomic-embed-text-v1.5 (~270MB)</h4>
|
|
879
|
+
<p>Embeddings</p>
|
|
880
|
+
</div>
|
|
881
|
+
<div class="model-card">
|
|
882
|
+
<h4>bge-reranker-v2-m3 (~1.1GB)</h4>
|
|
883
|
+
<p>Reranking</p>
|
|
884
|
+
</div>
|
|
885
|
+
<div class="model-card">
|
|
886
|
+
<h4>qmd-query-expansion-1.7B (~1GB)</h4>
|
|
887
|
+
<p>Query Expansion</p>
|
|
888
|
+
</div>
|
|
889
|
+
</div>
|
|
890
|
+
</section>
|
|
891
|
+
<section id="tech" class="fade-in">
|
|
892
|
+
<h2 class="section-title">Tech Stack</h2>
|
|
893
|
+
<div class="tech-stack">
|
|
894
|
+
<span class="tech-pill">TypeScript</span>
|
|
895
|
+
<span class="tech-pill">Bun</span>
|
|
896
|
+
<span class="tech-pill">SQLite</span>
|
|
897
|
+
<span class="tech-pill">sqlite-vec</span>
|
|
898
|
+
<span class="tech-pill">FTS5</span>
|
|
899
|
+
<span class="tech-pill">node-llama-cpp</span>
|
|
900
|
+
<span class="tech-pill">MCP SDK</span>
|
|
901
|
+
<span class="tech-pill">chokidar</span>
|
|
902
|
+
</div>
|
|
903
|
+
</section>
|
|
904
|
+
<div class="stats fade-in">2700+ documents indexed | 15 workspaces | 3 AI models | 10 MCP tools | 428 tests passing</div>
|
|
905
|
+
<footer>
|
|
906
|
+
<div>MIT License · Inspired by <a href="https://github.com/tobi/qmd">QMD</a> & <a href="https://github.com/openclaw/openclaw">OpenClaw</a></div>
|
|
907
|
+
<div>
|
|
908
|
+
<a href="https://github.com/kokorolx/nano-brain">GitHub</a>
|
|
909
|
+
</div>
|
|
910
|
+
</footer>
|
|
911
|
+
</div>
|
|
912
|
+
|
|
913
|
+
<script>
|
|
914
|
+
const observer = new IntersectionObserver(
|
|
915
|
+
(entries) => {
|
|
916
|
+
entries.forEach((entry) => {
|
|
917
|
+
if (entry.isIntersecting) {
|
|
918
|
+
entry.target.classList.add('visible')
|
|
919
|
+
}
|
|
920
|
+
})
|
|
921
|
+
},
|
|
922
|
+
{ threshold: 0.15 }
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
document.querySelectorAll('.fade-in').forEach((el) => observer.observe(el))
|
|
926
|
+
|
|
927
|
+
</script>
|
|
928
|
+
</body>
|
|
929
|
+
</html>
|