Jens Mittelbach120 downloadsFederated, provider-neutral RAG chat over existing Obsidian Hybrid Search MCP services.
Hybrid Chat is a desktop-only Obsidian 1.13+ plugin that provides federated, provider-neutral RAG chat over existing Obsidian Hybrid Search (OHS) services.
It does not create a vector index, read OHS SQLite databases, or duplicate indexing. Retrieval is read-only: the plugin calls only the OHS MCP search and read tools. The user-invoked copy actions write Markdown to the system clipboard; the plugin never reads clipboard contents and does not create or modify vault notes.
Hybrid Chat is a thin client over existing services and depends on:
http://127.0.0.1:3939/mcp). Hybrid Chat does not bundle or start OHS; it only queries the endpoint's search and read tools read-only.POST /v1/chat/completions, for example a local LM Studio server (default base URL http://127.0.0.1:1234/v1) or a remote HTTPS endpoint. Remote providers must use HTTPS; plain HTTP is accepted only on loopback hosts. Provider API keys are stored as Obsidian SecretStorage secrets, never in plugin data.main.js, manifest.json, and styles.css from the latest release into <vault>/.obsidian/plugins/hybrid-chat/.OhsMcpClient queries the configured stateless Streamable HTTP MCP endpoints concurrently through Obsidian's desktop HTTP API, avoiding browser CORS requirements for loopback services. Discovered tool names and input schemas are cached per endpoint for five minutes, avoiding repeated tools/list calls while preserving a short compatibility refresh window.@property(status=todo) includes an exact value, @property(status!=done) excludes one, and @property(publication_date) requests a property without filtering.FederatedRetriever merges per-vault ranks without comparing raw cross-vault scores, and a diversity pass gives each healthy vault a chance to contribute. When the opt-in related-note setting is enabled and the question explicitly asks about relationships, the best direct result from each healthy vault is expanded through one vault-local hop of links and backlinks; at most two linked candidates per anchor are promoted.read. If a selected path is missing or a vault read fails, the retriever moves down the ranked candidates until the requested number of readable notes is filled or candidates are exhausted. Unavailable endpoints remain visible partial failures.ContextPacker applies per-note and total character limits and centers long-note excerpts around the matching OHS snippet instead of always taking the beginning. Each source is namespaced as vault_id::vault/relative/path.md. Only explicitly requested YAML properties from the currently open vault are appended; current OHS read responses do not expose arbitrary cross-vault frontmatter.OpenAiCompatibleChatClient sends the current question and a bounded recent transcript to /v1/chat/completions, then streams SSE output. A new chat starts with empty conversational memory. Retrieval never depends on model tool-calling.obsidian://open?vault=…&file=… URIs.The source is split into the OHS client, federated retriever, rank fusion, context packer, OpenAI-compatible client, citation mapper, settings, and session/UI layers.
Chat window in the right-hand sidebar, source opens in the main editor:
Hybrid Chat accepts source markers such as [S1], [S1, S2], [1], and 【S1】, including harmless spacing or invisible characters inside the brackets. It renumbers cited notes in their first-mentioned order, starting at [1]. Markers for unknown sources are shown as unverified. Matching a marker to a retrieved note does not independently verify that the note supports the claim.
The source lists contain notes whose excerpts fit into the context sent to the chat provider. Notes found by search but excluded by the context limit are not shown as answer sources. If the answer cites none of the included notes, Hybrid Chat says so and keeps the notes under Other retrieved sources. Copying a message uses the displayed citation numbers; copying a whole chat as Markdown also includes the source grouping.
Some providers insert narrow no-break spaces between ordinary words, which can prevent line wrapping in the sidebar. Hybrid Chat converts those spaces to regular spaces for display and copying; the original provider response remains stored in the session.
SecretStorage through SecretComponent. Plugin data contains only secret identifiers.data.json so sessions survive restarts. If the vault configuration is synchronized, that plugin data may synchronize too.In Obsidian settings:
/models endpoint and choose one, or enter a model ID manually when discovery is unavailable.@property(field=value) filters by an exact value, @property(field!=value) excludes it, and @property(field) adds that current-vault value to answer context without filtering.Write the current question as a descriptive phrase or sentence that includes distinctive names, topics, dates, document types, and relationships. Hybrid Chat sends that question directly to OHS semantic/hybrid search; it does not reduce it to individual keywords. Because earlier turns are not part of retrieval, restate the subject in follow-up questions. When possible, search only the likely vault, use @property(...) filters to narrow the corpus, and enable one-hop related notes for questions explicitly about links or relationships.
For a balanced increase in recall, start with 24 results per vault, 10 notes read, 32,000 total context characters, and 4,000–5,000 characters per note, with OHS reranking enabled. For unusually difficult, high-recall searches, try 32 results per vault, 12 notes read, 48,000 total context characters, and 4,000 characters per note. The settings UI allows up to 50 results per vault and 20 notes read, but maximizing both can add latency and weakly related evidence.
Raise results per vault and notes read together: extra candidates normally cannot affect the answer unless enough globally ranked notes are subsequently read. Also raise the total context budget when reading more notes, or later sources may not fit in the provider prompt. Larger values are not always better; reduce them again when answers become slower or less focused.
The current public OHS contract exposes search and batch read over stateless Streamable HTTP. Tool prefixes and input schemas are discovered from each endpoint.
Streamable HTTP remains the default because multiple clients can share one long-lived OHS indexer and model cache. STDIO is not currently exposed as a Hybrid Chat transport; a future local-only mode would need to own a persistent child process and make its indexing, memory, logging, and cancellation lifecycle explicit.
npm install
npm run lint
npm run typecheck
npm test
npm run build
npm run check
For manual testing, copy manifest.json, main.js, and styles.css into <vault>/.obsidian/plugins/hybrid-chat/, enable the plugin, configure OHS and a chat profile, then use the ribbon icon or Hybrid Chat: Open chat command.
main.js is generated and intentionally not committed. Run npm run package-release to execute every quality gate, validate that package.json, manifest.json, and versions.json agree, and create these files under dist/release/:
main.jsmanifest.jsonstyles.csschecksums.sha256Pushing a tag that exactly matches manifest.json (for example, 0.1.8) runs the release workflow against the tagged source and generates build-provenance attestations from checksums.sha256. The workflow creates a draft release if needed, then uploads and verifies the three supported Obsidian assets: main.js, manifest.json, and styles.css. If a release for that tag already exists, it fills missing assets and checks existing assets against the tagged build without changing its notes or publication state. A new draft prepends the matching changelog entry to GitHub's generated notes. Review the draft before publishing. To repair an existing release after updating the workflow, run Release Obsidian plugin manually from GitHub Actions and enter the existing tag; the workflow checks out that tag before building.