Tool reference¶
18 tools, grouped by intent. Every tool description below includes a one-line Claude prompt you can copy-paste into chat to nudge routing in the right direction.
Tools marked requires companion plugin only work when the companion Obsidian plugin is installed and Obsidian is running. Every other tool works standalone against the vault on disk.
Find¶
search¶
Find notes by meaning (chunk-level semantic similarity) or by exact text (SQLite FTS5 with Porter stemming + BM25 title:body = 5:1). The default hybrid mode fuses both rankings via Reciprocal Rank Fusion.
| Arg | Type | Description |
|---|---|---|
query |
string | Natural-language query or keyword phrase. |
mode |
"hybrid" | "semantic" | "fulltext"? |
Default hybrid. Semantic-only queries chunk vectors; fulltext-only queries FTS5. |
limit |
number? | Max results to return. Default 20. |
unique |
"notes" | "chunks"? |
Default "notes" (one row per note). Set "chunks" for raw chunk rows with chunkHeading, chunkStartLine, chunkExcerpt. |
The response is wrapped as {data, context} — context.next_actions suggests the most useful follow-up call (e.g. read_note(top hit), find_connections(top-3), or a simplified query retry on zero hits). Clients that ignore context keep working.
mode: 'hybrid' + unique: 'chunks' returns chunk metadata (including chunkHeading, chunkStartLine, chunkExcerpt). FTS5 queries containing -, :, /, or parens are auto-phrase-quoted — a query like foo-bar-baz no longer crashes.
"Use
searchto find notes semantically about supply-chain tax."
list_notes¶
List notes, optionally filtered by directory, tag, or link-target status.
| Arg | Type | Description |
|---|---|---|
directory |
string? | Restrict to notes under this subdirectory prefix. |
tag |
string? | Restrict to notes containing this frontmatter tag. |
limit |
number? | Max results to return. Default 100. |
includeStubs |
boolean? | Default true. Set false to exclude unresolved wiki-link targets. |
"Use
list_notesto list every note underProjects/tagged#active."
read_note¶
Read a note's metadata (and optionally its full body). Fuzzy-matches filenames, so "Q4 planning" resolves to Meetings/2025-Q4 planning.md if unambiguous.
| Arg | Type | Description |
|---|---|---|
name |
string | Path, filename, or fuzzy match for the note to read. |
mode |
"brief" | "full"? |
Default "brief" (metadata + linked-note titles). "full" adds the body + edge context. |
maxContentLength |
number? | In full mode, max body chars before truncation. Default 2000. |
In full mode, the response includes truncated: true when the body exceeded maxContentLength and was sliced. Wrapped as {data, context} with next_actions hints — e.g. create_note for unresolved [[links]], find_connections for outgoing neighbours.
"Use
read_noteto open the note called 'Q4 planning' withmode: 'full'."
Map the graph¶
find_connections¶
N-hop link neighborhood around a note. Returns inbound + outbound links grouped by hop distance, optionally the full subgraph for visualization.
| Arg | Type | Description |
|---|---|---|
name |
string | Starting note (path or fuzzy match). |
depth |
number? | Number of hops to traverse. Default 1, max 3. |
returnSubgraph |
boolean? | Return all edges in the neighborhood as a full subgraph instead of a flat list. |
includeStubs |
boolean? | Default false. Set true to include broken-wikilink stub neighbours (frontmatter._stub: true). |
Response is wrapped as {data, context} — context.next_actions suggests detect_themes when the neighbourhood is large (> 10) and find_path_between to the furthest neighbour. Clients that ignore context keep working.
find_connections context envelope shape¶
{
"data": [ /* neighbours, or {nodes, edges} when returnSubgraph: true */ ],
"context": {
"state": {
"last_connections_root": "Epistemology.md",
"last_connections_count": 7
},
"next_actions": [
{ "description": "Cluster this neighbourhood via detect_themes" },
{ "description": "Trace path from Epistemology.md to <furthest>.md via find_path_between" }
]
}
}
context.state.last_connections_root— the resolved-from path of the call (lets the client correlate follow-ups).context.state.last_connections_count— neighbour count returned this call.context.next_actions[]— list of single-sentence suggestions an LLM can route directly into the next tool call. Empty when no useful follow-up exists (zero neighbours, depth=1 on a single-edge note). Skippingcontextis always safe —datacarries everything load-bearing.
"Use
find_connectionsto show everything within 2 hops ofEpistemology.md."
find_path_between¶
Shortest link chain(s) between two notes. Optionally return their shared neighbors as well.
| Arg | Type | Description |
|---|---|---|
from |
string | Source note (path or fuzzy match). |
to |
string | Target note (path or fuzzy match). |
maxDepth |
number? | Maximum path length in hops. Default 3. |
includeCommon |
boolean? | Also return notes that both from and to link to (shared neighbors). |
includeStubs |
boolean? | Default false. Set true to include broken-wikilink stub nodes (frontmatter._stub: true) in the path search. |
"Use
find_path_betweento find howBayesian updatingconnects toKelly criterion."
detect_themes¶
Auto-detected topic clusters via Louvain community detection over the backlink graph. Served from the community-detection cache; to recompute at a different resolution, call reindex({resolution: X}) first.
| Arg | Type | Description |
|---|---|---|
themeId |
string? | Drill into a single cluster by its id or label. |
includeStubs |
boolean? = false | Default false. Set true to include unresolved wiki-link targets (frontmatter._stub: true) in cluster membership. Older cached community data may still carry stub-dominated clusters until the next reindex regenerates the community table. |
Each cluster carries staleMembersFiltered — cached nodeIds that no longer exist on disk and were filtered on this read; a positive value triggers live regeneration of summary so the two fields stay consistent. If the vault's overall Louvain modularity is < 0.3, the response wraps as {clusters, warning, modularity} — the clusters aren't clearly separable and may not reflect meaningful themes.
"Use
detect_themesto surface the main themes across my vault."
rank_notes¶
Top notes by influence (PageRank over backlinks), bridging (betweenness centrality, normalized 0–1 so scores compare across vaults), or both.
| Arg | Type | Description |
|---|---|---|
metric |
"influence" | "bridging" | "both"? |
Ranking metric. Default "both". "influence" = PageRank; "bridging" = betweenness centrality. |
limit |
number? | Max results to return. Default 20. |
themeId |
string? | Restrict ranking to members of one theme cluster. |
includeStubs |
boolean? = false | Default false. Set true to include unresolved wiki-link target stubs (frontmatter._stub: true) in the ranked set. With stubs in, popular link targets dominate eigenvector-style centrality even when they have no real content behind them. |
minIncomingLinks |
number? = 2 | Minimum incoming links for influence ranking. Default 2. Pass 0 to see unfiltered PageRank. |
"Use
rank_noteswithmetric: 'influence'to list the top 10 most-linked-to notes."
Write¶
create_note¶
Create a new note with frontmatter and auto-index it. title: is auto-injected from the filename unless you explicitly pass frontmatter: { title: null }.
| Arg | Type | Description |
|---|---|---|
title |
string | Note title. Used as the filename base and auto-injected into frontmatter. |
content |
string | Markdown body (do not include frontmatter here). |
directory |
string? | Vault-relative subdirectory to create the note in. |
frontmatter |
object? | YAML frontmatter key/value map. title is auto-injected unless explicitly set. |
Creating a note that matches an existing [[ForwardRef]] stub automatically repoints the stub's inbound edges to the real note and deletes the stub.
"Use
create_noteto createMeetings/2026-04-21 standup.mdwith tags[meeting, standup]."
edit_note¶
Modify an existing note. Six modes: append, prepend, replace_window (find-and-replace; optionally fuzzy), patch_heading, patch_frontmatter, at_line.
| Arg | Type | Description |
|---|---|---|
name |
string | Path or fuzzy match. |
mode |
one of the six | Required. |
content |
string | New content (mode-dependent). |
search |
string | For replace_window: the block of text to locate. |
fuzzy |
boolean | For replace_window: tolerate whitespace + trailing punctuation drift. |
heading |
string | Target heading (for patch_heading). |
headingOp |
"replace" | "before" | "after" |
For patch_heading. replace (default) replaces the section below the heading; before / after insert adjacent to the heading line. |
scope |
"section" | "body" |
For patch_heading replace: section (default) consumes until the next same-or-higher heading or EOF; body stops at the first blank line. |
headingIndex |
number | For patch_heading when the heading text appears more than once — 0-indexed top-to-bottom picker. Without it, multiple matches throw MultipleMatchesError listing each occurrence with line numbers. |
line / lineOp |
For at_line. |
|
key / value / valueJson |
For patch_frontmatter. Use valueJson from clients that stringify tool params (e.g. valueJson: 'null' to clear a key, valueJson: 'true' for a real boolean, valueJson: '42' for a number). |
patch_heading responses include removedLen so callers can detect greedy trailing-heading consumption.
dryRun: true→ returns a unified diff +previewId; no file is mutated. Commit the preview withapply_edit_preview({ previewId }).edits: [...]— bulk edit array applied atomically on a single file. All or nothing; error names the failing index if any edit fails.fuzzyThreshold: 0–1onreplace_window(default0.7). Higher = stricter match required.from_buffer: true— onreplace_windowNoMatch, the proposed content is held in a buffer; retry viafrom_buffer: trueretries withfuzzy: true, fuzzyThreshold: 0.5.
"Use
edit_noteto append a 'Follow-ups' section to today's standup note."
apply_edit_preview¶
Commit an edit previewed via edit_note({ dryRun: true }).
| Arg | Type | Description |
|---|---|---|
previewId |
string | The previewId returned by edit_note with dryRun: true. |
- Preview not found or expired (5 min TTL) → error; regenerate the preview.
- Target file changed since preview was generated → error; regenerate the preview.
link_notes¶
Add a wiki-link between two notes plus a "why this connects" context sentence placed where the link is inserted.
| Arg | Type | Description |
|---|---|---|
source |
string | Source note to add the link from (path or fuzzy match). |
target |
string | Target note to link to (path, title, or new wiki-link ref). |
context |
string | One-sentence explanation of why these notes are connected. |
dryRun |
boolean? | If true, return the line that would be appended without writing. |
dryRun: true returns the line that would be appended without writing.
"Use
link_notesto linkBayesian updatingtoKelly criterionwith a note about risk-adjusted bets."
move_note¶
Rename or move a note. All inbound wiki-links ([[old]], [[old|alias]], ![[old]], [[old#heading]], [[old^block]]) are rewritten in place across every note that linked to the old stem; graph edges stay intact.
| Arg | Type | Description |
|---|---|---|
source |
string | Current path or fuzzy match of the note to move. |
destination |
string | New vault-relative path (including .md). .md is appended automatically if omitted. |
dryRun |
boolean? | If true, report what would be rewritten without mutating any files. |
Response adds linksRewritten: {files, occurrences} counting the rewrites applied.
dryRun: true reports what would be rewritten without mutating. Response on a real move includes stubsPruned: N.
"Use
move_notewithsource: 'Inbox/thought.md'anddestination: 'Areas/Ideas/thought.md'."
delete_note¶
Delete a note. Requires confirm: true as a Zod-level guard.
| Arg | Type | Description |
|---|---|---|
name |
string | Path or fuzzy match of the note to delete. |
confirm |
true | Must literally be true to execute. Guards against accidental deletion. |
dryRun |
boolean? | If true, report what would be deleted without removing any files. |
When the delete removed inbound edges, the response is wrapped in a {data, context: {next_actions}} envelope suggesting rank_notes({metric: 'influence', minIncomingLinks: 0}) as a follow-up to surface newly orphaned notes.
dryRun: true reports what would be deleted. Real deletes surface deletedFromIndex.stubsPruned: N when the deleted note's orphan-stub targets were cleaned up.
"Use
delete_notewithconfirm: trueto deleteInbox/obsolete.md."
Live editor¶
These tools require the companion plugin installed in your vault and Obsidian running.
active_note¶
Returns the note currently open in Obsidian — path, cursor position, and selection range. Requires the companion plugin (any current release; major.minor must match the server per the plugin-alignment contract).
No arguments.
"Use
active_noteto see what note I'm editing right now."
dataview_query¶
Run a Dataview DQL query. Returns a normalised discriminated union:
kind: "table"→{ headers, rows }kind: "list"→{ values }kind: "task"→{ items: [...] }with full STask fieldskind: "calendar"→{ events: [...] }
All Dataview Link / DateTime / DataArray / Duration values are flattened to JSON so tools consuming the output don't need Dataview runtime types.
| Arg | Type | Description |
|---|---|---|
query |
string | DQL source, e.g. 'TABLE file.name, rating FROM #book WHERE status = "reading" LIMIT 50' |
source |
string? | Optional origin file path (vault-relative) to set the DQL origin. Affects FROM "" and relative link resolution inside the query. |
timeoutMs |
number? | HTTP timeout in ms (default 30000). The Dataview query itself cannot be cancelled; this just bounds how long this tool waits. |
Requires:
- The companion plugin installed (see plugin.md) — current releases all advertise the
dataviewcapability. - The third-party Dataview community plugin by blacksmithgu — a separate community plugin with ~4M+ installs, not shipped with Obsidian or by us. Install via Obsidian → Settings → Community plugins → Browse → search "Dataview" → Install → Enable.
If Dataview isn't enabled, the tool returns a 424 with an actionable install message. Full details + DQL syntax reference: Companion plugin → Dataview.
"Use
dataview_queryto list every note tagged #book with its rating."
base_query¶
Evaluate an Obsidian Bases .base file and return its rows.
| Arg | Type | Description |
|---|---|---|
file |
string? | Vault-relative path to a .base YAML file (e.g. "Bases/Books.base"). Either file or yaml is required. |
yaml |
string? | Inline .base YAML source. Either file or yaml is required. |
view |
string | The name of the view inside the .base file to execute, e.g. "active-books". |
timeoutMs |
number? | HTTP timeout in ms (default 30000). The plugin evaluator itself cannot be cancelled; this just bounds how long this tool waits. |
Response shape: {view, rows, total, executedAt} — total is the pre-limit count; rows each contain {file: {name, path}, ...projected columns} with Dates flattened to ISO strings.
Requires:
- The companion plugin installed (see plugin.md) — current releases all advertise the
basecapability. - Obsidian ≥ 1.10.0.
- The Bases core plugin enabled (Obsidian → Settings → Core plugins → Bases). Bases is first-party core Obsidian, not a community plugin.
Supported expression subset: tree ops (and / or / not), comparisons (==, !=, >, >=, <, <=), leaf booleans (&&, ||, !), file.{name, path, folder, ext, size, mtime, ctime, tags}, file.hasTag(...), file.inFolder(...), frontmatter dot-access. Arithmetic, method calls other than hasTag/inFolder, function calls (today(), now(), date(), list(), link(), icon()), regex literals, formulas:, summaries:, and this context all return 400 unsupported_construct errors — not yet shipped. Full subset + error reference: Companion plugin → Bases.
"Use
base_queryonBases/Books.basewith viewactive-booksto list everything I'm currently reading."
Maintenance¶
reindex¶
Force a full re-index. You rarely need this — the live watcher picks up file changes automatically. Fall back to reindex if your vault lives somewhere FSEvents/inotify can't observe (SMB, NFS), or after bulk edits outside Claude. A bare reindex({}) call defaults resolution to 1.0, re-runs Louvain community detection, and prunes orphan stubs.
| Arg | Type | Description |
|---|---|---|
resolution |
number? | Louvain resolution. Omit to skip community detection on no-op reindexes. Pass a value to force-rerun: 1.0 = equal-weight clusters (default); 0.5 = fewer/broader; 2.0 = more/finer. |
Response includes stubsPruned: N — the one-shot migration path for users upgrading from older versions with pre-fix orphan stubs.
reindex response field semantics¶
The reindex response carries several *Created / *Pruned / *Indexed counters. They're all deltas for this run, not totals:
nodesIndexed— notes whose content was re-embedded this run.nodesSkipped— notes whose mtime hasn't changed since the last index pass (skipped via thesynctable).edgesIndexed— wiki-link edges materialised this run.stubNodesCreated— broken-wikilink target stubs (_stub/Foo.md) newly materialised this run, not the total stub count in the graph. A vault with 2,433 long-standing stubs and zero new ones reportsstubNodesCreated: 0.stubsPruned— orphan stub nodes deleted this run (stubs whose only inbound edges came from a note that was just deleted, or stubs that got promoted to real notes because a matching.mdfile appeared).communitiesDetected— community count from this run's Louvain pass. Omitted/zero when the no-op guard short-circuits (no nodes/stubs/deletions changed AND no explicitresolutionwas passed).
"Use
reindexto refresh the index after I bulk-edited files outside Claude."
index_status¶
Read-only inspection of index health. Surfaces everything an LLM client needs to answer "is semantic search working?" without mutating any state.
No arguments.
Response fields:
embeddingModel,embeddingDim,provider— active embedder identity.notesTotal,notesWithEmbeddings,notesNoEmbeddableContent,notesMissingEmbeddings,chunksTotal— coverage counts.notesNoEmbeddableContentcovers notes recorded with reason'no-embeddable-content'infailed_chunks(empty / frontmatter-only / sub-minChunkCharsbody), sonotesMissingEmbeddingsreflects only genuine failures, not the daily-note tail.summary— one-line human-readable string ("X / Y notes indexed; Z have no embeddable content; W failed to embed"), so MCP clients can report status without conflating buckets.chunksSkippedInLastRun,failedChunks[],failedChunksTotal— fault-tolerant skip-log (failed_chunkstable). EachfailedChunksentry hasnote,reason(one oftoo-long/embed-error/note-too-long/note-embed-error/no-embeddable-content),at(epoch ms).advertisedMaxTokens,discoveredMaxTokens— capacity bounds (embedder_capabilitytable).advertisedfrom the bundled seed / metadata-cache or from the tokenizer //api/show;discoveredshrinks if embed failures reveal a tighter ceiling, floored atMIN_DISCOVERED_TOKENS=256and reset toadvertisedat the start of every full reindex.prefixSource— provenance of the active query/document prefixes. One of'override'(user set viamodels override/models add),'seed'(came fromdata/seed-models.json),'metadata'(live HFconfig_sentence_transformers.json),'metadata-base'(upstreambase_model's same JSON),'readme'(Tier 3 README fingerprinting),'fallback'(HF unreachable; safe defaults),'none'(symmetric — no prefix needed).overrideApplied— boolean; true iff a user override at~/.config/obsidian-brain/model-overrides.jsonpatched any of the resolved fields. Useful for diagnostics: distinguishes "the seed says X" from "the user overrode X to Y."lastReindexReasons— the bootstrap's stated reasons for any reindex on last boot (e.g. model switch, prefix-strategy version bump, schema migration).reindexInProgress— boolean; true while a background reindex is running.embedderReady,initError— live ctx state; any startup failure surfaces ininitErroras"Name: message".
"Use
index_statusto check whether semantic search is ready and see how many chunks were skipped in the last reindex."
Capability matrix¶
| Tool | Works offline | Needs plugin | Writes to vault |
|---|---|---|---|
search |
✅ | — | — |
list_notes |
✅ | — | — |
read_note |
✅ | — | — |
find_connections |
✅ | — | — |
find_path_between |
✅ | — | — |
detect_themes |
✅ | — | — |
rank_notes |
✅ | — | — |
create_note |
✅ | — | ✅ |
edit_note |
✅ | — | ✅ |
apply_edit_preview |
✅ | — | ✅ |
link_notes |
✅ | — | ✅ |
move_note |
✅ | — | ✅ |
delete_note |
✅ | — | ✅ |
active_note |
— | ✅ | — |
dataview_query |
— | ✅ + Dataview community plugin | — |
base_query |
— | ✅ + Obsidian ≥ 1.10.0 + Bases core plugin | — |
reindex |
✅ | — | — |
index_status |
✅ | — | — |