The vault.
ContextPackArgs. query required + non-empty.
Server-side context — the SAME shape as searchHybrid's
ctx, forwarded verbatim to the inner retrieval. v3.11.6-rc.14: pre-rc.14
only ftsIndex/embedFile were accepted, so a server started with
--enable-reranker / --use-hnsw / --recency-weight / --feedback-weight
silently packed context in PLAIN RRF order while obsidian_search ranked
with the enabled enhancements — an "enabled but not wired" divergence
(the CRL-1/M5 class). Now the full ctx flows through, so the pack's
top-10 is ranked exactly like obsidian_search would rank it.
Path to the .embed.db (file may or may not exist — checked at call time).
Optionalfeedback?: { scores: ReadonlyMap<string, number>; weight: number }v3.11.0 — optional opt-in closed-loop feedback re-ranking. When weight > 0
AND scores is non-empty, the final fused order is re-sorted by a blend of
relevance rank and each note's feedback score (useful/(useful+notUseful+1),
from obsidian_mark_useful via the FeedbackStore). weight = 0 / empty
scores is a provable no-op. Applied AFTER recency so a "human said this
helped" signal is the final tie-break. scores is keyed by relPath.
FTS5 index, if --persistent-index is enabled at server start.
Optionalhnsw?: HnswSearchContext | nullv2.13.0 — optional HNSW context for the embeddings-search arm. When passed, the embedding-side k-NN goes through the in-memory HNSW approximate nearest-neighbor index instead of the O(n) brute-force cosine in EmbedDb.search(). Built on serve start; lives in ServerDeps.hnswContext. Null/undefined → brute-force fallback.
Optionalrecency?: { staleDays: number; weight: number }v3.10 (rc.5) — optional opt-in recency re-ranking. When weight > 0,
the final fused order is re-sorted by a blend of relevance rank and the
note's live-mtime recency (see recencyScore in staleness.ts). weight = 0 (or
undefined) is a no-op — the default keeps ranking purely relevance-driven.
staleDays is the recency half-life (the age at which recency = 0.5).
Optionalreranker?: { alias?: string; topN?: number }v2.9.0 — optional cross-encoder reranker config. When set, the top-N hits from RRF (default 50) are re-scored by a BGE-style cross-encoder and re-sorted before truncation. Adds ~30-50ms per query on M1 CPU for a 50-candidate set.
alias resolves to a RERANKER_MODELS entry. topN defaults to 50.
Lazy-loaded from the local transformers.js cache. Runtime callers are
offline-enforced; pre-cache with enquire-mcp install-model <alias>.
Failures are swallowed and surface
via signal_errors.reranker so the whole search doesn't break on a
model load issue.
OptionalrerankerOverride?: { score(query: string, passages: readonly string[]): Promise<number[]> }v2.9.0 — test-only injection point. When set, this pre-loaded
reranker is used instead of lazy-loading via loadReranker(alias).
Lets unit tests validate the rerank-and-resort plumbing without
pulling in the real ML model. Unused in production callers.
A ContextPackResult with the packed bundle + meta.
const pack = await contextPack(
vault,
{
query: "How do I tune the hybrid retrieval?",
subqueries: ["Which rankers contribute?", "How is the final order fused?"],
budget_tokens: 3000,
include_backlinks: true,
recent_dailies: 3
},
{ ftsIndex, embedFile: "/path/to/vault.embed.db" }
);
console.log(pack.bundle); // ready to paste into any chat
Token-budgeted vault context export — runs hybrid retrieval, gathers note bodies + backlinks + recent dailies, packs to a token budget, and returns one ready-to-paste markdown blob. With
subqueries[], it executes at mostMAX_RESEARCH_SUBQUERIESextra searches sequentially, reserves the best available unique evidence candidate per atomic sub-question, then fills remaining slots with RRF. The default single-query path is unchanged.The MCP-native answer to Smart Connections' "Send to Smart Context" pattern, but works in any chat (Claude / Cursor / Codex / web UI) by producing a plain-text bundle. Saves the agent from orchestrating 5 separate tool calls.
Budget enforcement: each note's body is truncated to ~50% of remaining budget so room remains for backlinks + dailies; oversize bodies get a
[…truncated…]marker. As a final defense-in-depth, the assembled bundle is hard-capped atbudget_tokens × 4chars and marked[…budget cap reached…]if truncated. Top-3 included notes get 1-line backlink summaries wheninclude_backlinksis true.