← Journal
Jiva Studio

The library, in your assistant

AICharya opens the Listen to Sadhu corpus to any AI assistant — how the library is shaped, the two ways to address it, and the two-lane search that fuses meaning with exact strings so a paraphrase and a rare Sanskrit term both land on the real passage.

AICharyaEngineeringAIMCPSearch

Ask a language model to explain a verse of the Bhagavad-gītā and it will oblige, fluently, whether or not it has ever seen the verse. That is the whole problem with scripture and a model’s memory: the confident paraphrase and the faithful quotation look identical until you check the source.

AICharya is our answer to that. It is a small, public server that hands an AI assistant the actual corpus behind Listen to Sadhu — the verses, the purports, the transcribed lectures — addressed and citable, so the assistant can read the real text instead of reconstructing it. The name is a quiet pun: an ācārya is the teacher who transmits the text without distorting it, which is precisely the job we asked this server to do.

This is the article about how it is built: what lives in the library, the two ways to reach into it, and — the part worth the most words — how the search actually finds a passage.

What it is: one socket into the corpus

AICharya speaks MCP, the Model Context Protocol — the standard that lets an assistant call out to external tools and data. In practice that means a single URL. You add https://mcp.listentosadhu.app/mcp as a custom connector in Claude, ChatGPT, Grok, Mistral Le Chat, Perplexity, or any other MCP client, and the whole library becomes something the assistant can search and quote inside your ordinary conversation.

Two properties are load-bearing, and both are deliberate:

  • No key, no account. It is public. The corpus is meant to be read, so there is nothing to sign up for and nothing to install.
  • Read-only, all the way down. Every tool is annotated read-only; the server opens its data read-only and holds no write path at all. AICharya can show you the library. It cannot change it.

The assistant sees a compact set of tools — roughly a dozen and a half — and each returns the same tidy envelope: either { ok: true, result } or { ok: false, error } with a small, honest set of error codes (invalid_argument, not_found, dependency_failed). Nothing to parse by feel.

What lives in the library

Everything reduces to three shapes, because a citation has to point at the right kind of thing:

  • Verses. A verse carries its original Devanāgarī or Bengali, the stored IAST transliteration, and the translation. Its address is structural — the book, the chapter, the verse — so “BG 2.13” names a real place, not a phrase.
  • Documents. The prose of the tradition: purports and commentaries, prose chapters, letters. A verse’s purport is simply the commentary document filed at that verse’s address — one call to list it.
  • Tracks. The lectures and conversations, transcribed. Each track keeps its metadata — speaker, place, date, language — the references it cites, and a transcript you can read around any moment, down to the millisecond.

Underneath, these sit in two different stores, split by what they need. The verses and documents live in a compact library file; the catalog — every book, author, and place, plus the lecture index — lives in another. The lecture transcripts, the part that has to be searched by meaning, live in Postgres with pgvector alongside their embeddings. The division is invisible from the outside; you just ask, and the right store answers.

Two ways in: a name, or a question

There are exactly two ways to reach a passage, and keeping them distinct is what makes the answers trustworthy.

By name. If you already know the address, you say it. AICharya resolves canonical references the way a reader writes them — “BG 2.13”, “ŚB 5.5.3”, “CC Madhya 8.128” — and it does so in both Latin and Cyrillic, so “ШБ 5.5.3” and “SB 5.5.3” land on the same verse. Book codes resolve fuzzily too: “gita”, “бхагаватам”, “CC Madhya” all find their book. A bare chapter number means the whole chapter — tokens: "7" is all of chapter 7, tokens: "7.1" just the one verse. This path never guesses; a reference either resolves to a real location or it does not.

By question. When you do not know where to look — “where does Prabhupāda say the soul is eternal?” — you search. This is the interesting half.

How the search works

The naïve approach is to embed the query and the corpus into vectors and take the nearest neighbours by cosine similarity. That finds meaning: it will match “the self never dies” to a passage about the soul’s eternality even with no word in common. But it is blind to exact strings — and scripture is full of exact strings that matter. A Sanskrit term like sanātana, a name, a canonical phrase: a meaning-vector will happily round these off to something merely similar.

So AICharya runs two lanes at once and fuses them.

flowchart TD
  Q["Natural-language query"] --> E["Embed the query"]
  E --> V["Meaning lane · pgvector HNSW · cosine nearest-neighbour"]
  Q --> L["Exact-string lane · Postgres full-text plus trigram"]
  V --> F["Reciprocal Rank Fusion · k is 60"]
  L --> F
  F --> R["Ranked passages · each with the id to fetch the full record"]

The meaning lane embeds the query into a 1536-dimension vector and asks pgvector for the nearest chunks by cosine distance, walking an HNSW index. It is tuned to search a little harder than the default — a wider ef_search and a relaxed iterative scan — so a filtered query still comes back with a full slate rather than a thin one.

The exact-string lane is Postgres full-text search, and it runs under two configurations on purpose. One is russian, with Snowball stemming, so Russian queries match across word forms. The other is simple — no stemming at all — and that one is quietly essential: it lets IAST transliteration survive verbatim, so a search for sanātana-dharma is not stemmed into gibberish before it can match. A trigram index rides alongside to catch canonical addresses and near-spellings.

Then the two ranked lists are merged by Reciprocal Rank Fusion. RRF is a pleasingly boring algorithm: each lane contributes to a passage’s score by the reciprocal of its rank in that lane, 1/(k+rank)1 / (k + \text{rank}), with k=60k = 60; add the contributions, sort, break ties by raw cosine for determinism. What makes it the right tool is what it doesn’t need — the two lanes produce scores on utterly different scales (a cosine similarity and a text-rank), and RRF never compares those scores directly. It only ever compares ranks. A passage that both lanes like rises to the top; a passage only one lane found still gets its say. Meaning and exact-match, neither drowning the other.

The result is a ranked list where a plain-English paraphrase and a rare Sanskrit term both find their passage — and every hit carries a min_score you can raise to drop weak matches, because a search that admits it found little is worth more than one that pads the list.

From a hit back to the source

A search result is not the end; it is a pointer. Every hit carries exactly the id the assistant needs to fetch the full record, and the contract is uniform:

  • a verse_id goes to verse_get for the original, transliteration, and translation;
  • a document_id goes to document_get for the full commentary or letter;
  • a track_id with a start_ms and end_ms goes to transcript_window, which reads the transcript around that moment — the sentences on either side, not a bare fragment;
  • a media_id goes to media_get.

Those last two open onto something nicer than text. When the answer is a lecture, the assistant can render an inline audio player cued to the exact passage — the source spoken aloud, generated on demand for that precise span. When the answer is a filmed moment — a disciple’s remembrance, a recorded talk — an inline video player plays it right in the conversation. The citation is not a footnote you have to go chase; it is the recording itself, one tap away.

Why read-only is the point

It would have been easy to let AICharya do more — annotate, bookmark, write back. We deliberately didn’t. A public corpus of scripture is a thing you want many assistants reading and none of them editing. Read-only is not a limitation we apologise for; it is the guarantee that makes it safe to hand the same library to everyone at once.

And that is the whole shape of it. Listen to Sadhu already answers these questions inside its own app, with its own grounded chat. AICharya takes the layer underneath that — the addressed, searchable, citable corpus — and makes it something your assistant can read too. The teacher’s job, handed to a socket: give the model the real text, and let it quote the source instead of its memory of the source.


Part of

AICharya

Open project