@andespindola/brainlink 1.10.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/application/get-graph-neighbors.js +44 -0
- package/dist/cli/commands/read-commands.js +28 -0
- package/dist/domain/graph-neighbors.js +79 -0
- package/dist/mcp/server.js +6 -1
- package/dist/mcp/tools/read-tools.js +34 -0
- package/dist/mcp/tools.js +1 -1
- package/docs/AGENT_USAGE.md +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -585,6 +585,7 @@ Available tools:
|
|
|
585
585
|
- `brainlink_vault_transfer_export` / `brainlink_vault_transfer_import`: move a vault **between two Brainlinks over MCP** without a file on disk. An agent connected to both servers calls `transfer_export` on the source (returns the vault as an encrypted, base64 payload) and `transfer_import` on the target (applies the payload and reindexes). A shared `passphrase` (min 8 chars) is mandatory since the payload travels through the agent's context. Same checksum verification and `*.conflict-<ts>.md` preservation as snapshot import.
|
|
586
586
|
- `brainlink_vault_merge_agents`: losslessly merge one agent namespace into another within the same vault (e.g. `claude-code` → `shared`). Identical notes are skipped, colliding slugs with different content are kept under a `-from-<agent>` name, everything else is moved, and merged notes are aggregated into domain `<context> Hub` notes. Source notes are kept unless `deleteSource` is set; `dryRun` previews the plan.
|
|
587
587
|
- `brainlink_graph`: read indexed graph nodes and weighted links.
|
|
588
|
+
- `brainlink_neighbors`: traverse the wiki-link graph outward from a root note (by `title` or `path`) up to `depth` hops, returning the reached nodes annotated with hop distance plus the edges between them. `limit` caps the node count (default 50) and reports `truncated` when it stops early. Complements `brainlink_graph` (whole graph) and `brainlink_similar_notes` (semantic neighbors).
|
|
588
589
|
- `brainlink_graph_contexts`: list the visual graph contexts used by the local server.
|
|
589
590
|
- `brainlink_broken_links`: list unresolved wiki links.
|
|
590
591
|
- `brainlink_suggest_links`: suggest Context Links for content or fixes for unresolved wiki links.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { traverseGraphNeighbors } from '../domain/graph-neighbors.js';
|
|
3
|
+
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
4
|
+
import { getGraph } from './get-graph.js';
|
|
5
|
+
const defaultDepth = 1;
|
|
6
|
+
const defaultLimit = 50;
|
|
7
|
+
const normalizeTitleKey = (title) => title.trim().replace(/\.md$/i, '').toLowerCase();
|
|
8
|
+
const resolveRoot = (absoluteVaultPath, nodes, input) => {
|
|
9
|
+
if (input.path != null && input.path.trim().length > 0) {
|
|
10
|
+
const expected = resolve(absoluteVaultPath, input.path);
|
|
11
|
+
const match = nodes.find((node) => resolve(absoluteVaultPath, node.path) === expected);
|
|
12
|
+
if (!match) {
|
|
13
|
+
throw new Error(`No note found at path: ${input.path}`);
|
|
14
|
+
}
|
|
15
|
+
return match;
|
|
16
|
+
}
|
|
17
|
+
const expectedTitle = normalizeTitleKey(input.title ?? '');
|
|
18
|
+
const matches = nodes.filter((node) => normalizeTitleKey(node.title) === expectedTitle);
|
|
19
|
+
if (matches.length === 0) {
|
|
20
|
+
throw new Error(`No note found with title: ${input.title}`);
|
|
21
|
+
}
|
|
22
|
+
if (matches.length > 1) {
|
|
23
|
+
throw new Error(`Multiple notes match title "${input.title}". Use path instead: ${matches.map((node) => node.path).join(', ')}`);
|
|
24
|
+
}
|
|
25
|
+
return matches[0];
|
|
26
|
+
};
|
|
27
|
+
// Expand the wiki-link graph outward from a single root note, selected by title
|
|
28
|
+
// or path, up to a bounded hop distance. This is the traversal counterpart to
|
|
29
|
+
// `getGraph` (whole graph) and `findSimilarNotes` (semantic neighbors).
|
|
30
|
+
export const getGraphNeighbors = async (vaultPath, input) => {
|
|
31
|
+
const hasTitle = input.title != null && input.title.trim().length > 0;
|
|
32
|
+
const hasPath = input.path != null && input.path.trim().length > 0;
|
|
33
|
+
if (hasTitle === hasPath) {
|
|
34
|
+
throw new Error('Use exactly one selector: title or path.');
|
|
35
|
+
}
|
|
36
|
+
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
37
|
+
const graph = await getGraph(vaultPath, input.agentId);
|
|
38
|
+
const root = resolveRoot(absoluteVaultPath, graph.nodes, input);
|
|
39
|
+
const neighborhood = traverseGraphNeighbors(graph, root.id, {
|
|
40
|
+
depth: input.depth ?? defaultDepth,
|
|
41
|
+
limit: input.limit ?? defaultLimit
|
|
42
|
+
});
|
|
43
|
+
return { ...neighborhood, root: { id: root.id, title: root.title, path: root.path } };
|
|
44
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getBrokenLinksReport, getExtendedStats, getOrphansReport, getStats, validateVault } from '../../application/analyze-vault.js';
|
|
2
2
|
import { buildContextPackage, readContextDataSignature, readVolatileSignature } from '../../application/build-context.js';
|
|
3
3
|
import { getGraph } from '../../application/get-graph.js';
|
|
4
|
+
import { getGraphNeighbors } from '../../application/get-graph-neighbors.js';
|
|
4
5
|
import { listAgents } from '../../application/list-agents.js';
|
|
5
6
|
import { listBacklinks, listLinks } from '../../application/list-links.js';
|
|
6
7
|
import { explainSearchResults } from '../../application/memory-suggestions.js';
|
|
@@ -133,6 +134,33 @@ export const registerReadCommands = (program) => {
|
|
|
133
134
|
const graph = await getGraph(resolved.vault, resolved.agent);
|
|
134
135
|
print(options.json, graph, () => JSON.stringify(graph, null, 2));
|
|
135
136
|
});
|
|
137
|
+
program
|
|
138
|
+
.command('neighbors')
|
|
139
|
+
.option('-v, --vault <vault>', 'vault directory')
|
|
140
|
+
.option('-a, --agent <agent>', 'filter by agent memory namespace')
|
|
141
|
+
.option('-t, --title <title>', 'title of the root note to expand from')
|
|
142
|
+
.option('-p, --path <path>', 'path of the root note to expand from')
|
|
143
|
+
.option('-d, --depth <depth>', 'number of hops to traverse outward (default 1)')
|
|
144
|
+
.option('-l, --limit <limit>', 'maximum nodes to return including the root (default 50)')
|
|
145
|
+
.option('--json', 'print machine-readable JSON')
|
|
146
|
+
.description('traverse the wiki-link graph outward from a root note up to a given depth')
|
|
147
|
+
.action(async (options) => {
|
|
148
|
+
const resolved = await resolveOptions(options);
|
|
149
|
+
const depth = options.depth != null ? parsePositiveInteger(options.depth, 1) : undefined;
|
|
150
|
+
const limit = options.limit != null ? parsePositiveInteger(options.limit, 50) : undefined;
|
|
151
|
+
const result = await getGraphNeighbors(resolved.vault, {
|
|
152
|
+
title: options.title,
|
|
153
|
+
path: options.path,
|
|
154
|
+
agentId: resolved.agent,
|
|
155
|
+
depth,
|
|
156
|
+
limit
|
|
157
|
+
});
|
|
158
|
+
print(options.json, result, () => [
|
|
159
|
+
`root: ${result.root.title} (${result.root.path})`,
|
|
160
|
+
`depth=${result.depth} reached=${result.reachedDepth} nodes=${result.nodes.length}${result.truncated ? ' (truncated)' : ''}`,
|
|
161
|
+
...result.nodes.map((node) => ` [${node.depth}] ${node.title} (${node.path})`)
|
|
162
|
+
].join('\n'));
|
|
163
|
+
});
|
|
136
164
|
program
|
|
137
165
|
.command('agents')
|
|
138
166
|
.option('-v, --vault <vault>', 'vault directory')
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const priorityRank = {
|
|
2
|
+
low: 0,
|
|
3
|
+
normal: 1,
|
|
4
|
+
high: 2,
|
|
5
|
+
critical: 3
|
|
6
|
+
};
|
|
7
|
+
// Rank an edge so the traversal expands the strongest links first. Weight is the
|
|
8
|
+
// primary signal; priority breaks ties between equally weighted links.
|
|
9
|
+
const edgeStrength = (edge) => edge.weight + priorityRank[edge.priority] * 0.001;
|
|
10
|
+
// Build an undirected adjacency map from the directed wiki-link edges. A note is
|
|
11
|
+
// a neighbor whether it links out to the current node or is linked from it, so
|
|
12
|
+
// each resolved edge contributes in both directions. Unresolved edges (null
|
|
13
|
+
// target) lead nowhere and are skipped.
|
|
14
|
+
const buildAdjacency = (edges) => {
|
|
15
|
+
const map = new Map();
|
|
16
|
+
const connect = (from, to, strength) => {
|
|
17
|
+
const list = map.get(from) ?? [];
|
|
18
|
+
list.push({ nodeId: to, strength });
|
|
19
|
+
map.set(from, list);
|
|
20
|
+
};
|
|
21
|
+
for (const edge of edges) {
|
|
22
|
+
if (edge.target == null) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const strength = edgeStrength(edge);
|
|
26
|
+
connect(edge.source, edge.target, strength);
|
|
27
|
+
connect(edge.target, edge.source, strength);
|
|
28
|
+
}
|
|
29
|
+
return new Map(Array.from(map.entries(), ([nodeId, neighbors]) => [
|
|
30
|
+
nodeId,
|
|
31
|
+
[...neighbors].sort((left, right) => right.strength - left.strength || left.nodeId.localeCompare(right.nodeId))
|
|
32
|
+
]));
|
|
33
|
+
};
|
|
34
|
+
// Breadth-first expansion from a root node up to `depth` hops, capped at `limit`
|
|
35
|
+
// nodes. Pure over the graph so it is trivially testable and reusable by the CLI
|
|
36
|
+
// and MCP surfaces.
|
|
37
|
+
export const traverseGraphNeighbors = (graph, rootId, options) => {
|
|
38
|
+
const maxDepth = Math.max(0, Math.floor(options.depth));
|
|
39
|
+
const limit = Math.max(1, Math.floor(options.limit));
|
|
40
|
+
const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
41
|
+
if (!nodeById.has(rootId)) {
|
|
42
|
+
throw new Error(`Root node is not part of the graph: ${rootId}`);
|
|
43
|
+
}
|
|
44
|
+
const adjacency = buildAdjacency(graph.edges);
|
|
45
|
+
const depthById = new Map([[rootId, 0]]);
|
|
46
|
+
const order = [rootId];
|
|
47
|
+
let reachedDepth = 0;
|
|
48
|
+
let truncated = false;
|
|
49
|
+
for (let head = 0; head < order.length; head += 1) {
|
|
50
|
+
const currentId = order[head];
|
|
51
|
+
const currentDepth = depthById.get(currentId) ?? 0;
|
|
52
|
+
if (currentDepth >= maxDepth) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
for (const { nodeId } of adjacency.get(currentId) ?? []) {
|
|
56
|
+
if (depthById.has(nodeId) || !nodeById.has(nodeId)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (order.length >= limit) {
|
|
60
|
+
truncated = true;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
const nextDepth = currentDepth + 1;
|
|
64
|
+
depthById.set(nodeId, nextDepth);
|
|
65
|
+
order.push(nodeId);
|
|
66
|
+
reachedDepth = Math.max(reachedDepth, nextDepth);
|
|
67
|
+
}
|
|
68
|
+
if (truncated) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const includedIds = new Set(order);
|
|
73
|
+
const nodes = order.map((id) => {
|
|
74
|
+
const { content: _content, ...rest } = nodeById.get(id);
|
|
75
|
+
return { ...rest, depth: depthById.get(id) ?? 0 };
|
|
76
|
+
});
|
|
77
|
+
const edges = graph.edges.filter((edge) => edge.target != null && includedIds.has(edge.source) && includedIds.has(edge.target));
|
|
78
|
+
return { rootId, depth: maxDepth, reachedDepth, nodes, edges, truncated };
|
|
79
|
+
};
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { addNoteInputSchema, addFileInputSchema, addFileTool, addImageInputSchema, addImageTool, addNoteTool, addNotesInputSchema, addNotesTool, deleteNoteInputSchema, deleteNoteTool, deleteNotesInputSchema, deleteNotesTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, brokenLinksInputSchema, brokenLinksTool, bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, getImageInputSchema, getImageTool, explainInputSchema, explainTool, indexInputSchema, indexTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, orphansInputSchema, orphansTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, recommendationsInputSchema, recommendationsTool, rememberInputSchema, rememberTool, repairLinksInputSchema, repairLinksTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, sessionCloseInputSchema, sessionCloseTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, syncInputSchema, syncTool, validateInputSchema, validateTool, vaultBundleListInputSchema, vaultBundleListTool, vaultCommitInputSchema, vaultCommitTool, vaultExportBundleInputSchema, vaultExportBundleTool, vaultExportInputSchema, vaultExportTool, vaultHistoryInputSchema, vaultHistoryTool, vaultImportBundleInputSchema, vaultImportBundleTool, vaultImportInputSchema, vaultImportTool, vaultInitInputSchema, vaultInitTool, vaultMergeAgentsInputSchema, vaultMergeAgentsTool, vaultProvisionInputSchema, vaultProvisionTool, vaultPullInputSchema, vaultPullTool, vaultRestoreInputSchema, vaultRestoreTool, vaultStatusInputSchema, vaultStatusTool, vaultTransferExportInputSchema, vaultTransferExportTool, vaultTransferImportInputSchema, vaultTransferImportTool, versionInputSchema, versionTool } from './tools.js';
|
|
2
|
+
import { addNoteInputSchema, addFileInputSchema, addFileTool, addImageInputSchema, addImageTool, addNoteTool, addNotesInputSchema, addNotesTool, deleteNoteInputSchema, deleteNoteTool, deleteNotesInputSchema, deleteNotesTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, brokenLinksInputSchema, brokenLinksTool, bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, neighborsInputSchema, neighborsTool, getImageInputSchema, getImageTool, explainInputSchema, explainTool, indexInputSchema, indexTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, orphansInputSchema, orphansTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, recommendationsInputSchema, recommendationsTool, rememberInputSchema, rememberTool, repairLinksInputSchema, repairLinksTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, sessionCloseInputSchema, sessionCloseTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, syncInputSchema, syncTool, validateInputSchema, validateTool, vaultBundleListInputSchema, vaultBundleListTool, vaultCommitInputSchema, vaultCommitTool, vaultExportBundleInputSchema, vaultExportBundleTool, vaultExportInputSchema, vaultExportTool, vaultHistoryInputSchema, vaultHistoryTool, vaultImportBundleInputSchema, vaultImportBundleTool, vaultImportInputSchema, vaultImportTool, vaultInitInputSchema, vaultInitTool, vaultMergeAgentsInputSchema, vaultMergeAgentsTool, vaultProvisionInputSchema, vaultProvisionTool, vaultPullInputSchema, vaultPullTool, vaultRestoreInputSchema, vaultRestoreTool, vaultStatusInputSchema, vaultStatusTool, vaultTransferExportInputSchema, vaultTransferExportTool, vaultTransferImportInputSchema, vaultTransferImportTool, versionInputSchema, versionTool } from './tools.js';
|
|
3
3
|
import { getRuntimeVersion } from './runtime.js';
|
|
4
4
|
import { brainlinkServerInstructions } from './server-instructions.js';
|
|
5
5
|
import { guardToolHandler } from './tool-guard.js';
|
|
@@ -246,6 +246,11 @@ export const createBrainlinkMcpServer = () => {
|
|
|
246
246
|
description: 'Read indexed graph nodes and wiki-link edges. Edges include weight and priority fields so agents can rank importance and priority.',
|
|
247
247
|
inputSchema: graphInputSchema
|
|
248
248
|
}, graphTool);
|
|
249
|
+
server.registerTool('brainlink_neighbors', {
|
|
250
|
+
title: 'Traverse Brainlink Graph Neighbors',
|
|
251
|
+
description: 'Traverse the wiki-link graph outward from a root note (selected by title or path) up to a given depth (hops), returning the reached nodes annotated with hop distance plus the edges between them. Complements brainlink_graph (whole graph) and brainlink_similar_notes (semantic neighbors).',
|
|
252
|
+
inputSchema: neighborsInputSchema
|
|
253
|
+
}, neighborsTool);
|
|
249
254
|
server.registerTool('brainlink_graph_contexts', {
|
|
250
255
|
title: 'List Brainlink Graph Contexts',
|
|
251
256
|
description: 'List visual graph contexts used by the Brainlink server to separate memory domains such as preferences, repositories and machine configuration.',
|
|
@@ -3,6 +3,7 @@ import { getBrokenLinksReport, getOrphansReport, getStats, validateVault } from
|
|
|
3
3
|
import { buildContextPackage, readContextDataSignature, readVolatileSignature } from '../../application/build-context.js';
|
|
4
4
|
import { getGraph } from '../../application/get-graph.js';
|
|
5
5
|
import { getGraphContexts } from '../../application/get-graph-contexts.js';
|
|
6
|
+
import { getGraphNeighbors } from '../../application/get-graph-neighbors.js';
|
|
6
7
|
import { getImage } from '../../application/get-image.js';
|
|
7
8
|
import { explainSearchResults, suggestBrokenLinkFixes, suggestContextLinks } from '../../application/memory-suggestions.js';
|
|
8
9
|
import { buildActionableDoctor } from '../../application/operational-workflows.js';
|
|
@@ -66,6 +67,14 @@ export const graphContextsInputSchema = {
|
|
|
66
67
|
...vaultInput,
|
|
67
68
|
...agentInput
|
|
68
69
|
};
|
|
70
|
+
export const neighborsInputSchema = {
|
|
71
|
+
...vaultInput,
|
|
72
|
+
...agentInput,
|
|
73
|
+
title: z.string().min(1).optional().describe('Title of the root note to expand from. Use agent or path to disambiguate.'),
|
|
74
|
+
path: z.string().min(1).optional().describe('Vault-relative or absolute path of the root note to expand from.'),
|
|
75
|
+
depth: optionalPositiveInteger().describe('Number of hops to traverse outward from the root note along wiki-link edges. Defaults to 1.'),
|
|
76
|
+
limit: optionalPositiveInteger().describe('Maximum number of nodes to return, including the root. Defaults to 50; further nodes are truncated.')
|
|
77
|
+
};
|
|
69
78
|
export const brokenLinksInputSchema = {
|
|
70
79
|
...vaultInput,
|
|
71
80
|
...agentInput
|
|
@@ -281,6 +290,31 @@ export const graphTool = async (input) => {
|
|
|
281
290
|
...graph
|
|
282
291
|
});
|
|
283
292
|
};
|
|
293
|
+
export const neighborsTool = async (input) => {
|
|
294
|
+
const context = await resolveExecutionContext(input);
|
|
295
|
+
const readiness = await ensureBootstrapReady(context, input, 'brainlink_neighbors');
|
|
296
|
+
if (readiness.preflight) {
|
|
297
|
+
return readiness.preflight;
|
|
298
|
+
}
|
|
299
|
+
const contextReadiness = await ensureContextReady(context, input, 'brainlink_neighbors');
|
|
300
|
+
if (contextReadiness.preflight) {
|
|
301
|
+
return contextReadiness.preflight;
|
|
302
|
+
}
|
|
303
|
+
const result = await getGraphNeighbors(context.vault, {
|
|
304
|
+
title: input.title,
|
|
305
|
+
path: input.path,
|
|
306
|
+
agentId: context.agent,
|
|
307
|
+
depth: input.depth,
|
|
308
|
+
limit: input.limit
|
|
309
|
+
});
|
|
310
|
+
return jsonResult({
|
|
311
|
+
vault: context.vault,
|
|
312
|
+
agent: context.agent,
|
|
313
|
+
...(readiness.bootstrap ? { bootstrap: readiness.bootstrap } : {}),
|
|
314
|
+
...(contextReadiness.context ? { contextReadiness: contextReadiness.context } : {}),
|
|
315
|
+
...result
|
|
316
|
+
});
|
|
317
|
+
};
|
|
284
318
|
export const graphContextsTool = async (input) => {
|
|
285
319
|
const context = await resolveExecutionContext(input);
|
|
286
320
|
const readiness = await ensureBootstrapReady(context, input, 'brainlink_graph_contexts');
|
package/dist/mcp/tools.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { brokenLinksInputSchema, brokenLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, explainInputSchema, explainTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, getImageInputSchema, getImageTool, orphansInputSchema, orphansTool, recommendationsInputSchema, recommendationsTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, validateInputSchema, validateTool, versionInputSchema, versionTool } from './tools/read-tools.js';
|
|
1
|
+
export { brokenLinksInputSchema, brokenLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, explainInputSchema, explainTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, neighborsInputSchema, neighborsTool, getImageInputSchema, getImageTool, orphansInputSchema, orphansTool, recommendationsInputSchema, recommendationsTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, validateInputSchema, validateTool, versionInputSchema, versionTool } from './tools/read-tools.js';
|
|
2
2
|
export { addFileInputSchema, addFileTool, addImageInputSchema, addImageTool, addNoteInputSchema, addNoteTool, addNotesInputSchema, addNotesTool, deleteNoteInputSchema, deleteNoteTool, deleteNotesInputSchema, deleteNotesTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, rememberInputSchema, rememberTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool } from './tools/write-tools.js';
|
|
3
3
|
export { bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, indexInputSchema, indexTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, repairLinksInputSchema, repairLinksTool, sessionCloseInputSchema, sessionCloseTool, syncInputSchema, syncTool } from './tools/maintenance-tools.js';
|
|
4
4
|
export { vaultBundleListInputSchema, vaultBundleListTool, vaultCommitInputSchema, vaultCommitTool, vaultExportBundleInputSchema, vaultExportBundleTool, vaultExportInputSchema, vaultExportTool, vaultHistoryInputSchema, vaultHistoryTool, vaultImportBundleInputSchema, vaultImportBundleTool, vaultImportInputSchema, vaultImportTool, vaultInitInputSchema, vaultInitTool, vaultMergeAgentsInputSchema, vaultMergeAgentsTool, vaultProvisionInputSchema, vaultProvisionTool, vaultPullInputSchema, vaultPullTool, vaultRestoreInputSchema, vaultRestoreTool, vaultStatusInputSchema, vaultStatusTool, vaultTransferExportInputSchema, vaultTransferExportTool, vaultTransferImportInputSchema, vaultTransferImportTool } from './tools/vault-tools.js';
|
package/docs/AGENT_USAGE.md
CHANGED
|
@@ -750,6 +750,7 @@ Available MCP tools:
|
|
|
750
750
|
- `brainlink_validate`
|
|
751
751
|
- `brainlink_sync`
|
|
752
752
|
- `brainlink_graph`
|
|
753
|
+
- `brainlink_neighbors`
|
|
753
754
|
- `brainlink_graph_contexts`
|
|
754
755
|
- `brainlink_broken_links`
|
|
755
756
|
- `brainlink_suggest_links`
|
|
@@ -770,6 +771,7 @@ MCP context is plug-and-play: agents may omit `strategy` for the configured defa
|
|
|
770
771
|
MCP clients can pass `vault` and `agent` arguments per tool call. Set `BRAINLINK_ALLOWED_VAULTS` when exposing Brainlink to an external agent process so a tool cannot pass arbitrary vault paths:
|
|
771
772
|
|
|
772
773
|
`brainlink_graph` returns weighted edges. Agents should prefer higher `weight` and stronger `priority` when deciding which related notes matter most.
|
|
774
|
+
`brainlink_neighbors` traverses those edges outward from one root note (by `title` or `path`) up to `depth` hops, returning each reached node with its hop distance and the edges among the reached set. It expands the strongest links first and caps the result at `limit` nodes (default 50), setting `truncated: true` when it stops early. Prefer it over `brainlink_graph` when only the local neighborhood of a note matters instead of the whole graph.
|
|
773
775
|
`brainlink_add_note` and `brainlink_add_file` return `writeConnectivity` metadata and guarantee at least one edge for new notes.
|
|
774
776
|
Agents should use `brainlink_volatile_add` for temporary task state, hypotheses, local execution details and unconfirmed findings. Volatile memory is included in `brainlink_context` with `Volatile: true`, expires by TTL and does not create durable Markdown notes or graph edges.
|
|
775
777
|
|
package/package.json
CHANGED