@nano-step/nano-brain 2026.1.14
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/.opencode/command/nano-brain-init.md +13 -0
- package/.opencode/command/nano-brain-reindex.md +11 -0
- package/.opencode/command/nano-brain-status.md +12 -0
- package/AGENTS.md +41 -0
- package/AGENTS_SNIPPET.md +44 -0
- package/CHANGELOG.md +186 -0
- package/README.md +298 -0
- package/SKILL.md +109 -0
- package/bin/cli.js +29 -0
- package/commands/nano-brain-init.md +36 -0
- package/commands/nano-brain-reindex.md +31 -0
- package/commands/nano-brain-status.md +32 -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/changes/fix-session-harvest-workspace-scoping/.openspec.yaml +2 -0
- package/openspec/changes/fix-session-harvest-workspace-scoping/design.md +84 -0
- package/openspec/changes/fix-session-harvest-workspace-scoping/proposal.md +26 -0
- package/openspec/changes/fix-session-harvest-workspace-scoping/specs/workspace-scoping/spec.md +65 -0
- package/openspec/changes/fix-session-harvest-workspace-scoping/tasks.md +33 -0
- package/openspec/changes/performance-and-search-quality/.openspec.yaml +2 -0
- package/openspec/changes/performance-and-search-quality/proposal.md +37 -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 +37 -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 +425 -0
- package/src/collections.ts +217 -0
- package/src/embeddings.ts +325 -0
- package/src/expansion.ts +79 -0
- package/src/harvester.ts +306 -0
- package/src/index.ts +778 -0
- package/src/reranker.ts +103 -0
- package/src/search.ts +294 -0
- package/src/server.ts +876 -0
- package/src/storage.ts +221 -0
- package/src/store.ts +653 -0
- package/src/types.ts +215 -0
- package/src/watcher.ts +389 -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 +219 -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 +530 -0
- package/test/watcher.test.ts +717 -0
- package/test/workspace.test.ts +239 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# workspace-scoping Specification
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
TBD - created by archiving change workspace-scoped-memory-and-storage-limits. Update Purpose after archive.
|
|
5
|
+
## Requirements
|
|
6
|
+
### Requirement: Workspace detection from PWD
|
|
7
|
+
The MCP server SHALL compute a `projectHash` from `process.cwd()` at startup using `sha256(cwd).substring(0, 12)`. This hash SHALL be stored as `currentProjectHash` on the server context and used for all default search filtering.
|
|
8
|
+
|
|
9
|
+
#### Scenario: Server starts in a workspace directory
|
|
10
|
+
- **WHEN** the MCP server starts with `PWD=/Users/alice/projects/my-app`
|
|
11
|
+
- **THEN** `currentProjectHash` is set to the first 12 characters of `sha256("/Users/alice/projects/my-app")`
|
|
12
|
+
- **THEN** the hash is consistent across restarts in the same directory
|
|
13
|
+
|
|
14
|
+
#### Scenario: Hash matches harvester convention
|
|
15
|
+
- **WHEN** the MCP server computes `currentProjectHash` for a workspace
|
|
16
|
+
- **THEN** the hash matches the directory name used by the harvester for that workspace's sessions (`sessions/{projectHash}/*.md`)
|
|
17
|
+
|
|
18
|
+
### Requirement: Document-level project tagging
|
|
19
|
+
The `documents` table SHALL have a `project_hash TEXT` column. Every document indexed from a session file SHALL be tagged with the projectHash extracted from its file path. Non-session documents (MEMORY.md, daily logs) SHALL be tagged with `'global'`.
|
|
20
|
+
|
|
21
|
+
#### Scenario: New document indexed from session file
|
|
22
|
+
- **WHEN** a document is indexed from path `sessions/abc123def456/session-title.md`
|
|
23
|
+
- **THEN** the document's `project_hash` column is set to `abc123def456`
|
|
24
|
+
|
|
25
|
+
#### Scenario: New document indexed from non-session file
|
|
26
|
+
- **WHEN** a document is indexed from `MEMORY.md` or a daily log file
|
|
27
|
+
- **THEN** the document's `project_hash` column is set to `'global'`
|
|
28
|
+
|
|
29
|
+
#### Scenario: Document path does not match session pattern
|
|
30
|
+
- **WHEN** a document is indexed from a path that does not match `sessions/{hash}/*.md`
|
|
31
|
+
- **THEN** the document's `project_hash` column is set to `'global'`
|
|
32
|
+
|
|
33
|
+
### Requirement: Database migration for existing documents
|
|
34
|
+
On startup, the store SHALL add the `project_hash` column if it does not exist, then backfill existing documents by extracting the projectHash from their file paths.
|
|
35
|
+
|
|
36
|
+
#### Scenario: First startup after upgrade
|
|
37
|
+
- **WHEN** the store opens a database that lacks the `project_hash` column
|
|
38
|
+
- **THEN** the column is added via `ALTER TABLE documents ADD COLUMN project_hash TEXT DEFAULT 'global'`
|
|
39
|
+
- **THEN** existing documents with paths matching `sessions/{hash}/*.md` are updated with the correct projectHash
|
|
40
|
+
- **THEN** existing documents not matching the pattern retain `project_hash = 'global'`
|
|
41
|
+
|
|
42
|
+
#### Scenario: Subsequent startup
|
|
43
|
+
- **WHEN** the store opens a database that already has the `project_hash` column
|
|
44
|
+
- **THEN** no migration runs
|
|
45
|
+
- **THEN** no data is modified
|
|
46
|
+
|
|
47
|
+
### Requirement: Default search scoping to current workspace
|
|
48
|
+
All search operations SHALL filter results to documents matching `currentProjectHash` or `'global'` by default. This ensures searches return only results relevant to the current workspace plus cross-project notes.
|
|
49
|
+
|
|
50
|
+
#### Scenario: Search without workspace parameter
|
|
51
|
+
- **WHEN** `memory_search` is called with `{"query": "authentication"}` and no `workspace` parameter
|
|
52
|
+
- **THEN** only documents with `project_hash = currentProjectHash` or `project_hash = 'global'` are returned
|
|
53
|
+
- **THEN** documents from other workspaces are excluded
|
|
54
|
+
|
|
55
|
+
#### Scenario: Global documents always included
|
|
56
|
+
- **WHEN** a search is performed with default workspace scoping
|
|
57
|
+
- **THEN** MEMORY.md entries and daily logs (tagged `'global'`) are included in results
|
|
58
|
+
- **THEN** session documents from other workspaces are excluded
|
|
59
|
+
|
|
60
|
+
### Requirement: Cross-workspace search opt-in
|
|
61
|
+
All search tools SHALL accept an optional `workspace` parameter. When set to `"all"`, search results SHALL include documents from all workspaces. When set to a specific hash, results SHALL be filtered to that workspace plus `'global'`.
|
|
62
|
+
|
|
63
|
+
#### Scenario: Search with workspace="all"
|
|
64
|
+
- **WHEN** `memory_search` is called with `{"query": "auth", "workspace": "all"}`
|
|
65
|
+
- **THEN** documents from all workspaces are included in results
|
|
66
|
+
|
|
67
|
+
#### Scenario: Search with specific workspace hash
|
|
68
|
+
- **WHEN** `memory_search` is called with `{"query": "auth", "workspace": "abc123def456"}`
|
|
69
|
+
- **THEN** only documents with `project_hash = 'abc123def456'` or `project_hash = 'global'` are returned
|
|
70
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nano-step/nano-brain",
|
|
3
|
+
"version": "2026.1.14",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"nano-brain": "./bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "src/index.ts",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "bun src/index.ts",
|
|
11
|
+
"start": "node bin/cli.js",
|
|
12
|
+
"mcp": "node bin/cli.js mcp",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"lint:esm": "! grep -r 'require(' src/ --include='*.ts'"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
19
|
+
"better-sqlite3": "^12.6.2",
|
|
20
|
+
"chokidar": "^5.0.0",
|
|
21
|
+
"fast-glob": "^3.3.3",
|
|
22
|
+
"node-llama-cpp": "^3.3.3",
|
|
23
|
+
"sqlite-vec": "^0.1.7-alpha.2",
|
|
24
|
+
"tsx": "^4.21.0",
|
|
25
|
+
"yaml": "^2.8.2",
|
|
26
|
+
"zod": "^4.3.6"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
30
|
+
"bun-types": "^1.3.9",
|
|
31
|
+
"typescript": "^5.9.3",
|
|
32
|
+
"vitest": "^4.0.18"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/site/build.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, writeFileSync, readdirSync, watchFile, statSync } from 'node:fs'
|
|
4
|
+
import { join, dirname, resolve } from 'node:path'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
8
|
+
const __dirname = dirname(__filename)
|
|
9
|
+
|
|
10
|
+
const SITE_DIR = __dirname
|
|
11
|
+
const ROOT_DIR = resolve(SITE_DIR, '..')
|
|
12
|
+
const PARTIALS_DIR = join(SITE_DIR, 'partials')
|
|
13
|
+
const OUTPUT = join(ROOT_DIR, 'index.html')
|
|
14
|
+
|
|
15
|
+
function readFile(path) {
|
|
16
|
+
return readFileSync(path, 'utf-8')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function build() {
|
|
20
|
+
const start = Date.now()
|
|
21
|
+
|
|
22
|
+
let shell = readFile(join(SITE_DIR, 'shell.html'))
|
|
23
|
+
const styles = readFile(join(SITE_DIR, 'styles.css'))
|
|
24
|
+
const script = readFile(join(SITE_DIR, 'script.js'))
|
|
25
|
+
|
|
26
|
+
shell = shell.replace('{{styles}}', styles)
|
|
27
|
+
shell = shell.replace('{{script}}', script)
|
|
28
|
+
|
|
29
|
+
shell = shell.replace(/\{\{partial:([a-z0-9-]+)\}\}/g, (_match, name) => {
|
|
30
|
+
const partialPath = join(PARTIALS_DIR, `_${name}.html`)
|
|
31
|
+
try {
|
|
32
|
+
return readFile(partialPath).trimEnd()
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(` ❌ Missing partial: ${partialPath}`)
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
writeFileSync(OUTPUT, shell, 'utf-8')
|
|
40
|
+
|
|
41
|
+
const size = statSync(OUTPUT).size
|
|
42
|
+
const kb = (size / 1024).toFixed(1)
|
|
43
|
+
const ms = Date.now() - start
|
|
44
|
+
console.log(` ✅ Built index.html (${kb} KB) in ${ms}ms`)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log('🔨 Building nano-brain landing page...')
|
|
48
|
+
build()
|
|
49
|
+
|
|
50
|
+
if (process.argv.includes('--watch')) {
|
|
51
|
+
console.log('👀 Watching for changes...')
|
|
52
|
+
|
|
53
|
+
const watchTargets = [
|
|
54
|
+
join(SITE_DIR, 'shell.html'),
|
|
55
|
+
join(SITE_DIR, 'styles.css'),
|
|
56
|
+
join(SITE_DIR, 'script.js'),
|
|
57
|
+
...readdirSync(PARTIALS_DIR).map((f) => join(PARTIALS_DIR, f)),
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
for (const file of watchTargets) {
|
|
61
|
+
watchFile(file, { interval: 300 }, () => {
|
|
62
|
+
console.log(` 🔄 Changed: ${file.replace(ROOT_DIR + '/', '')}`)
|
|
63
|
+
build()
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<section id="api" class="fade-in">
|
|
2
|
+
<h2 class="section-title">API Reference</h2>
|
|
3
|
+
<p class="section-subtitle">MCP tools for hybrid search, retrieval, and maintenance.</p>
|
|
4
|
+
<div class="grid api-grid">
|
|
5
|
+
<div class="api-card">
|
|
6
|
+
<h4><span class="chip">memory_search</span></h4>
|
|
7
|
+
<p>BM25 keyword search.</p>
|
|
8
|
+
<div class="params">
|
|
9
|
+
<span class="chip">query (required)</span>
|
|
10
|
+
<span class="chip">limit (default 10)</span>
|
|
11
|
+
<span class="chip">collection</span>
|
|
12
|
+
<span class="chip">workspace</span>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="api-card">
|
|
16
|
+
<h4><span class="chip">memory_vsearch</span></h4>
|
|
17
|
+
<p>Semantic vector search using embeddings.</p>
|
|
18
|
+
<div class="params">
|
|
19
|
+
<span class="chip">query (required)</span>
|
|
20
|
+
<span class="chip">limit (default 10)</span>
|
|
21
|
+
<span class="chip">collection</span>
|
|
22
|
+
<span class="chip">workspace</span>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="api-card">
|
|
26
|
+
<h4><span class="chip">memory_query</span></h4>
|
|
27
|
+
<p>Full hybrid search with query expansion, RRF fusion, and LLM reranking.</p>
|
|
28
|
+
<div class="params">
|
|
29
|
+
<span class="chip">query (required)</span>
|
|
30
|
+
<span class="chip">limit (default 10)</span>
|
|
31
|
+
<span class="chip">collection</span>
|
|
32
|
+
<span class="chip">minScore</span>
|
|
33
|
+
<span class="chip">workspace</span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="api-card">
|
|
37
|
+
<h4><span class="chip">memory_get</span></h4>
|
|
38
|
+
<p>Retrieve document by path or docid (#abc123).</p>
|
|
39
|
+
<div class="params">
|
|
40
|
+
<span class="chip">id (required)</span>
|
|
41
|
+
<span class="chip">fromLine</span>
|
|
42
|
+
<span class="chip">maxLines</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="api-card">
|
|
46
|
+
<h4><span class="chip">memory_multi_get</span></h4>
|
|
47
|
+
<p>Batch retrieve by glob pattern.</p>
|
|
48
|
+
<div class="params">
|
|
49
|
+
<span class="chip">pattern (required)</span>
|
|
50
|
+
<span class="chip">maxBytes (default 50000)</span>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="api-card">
|
|
54
|
+
<h4><span class="chip">memory_write</span></h4>
|
|
55
|
+
<p>Write to daily log or MEMORY.md.</p>
|
|
56
|
+
<div class="params">
|
|
57
|
+
<span class="chip">content (required)</span>
|
|
58
|
+
<span class="chip">target ("daily" or "memory")</span>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="api-card">
|
|
62
|
+
<h4><span class="chip">memory_status</span></h4>
|
|
63
|
+
<p>Show index health, collections, model status.</p>
|
|
64
|
+
<div class="params">
|
|
65
|
+
<span class="chip">no params</span>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="api-card">
|
|
69
|
+
<h4><span class="chip">memory_update</span></h4>
|
|
70
|
+
<p>Trigger immediate reindex of all collections.</p>
|
|
71
|
+
<div class="params">
|
|
72
|
+
<span class="chip">no params</span>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="api-card">
|
|
75
|
+
<h4><span class="chip">memory_index_codebase</span></h4>
|
|
76
|
+
<p>Index source files in the current workspace.</p>
|
|
77
|
+
<div class="params">
|
|
78
|
+
<span class="chip">root (optional)</span>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</section>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<section id="compare" class="fade-in">
|
|
2
|
+
<h2 class="section-title">How nano-brain Compares</h2>
|
|
3
|
+
<p class="section-subtitle">The only MCP memory server with a full hybrid search pipeline — BM25 + vector + query expansion + LLM reranking. All local.</p>
|
|
4
|
+
<div class="compare-table-wrap">
|
|
5
|
+
<table class="compare-table">
|
|
6
|
+
<thead>
|
|
7
|
+
<tr>
|
|
8
|
+
<th>Feature</th>
|
|
9
|
+
<th class="highlight">nano-brain</th>
|
|
10
|
+
<th>Mem0</th>
|
|
11
|
+
<th>Zep</th>
|
|
12
|
+
<th>OMEGA</th>
|
|
13
|
+
<th>Letta</th>
|
|
14
|
+
</tr>
|
|
15
|
+
</thead>
|
|
16
|
+
<tbody>
|
|
17
|
+
<tr>
|
|
18
|
+
<td>Search</td>
|
|
19
|
+
<td class="highlight">BM25 + Vector + Reranking</td>
|
|
20
|
+
<td>Vector only</td>
|
|
21
|
+
<td>Graph + Vector</td>
|
|
22
|
+
<td>Semantic + BM25</td>
|
|
23
|
+
<td>Agent-managed</td>
|
|
24
|
+
</tr>
|
|
25
|
+
<tr>
|
|
26
|
+
<td>Storage</td>
|
|
27
|
+
<td class="highlight">SQLite (single file)</td>
|
|
28
|
+
<td>PostgreSQL + Qdrant</td>
|
|
29
|
+
<td>Neo4j</td>
|
|
30
|
+
<td>SQLite</td>
|
|
31
|
+
<td>PostgreSQL</td>
|
|
32
|
+
</tr>
|
|
33
|
+
<tr>
|
|
34
|
+
<td>Local AI Models</td>
|
|
35
|
+
<td class="highlight">GGUF (nomic + bge)</td>
|
|
36
|
+
<td>Cloud API</td>
|
|
37
|
+
<td>Cloud API</td>
|
|
38
|
+
<td>ONNX</td>
|
|
39
|
+
<td>Cloud API</td>
|
|
40
|
+
</tr>
|
|
41
|
+
<tr>
|
|
42
|
+
<td>Codebase Indexing</td>
|
|
43
|
+
<td class="highlight">✓</td>
|
|
44
|
+
<td>✗</td>
|
|
45
|
+
<td>✗</td>
|
|
46
|
+
<td>✗</td>
|
|
47
|
+
<td>✗</td>
|
|
48
|
+
</tr>
|
|
49
|
+
<tr>
|
|
50
|
+
<td>Session Recall</td>
|
|
51
|
+
<td class="highlight">✓</td>
|
|
52
|
+
<td>✗</td>
|
|
53
|
+
<td>✗</td>
|
|
54
|
+
<td>✗</td>
|
|
55
|
+
<td>✗</td>
|
|
56
|
+
</tr>
|
|
57
|
+
<tr>
|
|
58
|
+
<td>Query Expansion</td>
|
|
59
|
+
<td class="highlight">✓</td>
|
|
60
|
+
<td>✗</td>
|
|
61
|
+
<td>✗</td>
|
|
62
|
+
<td>✗</td>
|
|
63
|
+
<td>✗</td>
|
|
64
|
+
</tr>
|
|
65
|
+
<tr>
|
|
66
|
+
<td>LLM Reranking</td>
|
|
67
|
+
<td class="highlight">✓</td>
|
|
68
|
+
<td>✗</td>
|
|
69
|
+
<td>✗</td>
|
|
70
|
+
<td>✗</td>
|
|
71
|
+
<td>✗</td>
|
|
72
|
+
</tr>
|
|
73
|
+
<tr>
|
|
74
|
+
<td>Privacy</td>
|
|
75
|
+
<td class="highlight">100% local</td>
|
|
76
|
+
<td>Cloud API calls</td>
|
|
77
|
+
<td>Cloud / self-host</td>
|
|
78
|
+
<td>100% local</td>
|
|
79
|
+
<td>Self-host / cloud</td>
|
|
80
|
+
</tr>
|
|
81
|
+
<tr>
|
|
82
|
+
<td>External Deps</td>
|
|
83
|
+
<td class="highlight">None</td>
|
|
84
|
+
<td>Docker + PG + Qdrant</td>
|
|
85
|
+
<td>Docker + Neo4j</td>
|
|
86
|
+
<td>None</td>
|
|
87
|
+
<td>PostgreSQL</td>
|
|
88
|
+
</tr>
|
|
89
|
+
<tr>
|
|
90
|
+
<td>Pricing</td>
|
|
91
|
+
<td class="highlight">Free (MIT)</td>
|
|
92
|
+
<td>Free / $249/mo</td>
|
|
93
|
+
<td>Free / $25-475/mo</td>
|
|
94
|
+
<td>Free (Apache-2.0)</td>
|
|
95
|
+
<td>Free (Apache-2.0)</td>
|
|
96
|
+
</tr>
|
|
97
|
+
</tbody>
|
|
98
|
+
</table>
|
|
99
|
+
</div>
|
|
100
|
+
</section>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<section id="config" class="fade-in">
|
|
2
|
+
<h2 class="section-title">Configuration</h2>
|
|
3
|
+
<p class="section-subtitle">Drop this MCP config into your OpenCode settings.</p>
|
|
4
|
+
<pre class="codeblock"><code>{
|
|
5
|
+
<span class="token-string">"mcp"</span>: {
|
|
6
|
+
<span class="token-string">"nano-brain"</span>: {
|
|
7
|
+
<span class="token-string">"type"</span>: <span class="token-string">"local"</span>,
|
|
8
|
+
<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>],
|
|
9
|
+
<span class="token-string">"enabled"</span>: <span class="token-boolean">true</span>
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}</code></pre>
|
|
13
|
+
<pre class="codeblock"><code><span class="token-comment"># ~/.config/nano-brain/config.yml</span>
|
|
14
|
+
<span class="token-key">collections</span>:
|
|
15
|
+
<span class="token-key">memory</span>:
|
|
16
|
+
<span class="token-key">path</span>: <span class="token-string">~/.nano-brain</span>
|
|
17
|
+
<span class="token-key">pattern</span>: <span class="token-string">"**/*.md"</span>
|
|
18
|
+
<span class="token-key">update</span>: <span class="token-string">auto</span>
|
|
19
|
+
<span class="token-key">sessions</span>:
|
|
20
|
+
<span class="token-key">path</span>: <span class="token-string">~/.local/share/opencode/sessions</span>
|
|
21
|
+
<span class="token-key">pattern</span>: <span class="token-string">"**/*.json"</span>
|
|
22
|
+
<span class="token-key">update</span>: <span class="token-string">auto</span></code></pre>
|
|
23
|
+
</section>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<section id="features" class="fade-in">
|
|
2
|
+
<h2 class="section-title">Features</h2>
|
|
3
|
+
<p class="section-subtitle">
|
|
4
|
+
Premium local memory with a hybrid search pipeline, SQLite foundations, codebase indexing, and MCP-first ergonomics.
|
|
5
|
+
</p>
|
|
6
|
+
<div class="grid features">
|
|
7
|
+
<div class="card">
|
|
8
|
+
<div class="icon">🔍</div>
|
|
9
|
+
<h3>Hybrid Search Pipeline</h3>
|
|
10
|
+
<p>Query expansion → parallel BM25 + vector search → RRF fusion → LLM reranking</p>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="card">
|
|
13
|
+
<div class="icon">🧠</div>
|
|
14
|
+
<h3>Local AI Models</h3>
|
|
15
|
+
<p>nomic-embed-text-v1.5, bge-reranker-v2-m3, qmd-query-expansion-1.7B — all GGUF, fully offline</p>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="card">
|
|
18
|
+
<div class="icon">🗄️</div>
|
|
19
|
+
<h3>SQLite + sqlite-vec</h3>
|
|
20
|
+
<p>FTS5 for BM25 keyword search, sqlite-vec for vector similarity — single-file database</p>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="card">
|
|
23
|
+
<div class="icon">🔌</div>
|
|
24
|
+
<h3>MCP Server</h3>
|
|
25
|
+
<p>10 tools via stdio transport, integrates with any MCP-compatible AI agent</p>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="card">
|
|
28
|
+
<div class="icon">📚</div>
|
|
29
|
+
<h3>Multi-Collection</h3>
|
|
30
|
+
<p>Sessions, daily logs, curated memory — all indexed and searchable</p>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="card">
|
|
33
|
+
<div class="icon">🔒</div>
|
|
34
|
+
<h3>Privacy First</h3>
|
|
35
|
+
<p>100% local processing, no cloud dependencies, your data stays on your machine</p>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="card">
|
|
38
|
+
<div class="icon">🧬</div>
|
|
39
|
+
<h3>Codebase Indexing</h3>
|
|
40
|
+
<p>Index source files with structural boundary detection. Workspace-scoped search across sessions and code.</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</section>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<section class="hero fade-in" id="hero">
|
|
2
|
+
<span class="badge">v2026.1.0</span>
|
|
3
|
+
<h1>nano-brain</h1>
|
|
4
|
+
<p>Persistent hybrid search memory for AI coding agents.</p>
|
|
5
|
+
<div class="hero-actions">
|
|
6
|
+
<a class="button primary" href="https://github.com/kokorolx/nano-brain">GitHub</a>
|
|
7
|
+
<span class="code-pill">npm i nano-brain</span>
|
|
8
|
+
</div>
|
|
9
|
+
</section>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<section id="how" class="fade-in">
|
|
2
|
+
<h2 class="section-title">How It Works</h2>
|
|
3
|
+
<p class="section-subtitle">
|
|
4
|
+
Query expansion and dual retrieval streams converge through RRF fusion (k=60), then a reranker refines the final ordering.
|
|
5
|
+
</p>
|
|
6
|
+
<div class="pipeline">
|
|
7
|
+
<div class="pipeline-row">
|
|
8
|
+
<div class="node">Query</div>
|
|
9
|
+
<div class="connector"></div>
|
|
10
|
+
<div class="node">Query Expansion</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="merge"></div>
|
|
13
|
+
<div class="pipeline-row split">
|
|
14
|
+
<div class="node">BM25 Search</div>
|
|
15
|
+
<div class="node">Vector Search</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="merge"></div>
|
|
18
|
+
<div class="pipeline-row">
|
|
19
|
+
<div class="node">RRF Fusion (k=60)</div>
|
|
20
|
+
<div class="connector"></div>
|
|
21
|
+
<div class="node">LLM Reranking</div>
|
|
22
|
+
<div class="connector"></div>
|
|
23
|
+
<div class="node">Results</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</section>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<section id="models" class="fade-in">
|
|
2
|
+
<h2 class="section-title">Models</h2>
|
|
3
|
+
<p class="section-subtitle">Local GGUF models sized for efficient offline retrieval.</p>
|
|
4
|
+
<div class="grid models">
|
|
5
|
+
<div class="model-card">
|
|
6
|
+
<h4>nomic-embed-text-v1.5 (~270MB)</h4>
|
|
7
|
+
<p>Embeddings</p>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="model-card">
|
|
10
|
+
<h4>bge-reranker-v2-m3 (~1.1GB)</h4>
|
|
11
|
+
<p>Reranking</p>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="model-card">
|
|
14
|
+
<h4>qmd-query-expansion-1.7B (~1GB)</h4>
|
|
15
|
+
<p>Query Expansion</p>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</section>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<section id="quick-start" class="fade-in">
|
|
2
|
+
<h2 class="section-title">Quick Start</h2>
|
|
3
|
+
<p class="section-subtitle">CLI workflows for MCP, search, and indexing.</p>
|
|
4
|
+
<pre class="codeblock"><code><span class="token-comment"># MCP server</span>
|
|
5
|
+
nano-brain mcp <span class="token-comment"># Start MCP server (stdio)</span>
|
|
6
|
+
nano-brain mcp --http <span class="token-comment"># Start MCP server (HTTP)</span>
|
|
7
|
+
|
|
8
|
+
<span class="token-comment"># Search</span>
|
|
9
|
+
nano-brain search "query" <span class="token-comment"># BM25 search</span>
|
|
10
|
+
nano-brain query "query" <span class="token-comment"># Hybrid search</span>
|
|
11
|
+
|
|
12
|
+
<span class="token-comment"># Index management</span>
|
|
13
|
+
nano-brain status <span class="token-comment"># Show index health</span>
|
|
14
|
+
nano-brain update <span class="token-comment"># Reindex all collections</span></code></pre>
|
|
15
|
+
</section>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<div class="stats fade-in">2700+ documents indexed | 15 workspaces | 3 AI models | 10 MCP tools | 428 tests passing</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<section id="tech" class="fade-in">
|
|
2
|
+
<h2 class="section-title">Tech Stack</h2>
|
|
3
|
+
<div class="tech-stack">
|
|
4
|
+
<span class="tech-pill">TypeScript</span>
|
|
5
|
+
<span class="tech-pill">Bun</span>
|
|
6
|
+
<span class="tech-pill">SQLite</span>
|
|
7
|
+
<span class="tech-pill">sqlite-vec</span>
|
|
8
|
+
<span class="tech-pill">FTS5</span>
|
|
9
|
+
<span class="tech-pill">node-llama-cpp</span>
|
|
10
|
+
<span class="tech-pill">MCP SDK</span>
|
|
11
|
+
<span class="tech-pill">chokidar</span>
|
|
12
|
+
</div>
|
|
13
|
+
</section>
|
package/site/script.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const observer = new IntersectionObserver(
|
|
2
|
+
(entries) => {
|
|
3
|
+
entries.forEach((entry) => {
|
|
4
|
+
if (entry.isIntersecting) {
|
|
5
|
+
entry.target.classList.add('visible')
|
|
6
|
+
}
|
|
7
|
+
})
|
|
8
|
+
},
|
|
9
|
+
{ threshold: 0.15 }
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
document.querySelectorAll('.fade-in').forEach((el) => observer.observe(el))
|
package/site/shell.html
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
{{styles}}
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<header class="nav">
|
|
13
|
+
<div class="nav-inner">
|
|
14
|
+
<div class="brand"><span class="brand-dot"></span>nano-brain</div>
|
|
15
|
+
<nav class="nav-links">
|
|
16
|
+
<a href="#features">Features</a>
|
|
17
|
+
<a href="#compare">Compare</a>
|
|
18
|
+
<a href="#how">How It Works</a>
|
|
19
|
+
<a href="#api">API</a>
|
|
20
|
+
<a href="#config">Config</a>
|
|
21
|
+
<a href="#models">Models</a>
|
|
22
|
+
</nav>
|
|
23
|
+
</div>
|
|
24
|
+
</header>
|
|
25
|
+
|
|
26
|
+
<div class="page">
|
|
27
|
+
{{partial:hero}}
|
|
28
|
+
{{partial:features}}
|
|
29
|
+
{{partial:compare}}
|
|
30
|
+
{{partial:how-it-works}}
|
|
31
|
+
{{partial:api}}
|
|
32
|
+
{{partial:config}}
|
|
33
|
+
{{partial:quick-start}}
|
|
34
|
+
{{partial:models}}
|
|
35
|
+
{{partial:tech-stack}}
|
|
36
|
+
{{partial:stats}}
|
|
37
|
+
{{partial:footer}}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<script>
|
|
41
|
+
{{script}}
|
|
42
|
+
</script>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|