kpulik478 downloadsMulti-provider AI chat with file reading, editing, creation, and deletion. Supports Anthropic, OpenAI, Google Gemini, OpenRouter, and Ollama.
A local-first AI chat for Obsidian that can actually edit your vault.
Point it at Ollama, LM Studio, or any OpenAI-compatible server and the model can read your notes, propose edits as a reviewable diff, create new notes, and delete files behind a double confirmation. Nothing leaves your machine unless you choose a hosted provider.
Plenty of Obsidian plugins talk to local models, and a couple of the largest can edit your vault too. Three things are different here:
127.0.0.1 and never asks for a key.Hosted providers are supported too and are entirely optional: Anthropic (Claude), OpenAI, Google Gemini, and OpenRouter.
Local needs no API key. Hosted providers each need their own standard key. Claude Code OAuth tokens (
sk-ant-oat01-...) do not work, and using them in a third-party tool violates Anthropic's terms.
dataviewjs fence would execute JavaScript with vault access. Fences that known executors claim are rewritten before rendering; the code stays readable, it just cannot rundata.json, with existing keys migrated automaticallySearch vault in the command palette ranks notes by name, alias, tag and heading, and shows why each one matched2/3 stepper you can page through3 files · ~8,410 tokens), clickable for the full list with the reason each file is includedTemplates, or .trash. ConfigurableShow activity and undo changes lists what VaultChat has changed and what can still be taken back| Provider | API key source | Notes |
|---|---|---|
| Local | None needed | Default. Any OpenAI-compatible server; saved as named endpoint profiles |
| Anthropic | console.anthropic.com | Uses x-api-key header |
| OpenAI | platform.openai.com | Bearer token |
| Google Gemini | aistudio.google.com | OpenAI-compatible endpoint |
| OpenRouter | openrouter.ai | Access 100+ models with one key |
From Obsidian (recommended)
Build from source
If you prefer to install manually or want to contribute:
git clone https://github.com/kpulik/VaultChat
cd VaultChat
npm install
npm run build
Then copy the built files into your vault:
mkdir -p /path/to/your/vault/.obsidian/plugins/VaultChat
cp main.js manifest.json styles.css /path/to/your/vault/.obsidian/plugins/VaultChat/
Restart Obsidian. The plugin will appear in Settings > Community Plugins.
The Local (OpenAI-compatible) provider works with any server that exposes the OpenAI chat-completions API. No API key, no cost, no data leaving your machine. Tested with Ollama and LM Studio; llama.cpp, vLLM, LocalAI, and Jan expose the same API and should work too.
1. Install a server
| Server | Where | Default base URL |
|---|---|---|
| Ollama | ollama.com | http://localhost:11434 |
| LM Studio | lmstudio.ai | http://localhost:1234 |
2. Get a model
With Ollama, pull one from the terminal:
ollama pull llama3.2 # 2GB, good general purpose
ollama pull llama3.2:1b # 1GB, fastest and smallest
ollama pull mistral # 4GB, strong reasoning
ollama pull qwen2.5 # 4GB, strong at multilingual
With LM Studio, download a model from its in-app browser and start the local server from the Developer tab.
3. Open VaultChat
Select Local (OpenAI-compatible) from the provider dropdown, then pick the server you want from the endpoint dropdown beside it.
Local servers are saved as named profiles rather than a single base URL, so you can keep Ollama, LM Studio and a remote proxy configured at once and switch between them from the chat header.
In Settings → OpenAI-compatible endpoints, each profile has its own:
11434 becomes "Ollama", 1234 becomes "LM Studio", and so on)data.json. Needed for vLLM started with --api-key, a LiteLLM proxy, and similar/v1/models endpointThe refresh button next to Model doubles as a connection test: it reads /v1/models and reports how many models came back, or why the server could not be reached. Nothing claims "connected" without having read a real response.
Use 127.0.0.1 rather than localhost. Most local servers listen on IPv4 only, while localhost can resolve to IPv6 first and fail with a connection-refused error. VaultChat substitutes the address automatically, but typing it directly avoids the whole class of problem.
Upgrading from an older version: your existing local base URL, model and API key are migrated into your first endpoint profile automatically, and the saved key keeps working without being re-entered.
What the model can see is built from sources that combine, rather than one mode that excludes the others:
| Source | What it sends |
|---|---|
| Entire vault | Enables indexed search and on-demand reads; it does not send every note automatically |
| Current note | The note open in the editor |
| Current folder | Every note under the open note's folder, recursively |
| + file | Individual notes, chosen from a searchable picker |
| + folder | Whole folders, chosen from a searchable picker |
Each source becomes a removable chip. Below them, one line says what the chat can actually see:
Context: 12 files · ~8,410 tokens · 2 skipped inspect
Counts come from resolving the sources and reading the files, not from counting chips — one folder chip can be forty notes. Click inspect for the exact paths, the reason each is included, and its size.
Entire vault is a separate capability source. When enabled, the agent can search indexed paths and read only notes relevant to the request. The context inspector states that vault search is enabled, while the file count reports only content actually read into the current prompt.
Current-note context is snapshotted to the note selected when it is added, so changing tabs cannot silently change an existing chat's context. Enable Dynamic current note in settings if that source should follow the active editor note instead.
Context is capped at an estimated token budget (30,000 by default). A folder bigger than the budget is not quietly trimmed: the files that did not fit are listed in the inspector and a notice says how many, so a short answer is never the result of a prompt you did not know was shortened.
Folders in the ignored list stay out of context and search; folders in the protected list additionally refuse destructive operations. Both lists are editable in settings, one path pattern per line. Your vault's configuration folder is always protected, under whatever name it actually has.
The model reaches the vault through tools rather than guessing from a file list. It calls one in a fenced block, gets a structured JSON result back, and may chain several before answering — capped at five rounds per question so it cannot loop.
Read tools available now:
| Tool | What it does |
|---|---|
search_vault |
Rank notes matching a description, with a reason and confidence for each |
find_file |
Resolve one note — or refuse, and hand back the candidates |
read_file |
Read a note in full |
list_folder / read_folder |
List or read a folder, capped so one call cannot fill the context |
get_note_metadata |
Aliases, tags, headings, properties, size |
get_links / get_backlinks / get_unresolved_links |
What a note points at, what points at it, and what is broken |
Every path the model sends is normalised and checked before anything runs; one that escapes the vault is refused, and in a batch a single bad path rejects the whole call.
Write and destructive tools do not execute inline. Creating, editing, renaming, moving, copying and deleting are collected into a reviewable plan. Protected paths are removed before the preview, destructive plans require an additional deliberate confirmation, and the plan is offered for undo only when the required before-state was captured. A model-generated tool call can never bypass those application-level checks.
What the agent read is shown under a collapsed Tool results block on each turn. Hiding it would make the answers unauditable.
| Command | What it does |
|---|---|
| Open chat / New chat | Opens or resets the chat pane |
| Add current note to context | Attaches the open note |
| Ask about current note | Seeds a question with the note attached |
| Summarize current note | Seeds a summary prompt |
| Organize current folder | Attaches the folder and asks for a plan |
| Explain / Rewrite selection | Sends the selected text as the question |
| Create note from selection | Proposes a note, filename and folder from a selection |
| Search vault | Ranked natural-language note search |
| Show activity and undo changes | The activity log |
Selection commands only appear when text is actually selected. None of these send on their own — each seeds the composer so you can adjust the wording first.
A preset bundles a system prompt and, optionally, a provider, endpoint, model and token limit. Four are built in — Research, Summarize, Obsidian editor, Vault organizer — and you can save your own.
A preset changes only the fields it names. Picking Summarize will not silently move you off the model you chose.
Tool calls that write never take effect when the model makes them. They are collected into a single plan, shown as a preview, and applied only when you say so.
Vault changes [ DESTRUCTIVE — READ CAREFULLY ]
CREATE FOLDER
School/Networking
MOVE 5 files
Old/TCP.md → School/Networking/TCP.md
Old/IP.md → School/Networking/IP.md
…
DELETE
Old/duplicate.md
6 operations, 7 files · 8 links in 3 other notes will be updated by Obsidian
[ Apply changes ] [ Cancel ]
Everything needed to reverse a plan is captured before it runs, so a failure halfway cannot leave some steps reversible and others not.
Undo is offered only when every completed step is genuinely reversible. If a file's previous contents could not be read, the receipt says so and shows no button, rather than offering an Undo that would quietly do nothing. Deletions go to the system trash, so they remain recoverable through Obsidian even when the plugin's own undo is unavailable.
A conversation is a tree rather than a list, so nothing you have already said is overwritten:
2/3 stepper appears on the message; paging through it switches the whole conversation below to that branchCopy conversation in the header exports the branch currently on screen as Markdown.
Existing chats from before 2.0 are read back as a single-branch tree, so no history is lost and nothing has to be re-created.
Reasoning models stream their chain of thought separately from their answer. VaultChat shows a "Thinking…" indicator while that is happening and then renders the answer when it arrives. The chain of thought is not added to the transcript.
If a model or router accepts the request but sends nothing back, VaultChat says so rather than leaving a blank message. This usually means the route you picked has no working upstream, so try a different model.
Go to Settings > VaultChat to configure:
npm run dev # watch mode, rebuilds on every save
For live reloading inside Obsidian, install the Hot Reload community plugin and symlink the project folder into your vault's plugins directory:
ln -s /path/to/VaultChat /path/to/vault/.obsidian/plugins/VaultChat
Open Obsidian's developer tools with Cmd+Option+I to debug.
If VaultChat is useful to you, consider buying me a coffee.
MIT