@nano-step/nano-brain 2026.1.14 → 2026.5.25-beta.25
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/README.md +228 -245
- package/npm/postinstall.js +89 -0
- package/npm/run.js +22 -0
- package/package.json +24 -28
- package/.opencode/command/nano-brain-init.md +0 -13
- package/.opencode/command/nano-brain-reindex.md +0 -11
- package/.opencode/command/nano-brain-status.md +0 -12
- package/AGENTS.md +0 -41
- package/AGENTS_SNIPPET.md +0 -44
- package/CHANGELOG.md +0 -186
- package/SKILL.md +0 -109
- package/bin/cli.js +0 -29
- package/commands/nano-brain-init.md +0 -36
- package/commands/nano-brain-reindex.md +0 -31
- package/commands/nano-brain-status.md +0 -32
- package/index.html +0 -929
- package/nano-brain +0 -4
- package/opencode-mcp.json +0 -9
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/design.md +0 -68
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/proposal.md +0 -27
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/specs/mcp-integration-testing/spec.md +0 -50
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/specs/mcp-server/spec.md +0 -40
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/specs/search-pipeline/spec.md +0 -29
- package/openspec/changes/archive/2026-02-16-fix-mcp-server-bugs/tasks.md +0 -37
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/design.md +0 -111
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/proposal.md +0 -30
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/specs/mcp-server/spec.md +0 -33
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/specs/storage-limits/spec.md +0 -90
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/specs/workspace-scoping/spec.md +0 -66
- package/openspec/changes/archive/2026-02-23-workspace-scoped-memory-and-storage-limits/tasks.md +0 -199
- package/openspec/changes/codebase-indexing/.openspec.yaml +0 -2
- package/openspec/changes/codebase-indexing/design.md +0 -169
- package/openspec/changes/codebase-indexing/proposal.md +0 -30
- package/openspec/changes/codebase-indexing/specs/codebase-collection/spec.md +0 -187
- package/openspec/changes/codebase-indexing/specs/mcp-server/spec.md +0 -36
- package/openspec/changes/codebase-indexing/tasks.md +0 -56
- package/openspec/changes/fix-session-harvest-workspace-scoping/.openspec.yaml +0 -2
- package/openspec/changes/fix-session-harvest-workspace-scoping/design.md +0 -84
- package/openspec/changes/fix-session-harvest-workspace-scoping/proposal.md +0 -26
- package/openspec/changes/fix-session-harvest-workspace-scoping/specs/workspace-scoping/spec.md +0 -65
- package/openspec/changes/fix-session-harvest-workspace-scoping/tasks.md +0 -33
- package/openspec/changes/performance-and-search-quality/.openspec.yaml +0 -2
- package/openspec/changes/performance-and-search-quality/proposal.md +0 -37
- package/openspec/specs/mcp-integration-testing/spec.md +0 -50
- package/openspec/specs/mcp-server/spec.md +0 -75
- package/openspec/specs/search-pipeline/spec.md +0 -29
- package/openspec/specs/storage-limits/spec.md +0 -94
- package/openspec/specs/workspace-scoping/spec.md +0 -70
- package/site/build.js +0 -66
- package/site/partials/_api.html +0 -83
- package/site/partials/_compare.html +0 -100
- package/site/partials/_config.html +0 -23
- package/site/partials/_features.html +0 -43
- package/site/partials/_footer.html +0 -6
- package/site/partials/_hero.html +0 -9
- package/site/partials/_how-it-works.html +0 -26
- package/site/partials/_models.html +0 -18
- package/site/partials/_quick-start.html +0 -15
- package/site/partials/_stats.html +0 -1
- package/site/partials/_tech-stack.html +0 -13
- package/site/script.js +0 -12
- package/site/shell.html +0 -44
- package/site/styles.css +0 -548
- package/src/chunker.ts +0 -427
- package/src/codebase.ts +0 -425
- package/src/collections.ts +0 -217
- package/src/embeddings.ts +0 -325
- package/src/expansion.ts +0 -79
- package/src/harvester.ts +0 -306
- package/src/index.ts +0 -778
- package/src/reranker.ts +0 -103
- package/src/search.ts +0 -294
- package/src/server.ts +0 -876
- package/src/storage.ts +0 -221
- package/src/store.ts +0 -653
- package/src/types.ts +0 -215
- package/src/watcher.ts +0 -389
- package/test/chunker.test.ts +0 -479
- package/test/cli.test.ts +0 -309
- package/test/codebase-chunker.test.ts +0 -446
- package/test/codebase.test.ts +0 -678
- package/test/collections.test.ts +0 -571
- package/test/harvester.test.ts +0 -636
- package/test/integration.test.ts +0 -219
- package/test/llm.test.ts +0 -322
- package/test/search.test.ts +0 -572
- package/test/server.test.ts +0 -541
- package/test/storage.test.ts +0 -302
- package/test/store.test.ts +0 -530
- package/test/watcher.test.ts +0 -717
- package/test/workspace.test.ts +0 -239
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -16
package/README.md
CHANGED
|
@@ -1,297 +1,280 @@
|
|
|
1
1
|
# nano-brain
|
|
2
2
|
|
|
3
|
-
Persistent memory
|
|
3
|
+
**Persistent memory and code intelligence for AI coding agents.**
|
|
4
|
+
|
|
5
|
+
[](https://go.dev/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/nano-step/nano-brain)
|
|
4
8
|
|
|
5
9
|
## What It Does
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
nano-brain is a persistent memory server for AI coding agents that solves session amnesia. It automatically ingests AI sessions, notes, and codebase files, indexes everything with hybrid search (BM25 + pgvector), and serves memories via MCP tools and REST API. Built in Go with PostgreSQL — single static binary, zero CGO dependencies.
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
## Key Features
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
- **Hybrid search** — BM25 full-text + pgvector HNSW cosine similarity + RRF fusion + recency decay
|
|
16
|
+
- **9 MCP tools** — query, search, vsearch, get, write, tags, status, update, wake_up
|
|
17
|
+
- **Session harvesting** — auto-ingest OpenCode and Claude Code sessions
|
|
18
|
+
- **File watcher** — fsnotify-based directory monitoring with debounce
|
|
19
|
+
- **Content-addressed storage** — SHA-256 deduplication
|
|
20
|
+
- **Heading-aware markdown chunking**
|
|
21
|
+
- **Multi-workspace isolation** with per-workspace data
|
|
22
|
+
- **Config hot-reload** — `POST /api/reload-config`
|
|
23
|
+
- **V1 migration** — import from SQLite (pure Go, no CGO)
|
|
24
|
+
- **Benchmarking suite** — generate, run, compare, stress
|
|
25
|
+
- **Search telemetry** — local-only, 90-day retention, non-blocking
|
|
12
26
|
|
|
13
|
-
|
|
14
|
-
User Query
|
|
15
|
-
│
|
|
16
|
-
▼
|
|
17
|
-
┌─────────────────┐
|
|
18
|
-
│ Query Expansion │ ← qmd-query-expansion-1.7B (GGUF)
|
|
19
|
-
│ (optional) │ generates 2-3 query variants
|
|
20
|
-
└────────┬────────┘
|
|
21
|
-
│
|
|
22
|
-
┌────┴────┐
|
|
23
|
-
▼ ▼
|
|
24
|
-
┌────────┐ ┌──────────┐
|
|
25
|
-
│ BM25 │ │ Vector │
|
|
26
|
-
│ (FTS5) │ │(sqlite- │
|
|
27
|
-
│ │ │ vec) │
|
|
28
|
-
└───┬────┘ └────┬─────┘
|
|
29
|
-
│ │
|
|
30
|
-
▼ ▼
|
|
31
|
-
┌─────────────────┐
|
|
32
|
-
│ RRF Fusion │ ← k=60, original query 2× weight
|
|
33
|
-
│ │
|
|
34
|
-
└────────┬────────┘
|
|
35
|
-
│
|
|
36
|
-
▼
|
|
37
|
-
┌─────────────────┐
|
|
38
|
-
│ LLM Reranking │ ← bge-reranker-v2-m3 (GGUF)
|
|
39
|
-
│ (optional) │
|
|
40
|
-
└────────┬────────┘
|
|
41
|
-
│
|
|
42
|
-
▼
|
|
43
|
-
┌─────────────────┐
|
|
44
|
-
│ Position-Aware │ ← top 3: 75/25, 4-10: 60/40, 11+: 40/60
|
|
45
|
-
│ Blending │ (RRF weight / rerank weight)
|
|
46
|
-
└────────┬────────┘
|
|
47
|
-
│
|
|
48
|
-
▼
|
|
49
|
-
Final Results
|
|
50
|
-
```
|
|
27
|
+
## Prerequisites
|
|
51
28
|
|
|
52
|
-
|
|
29
|
+
- **Go 1.23+** (building from source) OR pre-built binary
|
|
30
|
+
- **PostgreSQL 17** with **pgvector 0.8.2** extension
|
|
31
|
+
- **Embedding provider:** Ollama (default, local) or Voyage AI
|
|
53
32
|
|
|
54
|
-
|
|
33
|
+
## Quick Start
|
|
55
34
|
|
|
56
|
-
|
|
57
|
-
- **FTS5** virtual table with porter stemming for BM25 full-text search
|
|
58
|
-
- **sqlite-vec** extension for vector similarity search (cosine distance)
|
|
59
|
-
- **Content-addressed storage** using SHA-256 hash deduplication
|
|
35
|
+
### Option A: Via npx (no Go required)
|
|
60
36
|
|
|
61
|
-
|
|
37
|
+
```bash
|
|
38
|
+
# Start PostgreSQL + pgvector
|
|
39
|
+
docker run -d --name nanobrain-pg -p 5432:5432 \
|
|
40
|
+
-e POSTGRES_USER=nanobrain -e POSTGRES_PASSWORD=nanobrain -e POSTGRES_DB=nanobrain_dev \
|
|
41
|
+
pgvector/pgvector:pg17
|
|
62
42
|
|
|
63
|
-
|
|
43
|
+
# Start Ollama + pull embedding model
|
|
44
|
+
ollama pull nomic-embed-text
|
|
64
45
|
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
- **Respects boundaries:** Code fences, headings, paragraphs
|
|
68
|
-
- **Break point scoring:** h1=100, h2=90, h3=80, code-fence=80, hr=60, blank-line=40
|
|
46
|
+
# Check prerequisites
|
|
47
|
+
npx @nano-step/nano-brain@beta doctor
|
|
69
48
|
|
|
70
|
-
|
|
49
|
+
# Start server
|
|
50
|
+
npx @nano-step/nano-brain@beta
|
|
51
|
+
```
|
|
71
52
|
|
|
72
|
-
|
|
53
|
+
> **Also available as:** `npx nano-brain@beta` (unscoped alias)
|
|
54
|
+
>
|
|
55
|
+
> **Note:** Do NOT run `npx nano-brain` from the nano-brain source directory — npm will resolve the local package instead of the registry. Run from any other directory.
|
|
73
56
|
|
|
74
|
-
|
|
57
|
+
### Option B: Build from source
|
|
75
58
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
3. RRF fusion (k=60, original query weighted 2×)
|
|
80
|
-
4. LLM reranking with bge-reranker-v2-m3 (optional)
|
|
81
|
-
5. Position-aware blending:
|
|
82
|
-
- Top 3 results: 75% RRF / 25% rerank
|
|
83
|
-
- Ranks 4-10: 60% RRF / 40% rerank
|
|
84
|
-
- Ranks 11+: 40% RRF / 60% rerank
|
|
59
|
+
```bash
|
|
60
|
+
# Build
|
|
61
|
+
CGO_ENABLED=0 go build -o nano-brain ./cmd/nano-brain
|
|
85
62
|
|
|
86
|
-
|
|
63
|
+
# Start PostgreSQL + pgvector (example with Docker)
|
|
64
|
+
docker run -d --name nanobrain-pg -p 5432:5432 \
|
|
65
|
+
-e POSTGRES_USER=nanobrain -e POSTGRES_PASSWORD=nanobrain -e POSTGRES_DB=nanobrain_dev \
|
|
66
|
+
pgvector/pgvector:pg17
|
|
87
67
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- **Incremental updates** using dirty-flag tracking
|
|
91
|
-
- **Session harvesting** converts OpenCode JSON sessions into searchable markdown
|
|
68
|
+
# Start server
|
|
69
|
+
DATABASE_URL="postgres://nanobrain:nanobrain@localhost:5432/nanobrain_dev" ./nano-brain
|
|
92
70
|
|
|
93
|
-
|
|
71
|
+
# Register workspace
|
|
72
|
+
curl -X POST http://localhost:3100/api/v1/init \
|
|
73
|
+
-H "Content-Type: application/json" \
|
|
74
|
+
-d '{"root_path":"/path/to/project","name":"my-project"}'
|
|
94
75
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
| `memory_index_codebase` | Index codebase files in current workspace |
|
|
105
|
-
| `memory_update` | Trigger reindex of all collections |
|
|
106
|
-
|
|
107
|
-
## Installation
|
|
108
|
-
```bash
|
|
109
|
-
npm install -g nano-brain
|
|
76
|
+
# Write a document
|
|
77
|
+
curl -X POST http://localhost:3100/api/v1/write \
|
|
78
|
+
-H "Content-Type: application/json" \
|
|
79
|
+
-d '{"workspace":"<hash>","source_path":"notes/decision.md","content":"# Decision\nUse PostgreSQL.","tags":["decision"]}'
|
|
80
|
+
|
|
81
|
+
# Search
|
|
82
|
+
curl -X POST http://localhost:3100/api/v1/query \
|
|
83
|
+
-H "Content-Type: application/json" \
|
|
84
|
+
-d '{"workspace":"<hash>","query":"database decision"}'
|
|
110
85
|
```
|
|
111
86
|
|
|
112
|
-
|
|
87
|
+
## Configuration
|
|
113
88
|
|
|
114
|
-
|
|
115
|
-
# Initialize (creates config, indexes codebase, generates embeddings)
|
|
116
|
-
npx nano-brain init --root=/path/to/your/project
|
|
89
|
+
Config file: `~/.nano-brain/config.yml`
|
|
117
90
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
91
|
+
```yaml
|
|
92
|
+
server:
|
|
93
|
+
host: localhost
|
|
94
|
+
port: 3100
|
|
121
95
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
"mcp": {
|
|
126
|
-
"nano-brain": {
|
|
127
|
-
"type": "local",
|
|
128
|
-
"command": ["npx", "nano-brain", "mcp"],
|
|
129
|
-
"enabled": true
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
```
|
|
96
|
+
database:
|
|
97
|
+
url: postgres://nanobrain:nanobrain@localhost:5432/nanobrain_dev
|
|
134
98
|
|
|
135
|
-
## Configuration
|
|
136
|
-
Create `~/.nano-brain/config.yml` (auto-generated by `init`):
|
|
137
|
-
```yaml
|
|
138
|
-
collections:
|
|
139
|
-
memory:
|
|
140
|
-
path: ~/.nano-brain/memory
|
|
141
|
-
pattern: "**/*.md"
|
|
142
|
-
update: auto
|
|
143
|
-
sessions:
|
|
144
|
-
path: ~/.nano-brain/sessions
|
|
145
|
-
pattern: "**/*.md"
|
|
146
|
-
update: auto
|
|
147
|
-
|
|
148
|
-
# Embedding configuration
|
|
149
99
|
embedding:
|
|
150
|
-
provider: ollama
|
|
151
|
-
url: http://localhost:11434
|
|
100
|
+
provider: ollama # ollama or voyage
|
|
101
|
+
url: http://localhost:11434
|
|
152
102
|
model: nomic-embed-text
|
|
103
|
+
dimension: 0 # auto-detect from provider
|
|
104
|
+
concurrency: 3
|
|
105
|
+
|
|
106
|
+
search:
|
|
107
|
+
rrf_k: 60
|
|
108
|
+
recency_weight: 0.3
|
|
109
|
+
recency_half_life_days: 180
|
|
110
|
+
limit: 20
|
|
111
|
+
|
|
112
|
+
harvester:
|
|
113
|
+
opencode:
|
|
114
|
+
session_dir: "" # e.g., ~/.local/share/opencode/storage
|
|
115
|
+
claudecode:
|
|
116
|
+
enabled: false
|
|
117
|
+
session_dir: ""
|
|
118
|
+
|
|
119
|
+
watcher:
|
|
120
|
+
debounce_ms: 2000
|
|
121
|
+
reindex_interval: 300
|
|
122
|
+
|
|
123
|
+
storage:
|
|
124
|
+
max_file_size: 314572800 # 300MB
|
|
125
|
+
max_size: 10737418240 # 10GB
|
|
126
|
+
|
|
127
|
+
telemetry:
|
|
128
|
+
retention_days: 90
|
|
129
|
+
|
|
130
|
+
logging:
|
|
131
|
+
level: info
|
|
132
|
+
file: "" # empty = stdout only
|
|
153
133
|
```
|
|
154
134
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
135
|
+
### Environment Variables
|
|
136
|
+
|
|
137
|
+
| Variable | Description |
|
|
138
|
+
|----------|-------------|
|
|
139
|
+
| `DATABASE_URL` | PostgreSQL connection string |
|
|
140
|
+
| `VOYAGE_API_KEY` | Voyage AI API key |
|
|
141
|
+
| `OPENCODE_STORAGE_DIR` | OpenCode session directory |
|
|
142
|
+
| `NANO_BRAIN_*` | Override any config (e.g., `NANO_BRAIN_SERVER_PORT=3100`) |
|
|
143
|
+
|
|
144
|
+
## REST API
|
|
145
|
+
|
|
146
|
+
### Public Endpoints
|
|
147
|
+
|
|
148
|
+
| Method | Path | Description |
|
|
149
|
+
|--------|------|-------------|
|
|
150
|
+
| GET | `/health` | Health check |
|
|
151
|
+
| GET | `/api/status` | Server status with version, uptime, workspace stats |
|
|
152
|
+
| POST | `/api/v1/init` | Register workspace |
|
|
153
|
+
| GET | `/api/v1/workspaces` | List all workspaces (with doc counts) |
|
|
154
|
+
| GET | `/api/v1/wake-up` | Workspace briefing |
|
|
155
|
+
| POST | `/api/harvest` | Trigger session harvesting |
|
|
156
|
+
| POST | `/api/reload-config` | Hot-reload configuration |
|
|
157
|
+
|
|
158
|
+
### Workspace-Scoped Endpoints
|
|
159
|
+
|
|
160
|
+
Workspace is passed in the JSON body for POST, query param for GET.
|
|
161
|
+
|
|
162
|
+
| Method | Path | Description |
|
|
163
|
+
|--------|------|-------------|
|
|
164
|
+
| POST | `/api/v1/write` | Write/update document |
|
|
165
|
+
| POST | `/api/v1/embed` | Trigger embedding |
|
|
166
|
+
| POST | `/api/v1/search` | BM25 keyword search |
|
|
167
|
+
| POST | `/api/v1/vsearch` | Vector similarity search |
|
|
168
|
+
| POST | `/api/v1/query` | Hybrid search (BM25 + vector + RRF + recency) |
|
|
169
|
+
| POST | `/api/v1/collections` | Add collection |
|
|
170
|
+
| GET | `/api/v1/collections` | List collections |
|
|
171
|
+
| PUT | `/api/v1/collections/:name` | Rename collection |
|
|
172
|
+
| DELETE | `/api/v1/collections/:name` | Remove collection |
|
|
173
|
+
| GET | `/api/v1/tags` | List tags with counts |
|
|
174
|
+
| POST | `/api/v1/reindex` | Queue reindex (202) |
|
|
175
|
+
| POST | `/api/v1/update` | Queue update (202) |
|
|
176
|
+
| POST | `/api/v1/wake-up` | Workspace briefing with session_dir |
|
|
177
|
+
|
|
178
|
+
### MCP Endpoints
|
|
179
|
+
|
|
180
|
+
| Method | Path | Description |
|
|
181
|
+
|--------|------|-------------|
|
|
182
|
+
| GET/POST | `/mcp` | Streamable HTTP (MCP 2025-03-26) |
|
|
183
|
+
| GET/POST | `/sse` | SSE transport (legacy) |
|
|
184
|
+
|
|
185
|
+
## CLI Commands
|
|
186
|
+
|
|
187
|
+
| Command | Description |
|
|
188
|
+
|---------|-------------|
|
|
189
|
+
| `nano-brain` (no args) | Start HTTP server (default: port 3100) |
|
|
190
|
+
| `nano-brain init --root=<path>` | Register workspace |
|
|
191
|
+
| `nano-brain write` | Write document via CLI |
|
|
192
|
+
| `nano-brain query` | Hybrid search |
|
|
193
|
+
| `nano-brain search` | BM25 keyword search |
|
|
194
|
+
| `nano-brain vsearch` | Vector similarity search |
|
|
195
|
+
| `nano-brain collection add\|remove\|list` | Manage collections |
|
|
196
|
+
| `nano-brain harvest` | Trigger session harvesting |
|
|
197
|
+
| `nano-brain bench generate\|run\|compare\|stress` | Benchmarking suite |
|
|
198
|
+
| `nano-brain db:migrate` | Run pending goose migrations |
|
|
199
|
+
| `nano-brain db:migrate --from-v1 <path>` | Import V1 SQLite data |
|
|
200
|
+
| `nano-brain logs [-n 50] [-f]` | Tail log file |
|
|
201
|
+
| `nano-brain docker start\|stop\|status` | Docker compose management |
|
|
202
|
+
| `nano-brain status [--json]` | Server status |
|
|
203
|
+
| `nano-brain doctor [--json]` | Check prerequisites (config, PostgreSQL, pgvector, Ollama, model) |
|
|
159
204
|
|
|
160
|
-
|
|
161
|
-
- `provider` — `ollama` (default)
|
|
162
|
-
- `url` — Ollama API URL (auto-detected during `init`)
|
|
163
|
-
- `model` — Embedding model name (default: `nomic-embed-text`)
|
|
205
|
+
## MCP Tools
|
|
164
206
|
|
|
165
|
-
|
|
166
|
-
```
|
|
167
|
-
~/.nano-brain/
|
|
168
|
-
├── config.yml # Configuration
|
|
169
|
-
├── data/ # SQLite databases (per-workspace)
|
|
170
|
-
├── models/ # Embedding model cache
|
|
171
|
-
├── memory/ # Curated notes
|
|
172
|
-
└── sessions/ # Harvested sessions
|
|
173
|
-
```
|
|
207
|
+
nano-brain exposes 9 tools via MCP (Model Context Protocol):
|
|
174
208
|
|
|
175
|
-
|
|
209
|
+
| Tool | Description |
|
|
210
|
+
|------|-------------|
|
|
211
|
+
| `memory_query` | Hybrid search (BM25 + vector + RRF + recency) |
|
|
212
|
+
| `memory_search` | BM25 keyword search |
|
|
213
|
+
| `memory_vsearch` | Vector similarity search |
|
|
214
|
+
| `memory_get` | Get document by path |
|
|
215
|
+
| `memory_write` | Write/update document |
|
|
216
|
+
| `memory_tags` | List tags with counts |
|
|
217
|
+
| `memory_status` | Server and embedding status |
|
|
218
|
+
| `memory_update` | Trigger re-embedding |
|
|
219
|
+
| `memory_wake_up` | Workspace briefing |
|
|
220
|
+
|
|
221
|
+
### MCP Configuration
|
|
176
222
|
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
nano-brain
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
nano-brain update # Reindex all collections
|
|
187
|
-
# Search
|
|
188
|
-
nano-brain search "query" # BM25 search
|
|
189
|
-
nano-brain vsearch "query" # Vector search
|
|
190
|
-
nano-brain query "query" # Hybrid search
|
|
191
|
-
# Collections
|
|
192
|
-
nano-brain collection add <name> <path> # Add collection
|
|
193
|
-
nano-brain collection remove <name> # Remove collection
|
|
194
|
-
nano-brain collection list # List collections
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"mcp": {
|
|
226
|
+
"nano-brain": {
|
|
227
|
+
"type": "remote",
|
|
228
|
+
"url": "http://localhost:3100/mcp"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
195
232
|
```
|
|
196
233
|
|
|
197
|
-
##
|
|
234
|
+
## Search Pipeline
|
|
198
235
|
|
|
199
236
|
```
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
├── store.ts # SQLite storage (FTS5 + sqlite-vec)
|
|
204
|
-
├── search.ts # Hybrid search pipeline (RRF, reranking, blending)
|
|
205
|
-
├── chunker.ts # Heading-aware markdown chunking
|
|
206
|
-
├── collections.ts # YAML config, collection scanning
|
|
207
|
-
├── embeddings.ts # Embedding providers (Ollama API + GGUF fallback)
|
|
208
|
-
├── reranker.ts # GGUF reranker model (bge-reranker-v2-m3)
|
|
209
|
-
├── expansion.ts # GGUF query expansion (qmd-query-expansion-1.7B)
|
|
210
|
-
├── harvester.ts # OpenCode session → markdown converter
|
|
211
|
-
├── watcher.ts # File watcher (chokidar, dirty flags)
|
|
212
|
-
└── types.ts # TypeScript interfaces
|
|
213
|
-
bin/
|
|
214
|
-
└── cli.js # CLI wrapper
|
|
215
|
-
|
|
216
|
-
test/
|
|
217
|
-
└── *.test.ts # 428 tests (vitest)
|
|
218
|
-
SKILL.md # AI agent routing instructions (auto-loaded by OpenCode)
|
|
219
|
-
AGENTS_SNIPPET.md # Optional project-level AGENTS.md managed block
|
|
237
|
+
Query --> BM25 (ts_rank_cd) ---+
|
|
238
|
+
+--> RRF Fusion (k=60) --> Recency Decay --> Results
|
|
239
|
+
Query --> Vector (HNSW cos) ---+
|
|
220
240
|
```
|
|
221
241
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
- **
|
|
225
|
-
- **
|
|
226
|
-
- **@modelcontextprotocol/sdk** for MCP server
|
|
227
|
-
- **node-llama-cpp** for GGUF model inference
|
|
228
|
-
- **chokidar** for file watching
|
|
229
|
-
- **vitest** for testing (428 tests)
|
|
230
|
-
|
|
231
|
-
## Models
|
|
232
|
-
|
|
233
|
-
All models are GGUF format, loaded on-demand:
|
|
234
|
-
|
|
235
|
-
- **Embeddings:** nomic-embed-text-v1.5 (~270MB)
|
|
236
|
-
- **Reranker:** bge-reranker-v2-m3 (~1.1GB)
|
|
237
|
-
- **Query Expansion:** qmd-query-expansion-1.7B (~1GB)
|
|
242
|
+
- **BM25:** `websearch_to_tsquery` + `ts_rank_cd` on PostgreSQL tsvector
|
|
243
|
+
- **Vector:** pgvector HNSW index with cosine distance
|
|
244
|
+
- **RRF:** Reciprocal Rank Fusion (k=60), scores normalized to [0,1]
|
|
245
|
+
- **Recency:** exponential half-life decay (default 180 days, weight 0.3)
|
|
238
246
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
## How nano-brain Compares
|
|
242
|
-
|
|
243
|
-
| | nano-brain | Mem0 / OpenMemory | Zep / Graphiti | OMEGA | Letta (MemGPT) | Claude Native |
|
|
244
|
-
|---|---|---|---|---|---|---|
|
|
245
|
-
| **Search** | Hybrid (BM25 + vector + LLM reranking) | Vector only | Graph traversal + vector | Semantic + BM25 | Agent-managed | Text file read |
|
|
246
|
-
| **Storage** | SQLite (single file) | PostgreSQL + Qdrant | Neo4j | SQLite | PostgreSQL / SQLite | Flat text files |
|
|
247
|
-
| **MCP Tools** | 10 | 4-9 | 9-10 | 12 | 7 | 0 |
|
|
248
|
-
| **Local-First** | Yes (zero cloud) | Requires OpenAI API key | Requires Docker + Neo4j | Yes | Yes | Yes |
|
|
249
|
-
| **AI Models** | Local GGUF (nomic-embed, bge-reranker) | Cloud API (OpenAI) | Cloud API | Local ONNX | Cloud API | None |
|
|
250
|
-
| **Codebase Indexing** | Yes (structural boundary detection) | No | No | No | No | No |
|
|
251
|
-
| **Session Recall** | Yes (auto-harvests past sessions) | No | No | No | No | Limited (CLAUDE.md) |
|
|
252
|
-
| **Query Expansion** | Yes (local LLM) | No | No | No | No | No |
|
|
253
|
-
| **LLM Reranking** | Yes (bge-reranker-v2-m3) | No | No | No | No | No |
|
|
254
|
-
| **Privacy** | 100% local, no data leaves machine | Cloud API calls | Cloud or self-host | 100% local | Self-host or cloud | Local files |
|
|
255
|
-
| **Dependencies** | SQLite + GGUF models (~1.5GB) | Docker + PostgreSQL + Qdrant + OpenAI key | Docker + Neo4j | SQLite + ONNX | PostgreSQL | None |
|
|
256
|
-
| **Pricing** | Free (open source, MIT) | Free tier / Pro $249/mo | Free self-host / Cloud $25-475/mo | Free (Apache-2.0) | Free (Apache-2.0) | Free (with Claude) |
|
|
257
|
-
| **GitHub Stars** | New | ~47K | ~23K | ~25 | ~21K | N/A |
|
|
258
|
-
|
|
259
|
-
### Where nano-brain shines
|
|
260
|
-
|
|
261
|
-
- **Hybrid search pipeline** — the only MCP memory server with BM25 + vector + query expansion + LLM reranking in a single pipeline
|
|
262
|
-
- **Codebase indexing** — index your source files with structural boundary detection, not just conversations
|
|
263
|
-
- **Session recall** — automatically harvests and indexes past AI coding sessions
|
|
264
|
-
- **Zero dependencies** — single SQLite file, local GGUF models, no Docker/PostgreSQL/Neo4j/API keys
|
|
265
|
-
- **Privacy** — 100% local processing, your code and conversations never leave your machine
|
|
266
|
-
|
|
267
|
-
### Consider alternatives if
|
|
268
|
-
|
|
269
|
-
- You need a knowledge graph with temporal reasoning (Zep/Graphiti)
|
|
270
|
-
- You want a full agent framework, not just memory (Letta)
|
|
271
|
-
- You need cloud-hosted memory shared across teams (Mem0 Cloud)
|
|
272
|
-
- You only need basic session notes (Claude native memory)
|
|
273
|
-
|
|
274
|
-
## AI Agent Integration
|
|
275
|
-
|
|
276
|
-
nano-brain ships with a SKILL.md that teaches AI agents when and how to use memory tools. When loaded as an OpenCode skill, agents automatically:
|
|
277
|
-
|
|
278
|
-
- **Check memory before starting work** — recall past decisions, patterns, and context
|
|
279
|
-
- **Save context after completing work** — persist key decisions and debugging insights
|
|
280
|
-
- **Route queries to the right search tool** — BM25 for exact terms, vector for concepts, hybrid for best quality
|
|
281
|
-
|
|
282
|
-
### SKILL.md (Auto-loaded)
|
|
283
|
-
|
|
284
|
-
The skill file at `SKILL.md` provides routing rules, trigger phrases, tool selection guides, and integration patterns. It's automatically loaded when any agent references the `nano-brain` skill.
|
|
247
|
+
## Architecture
|
|
285
248
|
|
|
286
|
-
|
|
249
|
+
- 15 internal packages: config, server, handlers, storage, sqlc, embed, search, watcher, harvest, mcp, migrate, telemetry, health, bench
|
|
250
|
+
- 7 goose SQL migrations (embedded)
|
|
251
|
+
- Constructor injection (no DI framework)
|
|
252
|
+
- errgroup + context for goroutine lifecycle
|
|
253
|
+
- Echo v4 middleware: workspace extraction, content-type enforcement, version header
|
|
287
254
|
|
|
288
|
-
|
|
255
|
+
## Migration from V1
|
|
289
256
|
|
|
290
257
|
```bash
|
|
291
|
-
|
|
258
|
+
# Import V1 SQLite data to PostgreSQL
|
|
259
|
+
nano-brain db:migrate --from-v1 /path/to/old/index.db
|
|
260
|
+
|
|
261
|
+
# Idempotent — safe to run multiple times
|
|
262
|
+
# Uses content-addressed SHA-256 hashing
|
|
263
|
+
# Pure Go SQLite reader (modernc.org/sqlite, no CGO)
|
|
292
264
|
```
|
|
293
265
|
|
|
294
|
-
|
|
266
|
+
## Tech Stack
|
|
267
|
+
|
|
268
|
+
- **Go 1.23** — compiled to single static binary (`CGO_ENABLED=0`)
|
|
269
|
+
- **PostgreSQL 17** — relational storage + full-text search (tsvector/tsquery)
|
|
270
|
+
- **pgvector 0.8.2** — HNSW vector indexing
|
|
271
|
+
- **Echo v4** — HTTP framework
|
|
272
|
+
- **sqlc** — type-safe SQL code generation
|
|
273
|
+
- **goose v3** — database migrations
|
|
274
|
+
- **zerolog** — structured JSON logging
|
|
275
|
+
- **koanf** — YAML + env configuration
|
|
276
|
+
- **fsnotify** — file system watching
|
|
277
|
+
- **modernc.org/sqlite** — V1 migration reader (pure Go)
|
|
295
278
|
|
|
296
279
|
## License
|
|
297
280
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const https = require("https");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
const { execSync } = require("child_process");
|
|
9
|
+
|
|
10
|
+
const VERSION = require("../package.json").version;
|
|
11
|
+
const REPO = "nano-step/nano-brain";
|
|
12
|
+
|
|
13
|
+
const PLATFORM_MAP = {
|
|
14
|
+
darwin: "darwin",
|
|
15
|
+
linux: "linux",
|
|
16
|
+
};
|
|
17
|
+
const ARCH_MAP = {
|
|
18
|
+
arm64: "arm64",
|
|
19
|
+
x64: "amd64",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function getPlatformKey() {
|
|
23
|
+
const platform = PLATFORM_MAP[os.platform()];
|
|
24
|
+
const arch = ARCH_MAP[os.arch()];
|
|
25
|
+
if (!platform || !arch) {
|
|
26
|
+
console.error(`Unsupported platform: ${os.platform()}-${os.arch()}`);
|
|
27
|
+
console.error("Build from source: CGO_ENABLED=0 go build -o nano-brain ./cmd/nano-brain");
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
return `${platform}-${arch}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function download(url, dest) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const file = fs.createWriteStream(dest);
|
|
36
|
+
https.get(url, (res) => {
|
|
37
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
38
|
+
file.close();
|
|
39
|
+
fs.unlinkSync(dest);
|
|
40
|
+
return download(res.headers.location, dest).then(resolve).catch(reject);
|
|
41
|
+
}
|
|
42
|
+
if (res.statusCode !== 200) {
|
|
43
|
+
file.close();
|
|
44
|
+
fs.unlinkSync(dest);
|
|
45
|
+
return reject(new Error(`Download failed: HTTP ${res.statusCode}`));
|
|
46
|
+
}
|
|
47
|
+
res.pipe(file);
|
|
48
|
+
file.on("finish", () => {
|
|
49
|
+
file.close(resolve);
|
|
50
|
+
});
|
|
51
|
+
}).on("error", (err) => {
|
|
52
|
+
fs.unlinkSync(dest);
|
|
53
|
+
reject(err);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function main() {
|
|
59
|
+
const platformKey = getPlatformKey();
|
|
60
|
+
const binName = os.platform() === "win32" ? "nano-brain.exe" : "nano-brain";
|
|
61
|
+
const binPath = path.join(__dirname, binName);
|
|
62
|
+
|
|
63
|
+
if (fs.existsSync(binPath)) {
|
|
64
|
+
try {
|
|
65
|
+
const output = execSync(`"${binPath}" version --json`, { timeout: 5000 }).toString();
|
|
66
|
+
if (output.includes(VERSION)) {
|
|
67
|
+
console.log(`nano-brain v${VERSION} already installed.`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
// Wrong version or can't run — redownload
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/nano-brain-${platformKey}`;
|
|
76
|
+
console.log(`Downloading nano-brain v${VERSION} for ${platformKey}...`);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await download(url, binPath);
|
|
80
|
+
fs.chmodSync(binPath, 0o755);
|
|
81
|
+
console.log(`nano-brain v${VERSION} installed successfully.`);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.error(`Failed to download binary: ${err.message}`);
|
|
84
|
+
console.error("Build from source: CGO_ENABLED=0 go build -o npm/nano-brain ./cmd/nano-brain");
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
main();
|
package/npm/run.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const os = require("os");
|
|
8
|
+
|
|
9
|
+
const binName = os.platform() === "win32" ? "nano-brain.exe" : "nano-brain";
|
|
10
|
+
const binPath = path.join(__dirname, binName);
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(binPath)) {
|
|
13
|
+
console.error("nano-brain binary not found. Run: npx nano-brain (it will download automatically)");
|
|
14
|
+
console.error("Or build from source: CGO_ENABLED=0 go build -o npm/nano-brain ./cmd/nano-brain");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
|
|
20
|
+
} catch (e) {
|
|
21
|
+
process.exit(e.status || 1);
|
|
22
|
+
}
|