@andespindola/brainlink 0.1.0-beta.11 → 0.1.0-beta.110
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.md +8 -5
- package/CHANGELOG.md +26 -2
- package/CONTRIBUTING.md +2 -2
- package/COPYRIGHT.md +5 -0
- package/README.md +143 -18
- package/SECURITY.md +1 -1
- package/dist/application/analyze-vault.js +1 -9
- package/dist/application/build-context.js +56 -1
- package/dist/application/dedupe-notes.js +226 -0
- package/dist/application/frontend/client-css.js +93 -45
- package/dist/application/frontend/client-html.js +34 -25
- package/dist/application/frontend/client-js.js +3504 -132
- package/dist/application/frontend/client-worker-js.js +66 -0
- package/dist/application/get-graph-layout.js +2 -2
- package/dist/application/get-graph-node.js +3 -3
- package/dist/application/get-graph-summary.js +3 -3
- package/dist/application/get-graph.js +3 -3
- package/dist/application/import-legacy-sqlite.js +296 -0
- package/dist/application/index-vault.js +250 -24
- package/dist/application/list-agents.js +3 -3
- package/dist/application/list-links.js +5 -5
- package/dist/application/offline-pack-backup.js +44 -0
- package/dist/application/search-graph-node-ids.js +3 -3
- package/dist/application/search-knowledge.js +6 -6
- package/dist/application/server/routes.js +76 -1
- package/dist/application/start-server.js +75 -4
- package/dist/application/watch-vault.js +23 -2
- package/dist/benchmarks/large-vault.js +1 -1
- package/dist/cli/commands/agent-commands.js +7 -0
- package/dist/cli/commands/write-commands.js +818 -8
- package/dist/domain/context.js +53 -11
- package/dist/domain/graph-layout.js +47 -2
- package/dist/domain/middle-out.js +18 -0
- package/dist/infrastructure/config.js +38 -0
- package/dist/infrastructure/file-index.js +358 -0
- package/dist/infrastructure/file-system-vault.js +15 -0
- package/dist/infrastructure/index-state.js +56 -0
- package/dist/infrastructure/private-pack-codec.js +134 -0
- package/dist/infrastructure/search-packs.js +327 -26
- package/dist/mcp/server.js +11 -1
- package/dist/mcp/tools.js +62 -0
- package/docs/AGENT_USAGE.md +97 -17
- package/docs/ARCHITECTURE.md +23 -27
- package/docs/QUICKSTART.md +7 -0
- package/package.json +6 -4
- package/dist/infrastructure/sqlite/document-writer.js +0 -51
- package/dist/infrastructure/sqlite/graph-reader.js +0 -267
- package/dist/infrastructure/sqlite/recovery.js +0 -83
- package/dist/infrastructure/sqlite/schema.js +0 -114
- package/dist/infrastructure/sqlite/search-reader.js +0 -188
- package/dist/infrastructure/sqlite/types.js +0 -1
- package/dist/infrastructure/sqlite-index.js +0 -38
package/AGENTS.md
CHANGED
|
@@ -6,19 +6,19 @@ This file tells coding agents and AI assistants how to use this repository.
|
|
|
6
6
|
|
|
7
7
|
Brainlink is a local-first knowledge memory for agents.
|
|
8
8
|
|
|
9
|
-
It reads a Markdown vault, extracts `[[wiki links]]` and `#tags`, builds a local
|
|
9
|
+
It reads a Markdown vault, extracts `[[wiki links]]` and `#tags`, builds a local file index at `.brainlink/index.json`, and returns compact context packages that agents can inject into prompts.
|
|
10
10
|
|
|
11
11
|
## Source Of Truth
|
|
12
12
|
|
|
13
13
|
Markdown files are the source of truth.
|
|
14
14
|
|
|
15
|
-
The
|
|
15
|
+
The JSON index at `.brainlink/index.json` is derived. It can be deleted and rebuilt with:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
npm run dev -- index --vault ./vault
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Do not store permanent knowledge only in
|
|
21
|
+
Do not store permanent knowledge only in index artifacts.
|
|
22
22
|
|
|
23
23
|
By default, the installed Brainlink CLI uses `$HOME/.brainlink/vault` as its vault. Passing `--vault` or setting `vault` in `brainlink.config.json` intentionally selects a custom vault such as `./vault`.
|
|
24
24
|
|
|
@@ -83,6 +83,9 @@ Use watch mode while editing notes:
|
|
|
83
83
|
```bash
|
|
84
84
|
npm run dev -- server --vault ./vault --watch
|
|
85
85
|
npm run dev -- watch --vault ./vault
|
|
86
|
+
npm run dev -- bench --vault ./vault
|
|
87
|
+
npm run dev -- bench --vault ./vault --watch
|
|
88
|
+
npm run dev -- pack-backup --vault ./vault
|
|
86
89
|
```
|
|
87
90
|
|
|
88
91
|
Start MCP over stdio:
|
|
@@ -107,10 +110,10 @@ npm run dev -- doctor --vault ./vault
|
|
|
107
110
|
|
|
108
111
|
- Keep domain rules in `src/domain`.
|
|
109
112
|
- Keep use cases in `src/application`.
|
|
110
|
-
- Keep filesystem and
|
|
113
|
+
- Keep filesystem and index details in `src/infrastructure`.
|
|
111
114
|
- Keep CLI concerns in `src/cli`.
|
|
112
115
|
- Prefer pure functions for parsing, ranking, formatting, and transformation.
|
|
113
|
-
- Do not make
|
|
116
|
+
- Do not make index artifacts the canonical storage layer.
|
|
114
117
|
- Do not add comments with emojis.
|
|
115
118
|
- Keep JSON output backwards compatible where possible.
|
|
116
119
|
|
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,30 @@
|
|
|
22
22
|
- Added short-lived hybrid search cache with automatic invalidation on index changes.
|
|
23
23
|
- Added `stats --extended` observability output with storage, quality and latency probes.
|
|
24
24
|
- Added `docs/QUICKSTART.md` and aligned README/agent docs with the latest CLI/MCP flows.
|
|
25
|
+
- Added middle-out context assembly so chunk selection expands around the strongest note chunk.
|
|
26
|
+
- Added compressed-space pack prefiltering (token bloom index) before `.blpk` decryption and scan.
|
|
27
|
+
- Improved graph UI auto-fit and viewport recovery so loaded nodes are re-centered when zoom/pan drifts to empty canvas.
|
|
28
|
+
- Added cross-platform native desktop GUI auto-open for `blink server` (macOS Swift/WebKit, Windows PowerShell WinForms, Linux Python GTK/WebKit2), with app-window/browser fallback.
|
|
29
|
+
- Changed Linux default UI launch to app-window/browser for lighter startup; Linux native GUI is now opt-in via `BRAINLINK_LINUX_NATIVE_GUI=1`.
|
|
30
|
+
- Added native GUI parent-process monitoring so GUI windows close automatically when `blink server` stops.
|
|
31
|
+
- Improved non-mac browser detection fallback to try installed Edge/Chrome/Firefox/Chromium candidates before system default open.
|
|
32
|
+
- Improved graph filter rendering to keep hub anchor nodes visible (`Memory Hub`/`MOC`/high-degree fallback) for coherent relationship context.
|
|
33
|
+
- Fixed graph modal content loading by correcting agent query parameter composition for `/api/graph-node` and `/api/graph-filter` requests.
|
|
34
|
+
- Improved 50k+ graph rendering performance with viewport-aware spatial node culling, cached render visibility, and node-adjacent edge selection to avoid full graph scans every frame.
|
|
35
|
+
- Added incremental vault indexing with file snapshots to reuse unchanged documents/chunks/embeddings, plus adaptive search-pack rebuild thresholds to avoid full re-compression on small edits.
|
|
36
|
+
- Reduced large-graph HTTP payload size with compact `/api/graph-layout` encoding for high-node vaults and capped transmitted edges to improve UI load responsiveness.
|
|
37
|
+
- Added aggressive graph LOD clustering when zoomed out, dynamic per-zoom edge render budgets, and a dedicated frontend worker for off-main-thread graph filter matching.
|
|
38
|
+
- Improved Linux browser fallback launch stability by auto-applying Chromium compatibility flags (`--ozone-platform=x11`, `--disable-gpu`, `--disable-features=Vulkan,VaapiVideoDecoder`, `--disable-background-networking`) for app-window/browser modes.
|
|
39
|
+
- Improved massive-graph UI responsiveness with stricter render budgets, adaptive heavy-graph frame throttling, reduced interaction hit-test frequency, and URL-first agent selection on initial graph load.
|
|
40
|
+
- Improved 50k+ graph LOD behavior so zoomed-out views render lightweight cluster overviews and progressively reveal nodes/edges only as zoom increases.
|
|
41
|
+
- Added `blink bench` with realtime index phase telemetry and per-run compressed-pack analysis (input/output bytes, ratio, saved space, rebuild reason and duration), including continuous watch mode.
|
|
42
|
+
- Added tunable single-stage search-pack compression settings (`searchPack.rowChunkSize`, `searchPack.compressionLevel`, `searchPack.useDictionary`).
|
|
43
|
+
- Added benchmark guardrails for compression savings and latency regression (`searchPack.guardrailMinSavingsPercent`, `searchPack.guardrailMaxLatencyRegressionPercent`), reported in `blink bench`.
|
|
44
|
+
- Added `blink pack-backup` for offline second-stage compression backups of encrypted `.blpk` packs, outside the online query path.
|
|
45
|
+
- Hardened Linux browser launch flags for Ubuntu 26 Chromium/Wayland compatibility (`--disable-vulkan`, `--use-gl=swiftshader`, `--ozone-platform-hint=x11`).
|
|
46
|
+
- Improved pack resilience by auto-repairing missing search-pack manifests from existing `.blpk` files, avoiding unnecessary full repacks on small incremental updates.
|
|
47
|
+
- Updated Linux graph auto-open behavior to prioritize the system default browser (`xdg-open`) before explicit browser fallbacks.
|
|
48
|
+
- Removed implicit Chromium dependency in Linux auto-open flow; app-window launch is now opt-in (`BRAINLINK_LINUX_APP_WINDOW=1`).
|
|
25
49
|
|
|
26
50
|
## 0.1.0-beta.3
|
|
27
51
|
|
|
@@ -49,8 +73,8 @@
|
|
|
49
73
|
## 0.1.0-alpha.0
|
|
50
74
|
|
|
51
75
|
- Added local-first Markdown vault indexing.
|
|
52
|
-
- Added
|
|
53
|
-
- Added
|
|
76
|
+
- Added local full-text indexing, local semantic retrieval, wiki links, backlinks and graph retrieval.
|
|
77
|
+
- Added semantic candidate bucket indexing to narrow vector candidates for larger vaults.
|
|
54
78
|
- Optimized title/link resolution with precomputed agent-scoped title maps.
|
|
55
79
|
- Added CLI, JSON output, HTTP API and graph UI.
|
|
56
80
|
- Added vault diagnostics: stats, broken links, orphans, validation and doctor.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -22,7 +22,7 @@ npm run pack:smoke
|
|
|
22
22
|
## Design Rules
|
|
23
23
|
|
|
24
24
|
- Markdown files are the source of truth.
|
|
25
|
-
-
|
|
25
|
+
- Local index artifacts are derived and must remain rebuildable.
|
|
26
26
|
- Domain parsing, graph analysis and layout should stay pure and testable.
|
|
27
|
-
- CLI, HTTP, filesystem and
|
|
27
|
+
- CLI, HTTP, filesystem and index code are adapters around application use cases.
|
|
28
28
|
- MCP integration should live outside this package by wrapping the CLI with `--json`.
|
package/COPYRIGHT.md
ADDED
package/README.md
CHANGED
|
@@ -52,13 +52,15 @@ LLMs do not have infinite context. Brainlink gives agents an external memory lay
|
|
|
52
52
|
1. Durable knowledge is written as Markdown.
|
|
53
53
|
2. Notes are connected with `[[wiki links]]`.
|
|
54
54
|
3. Concepts are classified with `#tags`.
|
|
55
|
-
4. Brainlink builds a local
|
|
55
|
+
4. Brainlink builds a local JSON index (`.brainlink/index.json`) and private encrypted search packs.
|
|
56
56
|
5. Agents query the index before responding.
|
|
57
57
|
6. Brainlink returns compact, source-backed context.
|
|
58
58
|
|
|
59
|
-
Markdown is the source of truth. `.brainlink/
|
|
60
|
-
Brainlink
|
|
61
|
-
|
|
59
|
+
Markdown is the source of truth. `.brainlink/index.json` is a rebuildable index artifact.
|
|
60
|
+
After each index run, Brainlink also writes private encrypted search packs at `.brainlink/search-packs/*.blpk` to preserve fast retrieval and portable recovery.
|
|
61
|
+
Online retrieval always uses a single compression stage per pack; optional second-stage compression is reserved for offline backup artifacts only.
|
|
62
|
+
Pack decryption uses a Brainlink key from `$BRAINLINK_HOME/keys` or from `BRAINLINK_SEARCH_PACK_KEY` when explicitly configured.
|
|
63
|
+
Legacy `.jsonl.gz` packs are upgraded to `.blpk` automatically on first search/context access.
|
|
62
64
|
|
|
63
65
|
## Features
|
|
64
66
|
|
|
@@ -66,8 +68,12 @@ After each index run, Brainlink also writes compressed search packs at `.brainli
|
|
|
66
68
|
- Obsidian-compatible `[[wiki links]]` and `#tags`.
|
|
67
69
|
- Weighted graph edges so agents can rank relationship importance and priority.
|
|
68
70
|
- Backlinks, broken-link reports, orphan detection and validation.
|
|
69
|
-
- Full-text, semantic and hybrid retrieval
|
|
70
|
-
-
|
|
71
|
+
- Full-text, semantic and hybrid retrieval on a local file index.
|
|
72
|
+
- Middle-out context assembly around the strongest chunk per document.
|
|
73
|
+
- In-process index and context caching with automatic invalidation on index updates.
|
|
74
|
+
- Compressed-space prefiltering for `.blpk` packs before decryption and scan.
|
|
75
|
+
- Incremental indexing that reprocesses only changed markdown files and reuses existing chunks/embeddings for unchanged notes.
|
|
76
|
+
- Adaptive compressed-pack rebuild policy to keep indexing fast during small edit batches.
|
|
71
77
|
- Agent namespaces under `agents/<agent-id>/`.
|
|
72
78
|
- S3-compatible bucket vaults through `s3://bucket/prefix` URIs.
|
|
73
79
|
- CLI with machine-readable `--json` output.
|
|
@@ -75,6 +81,17 @@ After each index run, Brainlink also writes compressed search packs at `.brainli
|
|
|
75
81
|
- Built-in MCP stdio server for agent tool integration.
|
|
76
82
|
- Local HTTP API.
|
|
77
83
|
- Realtime graph UI with agent selector and colored knowledge groups.
|
|
84
|
+
- Graph renderer optimized for large datasets with viewport-driven node culling and edge lookup by visible nodes.
|
|
85
|
+
- Canvas graph rendering uses the same batched node and edge pipeline for every graph size, reducing per-frame draw calls while keeping selected and hovered items highlighted.
|
|
86
|
+
- WebGL acceleration is used when available for dense node and edge drawing, with Canvas 2D preserved as the interaction and fallback layer.
|
|
87
|
+
- Graph zoom-out renders hierarchical ecosystem subgraphs only above 1000 notes: the memory hub stays centered, 1000-note groups stay as compact sand-like points, and focused groups gradually expand into smaller graph meshes before individual notes are rendered.
|
|
88
|
+
- Large graph layout API automatically uses compact payload encoding with link-coverage-aware edge selection to reduce initial client load without hiding major relationships.
|
|
89
|
+
- Large-segment layout spacing now grows logarithmically to keep initial visual density consistent between medium and very large vaults (for example, ~1k vs ~50k notes).
|
|
90
|
+
- Graph coordinates are visually compacted across graph sizes so reset starts from a stable macro mass and zoom-in progressively expands toward local detail.
|
|
91
|
+
- Zoomed-out graph LOD renders nested subgraphs and progressively expands only the focused cluster as zoom increases, including very large vaults.
|
|
92
|
+
- Graph reset starts in macro "galaxy" overview mode and progressively reveals nearby nodes as zoom increases, including smaller vaults.
|
|
93
|
+
- Graph filtering runs in a dedicated browser worker to keep the UI thread responsive during heavy datasets.
|
|
94
|
+
- Edge rendering budgets adapt to zoom level to prevent frame spikes on large graph panoramas.
|
|
78
95
|
|
|
79
96
|
## Install
|
|
80
97
|
|
|
@@ -284,7 +301,7 @@ export BRAINLINK_S3_FORCE_PATH_STYLE=1
|
|
|
284
301
|
|
|
285
302
|
Bucket vaults mirror Markdown into a local cache under
|
|
286
303
|
`$BRAINLINK_HOME/bucket-cache`. The bucket remains canonical; the local
|
|
287
|
-
`.brainlink/
|
|
304
|
+
`.brainlink/index.json` stays a disposable index artifact. Run `index` after remote
|
|
288
305
|
bucket changes before relying on `search`, `context`, graph or validation
|
|
289
306
|
commands. Watch mode is only supported for local filesystem vaults.
|
|
290
307
|
|
|
@@ -300,7 +317,7 @@ vault/
|
|
|
300
317
|
research-agent/
|
|
301
318
|
source-review-policy.md
|
|
302
319
|
.brainlink/
|
|
303
|
-
|
|
320
|
+
index.json
|
|
304
321
|
```
|
|
305
322
|
|
|
306
323
|
Permanent data:
|
|
@@ -310,7 +327,7 @@ Permanent data:
|
|
|
310
327
|
|
|
311
328
|
Rebuildable data:
|
|
312
329
|
|
|
313
|
-
- `.brainlink/
|
|
330
|
+
- `.brainlink/index.json`
|
|
314
331
|
- full-text records
|
|
315
332
|
- local embedding vectors
|
|
316
333
|
- local embedding buckets
|
|
@@ -394,6 +411,7 @@ blink agent upgrade
|
|
|
394
411
|
```
|
|
395
412
|
|
|
396
413
|
This configures `~/.codex/config.toml` with Brainlink MCP (`brainlink-mcp`) so Brainlink is available by default in agent sessions.
|
|
414
|
+
`agent install` and `agent upgrade` also apply the MCP `fully-auto` bootstrap policy by default (`enforceBootstrap`, `enforceContextFirst`, `autoBootstrapOnRead`, `autoBootstrapOnStartup` all enabled).
|
|
397
415
|
|
|
398
416
|
If you are inside this repository and want plugin gallery setup too:
|
|
399
417
|
|
|
@@ -513,6 +531,8 @@ Available tools:
|
|
|
513
531
|
- `brainlink_recommendations`: return an automatic action plan so agents can run Brainlink in the recommended order.
|
|
514
532
|
- `brainlink_context`: read indexed context for a task or question.
|
|
515
533
|
- `brainlink_search`: search indexed notes.
|
|
534
|
+
- `brainlink_dedupe`: detect duplicate candidates using exact hash + semantic similarity scores.
|
|
535
|
+
- `brainlink_resolve_duplicate`: resolve duplicate pairs (`merge`, `link`, `ignore`) with connectivity-safe fallback edges.
|
|
516
536
|
- `brainlink_add_note`: write durable Markdown memory and reindex.
|
|
517
537
|
- `brainlink_add_file`: ingest a local file as a note and reindex.
|
|
518
538
|
- `brainlink_index`: rebuild the vault index.
|
|
@@ -551,6 +571,17 @@ blink server --host 127.0.0.1 --port 4321 --watch
|
|
|
551
571
|
```
|
|
552
572
|
|
|
553
573
|
By default, the server uses `$HOME/.brainlink/vault`. Pass `--vault ./vault` only when you want to inspect a custom vault.
|
|
574
|
+
By default, `blink server` tries to open the graph in a native desktop GUI window:
|
|
575
|
+
- macOS: Swift + WebKit
|
|
576
|
+
- Windows: PowerShell WinForms WebBrowser
|
|
577
|
+
- Linux: optional Python GTK + WebKit2 (requires `python3` + `gi` + `WebKit2`)
|
|
578
|
+
|
|
579
|
+
On Linux, native GUI is disabled by default for better startup performance. Enable it with `BRAINLINK_LINUX_NATIVE_GUI=1`.
|
|
580
|
+
If native GUI launch is unavailable on your system, it falls back to dedicated app-window mode and then to the default browser.
|
|
581
|
+
For Chromium-family browsers on Linux (`chromium`, `chromium-browser`, `google-chrome`, `microsoft-edge`, `brave-browser`), Brainlink now auto-applies compatibility flags during launch (`--ozone-platform=x11`, `--ozone-platform-hint=x11`, `--disable-gpu`, `--disable-vulkan`, `--use-gl=swiftshader`, `--disable-features=Vulkan,VaapiVideoDecoder`, `--disable-background-networking`) to avoid common Wayland/Vulkan/VAAPI startup issues.
|
|
582
|
+
On Linux, Brainlink opens the graph through the system default browser first (`xdg-open`), then `$BROWSER`/detected browsers as fallback. Chromium-family app-window mode is optional via `BRAINLINK_LINUX_APP_WINDOW=1`.
|
|
583
|
+
Use `--no-open` to keep it headless.
|
|
584
|
+
When native GUI is used, the GUI window automatically closes when the `blink server` process stops.
|
|
554
585
|
|
|
555
586
|
The graph UI shows:
|
|
556
587
|
|
|
@@ -558,13 +589,26 @@ The graph UI shows:
|
|
|
558
589
|
- `[[wiki links]]` as weighted edges
|
|
559
590
|
- details opened on node click (tags, outgoing links, backlinks, full Markdown content)
|
|
560
591
|
- neutral graph nodes with segment/group metadata
|
|
561
|
-
- agent selector for isolated views
|
|
592
|
+
- agent selector (id-only labels) for isolated views
|
|
562
593
|
- graph filter matches title, path, tags and note content
|
|
594
|
+
- graph filter keeps hub context nodes visible (`Memory Hub`/`MOC`/high-degree fallback) to preserve relationship readability
|
|
563
595
|
- realtime refresh while `--watch` is enabled
|
|
564
596
|
- graph controls for zoom in, zoom out, fit visible nodes and reset-to-fit-all
|
|
565
|
-
- wheel zoom anchored to cursor position for faster navigation in large graphs
|
|
597
|
+
- wheel zoom (including `cmd+scroll` and `ctrl+scroll`) anchored to cursor position for faster navigation in large graphs
|
|
598
|
+
- zoom-out floor for large and massive graphs, plus reset macro floor tied to hub-neighbor distance and first-level cluster spacing, with a tighter initial camera so the first graph appears as a closer cell instead of a distant mesh
|
|
599
|
+
- keyboard shortcuts: `+` zoom in, `-` zoom out, `0` reset fit
|
|
600
|
+
- double-click on canvas zooms in at cursor position
|
|
566
601
|
- floating graph totals (notes, links, tags) below the Brainlink title
|
|
567
|
-
-
|
|
602
|
+
- graph rendering safeguards (batched canvas drawing across graph sizes, edge draw caps, lower redraw rate, zoom-aware interaction)
|
|
603
|
+
- adaptive CPU safeguards for large graphs: idle frame pacing, throttled background physics updates and cached viewport dimensions to reduce redraw/layout overhead while preserving interaction responsiveness
|
|
604
|
+
- hierarchical hot-path optimizations reduce per-frame allocations and repeated scans during layered cluster expansion and edge projection
|
|
605
|
+
- hierarchical edge projection now caches hub membership and node-to-cluster resolution per frame to keep large recursive subgraph rendering smooth during continuous zoom and pan
|
|
606
|
+
- hierarchical projection now uses stronger perspective yaw/pitch and depth-based render ordering so layered subgraphs read as a true 3D field instead of a flat expansion
|
|
607
|
+
- node rendering also applies depth projection cues on large visible sets (position, scale, opacity and edge depth weighting) so the graph keeps 3D perception when leaving cluster-only LOD layers
|
|
608
|
+
- WebGL node and edge acceleration when supported, falling back to Canvas 2D without changing graph behavior
|
|
609
|
+
- compact macro-to-micro density progression so reset keeps the graph mass oriented and zoom-in separates local neighborhoods progressively
|
|
610
|
+
- graph camera treats hub-centered navigation as structural only when the hub is dominant; diffuse stress graphs reset and zoom around the full graph mass
|
|
611
|
+
- graph LOD progression: hierarchical rendering now follows one recursive graph-of-graphs standard whenever a graph has more than one hierarchy level; each level expands through intermediate subgraph sizes (instead of jumping directly to leaves), starts from a memory-hub-centered mesh, and each supernode can expand into another same-shape subgraph level (up to 999 children) with latent fade-in, aggregated real links and local sibling mesh links so org-heavy-like and stress-50k-like structures share the same layered behavior at different depths; layered clusters also receive stronger perspective depth projection (Z-depth) with vertical camera tilt/parallax so expansion reads as a true depth field instead of a flat 2D switch; for massive graphs the first expansion starts deeper in zoom and is additionally gated by focus readiness (screen-space isolation of the focused parent) so child levels open only when that subgraph is truly centered and separated in view
|
|
568
612
|
|
|
569
613
|
The server indexes before starting by default. Use `--no-index` to skip that step:
|
|
570
614
|
|
|
@@ -666,6 +710,18 @@ blink migrate-vault --from ~/.brainlink/vault --to ./team-vault --report ./migra
|
|
|
666
710
|
Runs explicit markdown migration between vaults while preserving conflicts as `.conflict-<timestamp>` files.
|
|
667
711
|
Use `--dry-run` to preview `copied`, `conflicted` and `unchanged` counts before writing.
|
|
668
712
|
|
|
713
|
+
### `db-import`
|
|
714
|
+
|
|
715
|
+
```bash
|
|
716
|
+
blink db-import --vault ./team-vault
|
|
717
|
+
blink db-import --vault ./team-vault --db ./legacy/brainlink.db
|
|
718
|
+
blink db-import --vault ./team-vault --db ./legacy/brainlink.db --table legacy_notes --dry-run
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
Imports durable memory from a legacy SQLite database into Markdown notes (`agents/<agent-id>/*.md`) and reindexes by default.
|
|
722
|
+
When `--db` is omitted, Brainlink auto-detects common legacy paths such as `<vault>/.brainlink/brainlink.db`.
|
|
723
|
+
Use `--agent <id>` to force all imported rows into one namespace, `--limit` for incremental imports, `--dry-run` to preview without writing files, and `--no-index` to defer reindexing.
|
|
724
|
+
|
|
669
725
|
### `init`
|
|
670
726
|
|
|
671
727
|
```bash
|
|
@@ -690,6 +746,28 @@ blink add "Note Title" --vault ./vault --content-file ./notes.md --no-auto-index
|
|
|
690
746
|
|
|
691
747
|
Creates a Markdown note under `agents/<agent-id>/`. Common secret patterns are blocked by default; use `--allow-sensitive` only for an intentionally protected vault.
|
|
692
748
|
To avoid disconnected memory, Brainlink auto-adds a fallback wiki edge when a note is written without links, creating agent hub notes when needed.
|
|
749
|
+
`add` also returns `possibleDuplicates` (exact hash + semantic candidates) so agents can resolve duplicate memory right after writes.
|
|
750
|
+
|
|
751
|
+
### `dedupe`
|
|
752
|
+
|
|
753
|
+
```bash
|
|
754
|
+
blink dedupe --vault ./vault --json
|
|
755
|
+
blink dedupe --vault ./vault --agent coding-agent --limit 20 --min-score 0.92 --json
|
|
756
|
+
blink dedupe --vault ./vault --no-semantic --json
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
Detects `possibleDuplicate` pairs using exact content hashes and optional semantic similarity.
|
|
760
|
+
|
|
761
|
+
### `dedupe-resolve`
|
|
762
|
+
|
|
763
|
+
```bash
|
|
764
|
+
blink dedupe-resolve --vault ./vault --left agents/shared/a.md --right agents/shared/b.md --action merge --json
|
|
765
|
+
blink dedupe-resolve --vault ./vault --left agents/shared/a.md --right agents/shared/b.md --action link --json
|
|
766
|
+
blink dedupe-resolve --vault ./vault --left agents/shared/a.md --right agents/shared/b.md --action ignore --json
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
Resolves a duplicate pair with `merge`, `link` or `ignore`.
|
|
770
|
+
When action is not `merge`, Brainlink still creates a low-priority related edge (`#related-to`) so notes remain connected.
|
|
693
771
|
|
|
694
772
|
### `index`
|
|
695
773
|
|
|
@@ -700,6 +778,38 @@ blink index --vault ./vault
|
|
|
700
778
|
|
|
701
779
|
Rebuilds the local index from Markdown files.
|
|
702
780
|
|
|
781
|
+
### `bench`
|
|
782
|
+
|
|
783
|
+
```bash
|
|
784
|
+
blink bench --vault ./vault
|
|
785
|
+
blink bench --vault ./vault --watch
|
|
786
|
+
blink bench --vault ./vault --watch --debounce 500
|
|
787
|
+
blink bench --vault ./vault --json
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
Runs indexing with realtime phase telemetry (`start`, `scan`, `parse`, `embed`, `persist`, `packs`, `complete`) and prints a benchmark summary at the end of each run.
|
|
791
|
+
|
|
792
|
+
Summary includes compression behavior for `.blpk` packs when rebuild happens:
|
|
793
|
+
- pack rebuild reason
|
|
794
|
+
- pack count and pack build duration
|
|
795
|
+
- uncompressed input bytes vs compressed output bytes
|
|
796
|
+
- saved percentage
|
|
797
|
+
- objective guardrails (minimum savings and maximum latency regression thresholds)
|
|
798
|
+
|
|
799
|
+
Use `--watch` to keep benchmarking incremental reindex runs after Markdown changes (local filesystem vaults only).
|
|
800
|
+
When `.brainlink/search-packs/manifest.json` is missing but `.blpk` files exist, Brainlink repairs the manifest first and avoids unnecessary full pack rebuild on small edits.
|
|
801
|
+
|
|
802
|
+
### `pack-backup`
|
|
803
|
+
|
|
804
|
+
```bash
|
|
805
|
+
blink pack-backup --vault ./vault
|
|
806
|
+
blink pack-backup --vault ./vault --output ./vault/.brainlink/backups/custom.blpkbak.gz
|
|
807
|
+
blink pack-backup --vault ./vault --json
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
Creates an offline backup artifact of encrypted search packs with a second compression pass.
|
|
811
|
+
This is intentionally outside the online retrieval path (`index`, `search`, `context`).
|
|
812
|
+
|
|
703
813
|
### `agents`
|
|
704
814
|
|
|
705
815
|
```bash
|
|
@@ -722,11 +832,12 @@ If `--mode` or `--limit` is omitted, Brainlink resolves values from the current
|
|
|
722
832
|
|
|
723
833
|
Modes:
|
|
724
834
|
|
|
725
|
-
- `hybrid`: default; combines
|
|
726
|
-
- `fts`: exact lexical retrieval
|
|
835
|
+
- `hybrid`: default; combines lexical matching with local embedding similarity.
|
|
836
|
+
- `fts`: exact lexical retrieval from the file index.
|
|
727
837
|
- `semantic`: local deterministic embedding similarity only.
|
|
728
838
|
|
|
729
839
|
Hybrid results are cached in-memory for a short TTL and invalidated automatically when the local index file changes.
|
|
840
|
+
Context selection uses a middle-out strategy: it starts from the strongest chunk in a note and expands to neighboring chunks while respecting token budget.
|
|
730
841
|
|
|
731
842
|
### `context`
|
|
732
843
|
|
|
@@ -737,6 +848,7 @@ blink context "question" --vault ./vault --agent coding-agent --mode hybrid --js
|
|
|
737
848
|
```
|
|
738
849
|
|
|
739
850
|
Builds a compact context package for an agent.
|
|
851
|
+
Repeated calls with the same vault, agent, query, mode and token/limit settings are served from a short in-memory cache while the index is unchanged.
|
|
740
852
|
|
|
741
853
|
### `links`
|
|
742
854
|
|
|
@@ -821,9 +933,15 @@ Watches Markdown files and rebuilds the index when notes change.
|
|
|
821
933
|
```bash
|
|
822
934
|
blink server --watch
|
|
823
935
|
blink server --vault ./vault --watch
|
|
936
|
+
blink server --vault ./vault --watch --no-open
|
|
824
937
|
```
|
|
825
938
|
|
|
826
939
|
Starts the local read-only graph UI and HTTP API.
|
|
940
|
+
By default, it tries to open a native desktop GUI window for the graph URL.
|
|
941
|
+
On Linux, native GUI is disabled by default; enable it with `BRAINLINK_LINUX_NATIVE_GUI=1`.
|
|
942
|
+
If native GUI launch is unavailable, it falls back to dedicated app-window mode and then browser open.
|
|
943
|
+
When fallback opens Chromium-family browsers on Linux, Brainlink automatically uses compatibility launch flags for stable rendering on Ubuntu/Wayland setups.
|
|
944
|
+
Use `--no-open` to skip that behavior.
|
|
827
945
|
|
|
828
946
|
The HTTP server only binds to loopback hosts such as `127.0.0.1`, `localhost` or `::1`.
|
|
829
947
|
|
|
@@ -864,6 +982,13 @@ If no `vault` is configured and no `--vault` flag is passed, Brainlink uses `$HO
|
|
|
864
982
|
"embeddingProvider": "local",
|
|
865
983
|
"defaultSearchMode": "hybrid",
|
|
866
984
|
"chunkSize": 1200,
|
|
985
|
+
"searchPack": {
|
|
986
|
+
"rowChunkSize": 5000,
|
|
987
|
+
"compressionLevel": 5,
|
|
988
|
+
"useDictionary": true,
|
|
989
|
+
"guardrailMinSavingsPercent": 8,
|
|
990
|
+
"guardrailMaxLatencyRegressionPercent": 5
|
|
991
|
+
},
|
|
867
992
|
"agentProfiles": {
|
|
868
993
|
"coding-agent": {
|
|
869
994
|
"defaultSearchMode": "semantic",
|
|
@@ -975,7 +1100,7 @@ src/
|
|
|
975
1100
|
application/ use cases
|
|
976
1101
|
cli/ command-line adapter
|
|
977
1102
|
domain/ pure knowledge rules
|
|
978
|
-
infrastructure/ filesystem and
|
|
1103
|
+
infrastructure/ filesystem and index adapters
|
|
979
1104
|
```
|
|
980
1105
|
|
|
981
1106
|
Detailed notes:
|
|
@@ -987,7 +1112,6 @@ Detailed notes:
|
|
|
987
1112
|
## Current Limits
|
|
988
1113
|
|
|
989
1114
|
- Semantic search uses deterministic local embeddings, not a remote model provider.
|
|
990
|
-
- Semantic search uses SQLite embedding buckets to narrow candidates before cosine scoring.
|
|
991
1115
|
- `embeddingProvider` currently supports `local` and `none`.
|
|
992
1116
|
- Link resolution is title-based inside each agent namespace, with `shared` as fallback.
|
|
993
1117
|
- HTTP API is local and unauthenticated.
|
|
@@ -998,7 +1122,7 @@ Detailed notes:
|
|
|
998
1122
|
The `0.1.0-beta` line is intended to stabilize the local-first memory loop:
|
|
999
1123
|
|
|
1000
1124
|
- Markdown as durable memory.
|
|
1001
|
-
-
|
|
1125
|
+
- Rebuildable file index plus local embeddings and encrypted pack exports.
|
|
1002
1126
|
- CLI as the primary agent interface.
|
|
1003
1127
|
- HTTP graph API and frontend as inspection tools.
|
|
1004
1128
|
- Agent namespaces to avoid context mixing.
|
|
@@ -1014,7 +1138,7 @@ Brainlink is local-first by default.
|
|
|
1014
1138
|
- Brainlink HTTP is localhost-only and refuses non-loopback hosts.
|
|
1015
1139
|
- Brainlink blocks common secret patterns by default when adding notes. Use `--allow-sensitive` only for intentional, protected vaults.
|
|
1016
1140
|
- Do not store secrets, credentials, API keys or regulated personal data unless the vault is protected by your own storage controls.
|
|
1017
|
-
- Treat `.brainlink/
|
|
1141
|
+
- Treat `.brainlink/index.json` and `.brainlink/search-packs/` as disposable derived artifacts.
|
|
1018
1142
|
|
|
1019
1143
|
See [SECURITY.md](SECURITY.md).
|
|
1020
1144
|
|
|
@@ -1025,6 +1149,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
|
1025
1149
|
## License
|
|
1026
1150
|
|
|
1027
1151
|
MIT. See [LICENSE](LICENSE).
|
|
1152
|
+
Copyright (c) 2026 Substructa. See [COPYRIGHT.md](COPYRIGHT.md).
|
|
1028
1153
|
|
|
1029
1154
|
### Memory Optimization Loop (1-7)
|
|
1030
1155
|
|
package/SECURITY.md
CHANGED
|
@@ -7,7 +7,7 @@ Brainlink is local-first.
|
|
|
7
7
|
- The HTTP server binds to `127.0.0.1` by default.
|
|
8
8
|
- The HTTP server always refuses non-loopback hosts.
|
|
9
9
|
- The HTTP server is read-only and does not expose note creation, indexing or update routes.
|
|
10
|
-
-
|
|
10
|
+
- Local index artifacts (`.brainlink/index.json` and `.brainlink/search-packs/`) are derived data.
|
|
11
11
|
- Markdown files are user-owned source data.
|
|
12
12
|
- Brainlink-created Markdown files use `0600` permissions.
|
|
13
13
|
- Brainlink-created directories and `.brainlink` use `0700` permissions.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
2
|
import { performance } from 'node:perf_hooks';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
3
|
import { validateGraph, getBrokenLinks, getOrphanNodes, getVaultStats } from '../domain/graph-analysis.js';
|
|
6
4
|
import { ensureVault, listVaultFiles, readMarkdownFiles } from '../infrastructure/file-system-vault.js';
|
|
7
5
|
import { resolveAgentRuntimeDefaults } from '../infrastructure/config.js';
|
|
@@ -96,17 +94,11 @@ export const doctorVault = async (vaultPath) => {
|
|
|
96
94
|
const files = await readMarkdownFiles(absoluteVaultPath);
|
|
97
95
|
const graph = await getGraphSummary(absoluteVaultPath);
|
|
98
96
|
const validation = validateGraph(graph);
|
|
99
|
-
const backupPath = join(absoluteVaultPath, '.brainlink', 'brainlink.db.backup');
|
|
100
|
-
const hasBackup = existsSync(backupPath);
|
|
101
|
-
const backupReady = graph.nodes.length === 0 || hasBackup;
|
|
102
97
|
const checks = [
|
|
103
98
|
createCheck('vault', true, `Vault ready at ${absoluteVaultPath}`),
|
|
104
99
|
createCheck('markdown-files', files.length > 0, `${files.length} markdown files found`),
|
|
105
100
|
createCheck('index', graph.nodes.length > 0, `${graph.nodes.length} indexed documents found`),
|
|
106
|
-
createCheck('broken-links', validation.brokenLinks.length === 0, `${validation.brokenLinks.length} broken links found`)
|
|
107
|
-
createCheck('index-backup', backupReady, backupReady
|
|
108
|
-
? (hasBackup ? 'SQLite recovery snapshot is available' : 'No index yet. Snapshot will be created after first indexing run')
|
|
109
|
-
: 'Recovery snapshot missing. Run blink index to create a rollback snapshot')
|
|
101
|
+
createCheck('broken-links', validation.brokenLinks.length === 0, `${validation.brokenLinks.length} broken links found`)
|
|
110
102
|
];
|
|
111
103
|
const recommendations = files.length === 0 && graph.nodes.length === 0
|
|
112
104
|
? [
|
|
@@ -1,13 +1,68 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
1
2
|
import { formatContextPackage, selectContextSections } from '../domain/context.js';
|
|
3
|
+
import { indexStoragePath } from '../infrastructure/file-index.js';
|
|
2
4
|
import { searchKnowledge } from './search-knowledge.js';
|
|
5
|
+
const contextCacheTtlMs = 45_000;
|
|
6
|
+
const contextCacheMaxEntries = 200;
|
|
7
|
+
const contextCache = new Map();
|
|
8
|
+
const readIndexMtimeMs = async (vaultPath) => {
|
|
9
|
+
try {
|
|
10
|
+
return (await stat(indexStoragePath(vaultPath))).mtimeMs;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const toCacheKey = (vaultPath, query, limit, maxTokens, agentId, mode) => JSON.stringify({
|
|
17
|
+
vaultPath,
|
|
18
|
+
query: query.trim().toLowerCase(),
|
|
19
|
+
limit,
|
|
20
|
+
maxTokens,
|
|
21
|
+
agentId: agentId?.trim().toLowerCase() ?? '*',
|
|
22
|
+
mode: mode ?? 'default'
|
|
23
|
+
});
|
|
24
|
+
const contextCacheGet = (key, indexMtimeMs) => {
|
|
25
|
+
const entry = contextCache.get(key);
|
|
26
|
+
if (!entry) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
const fresh = Date.now() - entry.createdAt <= contextCacheTtlMs && entry.indexMtimeMs === indexMtimeMs;
|
|
30
|
+
if (!fresh) {
|
|
31
|
+
contextCache.delete(key);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return entry.context;
|
|
35
|
+
};
|
|
36
|
+
const contextCacheSet = (entry) => {
|
|
37
|
+
contextCache.set(entry.key, entry);
|
|
38
|
+
if (contextCache.size <= contextCacheMaxEntries) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const overflow = contextCache.size - contextCacheMaxEntries;
|
|
42
|
+
const keys = Array.from(contextCache.keys()).slice(0, overflow);
|
|
43
|
+
keys.forEach((key) => contextCache.delete(key));
|
|
44
|
+
};
|
|
3
45
|
export const buildContextPackage = async (vaultPath, query, limit, maxTokens, agentId, mode) => {
|
|
46
|
+
const cacheKey = toCacheKey(vaultPath, query, limit, maxTokens, agentId, mode);
|
|
47
|
+
const indexMtimeMs = await readIndexMtimeMs(vaultPath);
|
|
48
|
+
const cached = contextCacheGet(cacheKey, indexMtimeMs);
|
|
49
|
+
if (cached) {
|
|
50
|
+
return cached;
|
|
51
|
+
}
|
|
4
52
|
const results = await searchKnowledge(vaultPath, query, limit, agentId, mode);
|
|
5
53
|
const sections = selectContextSections(results, maxTokens);
|
|
6
|
-
|
|
54
|
+
const context = {
|
|
7
55
|
query,
|
|
8
56
|
sections,
|
|
9
57
|
content: formatContextPackage(query, sections)
|
|
10
58
|
};
|
|
59
|
+
contextCacheSet({
|
|
60
|
+
key: cacheKey,
|
|
61
|
+
createdAt: Date.now(),
|
|
62
|
+
indexMtimeMs,
|
|
63
|
+
context
|
|
64
|
+
});
|
|
65
|
+
return context;
|
|
11
66
|
};
|
|
12
67
|
export const buildContext = async (vaultPath, query, limit, maxTokens, agentId, mode) => {
|
|
13
68
|
const contextPackage = await buildContextPackage(vaultPath, query, limit, maxTokens, agentId, mode);
|