API
indexbind has four runtime-facing entrypoints:
indexbindindexbind/buildindexbind/webindexbind/cloudflare
Node-side directory and artifact APIs also support optional index-scoped convention files:
indexbind.build.jsindexbind.search.js
These files live beside the indexed root’s .indexbind/ directory and are auto-discovered only from that exact root.
indexbind
Native Node entrypoint for SQLite artifacts:
import { openIndex } from 'indexbind';
const index = await openIndex('./index.sqlite');
const hits = await index.search('rust guide', {
topK: 5,
mode: 'hybrid',
reranker: { kind: 'embedding-v1', candidatePoolSize: 25 },
relativePathPrefix: 'guides/',
});
openIndex(artifactPath, options?)
Opens a native SQLite artifact and returns an Index.
Open options:
modeProfile?:'hybrid'or'lexical'
Use modeProfile: 'lexical' when this Index instance should stay lexical-only. In that profile, index.search() defaults to lexical mode and rejects mode: 'hybrid' / mode: 'vector'.
When the artifact sourceRoot contains an indexbind.search.js, openIndex() applies:
profiles.defaultas the default search profiletransformQuery()as a lightweight query rewrite hook
index.info()
Returns artifact metadata such as:
schemaVersionbuiltAtembeddingBackendlexicalTokenizersourceRootdocumentCountchunkCount
index.search(query, options?)
Main options:
topK?: number of hits to returnmode?:'hybrid','vector', or'lexical'minScore?: prune low-confidence tail hits after final scoringreranker?: optional final reranking stagerelativePathPrefix?: restrict retrieval to a path subtreemetadata?: exact-match metadata filterscoreAdjustment?: adjust final ranking using metadata-driven multipliers
On the Node entrypoint, metadata is currently exposed as a string-to-string map in the TypeScript API.
Reranker options:
kind?:embedding-v1orheuristic-v1candidatePoolSize?: candidate count forwarded into the reranker before finaltopK
Score-adjustment options:
metadataNumericMultiplier?: metadata field name whose numeric value should multiply the final score
The returned hits include:
docIdrelativePathcanonicalUrl?title?summary?metadatascorebestMatch
bestMatch contains:
chunkIdexcerptheadingPathcharStartcharEndscore
indexbind/build
Programmatic build and incremental cache API:
import {
buildCanonicalBundle,
updateBuildCache,
exportArtifactFromBuildCache,
exportCanonicalBundleFromBuildCache,
} from 'indexbind/build';
Main input shape:
docId?sourcePath?relativePathcanonicalUrl?title?summary?contentmetadata?
Use this entrypoint when your host application already has a normalized document set and wants to build directly from code instead of scanning a directory through the CLI.
For a larger mixed-content example where the host classifies documents and injects metadata before indexing, see Adoption Examples.
Available helpers:
buildCanonicalBundle(outputDir, documents, options?)buildFromDirectory(inputDir, outputPath, options?)buildCanonicalBundleFromDirectory(inputDir, outputDir, options?)updateBuildCache(cachePath, documents, options?, removedRelativePaths?)updateBuildCacheFromDirectory(inputDir, cachePath, options?, updateMode?)exportArtifactFromBuildCache(cachePath, outputPath)exportCanonicalBundleFromBuildCache(cachePath, outputDir)inspectArtifact(artifactPath)benchmarkArtifact(artifactPath, queriesJsonPath)
For directory-based helpers, if the input root contains indexbind.build.js, these APIs automatically apply:
includeDocument(relativePath, ctx)transformDocument(document, ctx)
This keeps host-specific document shaping attached to the shared directory scanner and incremental cache flow.
updateBuildCache(...) returns:
scannedDocumentCountnewDocumentCountchangedDocumentCountunchangedDocumentCountremovedDocumentCountactiveDocumentCountactiveChunkCount
Typical incremental flow:
import {
updateBuildCache,
exportArtifactFromBuildCache,
exportCanonicalBundleFromBuildCache,
} from 'indexbind/build';
await updateBuildCache(
'./.indexbind-cache.sqlite',
[
{
relativePath: 'guides/rust.md',
title: 'Rust Guide',
content: '# Rust Guide\n\nRust retrieval guide.',
metadata: { lang: 'rust' },
},
],
{ embeddingBackend: 'hashing' },
['guides/old.md'],
);
await exportArtifactFromBuildCache('./.indexbind-cache.sqlite', './index.sqlite');
await exportCanonicalBundleFromBuildCache('./.indexbind-cache.sqlite', './index.bundle');
indexbind/web
Browser and worker entrypoint for canonical bundles:
import { openWebIndex } from 'indexbind/web';
This path uses wasm for the default hybrid/vector-capable runtime. If you open with modeProfile: 'lexical', it can stay on the lighter lexical-only path without loading vectors or model files.
openWebIndex(base, options?) returns a WebIndex.
Open options:
fetch?: custom resource loadermodeProfile?:'hybrid'or'lexical'
modeProfile: 'lexical' skips vector/model loading for this WebIndex instance and makes lexical mode the default for search().
WebIndex.info() returns canonical bundle metadata such as:
schemaVersionartifactFormatbuiltAtembeddingBackenddocumentCountchunkCountvectorDimensionschunkingfeatures
WebIndex.search(query, options?) accepts the same search options as the Node entrypoint, except metadata values can use the broader JSON value shape.
indexbind/cloudflare
Cloudflare Worker entrypoint:
import { openWebIndex } from 'indexbind/cloudflare';
Use this instead of indexbind/web inside Workers so wasm can be loaded through the Worker-compatible static module path.
It accepts the same optional fetch override as indexbind/web, which is useful when the host wants to read bundle files through ASSETS.fetch(...) instead of public URLs.
Search Defaults and Patterns
Reasonable starting point:
const hits = await index.search(query, {
topK: 10,
mode: 'hybrid',
reranker: {
kind: 'embedding-v1',
candidatePoolSize: 25,
},
});
Use metadata filtering when your host application has clear product boundaries:
const hits = await index.search(query, {
metadata: {
lang: 'rust',
visibility: 'public',
},
});
Use metadata-based score adjustment when your application wants a host-defined ranking prior:
const hits = await index.search(query, {
scoreAdjustment: {
metadataNumericMultiplier: 'directory_weight',
},
});
Use minScore when your product wants to cut weak tail matches and allow fewer than topK hits:
const hits = await index.search(query, {
topK: 10,
minScore: 0.05,
});
mode: 'vector'means vector-only retrieval.mode: 'lexical'means lexical-only retrieval.
For a fuller explanation of how these knobs interact, see Search Quality Controls.