fill kosha from a repo, grep the working tree, and federate all of it with the prose
kosha is the code half of the vault: AST chunks, symbol names, and a call graph with PageRank over your repo and your installed packages. It embeds code with a code-trained model, deliberately — identifiers are not sentences — so the two stores share no vector space, and federate fuses their rankings rather than their distances. rgapi adds a third kind of evidence for free: ripgrep over the files as they are on disk right now, which is the only leg that sees what nothing has indexed.
def index_code(dir:str=None, # repo to index graph:bool=True, # also build the AST call graph (callers, callees, PageRank) env:bool=False, # also index installed packages (slow the first time) force:bool=False, verbose:bool=False, **kw)->dict: # forwarded to kosha update_repo/sync
Point the vault at a repo and fill kosha’s stores from it.
This is the code path proper — symbol search and call-graph navigation — as opposed to Vault.code(), which files source files into the vault as ordinary documents. Both can coexist, and federate() searches whichever exist.
def kosha(dir:str=None, # repo root; defaults to the cwd repo share_encoder:bool=False, # embed code with the vault's encoder instead of kosha's**kw):
The Kosha for dir, cached on the vault so index_code and code_search hit one store.
share_encoder=True makes the two stores directly comparable at the cost of worse code ranking; it needs a real encoder, so it is a no-op on the hashing fallback.
def grep( pattern:str, # a ripgrep regexdir:str='.', # tree to search limit:int=20, # matching lines returned**kw)->L: # forwarded to rgapi.rg (glob=, ext=, context=, hidden=, ...)
Exact matches in the files on disk, through ripgrep.
The leg neither of the others can serve: embeddings generalise and FTS5 stems, so an identifier that appears verbatim in a file the vault never ingested — or ingested an older copy of — is invisible to both. .gitignore applies, so build output stays out of the results.
Search code through kosha: FTS + ANN over repo and environment, fused and rank-boosted. Supports kosha’s key:value filters, so 'retry package:httpx' and 'lang:py chunker' work.
def federate( q:str, # the query limit:int=12, # fused hits returned prose:bool=True, # the vault's own documents, papers, notes repo:bool=True, # kosha's repo index env:bool=False, # kosha's installed-package index grep:bool=True, # ripgrep over the working tree kind:str=None, # restrict the prose leg to some KINDS weights:dict=None, # per-leg RRF weights, e.g. {'prose':1.0,'repo':1.5}dir:str=None, # repo for the code and grep legs per_leg:int=None, # hits pulled from each leg before fusion)->AttrDict:
One ranked answer across prose, indexed code and the files on disk, fused by RRF.
The legs share no vector space — the vault embeds prose, kosha embeds identifiers, ripgrep embeds nothing — so they cannot be merged by distance. Reciprocal Rank Fusion needs only each leg’s ordering, which is exactly what survives a change of encoder, and it is the same mechanism litesearch already uses to combine FTS with vectors. Each leg is tried independently: legs reports what each contributed, or why it did not.
Try it
Each leg is optional and each fails on its own: with no repo indexed, legs says so and the others still answer.
v = Vault(':memory:')v.note('litesearch fuses the FTS and vector legs with reciprocal rank fusion.')f = v.federate('rank fusion', repo=False, grep=False)f.hits[0].where, f.legs, f.note
/Users/71293/code/personal/orgs/vishalakshi/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
('litesearch fuses the FTS and vector legs with reciprocal rank fusion.',
{'prose': 1},
'RRF over prose; the legs use different encoders, so ranks are fused, not distances')
test_eq(f.legs['prose'], 1)test_eq(f.hits[0].source, 'prose')test_eq(v.federate('rank fusion', prose=False, repo=False, grep=False).hits, []) # every leg off: empty, not an errorassert v.grep('reciprocal rank fusion', '.') # ripgrep reads the disk, not the vault