@andespindola/brainlink 0.1.0-beta.3 → 0.1.0-beta.31

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.
Files changed (56) hide show
  1. package/AGENTS.md +5 -5
  2. package/CHANGELOG.md +37 -3
  3. package/CONTRIBUTING.md +2 -2
  4. package/COPYRIGHT.md +5 -0
  5. package/README.md +172 -20
  6. package/SECURITY.md +1 -1
  7. package/dist/application/add-note.js +62 -13
  8. package/dist/application/analyze-vault.js +95 -8
  9. package/dist/application/frontend/client-css.js +214 -100
  10. package/dist/application/frontend/client-html.js +60 -45
  11. package/dist/application/frontend/client-js.js +553 -91
  12. package/dist/application/get-graph-layout.js +22 -7
  13. package/dist/application/get-graph-node.js +12 -0
  14. package/dist/application/get-graph-summary.js +12 -0
  15. package/dist/application/get-graph.js +3 -3
  16. package/dist/application/import-legacy-sqlite.js +296 -0
  17. package/dist/application/index-vault.js +11 -4
  18. package/dist/application/list-agents.js +3 -3
  19. package/dist/application/list-links.js +5 -5
  20. package/dist/application/migrate-vault.js +91 -0
  21. package/dist/application/search-graph-node-ids.js +12 -0
  22. package/dist/application/search-knowledge.js +75 -5
  23. package/dist/application/server/routes.js +27 -1
  24. package/dist/benchmarks/large-vault.js +1 -1
  25. package/dist/cli/commands/agent-commands.js +412 -0
  26. package/dist/cli/commands/config-commands.js +167 -0
  27. package/dist/cli/commands/read-commands.js +25 -8
  28. package/dist/cli/commands/write-commands.js +205 -4
  29. package/dist/cli/main.js +4 -0
  30. package/dist/cli/runtime.js +5 -2
  31. package/dist/domain/context.js +53 -11
  32. package/dist/domain/embeddings.js +2 -1
  33. package/dist/domain/graph-layout.js +20 -14
  34. package/dist/domain/markdown.js +36 -4
  35. package/dist/domain/middle-out.js +18 -0
  36. package/dist/infrastructure/config.js +94 -8
  37. package/dist/infrastructure/file-index.js +294 -0
  38. package/dist/infrastructure/file-system-vault.js +15 -0
  39. package/dist/infrastructure/paths.js +9 -1
  40. package/dist/infrastructure/private-pack-codec.js +73 -0
  41. package/dist/infrastructure/search-packs.js +348 -0
  42. package/dist/infrastructure/session-state.js +172 -0
  43. package/dist/mcp/main.js +11 -3
  44. package/dist/mcp/server.js +17 -2
  45. package/dist/mcp/startup.js +35 -0
  46. package/dist/mcp/tools.js +571 -19
  47. package/docs/AGENT_USAGE.md +112 -16
  48. package/docs/ARCHITECTURE.md +37 -26
  49. package/docs/QUICKSTART.md +111 -0
  50. package/package.json +2 -3
  51. package/dist/infrastructure/sqlite/document-writer.js +0 -51
  52. package/dist/infrastructure/sqlite/graph-reader.js +0 -120
  53. package/dist/infrastructure/sqlite/schema.js +0 -111
  54. package/dist/infrastructure/sqlite/search-reader.js +0 -156
  55. package/dist/infrastructure/sqlite/types.js +0 -1
  56. package/dist/infrastructure/sqlite-index.js +0 -25
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 SQLite full-text index, and returns compact context packages that agents can inject into prompts.
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 SQLite database at `.brainlink/brainlink.db` is a derived index. It can be deleted and rebuilt with:
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 SQLite.
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
 
@@ -107,10 +107,10 @@ npm run dev -- doctor --vault ./vault
107
107
 
108
108
  - Keep domain rules in `src/domain`.
109
109
  - Keep use cases in `src/application`.
110
- - Keep filesystem and SQLite details in `src/infrastructure`.
110
+ - Keep filesystem and index details in `src/infrastructure`.
111
111
  - Keep CLI concerns in `src/cli`.
112
112
  - Prefer pure functions for parsing, ranking, formatting, and transformation.
113
- - Do not make SQLite the canonical storage layer.
113
+ - Do not make index artifacts the canonical storage layer.
114
114
  - Do not add comments with emojis.
115
115
  - Keep JSON output backwards compatible where possible.
116
116
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-beta.4
4
+
5
+ - Added bootstrap session-state persistence in `$BRAINLINK_HOME/session-state.json` for vault/agent readiness tracking.
6
+ - Added MCP `brainlink_policy` tool and default bootstrap enforcement for read tools.
7
+ - Added `agent install --self-test` diagnostics and bootstrap readiness details in `agent status`.
8
+ - Added `agent upgrade` for legacy installations to reapply latest MCP/plugin defaults with self-test diagnostics.
9
+ - Added `config doctor --fix` safe autofix mode with dry-run default behavior.
10
+ - Added detailed per-file migration reporting through `migrate-vault --report`.
11
+ - Added `quickstart` command to run plug-and-play vault + bootstrap + agent setup in one flow.
12
+ - Added structured MCP `nextActions` in bootstrap/policy/preflight responses for automatic client continuation.
13
+ - Added default MCP read auto-bootstrap behavior controlled by `brainlink_policy.autoBootstrapOnRead`.
14
+ - Added default MCP startup bootstrap behavior controlled by `brainlink_policy.autoBootstrapOnStartup`.
15
+ - Added CLI MCP policy presets through `blink agent policy --preset fully-auto|strict`.
16
+ - Added write-time non-orphan enforcement by auto-linking notes without wiki edges to agent hub notes.
17
+ - Added MCP `brainlink_policy` presets (`fully-auto`, `strict`) for one-call policy switching.
18
+ - Added MCP write connectivity metadata in `brainlink_add_note`/`brainlink_add_file` responses.
19
+ - Added MCP `brainlink_recommendations` tool for plug-and-play workflow guidance.
20
+ - Improved graph/index robustness by splitting oversized paragraphs into bounded chunks and dropping self-referential links.
21
+ - Added `agentProfiles` configuration support so CLI and MCP can resolve per-agent defaults for mode/limit/tokens.
22
+ - Added short-lived hybrid search cache with automatic invalidation on index changes.
23
+ - Added `stats --extended` observability output with storage, quality and latency probes.
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
+
28
+ ## 0.1.0-beta.3
29
+
30
+ - Added CLI configuration commands for effective vault management, including `config where`, `config get`, `config doctor` and `config set-vault`.
31
+ - Added explicit `migrate-vault` command with `--dry-run` preview and conflict-preserving copy behavior.
32
+ - Added one-command agent setup through `agent install` plus `agent status` diagnostics.
33
+ - Added MCP `brainlink_bootstrap` default entrypoint guidance for plug-and-play agent memory flows.
34
+ - Added migration coverage for S3 bucket vault targets.
35
+ - Updated architecture and agent-usage documentation to reflect current CLI/MCP behavior and configuration precedence.
36
+
3
37
  ## 0.1.0-beta.2
4
38
 
5
39
  - Added MCP installation guidance for direct server configuration and local client stores.
@@ -9,7 +43,7 @@
9
43
 
10
44
  ## 0.1.0-beta.0
11
45
 
12
- - Promoted the package from alpha to beta.
46
+ - Promoted the package to the beta prerelease channel.
13
47
  - Added built-in MCP stdio server distribution through `brainlink-mcp`.
14
48
  - Added agent namespaces, auto-indexing on writes and file ingestion flows.
15
49
  - Added S3-compatible bucket vault support and weighted graph relationships.
@@ -17,8 +51,8 @@
17
51
  ## 0.1.0-alpha.0
18
52
 
19
53
  - Added local-first Markdown vault indexing.
20
- - Added SQLite FTS, local semantic retrieval, wiki links, backlinks and graph retrieval.
21
- - Added SQLite semantic bucket indexing to narrow vector candidates for larger vaults.
54
+ - Added local full-text indexing, local semantic retrieval, wiki links, backlinks and graph retrieval.
55
+ - Added semantic candidate bucket indexing to narrow vector candidates for larger vaults.
22
56
  - Optimized title/link resolution with precomputed agent-scoped title maps.
23
57
  - Added CLI, JSON output, HTTP API and graph UI.
24
58
  - 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
- - SQLite is a derived index and must remain rebuildable.
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 SQLite code are adapters around application use cases.
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
@@ -0,0 +1,5 @@
1
+ Copyright (c) 2026 Anderson Espindola
2
+
3
+ This project is licensed under the MIT License.
4
+
5
+ See [LICENSE](./LICENSE) for full terms.
package/README.md CHANGED
@@ -52,11 +52,14 @@ 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 SQLite index with FTS records and local embeddings.
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/brainlink.db` is only a rebuildable index.
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
+ Pack decryption uses a Brainlink key from `$BRAINLINK_HOME/keys` or from `BRAINLINK_SEARCH_PACK_KEY` when explicitly configured.
62
+ Legacy `.jsonl.gz` packs are upgraded to `.blpk` automatically on first search/context access.
60
63
 
61
64
  ## Features
62
65
 
@@ -64,8 +67,9 @@ Markdown is the source of truth. `.brainlink/brainlink.db` is only a rebuildable
64
67
  - Obsidian-compatible `[[wiki links]]` and `#tags`.
65
68
  - Weighted graph edges so agents can rank relationship importance and priority.
66
69
  - Backlinks, broken-link reports, orphan detection and validation.
67
- - Full-text, semantic and hybrid retrieval modes.
68
- - SQLite-backed semantic candidate buckets for larger vaults.
70
+ - Full-text, semantic and hybrid retrieval on a local file index.
71
+ - Middle-out context assembly around the strongest chunk per document.
72
+ - Compressed-space prefiltering for `.blpk` packs before decryption and scan.
69
73
  - Agent namespaces under `agents/<agent-id>/`.
70
74
  - S3-compatible bucket vaults through `s3://bucket/prefix` URIs.
71
75
  - CLI with machine-readable `--json` output.
@@ -106,6 +110,8 @@ npx @andespindola/brainlink@latest --help
106
110
 
107
111
  This section is written for agents. If you are an AI agent operating in a user workspace, use this workflow to install and use Brainlink without requiring the user to run commands manually.
108
112
 
113
+ For a condensed setup path, see [docs/QUICKSTART.md](./docs/QUICKSTART.md).
114
+
109
115
  ### 1. Check Whether Brainlink Is Installed
110
116
 
111
117
  ```bash
@@ -280,7 +286,7 @@ export BRAINLINK_S3_FORCE_PATH_STYLE=1
280
286
 
281
287
  Bucket vaults mirror Markdown into a local cache under
282
288
  `$BRAINLINK_HOME/bucket-cache`. The bucket remains canonical; the local
283
- `.brainlink/brainlink.db` stays a disposable index. Run `index` after remote
289
+ `.brainlink/index.json` stays a disposable index artifact. Run `index` after remote
284
290
  bucket changes before relying on `search`, `context`, graph or validation
285
291
  commands. Watch mode is only supported for local filesystem vaults.
286
292
 
@@ -296,7 +302,7 @@ vault/
296
302
  research-agent/
297
303
  source-review-policy.md
298
304
  .brainlink/
299
- brainlink.db
305
+ index.json
300
306
  ```
301
307
 
302
308
  Permanent data:
@@ -306,7 +312,7 @@ Permanent data:
306
312
 
307
313
  Rebuildable data:
308
314
 
309
- - `.brainlink/brainlink.db`
315
+ - `.brainlink/index.json`
310
316
  - full-text records
311
317
  - local embedding vectors
312
318
  - local embedding buckets
@@ -380,6 +386,35 @@ Example MCP client configuration:
380
386
  }
381
387
  ```
382
388
 
389
+ ### One-Command Agent Setup
390
+
391
+ If your agent runtime is Codex-compatible, run:
392
+
393
+ ```bash
394
+ blink agent install --self-test
395
+ blink agent upgrade
396
+ ```
397
+
398
+ This configures `~/.codex/config.toml` with Brainlink MCP (`brainlink-mcp`) so Brainlink is available by default in agent sessions.
399
+
400
+ If you are inside this repository and want plugin gallery setup too:
401
+
402
+ ```bash
403
+ blink agent install --plugin-path ./plugins/brainlink
404
+ ```
405
+
406
+ To verify:
407
+
408
+ ```bash
409
+ blink agent status
410
+ ```
411
+
412
+ For fully automated first run (vault index + health + bootstrap readiness + agent integration):
413
+
414
+ ```bash
415
+ blink quickstart --query "what should I know before this task?" --json
416
+ ```
417
+
383
418
  For a locked-down setup, allowlist the vaults that MCP clients may access:
384
419
 
385
420
  ```json
@@ -475,6 +510,9 @@ Restart the client after changing marketplace or MCP configuration so it reloads
475
510
 
476
511
  Available tools:
477
512
 
513
+ - `brainlink_bootstrap`: plug-and-play entrypoint that runs index + health checks and can return context in one call.
514
+ - `brainlink_policy`: read or update bootstrap/context-first policy, including presets (`preset: "fully-auto" | "strict"`).
515
+ - `brainlink_recommendations`: return an automatic action plan so agents can run Brainlink in the recommended order.
478
516
  - `brainlink_context`: read indexed context for a task or question.
479
517
  - `brainlink_search`: search indexed notes.
480
518
  - `brainlink_add_note`: write durable Markdown memory and reindex.
@@ -487,7 +525,15 @@ Available tools:
487
525
  - `brainlink_broken_links`: list unresolved wiki links.
488
526
  - `brainlink_orphans`: list disconnected notes.
489
527
 
490
- The same linking rule applies through MCP: `brainlink_context` is read-only, and real graph links require Markdown notes with explicit `[[wiki links]]`. `brainlink_add_note` and `brainlink_add_file` reindex by default and include the index result when enabled.
528
+ For the most automatic workflow, start MCP sessions with `brainlink_bootstrap` (optionally with `query`) and then continue with `brainlink_context`/`brainlink_add_note`.
529
+ By default, Brainlink enforces context-first for MCP reads (`enforceContextFirst=true`): non-context read tools return preflight until `brainlink_context` is called for the vault/agent session.
530
+ By default, MCP startup already runs bootstrap on the configured default vault/agent (`autoBootstrapOnStartup=true`), so sessions begin warm.
531
+ By default, Brainlink enforces bootstrap and auto-runs it for read tools when session state is missing or stale (`autoBootstrapOnRead=true`).
532
+ If you disable `autoBootstrapOnRead` through `brainlink_policy`, read tools return a preflight instruction with suggested `brainlink_bootstrap` arguments.
533
+ `brainlink_bootstrap`, `brainlink_policy` and preflight responses include structured `nextActions` so MCP clients can continue automatically without custom parsing.
534
+ For one-call planning, use `brainlink_recommendations` to get the recommended tool sequence for the current vault/agent/query.
535
+
536
+ The same linking rule applies through MCP: `brainlink_context` is read-only, and real graph links require Markdown notes with explicit `[[wiki links]]`. `brainlink_add_note` and `brainlink_add_file` reindex by default and include index + `writeConnectivity` metadata. Brainlink guarantees at least one edge per new note by auto-linking when needed.
491
537
 
492
538
  Agents can raise the importance of a relationship by putting priority markers on the same line as a wiki link:
493
539
 
@@ -512,11 +558,17 @@ The graph UI shows:
512
558
 
513
559
  - notes as nodes
514
560
  - `[[wiki links]]` as weighted edges
515
- - backlinks and outgoing links
516
- - full Markdown content for the selected note
561
+ - details opened on node click (tags, outgoing links, backlinks, full Markdown content)
517
562
  - neutral graph nodes with segment/group metadata
518
- - agent selector for isolated views
563
+ - agent selector (id-only labels) for isolated views
564
+ - graph filter matches title, path, tags and note content
519
565
  - realtime refresh while `--watch` is enabled
566
+ - graph controls for zoom in, zoom out, fit visible nodes and reset-to-fit-all
567
+ - wheel zoom (including `cmd+scroll` and `ctrl+scroll`) anchored to cursor position for faster navigation in large graphs
568
+ - keyboard shortcuts: `+` zoom in, `-` zoom out, `0` reset fit
569
+ - double-click on canvas zooms in at cursor position
570
+ - floating graph totals (notes, links, tags) below the Brainlink title
571
+ - large-graph rendering safeguards (edge draw caps, lower redraw rate, zoom-aware interaction)
520
572
 
521
573
  The server indexes before starting by default. Use `--no-index` to skip that step:
522
574
 
@@ -535,6 +587,7 @@ Routes:
535
587
  - `GET /api/agents`
536
588
  - `GET /api/graph`
537
589
  - `GET /api/graph-layout`
590
+ - `GET /api/graph-node?id=<node-id>`
538
591
  - `GET /api/search?q=<query>&limit=10&mode=hybrid`
539
592
  - `GET /api/context?q=<query>&limit=12&tokens=2000&mode=hybrid`
540
593
  - `GET /api/links`
@@ -556,14 +609,89 @@ Read routes accept `agent=<agent-id>`:
556
609
 
557
610
  Every command works with either `brainlink` or `blink`.
558
611
 
612
+ ### `agent`
613
+
614
+ ```bash
615
+ blink agent install
616
+ blink agent install --self-test
617
+ blink agent upgrade
618
+ blink agent policy --preset fully-auto
619
+ blink agent policy --preset strict
620
+ blink agent policy --enforce-context-first false
621
+ blink agent install --plugin-path ./plugins/brainlink
622
+ blink agent install --mcp-only --allowed-vaults "/absolute/vault,/absolute/team-vault"
623
+ blink agent status
624
+ ```
625
+
626
+ Installs/checks agent integration. `install` writes Brainlink MCP config into `~/.codex/config.toml`.
627
+ When plugin files are available, it also links Brainlink plugin files into `~/plugins/brainlink` and updates `~/.agents/plugins/marketplace.json`.
628
+ With `--self-test`, install also validates MCP block presence, command wiring and local plugin registration signals.
629
+ Use `agent upgrade` on legacy installations to reapply current defaults and run the same self-test diagnostics.
630
+ Use `agent policy --preset fully-auto` for plug-and-play defaults, or `agent policy --preset strict` to require explicit bootstrap calls.
631
+ Both presets keep `enforceContextFirst=true` so Brainlink stays the primary context source for MCP sessions.
632
+
633
+ ### `quickstart`
634
+
635
+ ```bash
636
+ blink quickstart --json
637
+ blink quickstart --vault ./team-vault --agent coding-agent --query "architecture decisions" --json
638
+ blink quickstart --vault ./team-vault --mcp-only --json
639
+ ```
640
+
641
+ Runs index + doctor + stats + validation, refreshes bootstrap session readiness, optionally returns context for a query, and (by default) upgrades local agent integration for plug-and-play MCP usage.
642
+ When `--mode`, `--limit` or `--tokens` are omitted, quickstart uses agent profile defaults when available.
643
+
644
+ ### `config`
645
+
646
+ ```bash
647
+ blink config where
648
+ blink config get vault
649
+ blink config doctor
650
+ blink config doctor --fix
651
+ blink config set-vault /absolute/path/to/existing-vault
652
+ blink config set-vault /absolute/path/to/existing-vault --migrate-from ~/.brainlink/vault
653
+ blink config set-vault "s3://my-memory-bucket/brainlink" --global
654
+ ```
655
+
656
+ `config set-vault` writes configuration through CLI (no manual file edits required).
657
+ By default it writes local config (`./brainlink.config.json`), appends the vault to `allowedVaults`, and migrates Markdown memory from the current configured vault when the target is empty.
658
+ Use `--global` to write to `$BRAINLINK_HOME/brainlink.config.json`, `--no-migrate` to skip migration, and `--no-index` to skip post-migration indexing.
659
+ `config doctor` is dry-run by default; use `--fix` to apply safe config normalization and allowlist fixes.
660
+
661
+ ### `migrate-vault`
662
+
663
+ ```bash
664
+ blink migrate-vault --from ~/.brainlink/vault --to ./team-vault --dry-run
665
+ blink migrate-vault --from ~/.brainlink/vault --to ./team-vault
666
+ blink migrate-vault --from ~/.brainlink/vault --to "s3://my-memory-bucket/brainlink"
667
+ blink migrate-vault --from ~/.brainlink/vault --to ./team-vault --report ./migration-report.json
668
+ ```
669
+
670
+ Runs explicit markdown migration between vaults while preserving conflicts as `.conflict-<timestamp>` files.
671
+ Use `--dry-run` to preview `copied`, `conflicted` and `unchanged` counts before writing.
672
+
673
+ ### `db-import`
674
+
675
+ ```bash
676
+ blink db-import --vault ./team-vault
677
+ blink db-import --vault ./team-vault --db ./legacy/brainlink.db
678
+ blink db-import --vault ./team-vault --db ./legacy/brainlink.db --table legacy_notes --dry-run
679
+ ```
680
+
681
+ Imports durable memory from a legacy SQLite database into Markdown notes (`agents/<agent-id>/*.md`) and reindexes by default.
682
+ When `--db` is omitted, Brainlink auto-detects common legacy paths such as `<vault>/.brainlink/brainlink.db`.
683
+ 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.
684
+
559
685
  ### `init`
560
686
 
561
687
  ```bash
562
688
  blink init
563
689
  blink init ./vault
690
+ blink init ./team-vault --migrate-from ~/.brainlink/vault
564
691
  ```
565
692
 
566
693
  Initializes vault metadata. Without an argument, Brainlink initializes the default vault at `$HOME/.brainlink/vault`.
694
+ When initializing an empty custom vault, existing Markdown content from the default vault is copied into it and reindexed so context is not left behind. Use `--no-migrate-existing` to start with an empty custom vault, or `--migrate-from <vault>` to copy from a specific source. Existing target files are never overwritten; conflicting source files are preserved with a `.conflict-<timestamp>` suffix.
567
695
 
568
696
  ### `add`
569
697
 
@@ -577,6 +705,7 @@ blink add "Note Title" --vault ./vault --content-file ./notes.md --no-auto-index
577
705
  `--content` and `--content-file` are mutually exclusive. Add `--no-auto-index` when you want to defer reindexing.
578
706
 
579
707
  Creates a Markdown note under `agents/<agent-id>/`. Common secret patterns are blocked by default; use `--allow-sensitive` only for an intentionally protected vault.
708
+ To avoid disconnected memory, Brainlink auto-adds a fallback wiki edge when a note is written without links, creating agent hub notes when needed.
580
709
 
581
710
  ### `index`
582
711
 
@@ -605,13 +734,17 @@ blink search "query" --vault ./vault --mode semantic --json
605
734
  ```
606
735
 
607
736
  Runs retrieval over indexed chunks.
737
+ If `--mode` or `--limit` is omitted, Brainlink resolves values from the current agent profile before falling back to global defaults.
608
738
 
609
739
  Modes:
610
740
 
611
- - `hybrid`: default; combines SQLite FTS with local embedding similarity.
612
- - `fts`: exact lexical retrieval through SQLite FTS.
741
+ - `hybrid`: default; combines lexical matching with local embedding similarity.
742
+ - `fts`: exact lexical retrieval from the file index.
613
743
  - `semantic`: local deterministic embedding similarity only.
614
744
 
745
+ Hybrid results are cached in-memory for a short TTL and invalidated automatically when the local index file changes.
746
+ 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.
747
+
615
748
  ### `context`
616
749
 
617
750
  ```bash
@@ -654,9 +787,11 @@ Prints indexed graph data. Edges include `weight` and `priority` so agents can c
654
787
  ```bash
655
788
  blink stats --vault ./vault
656
789
  blink stats --vault ./vault --agent coding-agent --json
790
+ blink stats --vault ./vault --agent coding-agent --extended --json
657
791
  ```
658
792
 
659
793
  Prints vault metrics.
794
+ Use `--extended` to include storage footprint, link quality ratios and observability probes (`index`, `search`, `context` latencies).
660
795
 
661
796
  ### `broken-links`
662
797
 
@@ -688,7 +823,7 @@ Validates graph health. The command exits non-zero when required checks fail.
688
823
  blink doctor --vault ./vault
689
824
  ```
690
825
 
691
- Runs environment and vault checks.
826
+ Runs environment and vault checks. When vault has zero markdown and zero indexed documents, `doctor` prints recommended next steps (add note, inspect config source, migrate memory).
692
827
 
693
828
  ### `watch`
694
829
 
@@ -725,7 +860,13 @@ npm run --silent dev -- context "question" --vault ./vault --json
725
860
 
726
861
  ## Configuration
727
862
 
728
- Brainlink reads `brainlink.config.json` or `.brainlink.json` from the current working directory. If no `vault` is configured and no `--vault` flag is passed, Brainlink uses `$HOME/.brainlink/vault`.
863
+ Brainlink merges configuration in this order:
864
+
865
+ 1. Global: `$BRAINLINK_HOME/brainlink.config.json` (or `$HOME/.brainlink/brainlink.config.json` by default)
866
+ 2. Local: `brainlink.config.json` in the current working directory
867
+ 3. Local legacy compatibility: `.brainlink.json` in the current working directory
868
+
869
+ If no `vault` is configured and no `--vault` flag is passed, Brainlink uses `$HOME/.brainlink/vault`.
729
870
 
730
871
  ```json
731
872
  {
@@ -739,11 +880,22 @@ Brainlink reads `brainlink.config.json` or `.brainlink.json` from the current wo
739
880
  "defaultContextTokens": 2000,
740
881
  "embeddingProvider": "local",
741
882
  "defaultSearchMode": "hybrid",
742
- "chunkSize": 1200
883
+ "chunkSize": 1200,
884
+ "agentProfiles": {
885
+ "coding-agent": {
886
+ "defaultSearchMode": "semantic",
887
+ "defaultSearchLimit": 8,
888
+ "defaultContextTokens": 2400
889
+ },
890
+ "*": {
891
+ "defaultSearchMode": "hybrid"
892
+ }
893
+ }
743
894
  }
744
895
  ```
745
896
 
746
897
  `defaultAgent` is optional. When set, CLI and MCP calls that omit `--agent`/`agent` use this value automatically. If not set, behavior remains as before.
898
+ `agentProfiles` is optional. When present, CLI and MCP resolve `mode`, `limit` and `tokens` per agent automatically, then fallback to global defaults.
747
899
 
748
900
  `autoIndexOnWrite` is optional and defaults to `true`. Set it to `false` to defer indexing after writes.
749
901
 
@@ -840,7 +992,7 @@ src/
840
992
  application/ use cases
841
993
  cli/ command-line adapter
842
994
  domain/ pure knowledge rules
843
- infrastructure/ filesystem and SQLite adapters
995
+ infrastructure/ filesystem and index adapters
844
996
  ```
845
997
 
846
998
  Detailed notes:
@@ -852,7 +1004,6 @@ Detailed notes:
852
1004
  ## Current Limits
853
1005
 
854
1006
  - Semantic search uses deterministic local embeddings, not a remote model provider.
855
- - Semantic search uses SQLite embedding buckets to narrow candidates before cosine scoring.
856
1007
  - `embeddingProvider` currently supports `local` and `none`.
857
1008
  - Link resolution is title-based inside each agent namespace, with `shared` as fallback.
858
1009
  - HTTP API is local and unauthenticated.
@@ -863,7 +1014,7 @@ Detailed notes:
863
1014
  The `0.1.0-beta` line is intended to stabilize the local-first memory loop:
864
1015
 
865
1016
  - Markdown as durable memory.
866
- - SQLite FTS plus local embeddings and semantic buckets as rebuildable retrieval index.
1017
+ - Rebuildable file index plus local embeddings and encrypted pack exports.
867
1018
  - CLI as the primary agent interface.
868
1019
  - HTTP graph API and frontend as inspection tools.
869
1020
  - Agent namespaces to avoid context mixing.
@@ -879,7 +1030,7 @@ Brainlink is local-first by default.
879
1030
  - Brainlink HTTP is localhost-only and refuses non-loopback hosts.
880
1031
  - Brainlink blocks common secret patterns by default when adding notes. Use `--allow-sensitive` only for intentional, protected vaults.
881
1032
  - Do not store secrets, credentials, API keys or regulated personal data unless the vault is protected by your own storage controls.
882
- - Treat `.brainlink/brainlink.db` as disposable derived data.
1033
+ - Treat `.brainlink/index.json` and `.brainlink/search-packs/` as disposable derived artifacts.
883
1034
 
884
1035
  See [SECURITY.md](SECURITY.md).
885
1036
 
@@ -890,6 +1041,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md).
890
1041
  ## License
891
1042
 
892
1043
  MIT. See [LICENSE](LICENSE).
1044
+ Copyright (c) 2026 Anderson Espindola. See [COPYRIGHT.md](COPYRIGHT.md).
893
1045
 
894
1046
  ### Memory Optimization Loop (1-7)
895
1047
 
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
- - The SQLite database is a derived local index.
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,30 +1,79 @@
1
+ import { access } from 'node:fs/promises';
2
+ import { join } from 'node:path';
1
3
  import { writeMarkdownFile } from '../infrastructure/file-system-vault.js';
2
4
  import { sanitizeAgentId, sharedAgentId } from '../domain/agents.js';
5
+ import { extractWikiLinks } from '../domain/markdown.js';
3
6
  import { validateNoteInput } from '../domain/note-safety.js';
7
+ import { ensureVault } from '../infrastructure/file-system-vault.js';
4
8
  const slugify = (title) => title
5
9
  .normalize('NFKD')
6
10
  .replace(/[\u0300-\u036f]/g, '')
7
11
  .toLowerCase()
8
12
  .replace(/[^a-z0-9]+/g, '-')
9
13
  .replace(/^-+|-+$/g, '');
10
- export const addNote = async (vaultPath, title, content, agentId = sharedAgentId, options = {}) => {
14
+ const systemHubTitle = 'Memory Hub';
15
+ const systemRootTitle = 'Knowledge Root';
16
+ const normalizeTitle = (title) => title.trim().replace(/\.md$/i, '').toLowerCase();
17
+ const noteFilename = (agentId, title) => `agents/${agentId}/${slugify(title) || 'untitled'}.md`;
18
+ const buildNote = (title, content, agentId) => [
19
+ `---`,
20
+ `title: "${title.replaceAll('"', '\\"')}"`,
21
+ `agent: "${agentId}"`,
22
+ `---`,
23
+ '',
24
+ `# ${title}`,
25
+ '',
26
+ content.trim(),
27
+ ''
28
+ ].join('\n');
29
+ const ensureSystemNote = async (vaultPath, absoluteVaultPath, agentId, title, content) => {
30
+ const filename = noteFilename(agentId, title);
31
+ const absolutePath = join(absoluteVaultPath, filename);
32
+ try {
33
+ await access(absolutePath);
34
+ return;
35
+ }
36
+ catch { }
37
+ await writeMarkdownFile(vaultPath, filename, buildNote(title, content, agentId));
38
+ };
39
+ const ensureNonOrphanContent = async (vaultPath, absoluteVaultPath, title, content, agentId) => {
40
+ const links = extractWikiLinks(content).filter((link) => normalizeTitle(link) !== normalizeTitle(title));
41
+ if (links.length > 0) {
42
+ return {
43
+ content: content.trim(),
44
+ autoLinked: false,
45
+ linkTarget: null
46
+ };
47
+ }
48
+ const fallbackTitle = normalizeTitle(title) === normalizeTitle(systemHubTitle) ? systemRootTitle : systemHubTitle;
49
+ if (fallbackTitle === systemRootTitle) {
50
+ await ensureSystemNote(vaultPath, absoluteVaultPath, agentId, systemRootTitle, `Entry point for agent memory. [[${systemHubTitle}]] #memory #root`);
51
+ }
52
+ else {
53
+ await ensureSystemNote(vaultPath, absoluteVaultPath, agentId, systemHubTitle, 'Central memory index for this agent namespace. #memory #hub');
54
+ }
55
+ return {
56
+ content: `${content.trim()}\n\nRelated: [[${fallbackTitle}]]`,
57
+ autoLinked: true,
58
+ linkTarget: fallbackTitle
59
+ };
60
+ };
61
+ export const addNoteWithMetadata = async (vaultPath, title, content, agentId = sharedAgentId, options = {}) => {
11
62
  validateNoteInput({
12
63
  title,
13
64
  content,
14
65
  allowSensitive: options.allowSensitive
15
66
  });
16
67
  const sanitizedAgentId = sanitizeAgentId(agentId);
68
+ const absoluteVaultPath = await ensureVault(vaultPath);
17
69
  const filename = `agents/${sanitizedAgentId}/${slugify(title) || 'untitled'}.md`;
18
- const note = [
19
- `---`,
20
- `title: "${title.replaceAll('"', '\\"')}"`,
21
- `agent: "${sanitizedAgentId}"`,
22
- `---`,
23
- '',
24
- `# ${title}`,
25
- '',
26
- content.trim(),
27
- ''
28
- ].join('\n');
29
- return writeMarkdownFile(vaultPath, filename, note);
70
+ const linkedContent = await ensureNonOrphanContent(vaultPath, absoluteVaultPath, title, content, sanitizedAgentId);
71
+ const note = buildNote(title, linkedContent.content, sanitizedAgentId);
72
+ const path = await writeMarkdownFile(vaultPath, filename, note);
73
+ return {
74
+ path,
75
+ autoLinked: linkedContent.autoLinked,
76
+ linkTarget: linkedContent.linkTarget
77
+ };
30
78
  };
79
+ export const addNote = async (vaultPath, title, content, agentId = sharedAgentId, options = {}) => (await addNoteWithMetadata(vaultPath, title, content, agentId, options)).path;