// what the agent sees
Ask digest
When you press ⌘K and ask a question, the agent doesn't read
these pages — it reads this. It's committed as
.hev-ask/digest.json, rendered here exactly the way the loop
discloses it: a map it holds in context, and details it opens on demand.
- level 1 · the map
Always in the prompt: every section's id, heading, and one-line summary, plus the glossary's aliases for widening a query. This is the collapsed row below.
- level 2 · open_section()
On demand, the agent opens a section to read its verbatim facts — and, for reference sections, the source text. That's what expanding a row reveals.
Expand a row to make the same call the agent does.
Orientation
The compact product overview the build distills — context for the keyword/expansion path.
hev ask (@hevmind/ask) is a ⌘K search overlay for Astro docs sites, documented at hevask.com — a site that searches itself with the package. Three moving parts: a heading-level chunk index with real rendered anchors (via github-slugger, gated by ask digest verify), a committed offline-built ask digest (.hev-ask/digest.json) holding the glossary, section summaries, and site overview, and a bounded Claude tool-use loop. Two retrieval paths: instant keyless keyword search (token overlap widened by the digest glossary, deep-linking to /docs/page#anchor) and an agentic answer on Enter (needs ANTHROPIC_API_KEY, streams SSE with inline citations). The digest is hash-gated — rebuilds skip model work when content is unchanged — and buildable three ways: a Claude Code skill (subscription, sharded), the one-shot CLI, or the sharded flow for big sites. Everything degrades instead of hard-failing: no key → keyword mode; no digest → plain excerpts. The corpus is only the configured content collection(s) — no crawler. The POST /api/ask endpoint renders on demand (keyword JSON vs. agentic SSE; keyless GET read routes for glossary/sections/overview), so a server or hybrid adapter is required. The ask CLI exposes read verbs, search, answer, an MCP server, and digest build/verify. Users compare it against Pagefind, Algolia DocSearch, and Orama; the Tradeoffs and Limits pages answer that directly.
Glossary 10 terms
Aliases that widen a reader's query before retrieval — so k8s finds kubernetes. List the terms; open one for its aliases and definition.
-
ask digest
digestkgknowledge graphThe committed, offline-built JSON artifact that distills the docs for the agent to read progressively.
-
agentic search
ask modeask aiagentic loopThe bounded Claude tool-use loop that gathers sections then streams a grounded, deep-linked answer on Enter.
-
keyword search
keyword modeinstant searchThe keyless, instant token-overlap retrieval over heading chunks, widened by the glossary.
-
chunk
sectionheading chunkA heading-bounded slice of a doc with its own URL and anchor; the unit indexed and searched.
-
glossary
synonymsaliasesTerms with aliases that expand queries before retrieval so synonyms find the right sections.
-
sharded build
shardingshardsSplitting the corpus along slug prefixes so each shard distills in its own context, removing the corpus-size limit.
-
MCP server
mcpmodel context protocolA stdio server exposing the digest's read/search/answer surface as tools for coding agents.
-
SearchOverlay
overlaycommand paletteThe Cmd-K Astro component that renders the search palette over a page.
-
hevAsk
integrationastro integrationThe Astro integration default export configured in astro.config.
-
anchor
deep linkslugA heading id generated by github-slugger so result links land on the exact section.
Sections 87 nodes
One node per heading — the map the agent navigates. Collapsed shows the summary it always sees; open a section to reveal its facts, just like the loop's open_section.
API
- CLI referenceThe ask CLI reads, builds, verifies, and serves the committed digest for agents and CI. It has consumer commands (progressive read/search verbs and an MCP server) and producer commands grouped under digest (build, corpus, assemble, verify, status).facts · quoted verbatim
@hevmind/askaskoverviewglossarysearchsectionssection getanswermcpask digestbuildcorpusassembleverifystatusCallout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Building the digest referenceProducer commands run from the Astro site root; the one-shot build is hash-gated and skips the model when the committed digest already matches the corpus, but is bounded and fails past a section-text size limit. The corpus/assemble pair exposes a deterministic seam where the model authors only context, glossary, per-section summaries, and suggestions while chunking, facts, overview, sources, and the content hash are computed in code.facts · quoted verbatim
ask digest build # one-shot build; needs ANTHROPIC_API_KEY only when stale ask digest corpus # emit sections for a keyless skill/model distillation ask digest assemble # assemble .hev-ask/digest.json from that distillation ask digest verify # build the site and verify anchors, coverage, fidelity ask digest status # report shard coverage for a sharded buildask digest build.hev-ask/digest.jsonask digest corpus.hev-ask/digest-input.jsonask digest assemble.hev-ask/digest-distill.jsoncontextglossarysummariessuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Claude Code skill referenceThe bundled build-digest skill builds the digest without an API key by running the deterministic producer seam in sharded form: emit per-shard inputs, distill each shard in a fresh context, synthesize global notes, then assemble. Because the model steps run inside your Claude Code subscription it costs no API tokens, never hits a context limit, and produces a digest identical in shape and hash gating to the one-shot build.facts · quoted verbatim
ask digest corpus --shards-dir .hev-ask/shards -> input-<id>.json + manifest.json ...one fresh-context distillation per shard -> distill-<id>.json... ...one synthesis pass over the shard notes -> global.json... ask digest assemble --input-dir .hev-ask/shards -> .hev-ask/digest.jsonbuild-digestANTHROPIC_API_KEYdigest.jsonask digest buildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Distribution referenceThe npm package exposes a single bin whose launcher resolves an env override first, then a platform-specific optional binary package, then the checked-out Go source. The source fallback is for development; published installs use the packaged binary.facts · quoted verbatim
askHEV_ASK_BINARYReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Flags referenceLists every CLI flag with its default and purpose, covering digest path, remote endpoint, JSON output, result caps, producer collection/path/glob/chunking settings, the build and sharding options, and the verify build controls. Global flags must come before the command.facts · quoted verbatim
ask --digest-path .hev-ask/digest.json --json search "openapi" ask --endpoint https://hevask.com/api/ask mcp ask digest build --collection docs --collection guides --chunk-heading-depth 2 ask digest verify --skip-build--digest-path <path>.hev-ask/digest.json--endpoint <url>/api/askanswer--json--max-results <n>--collection <name>docs--base-path <path>/docs/--content-glob <glob>--chunk-heading-depth <n>--digest-model <model>claude-opus-4-8ask digest build--out <path>.hev-ask/digest-input.jsonask digest corpus--input <path>.hev-ask/digest-distill.jsonask digest assemble--shards-dir <dir>Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Go library referenceA reusable Go API lets you call pure helpers directly or mount the dependency-free command group inside your own CLI. It exposes lower-level helpers for loading the digest, listing glossary, getting sections, searching, talking to an endpoint, building, verifying anchors, and serving MCP.facts · quoted verbatim
group := ask.NewCommandGroup(ask.CommandOptions{ DigestPath: ".hev-ask/digest.json", }) err := group.Run(ctx, []string{"search", "read endpoints"}, os.Stdin, os.Stdout, os.Stderr)pkg/askLoadDigestListGlossaryGetSectionSearchDigestNewEndpointClientBuildDigestVerifyAnchorsServeMCPReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - MCP referenceRunning the MCP subcommand starts a stdio Model Context Protocol server over the same read and search surface, offering glossary, section, overview, search, and answer tools. Configure it against a local digest path for checked-out repos or against a deployed endpoint when the agent needs the remote digest or the answer tool.facts · quoted verbatim
{ "mcpServers": { "docs": { "command": "ask", "args": ["--digest-path", ".hev-ask/digest.json", "mcp"] } } }{ "mcpServers": { "hevask": { "command": "ask", "args": ["--endpoint", "https://hevask.com/api/ask", "mcp"] } } }ask mcpglossary_listglossary_getsections_listsection_getoverviewsearchanswerReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Package scripts referenceYou can wire the digest build and verify commands into your site's package scripts so they run as part of your normal workflow.facts · quoted verbatim
{ "scripts": { "digest:build": "ask digest build", "digest:verify": "ask digest verify" } }ask digestReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Reading the digest referenceBy default the CLI reads the local committed digest from the current repo; passing an endpoint reads from a deployed site's HTTP API instead. The read verbs cover glossary, sections, section get, overview, and search, while the answer verb uses the deployed agentic SSE path and therefore requires an endpoint.facts · quoted verbatim
ask glossary list ask glossary get "ask digest" ask sections list --group API ask section get api/endpoint#digest-reads-get ask overview ask search "read endpoints" ask --endpoint https://hevask.com/api/ask answer "what read routes exist?" ask mcpask.hev-ask/digest.json--endpoint <url>ask answer--endpointask searchReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Sharded builds for large sites referenceSharding removes the single-context corpus bound by splitting the corpus along slug-prefix boundaries, distilling each shard independently in a fresh context, and merging the shards into one digest. It is stable and incremental, so editing one doc re-pends only the shard that owns it; each distillation names the shard hash it came from, stale work is detected and skipped to plain excerpts, merged glossaries are deduped and capped, and the verify step gates anchors, coverage, and fidelity with anchor drift always fatal.facts · quoted verbatim
ask digest corpus --shards-dir .hev-ask/shards # input-<id>.json per shard + manifest.json ask digest status --shards-dir .hev-ask/shards # distilled / pending / stale, per shard # ...one distillation per shard writes distill-<id>.json; a final pass writes global.json... ask digest assemble --input-dir .hev-ask/shards # merge + write .hev-ask/digest.jsonworkers/...pages/...corpusdistill-<id>.jsonsummariesglossaryshardHashnotesglobal.jsoncontextsuggestionsbuild-digestask digest verify--skip-build--strictReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Where it runs referenceProducer commands run locally or in CI with filesystem access, and the Astro integration also runs the build during astro build when a key is present, falling back to the committed artifact otherwise. The deployed site reads the committed digest through the virtual module with no filesystem access, and running the verify step on every build is the mechanical check that generated anchors still match Astro's rendered HTML.facts · quoted verbatim
ask digest buildastro buildANTHROPIC_API_KEYvirtual:hev-ask/digestask digest verifyReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Configuration referenceThe hevAsk integration is the default export of the package and takes a single options object where only the content collections setting is effectively required and everything else defaults. It configures collections, models, endpoint and base path, chunking depth, retrieval caps, and digest paths.facts · quoted verbatim
// astro.config.mjs import hevAsk from "@hevmind/ask"; export default defineConfig({ integrations: [ hevAsk({ collections: ["docs"], basePath: "/docs/", model: "claude-haiku-4-5", maxResults: 6, }), ], });hevAsk()@hevmind/askcollectionsCallout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Options referenceA full table of integration options with their types, defaults, and meaning, covering collections, base path, endpoint route, the loop and digest models, result and token caps, iteration and chunking limits, per-search and per-doc candidate caps, the digest path, and the content globs the offline builder reads. If you change the endpoint option you must pass the same value to the overlay's matching prop.facts · quoted verbatim
collectionsstring[]basePathstring'/docs/'basePath + slug#anchorendpoint'/api/ask'model'claude-haiku-4-5'digestModel'claude-opus-4-8'maxResultsnumberanswerMaxTokens1024maxIterationssearchchunkHeadingDepth#####candidatePerSearchperDocCapReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Tuning notes referenceGuidance on tuning the knobs: raise or lower chunk heading depth for anchor granularity, lower iterations to cap agentic latency or raise it for multi-part questions, use the per-doc cap to stop one page dominating results, and raise candidates per search to trade more recall for more tokens.facts · quoted verbatim
chunkHeadingDepth###maxIterationsperDocCapcandidatePerSearchReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - TypeScript referenceThe options type is exported so editors can offer help and you can type your config.facts · quoted verbatim
import type { HevAskOptions } from "@hevmind/ask";Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - What the integration does referenceAt Astro startup the integration injects the on-demand endpoint route, registers the config and digest virtual modules, watches the digest file for dev reloads, and warns if no collections are set. At build start it runs the hash-gated digest build when a key is present, otherwise warns and proceeds with the committed artifact, and it never fails the build for a missing key.facts · quoted verbatim
astro:config:setupendpoint@hevmind/ask/endpointprerender: falsevirtual:hev-ask/configvirtual:hev-ask/digestdigestPathcollectionsastro:build:startANTHROPIC_API_KEYReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Digest format referenceThe committed digest is a single JSON file built offline and committed to your repo, inlined into the build through a virtual module so the running site reads it without filesystem access. It is the agent's distilled, source-grounded view of your docs that the loop reads progressively, with every node linking back to a real page anchor.facts · quoted verbatim
.hev-ask/digest.jsonask digest buildkgvirtual:hev-ask/digesturl#anchorCallout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Degradation referenceThe digest is read defensively: if it is missing, malformed, or an older node-less version, the integration uses it as-is, the agentic loop falls back to keyword-style search, and nothing hard-fails. Because it is committed JSON its deterministic structure shows up and is reviewable in pull requests, with only the distillation being model-authored.facts · quoted verbatim
summaryglossarycontextsuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - DigestNode referenceDescribes the fields of a single distilled section node: its id mapping one-to-one to a real anchor, the model's summary the agent reasons from, deterministically extracted verbatim facts, provenance sources, a mode marking reference sections as source-primary, and distinctive terms used for the render-time link-support check.facts · quoted verbatim
DigestNodeidstringsummaryfactsFact[]sourcesSourceRef[]urlanchormode'agent-primary' \| 'source-primary'source-primarytermsstring[]Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Fields referenceLists the top-level digest fields and their roles: schema version, build timestamp, the content hash freshness gate, compact context, the glossary, a deterministic section overview, model-authored suggestions, the array of distilled nodes, and a reserved-empty edges array.facts · quoted verbatim
versiongeneratedAtstringcontentHashcontextglossaryGlossaryEntry[]overviewsuggestionsstring[]nodesDigestNode[]edgesDigestEdge[]Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - How each field is used referenceExplains how each field drives behavior: overview and nodes are injected and prompt-cached into the agentic loop, the glossary expands keyword queries, nodes also rank keyword results above incidental body mentions, terms back a render-time link-degradation check, suggestions populate the overlay, and the content hash gates whether the build calls the model.facts · quoted verbatim
overviewnodesfactsglossaryk8skubernetessummarytermssuggestionsGETcontentHashbuildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Regenerating referenceRebuild and commit the digest after content changes; the hash gate makes this safe to run every build since it only spends model work when content actually changed. Build it with the keyless Claude Code skill or the bounded one-shot CLI, use the sharded flow for large sites that re-distills only touched shards, and run verify to gate anchors, coverage, and fidelity.facts · quoted verbatim
ask digest buildastro buildask digest verifyReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Shape referenceShows a concrete example of the digest JSON, illustrating the top-level fields and the structure of a single node with its summary, facts, sources, mode, and terms.no verbatim facts in this section
Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Search endpoint referenceThe integration injects one on-demand route tree where the base route serves the overlay, returning JSON for keyword mode and streaming a grounded answer as Server-Sent Events for agentic mode. Keyless sub-routes expose the committed digest for CLIs, MCP servers, and generated clients, and an OpenAPI contract is published.facts · quoted verbatim
/api/asktext/event-stream/openapi.yamlCallout.astro3.1openapi.yamlReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Agentic response (SSE) referenceWhen a key is present and the mode is agentic, the endpoint streams the answer as named SSE frames: search events report context gathered, a one-time sources event sends the grounding set before any token, token events stream answer deltas, done ends the stream, and error reports a failure after streaming began. Sources carry no snippet because the prose carries the substance and links point at their URLs.facts · quoted verbatim
modeagenticcontent-type: text/event-streamsearch{ query }sources{ sources: Source[], model, mode }token{ text }done{}error{ error }200Source{ title, heading?, url, group? }snippeturlReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Digest reads (GET) referenceA set of GET routes read the digest without ever calling a model or needing a key, returning the glossary, a single glossary entry by term or alias, section summaries optionally filtered by group, a full node by id, and the overview plus context. Section ids containing slashes or hashes must be URL-encoded in the path, and missing terms, ids, or unknown routes return a 404 JSON error.facts · quoted verbatim
{ "error": "Not found." }virtual:hev-ask/digestGET /api/ask/glossary{ "terms": GlossaryEntry[] }GET /api/ask/glossary/{term}GlossaryEntryGET /api/ask/sections{ "sections": SectionSummary[] }GET /api/ask/sections?group=APIGET /api/ask/sections/{id}KnowledgeNodeGET /api/ask/overview{ "overview": string, "context": string }SectionSummary{ id, title, heading, group, url }/api/ask/sections/api%2Fcli%23flags404Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Errors referenceDocuments the endpoint's error responses by status: invalid JSON body, not-found for missing read routes or terms or section ids, server error when the chunk index fails to build, and a special case where failures during the agentic stream arrive as a final SSE error event because the HTTP status is already a success.facts · quoted verbatim
400{ "error": "Invalid JSON body." }404{ "error": "…" }500event: error200errore.gReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Index lifecycle referenceThe chunk index is built once per server instance on the first request and cached for the process lifetime. On that first request the endpoint also compares the live content hash against the digest's and logs a one-time warning if they differ, signaling that you should rebuild.facts · quoted verbatim
ask digest buildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Keyword response (JSON) referenceKeyword mode returns a success JSON envelope with ranked results, the echoed query, the configured model, the mode that ran, and an optional warning when agentic was requested but no key is configured. Each result's URL is the deep link carrying the section anchor, absent only for a document's intro chunk.facts · quoted verbatim
{ "results": [ { "title": "Concepts", "heading": "The agentic search loop", "url": "/docs/concepts#the-agentic-search-loop", "group": "Overview", "snippet": "When the reader presses Enter, the query goes to a bounded loop…" } ], "query": "how does agentic search work", "model": "claude-haiku-4-5", "mode": "keyword" }200resultsResult[]titleheading?urlgroup?snippetquerystringmodelmode'keyword'warningstring?#anchorReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - LLM tracing referenceSetting a PostHog key in the same environment makes every agentic answer emit a generation trace with model, tokens, latency, and tool calls, with additional env vars to override the ingestion host and control how much prompt and answer text ships. With no key it is a no-op and the answer path never depends on telemetry.facts · quoted verbatim
POSTHOG_KEYPOSTHOG_API_KEY$ai_generationPOSTHOG_HOSTPOSTHOG_CAPTURE_CONTENToffredactedfullReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Mode selection referenceThe endpoint chooses the path: an empty query returns an empty keyword result, keyword mode or a missing key returns keyword JSON, requesting agentic without a key downgrades to keyword JSON with a warning, and otherwise it streams the agentic answer. There is no AI-unavailable error path because a missing key simply downgrades to keyword results, and the overlay branches on the response content-type.facts · quoted verbatim
{ results: [], query: "", model, mode: "keyword" }mode: "keyword"mode: "agentic"warningcontent-typeReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Request referenceRequests are a POST with a JSON body carrying the query and an optional mode. An empty or whitespace query returns an empty result set, keyword forces the instant path, agentic requests the loop, and an omitted mode behaves like agentic when a key is present.facts · quoted verbatim
{ "query": "how does autoscaling work", "mode": "agentic" }POSTquerystringmode'keyword' \| 'agentic'keywordagenticReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Suggested questions (GET) referenceA GET on the base endpoint returns the digest's baked-in suggestions and the loop model with no query or model call. The overlay fetches this once on first open when AI is on, and an empty suggestions array simply means the overlay shows none.facts · quoted verbatim
{ "suggestions": ["How does the digest stay fresh?"], "model": "claude-haiku-4-5" }GET /api/asksuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - The API key referenceThe endpoint resolves the Anthropic API key in order from the adapter runtime env, then the process env, then the build-time import env. Set it wherever your host injects server secrets; it is never sent to the browser.facts · quoted verbatim
ANTHROPIC_API_KEYlocals.runtime.envprocess.envimport.meta.enve.gReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - MCP server referenceRunning the MCP subcommand starts a stdio Model Context Protocol server over the same digest reads as the CLI and HTTP API. It is the zero-glue path for coding agents: point the agent at a checked-out repo's digest or a deployed endpoint and it gets structured tools for your docs.facts · quoted verbatim
ask mcp.hev-ask/digest.json/api/askReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Configure referenceShows the MCP server configuration for local keyless digest reads versus a deployed site. Use the endpoint form when you want the freshest deployed digest or the answer tool, since local mode is fully offline and keyless but the answer tool errors without an endpoint.facts · quoted verbatim
{ "mcpServers": { "docs": { "command": "ask", "args": ["--digest-path", ".hev-ask/digest.json", "mcp"] } } }{ "mcpServers": { "hevask": { "command": "ask", "args": ["--endpoint", "https://hevask.com/api/ask", "mcp"] } } }answer--endpointReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Data sources referenceThe MCP server uses the same resolution as the CLI: an endpoint calls the deployed HTTP read API and streams the answer through the POST route, otherwise it reads the local digest path from disk. Local reads load the digest on each tool call so a just-rebuilt digest is visible without restarting the server.facts · quoted verbatim
ask mcp--endpoint <url>answerPOST /api/ask--digest-path.hev-ask/digest.jsondigest.jsonReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Protocol surface referenceThe server speaks newline-delimited JSON-RPC over stdio, handling initialize, tools listing and calls, and the initialized notification, with unknown methods returning a protocol error and tool failures returning an error tool result. It stays small because all substantive behavior lives in the shared Go package used by the CLI, embeddable command group, and MCP server.facts · quoted verbatim
initializetools/listtools/callisError: truepkg/askReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Tools referenceLists the MCP tools with their arguments and returns, covering glossary list and get, section list and get, overview, keyword search, and a collapsed agentic answer. Tool results include human-readable text plus the original machine shape in structured content so agents can read it or route it into later steps.facts · quoted verbatim
glossary_list{ terms: GlossaryEntry[] }glossary_get{ term }sections_list{ group? }{ sections: SectionSummary[] }section_get{ id }overview{ overview, context }search{ query, maxResults? }answer{ query }contentstructuredContentReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - SearchOverlay component referenceThe SearchOverlay component renders the Cmd-K command palette and is added once in a global layout. It opens over the page and does not affect layout until opened.facts · quoted verbatim
--- import SearchOverlay from "@hevmind/ask/components/SearchOverlay.astro"; --- <SearchOverlay />SearchOverlay.astro⌘K<dialog>Callout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Keyboard model referenceThe overlay is ask-first and uses the number of typed words to choose the path: suggestions on open, debounced keyless keyword search at one word with the first result auto-active, and a switch to ask mode once a space is typed so Enter sends the question to the agentic loop. Arrow keys move the active keyword result, Esc closes, and if no server key is present asking returns keyword results with a surfaced warning.facts · quoted verbatim
TabReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Keyword results and deep links referenceEach keyword result row shows the document title, an optional heading breadcrumb, and a one-line snippet. The row links to the chunk's URL which already carries the section anchor, so clicking lands on the exact heading.facts · quoted verbatim
Concepts › The agentic loopurl#anchorReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Opening the overlay referenceThe overlay opens two built-in ways: the Cmd-K or Ctrl-K shortcut bound automatically once the component is on the page, and any element carrying the opener attribute, of which you can wire up as many triggers as you like.facts · quoted verbatim
<button type="button" data-hev-ask-open> Search <kbd>⌘K</kbd> </button> <a href="#" data-hev-ask-open>Search the docs</a>⌘KCtrl-Kdata-hev-ask-openReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Props referenceDocuments the overlay's props with defaults: the endpoint it posts to (which must match the integration's endpoint option), the input placeholder text, and the debounce delay before a keyword query is sent.facts · quoted verbatim
<SearchOverlay endpoint="/api/ask" placeholder="Search hev ask…" debounce={400} />endpointstring'/api/ask'placeholder'Search the docs…'debouncenumber500Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Suggested questions referenceWhen AI is on, the overlay fetches a short list of suggested questions from the endpoint the first time it opens and shows them in the empty state. They come from the digest's suggestions baked in at build time so there is no model call to render them, and if the digest has none the overlay shows nothing extra.facts · quoted verbatim
GET /api/asksuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - The mode toggle referenceThe overlay persists an AI-on-Enter preference in localStorage so readers can flip it to keyword-only and never trigger a model call. In that mode a space just searches for a phrase, no suggested questions appear, and the choice survives reloads.facts · quoted verbatim
localStoragehev-ask:modeagentickeywordReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - The streamed answer referencePressing Enter with a key configured replaces the keyword rows with an answer panel showing the model's live sub-queries, then the grounded answer streaming token-by-token with a blinking caret. Inline deep links point at the exact section anchor and a Sources row lists every section drawn from, with any link outside the streamed source set rendered as plain text so a hallucinated anchor can never become a clickable dead link.facts · quoted verbatim
searched: …/docs/page#anchorReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Theming referenceThe overlay's markup uses a class prefix and reads your page's CSS custom properties, so defining a handful of color tokens on the root makes it inherit your palette. Because its scoped styles are keyed to those variables, matching your site's look usually requires no overlay CSS to override.facts · quoted verbatim
:root { --paper: #111111; /* overlay background */ --ink: #fafaf5; /* primary text */ --muted: #6b6b66; /* secondary text */ --signal: #e25822; /* accent / active state */ }as-:rootReference section — on open, the agent also receives this section's source text verbatim.
open section ↗
Overview
- Concepts summaryhev ask is three parts: a heading-chunk index with real anchors, an offline ask digest that is a distilled source-grounded index of every section, and a bounded agentic loop that reads the digest progressively from primer to summaries to full source. The split that matters is that the digest is built offline with a strong model and committed to git while the index and loop run on demand at the edge, with no durable state in the running site.
- Asking is the default summaryThe overlay is ask-first: a single word is a keyword lookup answered instantly from the index, and the moment the query grows past one word it switches to ask mode where Enter sends the question to the agentic loop. Suggested questions baked into the digest make asking the obvious move, but a reader can flip to keyword-only so a space just searches and the model is never called.
- Chunks and anchors summaryhev ask indexes sections rather than pages, splitting each document on its headings up to a configurable depth, with pre-heading content becoming an intro chunk whose URL is the page itself. Each chunk carries its heading, cleaned prose, and a URL whose anchor is generated by the same slugger Astro's renderer uses, and both the runtime index and the offline build chunk through one shared function so the anchors agree.facts · quoted verbatimopen section ↗
#####basePath + slug + #anchorgithub-sluggergetCollectiongithub.com - Degradation, by design summaryhev ask keeps working as pieces drop away: no key at runtime falls back to keyword mode, no key at build keeps the committed digest with only a warning, a missing or node-less digest degrades the loop to keyword-style retrieval and ranking to raw token overlap, and a stale digest logs a warning but still serves. Everything still works.
- Keyword search and the glossary summaryOn a single term the server runs a dependency-free prefilter: it expands the query with glossary aliases and matched-term tokens, scores by token overlap widened by the digest so sections it considers central rank above incidental body mentions, caps results per document, and excerpts around the first matched term. This instant path needs no key and no embeddings, and with no digest it degrades to plain token overlap so keyword search always works.
- The agentic search loop summaryOn a multi-word ask with a key, the query goes to a bounded two-phase tool-use loop that is progressive disclosure over the digest. In the gather phase the model is given a map of every section and one tool to open sections it needs, citing only what it opened and stopping within a capped number of rounds; in the answer phase the accumulated sources are sent to the overlay and the model is called once more with no tools so it can only write a grounded, inline-linked answer constrained to the surfaced sections.
- The ask digest summaryThe ask digest is built offline and committed as a reviewable artifact holding distilled section nodes with summaries, verbatim facts, and source links (reference sections marked source-primary), a deterministic overview, a compact context and glossary, and suggested questions. Only the summary, glossary, context, and suggestions are model-authored while the node structure, facts, overview, and content hash are derived deterministically, so the model supplies only the distillation.facts · quoted verbatimopen section ↗
digest.jsonnodessummaryfactssourcesource-primaryoverviewcontextglossarysuggestions - The system prompt is cached summaryThe digest's section map and summaries are injected into the system prompt with a cache marker so across the gather rounds it is a prompt-cache hit rather than re-sent tokens. The answer turn changes the tool set so it cannot reuse that cache, but it is the last call anyway, and the loop model defaults to a Haiku model and is configurable.
- Two ways to build it summaryThe model step can run two ways that feed the same deterministic assembler: the recommended Claude Code skill that walks Claude through the corpus inside your subscription with no API key or per-build token spend, or the fallback one-shot CLI call to the default Opus model for CI or non-Claude-Code users. Either way the build is hash-gated so an unchanged committed digest does no model work, and the JSON is reviewed in pull requests.
- Introduction summaryhev ask distills an Astro docs site into an ask digest, a token-efficient form of your docs that agents discover progressively through the ask CLI and readers reach through a Cmd-K overlay. Build the digest offline with the bundled skill and your Claude Code subscription, then serve single-turn Q&A over your docs for a few cents per query, suited to technical docs, internal wikis, and medium-sized corpora.
- Build it with your coding agent summaryThe digest is built inside your coding agent: the bundled Claude Code skill generates it using your existing subscription, with no API key and no per-build token spend. Commit the JSON and drop the overlay into a layout to get instant keyword results plus a Claude answer loop on Enter, every result deep-linked, with no crawler or external index because the docs you render are the digest and the committed file is reviewable in every PR.facts · quoted verbatimopen section ↗
.hev-ask/digest.jsonANTHROPIC_API_KEYSearchOverlay.astrodigest.json - Next steps summaryPoints to the next pages: Quick start to add search in five minutes, Concepts for chunks and the loop and digest, Tradeoffs and Limits for what you are choosing and what it does not do, and the CLI and API references.
- Who this is for summaryThe audience is anyone building or maintaining an Astro 5 docs site whose content lives in a Markdown or MDX content collection and who wants search that works without a service or crawler, deep-links to the right section, answers questions in the reader's own words, and is queryable by a coding agent. If you only need keyword search over a static site with no API key, Pagefind is a simpler and great fit.
- Limits summaryThese are the boundaries to know before adopting hev ask. None are bugs; they are the edges of what the current design covers.
- A server route is required summaryThe search endpoint renders on demand, so a fully static build cannot serve search and you need a server or hybrid adapter such as Node, Cloudflare, or Vercel. Static-only sites should use a static search tool instead.
- Agentic search adds latency summaryThe agentic path is bounded by a capped number of Claude round-trips, worst case a few seconds, so it is not instant by nature. The keyword path is the always-available instant lane, and lowering the iteration cap tightens the agentic ceiling.
- Anchors depend on Astro's slugger summaryDeep links stay correct only while the heading slugs hev ask generates match Astro's rendered id attributes, which it ensures by using the same github-slugger. It ships a verify command that fails if any chunk anchor is missing from the built HTML, and wiring that into CI is what catches any future slugging change before a broken link ships.
- Frontmatter parsing is a flat-YAML subset summaryThe offline build parses frontmatter with a small flat-YAML splitter rather than a full YAML parser, handling the common string and number docs schema but not nested structures. This affects only the offline build reading files from disk, since the runtime index uses Astro's own collection loader which honors your real schema.
- Recall has a keyword ceiling summaryRetrieval is glossary-widened keyword token overlap, not embeddings, and the agentic loop can only ground in and link to what retrieval surfaces. The glossary recovers most synonym cases, but a query that shares no tokens with your docs and is not in the glossary may never enter the candidate pool; embeddings are the deferred known fix, with a richer glossary the cheaper lever until analytics show consistent misses.
- Secrets live server-side summaryThe agentic path needs the Anthropic API key in the server environment that runs the endpoint, and the key is never exposed to the browser. Without it at runtime the endpoint serves keyword results, so search degrades rather than breaks.
- The corpus is your content collection summaryhev ask searches only the Astro content collections you configure and nothing else: there is no crawler, no sitemap ingestion, and no way to index non-collection pages such as hand-written Astro pages. Anything you want searchable must live in a configured collection.
- The one-shot digest build is bounded; sharded builds are not summaryThe one-shot build sends the full cleaned corpus to the model in one call, which fits typical docs sites but fails loudly past a section-text size limit, whereas the sharded build splits the corpus into prefix-stable shards each distilled in its own context and merged deterministically, scaling to very large corpora and re-distilling only touched shards. The remaining scale consideration is the runtime prompt, since the agentic path inlines node summaries, so digests with tens of thousands of nodes are not yet a fit for the answer loop.
- Quick start summaryYou can add search to an existing Astro 5 docs site whose content lives in a collection in about five minutes, getting keyword search working first and then adding an Anthropic API key to enable Claude-powered agentic answers. The overlay gives keyless instant keyword search that runs anywhere, and the same overlay runs the agentic loop on Enter once a server key is present.facts · quoted verbatimopen section ↗
src/content/docsANTHROPIC_API_KEYSearchOverlay.astroSteps.astroCallout.astro - 1. Install summaryInstall the package from npm once published, or until then consume it straight from the package subdirectory on GitHub.facts · quoted verbatimopen section ↗
pnpm add @hevmind/askpnpm add "git+ssh://[email protected]/hev/ask.git#main&path:/packages/ui" - 2. Register the integration summaryRegister the integration in your Astro config, passing your content collection name(s) and a base path. Collections is the one option you must set; everything else has a default.facts · quoted verbatimopen section ↗
// astro.config.mjs import { defineConfig } from "astro/config"; import hevAsk from "@hevmind/ask"; export default defineConfig({ integrations: [ hevAsk({ collections: ["docs"], // your content collection name(s) basePath: "/docs/", // slug → URL prefix: basePath + slug }), ], });collections - 3. Add a server adapter summaryBecause the search route renders on demand, add whichever server or hybrid adapter matches your host while existing pages stay prerendered and only the endpoint runs as a function.facts · quoted verbatimopen section ↗
// astro.config.mjs import cloudflare from "@astrojs/cloudflare"; export default defineConfig({ adapter: cloudflare({ platformProxy: { enabled: true } }), // ...integrations as above });/api/ask - 4. Render the overlay summaryAdd the overlay component once somewhere global like your base layout; any element with the opener attribute opens the palette and the Cmd-K shortcut is bound automatically. Keyword search then works in dev.facts · quoted verbatimopen section ↗
--- // src/layouts/Base.astro import SearchOverlay from "@hevmind/ask/components/SearchOverlay.astro"; --- <button type="button" data-hev-ask-open> Search <kbd>⌘K</kbd> </button> <slot /> <SearchOverlay />data-hev-ask-open⌘Kastro dev - 5. Build the digest summaryThe digest is an offline-built JSON file you commit that gives the agentic loop context, ranks keyword results, supplies the glossary, and holds the overlay's suggested questions. Build it with the recommended keyless Claude Code skill or the one-shot CLI for CI, then verify and commit; both paths are hash-gated and the integration also builds automatically during astro build when a key is present.facts · quoted verbatimopen section ↗
You: build the hev ask digest Claude runs: ask digest corpus # emits the sections to distil …writes context/glossary/summaries/suggestions… ask digest assemble # writes .hev-ask/digest.jsonexport ANTHROPIC_API_KEY=sk-ant-... pnpm exec ask digest build # writes .hev-ask/digest.jsonpnpm exec ask digest verify # builds the site, checks every anchor resolves git add .hev-ask/digest.jsonk8skubernetesastro buildclaude.com - Enable agentic search summarySet the Anthropic API key in the server environment where the endpoint runs, via your host's secrets or a local env file. With a key present, pressing Enter runs the agentic loop with self-issued sub-queries, a grounded answer, and inline deep links; without one, Enter returns keyword results.
- Prerequisites summaryPrerequisites are Astro 5 with at least one content collection, a server or hybrid adapter because the search route renders on demand, and an Anthropic API key to enable agentic search. Keyword search needs no key.
- Set up keyword search summarySection heading introducing the steps to set up keyword search.
- Verify it works summaryVerify keyword search by typing a single word from a heading and confirming the top result deep-links to that section, and verify agentic search by asking a multi-word question and confirming the sub-queries and a streamed, deep-linked answer appear. Also confirm the verify command exits non-zero if any chunk anchor is missing from the built HTML, and wire it into CI.
- Tradeoffs summaryEvery search tool makes choices, and this page is the honest account of what hev ask trades away to get what it gives so you can decide whether the trade fits your docs.
- A committed digest summaryThe digest is generated offline and committed to git as JSON rather than computed at runtime or hidden in a service, making it reviewable in pull requests, deterministic, free to read on the request path, and bundled into the edge worker with no runtime filesystem access. The cost is that it can go stale, since it only regenerates on content change plus a build; a warning fires when the live hash differs, and the cheap idempotent hash gate makes rebuild-on-every-content-change in CI the intended workflow.no verbatim facts in this section open section ↗
- Cost and latency of agentic search summaryThe agentic path calls Claude, so it costs small real money and latency: worst-case latency is roughly the iteration cap of Haiku round-trips, with the keyword path staying instant and the iteration cap as the tightening knob. Cost is one bounded loop per submitted query on the default Haiku model with domain context prompt-cached, the Opus offline build is paid only when content changes thanks to the hash gate, and keyword-only is a first-class mode if you want no key in the loop.
- How it compares summaryA comparison table and guidance versus Pagefind, Algolia DocSearch, and Orama across retrieval, AI ranking, deep links, and hosting. Choose Pagefind for simple keyless static keyword search, Algolia for a managed crawler-based service, Orama for client-side vector search, and hev ask when your docs are Astro content collections and you want section-level deep links and a reader's question, not just keywords, to find the right section.no verbatim facts in this section open section ↗
- Keyword retrieval, not embeddings summaryRetrieval is dependency-free token overlap widened by the glossary with no embeddings or vector store, so there is nothing to host or keep in sync, it is edge-safe and instant, and the glossary recovers a lot of synonym recall. The cost is a paraphrase-recall ceiling since the agent can only ground in what keyword retrieval surfaced, and embeddings would do better for readers who search in words that share no tokens with your docs; that upgrade is deferred, not designed out.no verbatim facts in this section open section ↗
- One dependency, deliberately summaryhev ask aims to be near zero-dependency with one deliberate exception: github-slugger, a tiny pure-JS edge-safe library. Generating heading anchors by hand risks drifting from Astro's renderer and shipping links that 404, so using the same slugger guarantees byte-identical anchors.
- Two paths instead of one summaryhev ask runs an instant keyword path and an agentic path and asks the reader to choose by pressing Enter, keeping the common one-or-two-word case instant and keyless while hard questions get a smarter ranker. The cost is a slightly more complex interaction model where readers must learn that Enter means ask AI, judged the right trade for docs where queries split into jumping to a known thing versus finding a thing you cannot name.no verbatim facts in this section open section ↗
Raw digest.json artifact
{
"version": 2,
"generatedAt": "2026-06-07T13:27:32.004Z",
"contentHash": "0e72409fab4ff7ed4fc4c953fb02b25baa78b98007a303ccd5fd5cd69816cffb",
"context": "**hev ask** (`@hevmind/ask`) is a `⌘K` search overlay for Astro docs sites, documented at hevask.com — a site that searches itself with the package. Three moving parts: a heading-level chunk index with real rendered anchors (via github-slugger, gated by `ask digest verify`), a committed offline-built **ask digest** (`.hev-ask/digest.json`) holding the glossary, section summaries, and site overview, and a bounded Claude tool-use loop. Two retrieval paths: instant keyless **keyword** search (token overlap widened by the digest glossary, deep-linking to `/docs/page#anchor`) and an **agentic** answer on Enter (needs `ANTHROPIC_API_KEY`, streams SSE with inline citations). The digest is hash-gated — rebuilds skip model work when content is unchanged — and buildable three ways: a Claude Code skill (subscription, sharded), the one-shot CLI, or the sharded flow for big sites. Everything degrades instead of hard-failing: no key → keyword mode; no digest → plain excerpts. The corpus is only the configured content collection(s) — no crawler. The `POST /api/ask` endpoint renders on demand (keyword JSON vs. agentic SSE; keyless GET read routes for glossary/sections/overview), so a server or hybrid adapter is required. The `ask` CLI exposes read verbs, search, answer, an MCP server, and `digest build`/`verify`. Users compare it against Pagefind, Algolia DocSearch, and Orama; the Tradeoffs and Limits pages answer that directly.",
"glossary": [
{
"term": "ask digest",
"aliases": [
"digest",
"kg",
"knowledge graph"
],
"definition": "The committed, offline-built JSON artifact that distills the docs for the agent to read progressively."
},
{
"term": "agentic search",
"aliases": [
"ask mode",
"ask ai",
"agentic loop"
],
"definition": "The bounded Claude tool-use loop that gathers sections then streams a grounded, deep-linked answer on Enter."
},
{
"term": "keyword search",
"aliases": [
"keyword mode",
"instant search"
],
"definition": "The keyless, instant token-overlap retrieval over heading chunks, widened by the glossary."
},
{
"term": "chunk",
"aliases": [
"section",
"heading chunk"
],
"definition": "A heading-bounded slice of a doc with its own URL and anchor; the unit indexed and searched."
},
{
"term": "glossary",
"aliases": [
"synonyms",
"aliases"
],
"definition": "Terms with aliases that expand queries before retrieval so synonyms find the right sections."
},
{
"term": "sharded build",
"aliases": [
"sharding",
"shards"
],
"definition": "Splitting the corpus along slug prefixes so each shard distills in its own context, removing the corpus-size limit."
},
{
"term": "MCP server",
"aliases": [
"mcp",
"model context protocol"
],
"definition": "A stdio server exposing the digest's read/search/answer surface as tools for coding agents."
},
{
"term": "SearchOverlay",
"aliases": [
"overlay",
"command palette"
],
"definition": "The Cmd-K Astro component that renders the search palette over a page."
},
{
"term": "hevAsk",
"aliases": [
"integration",
"astro integration"
],
"definition": "The Astro integration default export configured in astro.config."
},
{
"term": "anchor",
"aliases": [
"deep link",
"slug"
],
"definition": "A heading id generated by github-slugger so result links land on the exact section."
}
],
"overview": "## API\n- CLI — `api/cli`\n- Building the digest — `api/cli#building-the-digest`\n- Claude Code skill — `api/cli#claude-code-skill`\n- Distribution — `api/cli#distribution`\n- Flags — `api/cli#flags`\n- Go library — `api/cli#go-library`\n- MCP — `api/cli#mcp`\n- Package scripts — `api/cli#package-scripts`\n- Reading the digest — `api/cli#reading-the-digest`\n- Sharded builds for large sites — `api/cli#sharded-builds-for-large-sites`\n- Where it runs — `api/cli#where-it-runs`\n- Configuration — `api/configuration`\n- Options — `api/configuration#options`\n- Tuning notes — `api/configuration#tuning-notes`\n- TypeScript — `api/configuration#typescript`\n- What the integration does — `api/configuration#what-the-integration-does`\n- Digest format — `api/digest`\n- Degradation — `api/digest#degradation`\n- DigestNode — `api/digest#digestnode`\n- Fields — `api/digest#fields`\n- How each field is used — `api/digest#how-each-field-is-used`\n- Regenerating — `api/digest#regenerating`\n- Shape — `api/digest#shape`\n- Search endpoint — `api/endpoint`\n- Agentic response (SSE) — `api/endpoint#agentic-response-sse`\n- Digest reads (GET) — `api/endpoint#digest-reads-get`\n- Errors — `api/endpoint#errors`\n- Index lifecycle — `api/endpoint#index-lifecycle`\n- Keyword response (JSON) — `api/endpoint#keyword-response-json`\n- LLM tracing — `api/endpoint#llm-tracing`\n- Mode selection — `api/endpoint#mode-selection`\n- Request — `api/endpoint#request`\n- Suggested questions (GET) — `api/endpoint#suggested-questions-get`\n- The API key — `api/endpoint#the-api-key`\n- MCP server — `api/mcp`\n- Configure — `api/mcp#configure`\n- Data sources — `api/mcp#data-sources`\n- Protocol surface — `api/mcp#protocol-surface`\n- Tools — `api/mcp#tools`\n- SearchOverlay component — `api/search-overlay`\n- Keyboard model — `api/search-overlay#keyboard-model`\n- Keyword results and deep links — `api/search-overlay#keyword-results-and-deep-links`\n- Opening the overlay — `api/search-overlay#opening-the-overlay`\n- Props — `api/search-overlay#props`\n- Suggested questions — `api/search-overlay#suggested-questions`\n- The mode toggle — `api/search-overlay#the-mode-toggle`\n- The streamed answer — `api/search-overlay#the-streamed-answer`\n- Theming — `api/search-overlay#theming`\n## Overview\n- Concepts — `concepts`\n- Asking is the default — `concepts#asking-is-the-default`\n- Chunks and anchors — `concepts#chunks-and-anchors`\n- Degradation, by design — `concepts#degradation-by-design`\n- Keyword search and the glossary — `concepts#keyword-search-and-the-glossary`\n- The agentic search loop — `concepts#the-agentic-search-loop`\n- The ask digest — `concepts#the-ask-digest`\n- The system prompt is cached — `concepts#the-system-prompt-is-cached`\n- Two ways to build it — `concepts#two-ways-to-build-it`\n- Introduction — `index`\n- Build it with your coding agent — `index#build-it-with-your-coding-agent`\n- Next steps — `index#next-steps`\n- Who this is for — `index#who-this-is-for`\n- Limits — `limits`\n- A server route is required — `limits#a-server-route-is-required`\n- Agentic search adds latency — `limits#agentic-search-adds-latency`\n- Anchors depend on Astro's slugger — `limits#anchors-depend-on-astros-slugger`\n- Frontmatter parsing is a flat-YAML subset — `limits#frontmatter-parsing-is-a-flat-yaml-subset`\n- Recall has a keyword ceiling — `limits#recall-has-a-keyword-ceiling`\n- Secrets live server-side — `limits#secrets-live-server-side`\n- The corpus is your content collection — `limits#the-corpus-is-your-content-collection`\n- The one-shot digest build is bounded; sharded builds are not — `limits#the-one-shot-digest-build-is-bounded-sharded-builds-are-not`\n- Quick start — `quickstart`\n- 1. Install — `quickstart#1-install`\n- 2. Register the integration — `quickstart#2-register-the-integration`\n- 3. Add a server adapter — `quickstart#3-add-a-server-adapter`\n- 4. Render the overlay — `quickstart#4-render-the-overlay`\n- 5. Build the digest — `quickstart#5-build-the-digest`\n- Enable agentic search — `quickstart#enable-agentic-search`\n- Prerequisites — `quickstart#prerequisites`\n- Set up keyword search — `quickstart#set-up-keyword-search`\n- Verify it works — `quickstart#verify-it-works`\n- Tradeoffs — `tradeoffs`\n- A committed digest — `tradeoffs#a-committed-digest`\n- Cost and latency of agentic search — `tradeoffs#cost-and-latency-of-agentic-search`\n- How it compares — `tradeoffs#how-it-compares`\n- Keyword retrieval, not embeddings — `tradeoffs#keyword-retrieval-not-embeddings`\n- One dependency, deliberately — `tradeoffs#one-dependency-deliberately`\n- Two paths instead of one — `tradeoffs#two-paths-instead-of-one`",
"suggestions": [
"How do I add hev ask to my Astro site?",
"How does the agentic answer loop work?",
"Why keyword search instead of embeddings?",
"How do I build and refresh the ask digest?",
"What can't hev ask do?"
],
"nodes": [
{
"id": "api/cli",
"kind": "section",
"title": "CLI",
"heading": null,
"group": "API",
"url": "/docs/api/cli",
"summary": "The ask CLI reads, builds, verifies, and serves the committed digest for agents and CI. It has consumer commands (progressive read/search verbs and an MCP server) and producer commands grouped under digest (build, corpus, assemble, verify, status).",
"facts": [
{
"kind": "code",
"literal": "@hevmind/ask",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "ask",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "search",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "sections",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "section get",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "answer",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "mcp",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "ask digest",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "build",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "corpus",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "assemble",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "verify",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "status",
"chunkId": "api/cli"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/cli"
}
],
"sources": [
{
"chunkId": "api/cli",
"url": "/docs/api/cli",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"reads",
"builds",
"verifies",
"serves",
"committed",
"digest",
"agents",
"consumer",
"commands",
"progressive",
"read",
"search",
"verbs",
"server",
"producer",
"grouped",
"under",
"build",
"corpus",
"assemble",
"verify",
"status",
"hevmind",
"overview",
"glossary",
"sections",
"section",
"answer",
"callout",
"astro",
"ships",
"binary",
"command",
"groups",
"disclosure",
"skim",
"find",
"open",
"serve",
"agent"
]
},
{
"id": "api/cli#building-the-digest",
"kind": "section",
"title": "CLI",
"heading": "Building the digest",
"group": "API",
"url": "/docs/api/cli#building-the-digest",
"summary": "Producer commands run from the Astro site root; the one-shot build is hash-gated and skips the model when the committed digest already matches the corpus, but is bounded and fails past a section-text size limit. The corpus/assemble pair exposes a deterministic seam where the model authors only context, glossary, per-section summaries, and suggestions while chunking, facts, overview, sources, and the content hash are computed in code.",
"facts": [
{
"kind": "code",
"literal": "ask digest build # one-shot build; needs ANTHROPIC_API_KEY only when stale\nask digest corpus # emit sections for a keyless skill/model distillation\nask digest assemble # assemble .hev-ask/digest.json from that distillation\nask digest verify # build the site and verify anchors, coverage, fidelity\nask digest status # report shard coverage for a sharded build",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "ask digest corpus",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/digest-input.json",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "ask digest assemble",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/digest-distill.json",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "summaries",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/cli#building-the-digest"
}
],
"sources": [
{
"chunkId": "api/cli#building-the-digest",
"url": "/docs/api/cli#building-the-digest",
"anchor": "building-the-digest"
}
],
"mode": "source-primary",
"terms": [
"building",
"digest",
"producer",
"commands",
"astro",
"site",
"root",
"shot",
"build",
"hash",
"gated",
"skips",
"model",
"committed",
"already",
"matches",
"corpus",
"bounded",
"fails",
"past",
"section",
"text",
"size",
"limit",
"assemble",
"pair",
"exposes",
"deterministic",
"seam",
"authors",
"only",
"context",
"glossary",
"summaries",
"suggestions",
"while",
"chunking",
"facts",
"overview",
"sources"
]
},
{
"id": "api/cli#claude-code-skill",
"kind": "section",
"title": "CLI",
"heading": "Claude Code skill",
"group": "API",
"url": "/docs/api/cli#claude-code-skill",
"summary": "The bundled build-digest skill builds the digest without an API key by running the deterministic producer seam in sharded form: emit per-shard inputs, distill each shard in a fresh context, synthesize global notes, then assemble. Because the model steps run inside your Claude Code subscription it costs no API tokens, never hits a context limit, and produces a digest identical in shape and hash gating to the one-shot build.",
"facts": [
{
"kind": "code",
"literal": "ask digest corpus --shards-dir .hev-ask/shards -> input-<id>.json + manifest.json\n...one fresh-context distillation per shard -> distill-<id>.json...\n...one synthesis pass over the shard notes -> global.json...\nask digest assemble --input-dir .hev-ask/shards -> .hev-ask/digest.json",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "build-digest",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "digest.json",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/cli#claude-code-skill"
}
],
"sources": [
{
"chunkId": "api/cli#claude-code-skill",
"url": "/docs/api/cli#claude-code-skill",
"anchor": "claude-code-skill"
}
],
"mode": "source-primary",
"terms": [
"claude",
"code",
"skill",
"bundled",
"build",
"digest",
"builds",
"without",
"running",
"deterministic",
"producer",
"seam",
"sharded",
"form",
"emit",
"shard",
"inputs",
"distill",
"fresh",
"context",
"synthesize",
"global",
"notes",
"assemble",
"because",
"model",
"steps",
"inside",
"subscription",
"costs",
"tokens",
"never",
"hits",
"limit",
"produces",
"identical",
"shape",
"hash",
"gating",
"shot"
]
},
{
"id": "api/cli#distribution",
"kind": "section",
"title": "CLI",
"heading": "Distribution",
"group": "API",
"url": "/docs/api/cli#distribution",
"summary": "The npm package exposes a single bin whose launcher resolves an env override first, then a platform-specific optional binary package, then the checked-out Go source. The source fallback is for development; published installs use the packaged binary.",
"facts": [
{
"kind": "code",
"literal": "ask",
"chunkId": "api/cli#distribution"
},
{
"kind": "code",
"literal": "HEV_ASK_BINARY",
"chunkId": "api/cli#distribution"
}
],
"sources": [
{
"chunkId": "api/cli#distribution",
"url": "/docs/api/cli#distribution",
"anchor": "distribution"
}
],
"mode": "source-primary",
"terms": [
"distribution",
"package",
"exposes",
"single",
"whose",
"launcher",
"resolves",
"override",
"first",
"platform",
"specific",
"optional",
"binary",
"checked",
"source",
"fallback",
"development",
"published",
"installs",
"packaged",
"hevaskbinary",
"installed",
"monorepo",
"path"
]
},
{
"id": "api/cli#flags",
"kind": "section",
"title": "CLI",
"heading": "Flags",
"group": "API",
"url": "/docs/api/cli#flags",
"summary": "Lists every CLI flag with its default and purpose, covering digest path, remote endpoint, JSON output, result caps, producer collection/path/glob/chunking settings, the build and sharding options, and the verify build controls. Global flags must come before the command.",
"facts": [
{
"kind": "code",
"literal": "ask --digest-path .hev-ask/digest.json --json search \"openapi\"\nask --endpoint https://hevask.com/api/ask mcp\nask digest build --collection docs --collection guides --chunk-heading-depth 2\nask digest verify --skip-build",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--digest-path <path>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--endpoint <url>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "answer",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--json",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--max-results <n>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--collection <name>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "docs",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--base-path <path>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "/docs/",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--content-glob <glob>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--chunk-heading-depth <n>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--digest-model <model>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "claude-opus-4-8",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--out <path>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": ".hev-ask/digest-input.json",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "ask digest corpus",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--input <path>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": ".hev-ask/digest-distill.json",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "ask digest assemble",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--shards-dir <dir>",
"chunkId": "api/cli#flags"
}
],
"sources": [
{
"chunkId": "api/cli#flags",
"url": "/docs/api/cli#flags",
"anchor": "flags"
}
],
"mode": "source-primary",
"terms": [
"flags",
"lists",
"every",
"flag",
"default",
"purpose",
"covering",
"digest",
"path",
"remote",
"endpoint",
"json",
"output",
"result",
"caps",
"producer",
"collection",
"glob",
"chunking",
"settings",
"build",
"sharding",
"options",
"verify",
"controls",
"global",
"must",
"come",
"before",
"command",
"search",
"openapi",
"https",
"hevask",
"docs",
"guides",
"chunk",
"heading",
"depth",
"skip"
]
},
{
"id": "api/cli#go-library",
"kind": "section",
"title": "CLI",
"heading": "Go library",
"group": "API",
"url": "/docs/api/cli#go-library",
"summary": "A reusable Go API lets you call pure helpers directly or mount the dependency-free command group inside your own CLI. It exposes lower-level helpers for loading the digest, listing glossary, getting sections, searching, talking to an endpoint, building, verifying anchors, and serving MCP.",
"facts": [
{
"kind": "code",
"literal": "group := ask.NewCommandGroup(ask.CommandOptions{\n\tDigestPath: \".hev-ask/digest.json\",\n})\nerr := group.Run(ctx, []string{\"search\", \"read endpoints\"}, os.Stdin, os.Stdout, os.Stderr)",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "pkg/ask",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "LoadDigest",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "ListGlossary",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "GetSection",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "SearchDigest",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "NewEndpointClient",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "BuildDigest",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "VerifyAnchors",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "ServeMCP",
"chunkId": "api/cli#go-library"
}
],
"sources": [
{
"chunkId": "api/cli#go-library",
"url": "/docs/api/cli#go-library",
"anchor": "go-library"
}
],
"mode": "source-primary",
"terms": [
"library",
"reusable",
"lets",
"call",
"pure",
"helpers",
"directly",
"mount",
"dependency",
"free",
"command",
"group",
"inside",
"exposes",
"lower",
"level",
"loading",
"digest",
"listing",
"glossary",
"getting",
"sections",
"searching",
"talking",
"endpoint",
"building",
"verifying",
"anchors",
"serving",
"newcommandgroup",
"commandoptions",
"digestpath",
"json",
"string",
"search",
"read",
"endpoints",
"stdin",
"stdout",
"stderr"
]
},
{
"id": "api/cli#mcp",
"kind": "section",
"title": "CLI",
"heading": "MCP",
"group": "API",
"url": "/docs/api/cli#mcp",
"summary": "Running the MCP subcommand starts a stdio Model Context Protocol server over the same read and search surface, offering glossary, section, overview, search, and answer tools. Configure it against a local digest path for checked-out repos or against a deployed endpoint when the agent needs the remote digest or the answer tool.",
"facts": [
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"docs\": {\n \"command\": \"ask\",\n \"args\": [\"--digest-path\", \".hev-ask/digest.json\", \"mcp\"]\n }\n }\n}",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"hevask\": {\n \"command\": \"ask\",\n \"args\": [\"--endpoint\", \"https://hevask.com/api/ask\", \"mcp\"]\n }\n }\n}",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "ask mcp",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "glossary_list",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "glossary_get",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "sections_list",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "section_get",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "search",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "answer",
"chunkId": "api/cli#mcp"
}
],
"sources": [
{
"chunkId": "api/cli#mcp",
"url": "/docs/api/cli#mcp",
"anchor": "mcp"
}
],
"mode": "source-primary",
"terms": [
"running",
"subcommand",
"starts",
"stdio",
"model",
"context",
"protocol",
"server",
"same",
"read",
"search",
"surface",
"offering",
"glossary",
"section",
"overview",
"answer",
"tools",
"configure",
"against",
"local",
"digest",
"path",
"checked",
"repos",
"deployed",
"endpoint",
"agent",
"needs",
"remote",
"tool",
"mcpservers",
"docs",
"command",
"args",
"json",
"hevask",
"https",
"list",
"sections"
]
},
{
"id": "api/cli#package-scripts",
"kind": "section",
"title": "CLI",
"heading": "Package scripts",
"group": "API",
"url": "/docs/api/cli#package-scripts",
"summary": "You can wire the digest build and verify commands into your site's package scripts so they run as part of your normal workflow.",
"facts": [
{
"kind": "code",
"literal": "{\n \"scripts\": {\n \"digest:build\": \"ask digest build\",\n \"digest:verify\": \"ask digest verify\"\n }\n}",
"chunkId": "api/cli#package-scripts"
},
{
"kind": "code",
"literal": "ask digest",
"chunkId": "api/cli#package-scripts"
}
],
"sources": [
{
"chunkId": "api/cli#package-scripts",
"url": "/docs/api/cli#package-scripts",
"anchor": "package-scripts"
}
],
"mode": "source-primary",
"terms": [
"package",
"scripts",
"wire",
"digest",
"build",
"verify",
"commands",
"site",
"part",
"normal",
"workflow"
]
},
{
"id": "api/cli#reading-the-digest",
"kind": "section",
"title": "CLI",
"heading": "Reading the digest",
"group": "API",
"url": "/docs/api/cli#reading-the-digest",
"summary": "By default the CLI reads the local committed digest from the current repo; passing an endpoint reads from a deployed site's HTTP API instead. The read verbs cover glossary, sections, section get, overview, and search, while the answer verb uses the deployed agentic SSE path and therefore requires an endpoint.",
"facts": [
{
"kind": "code",
"literal": "ask glossary list\nask glossary get \"ask digest\"\nask sections list --group API\nask section get api/endpoint#digest-reads-get\nask overview\nask search \"read endpoints\"\nask --endpoint https://hevask.com/api/ask answer \"what read routes exist?\"\nask mcp",
"chunkId": "api/cli#reading-the-digest"
},
{
"kind": "code",
"literal": "ask",
"chunkId": "api/cli#reading-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/cli#reading-the-digest"
},
{
"kind": "code",
"literal": "--endpoint <url>",
"chunkId": "api/cli#reading-the-digest"
},
{
"kind": "code",
"literal": "ask answer",
"chunkId": "api/cli#reading-the-digest"
},
{
"kind": "code",
"literal": "--endpoint",
"chunkId": "api/cli#reading-the-digest"
},
{
"kind": "code",
"literal": "ask search",
"chunkId": "api/cli#reading-the-digest"
}
],
"sources": [
{
"chunkId": "api/cli#reading-the-digest",
"url": "/docs/api/cli#reading-the-digest",
"anchor": "reading-the-digest"
}
],
"mode": "source-primary",
"terms": [
"reading",
"digest",
"default",
"reads",
"local",
"committed",
"current",
"repo",
"passing",
"endpoint",
"deployed",
"site",
"http",
"instead",
"read",
"verbs",
"cover",
"glossary",
"sections",
"section",
"overview",
"search",
"while",
"answer",
"verb",
"uses",
"agentic",
"path",
"therefore",
"requires",
"list",
"group",
"endpoints",
"https",
"hevask",
"routes",
"exist",
"json",
"pass",
"keyless"
]
},
{
"id": "api/cli#sharded-builds-for-large-sites",
"kind": "section",
"title": "CLI",
"heading": "Sharded builds for large sites",
"group": "API",
"url": "/docs/api/cli#sharded-builds-for-large-sites",
"summary": "Sharding removes the single-context corpus bound by splitting the corpus along slug-prefix boundaries, distilling each shard independently in a fresh context, and merging the shards into one digest. It is stable and incremental, so editing one doc re-pends only the shard that owns it; each distillation names the shard hash it came from, stale work is detected and skipped to plain excerpts, merged glossaries are deduped and capped, and the verify step gates anchors, coverage, and fidelity with anchor drift always fatal.",
"facts": [
{
"kind": "code",
"literal": "ask digest corpus --shards-dir .hev-ask/shards # input-<id>.json per shard + manifest.json\nask digest status --shards-dir .hev-ask/shards # distilled / pending / stale, per shard\n# ...one distillation per shard writes distill-<id>.json; a final pass writes global.json...\nask digest assemble --input-dir .hev-ask/shards # merge + write .hev-ask/digest.json",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "workers/...",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "pages/...",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "corpus",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "distill-<id>.json",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "summaries",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "shardHash",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "notes",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "global.json",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "build-digest",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "ask digest verify",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "--skip-build",
"chunkId": "api/cli#sharded-builds-for-large-sites"
},
{
"kind": "code",
"literal": "--strict",
"chunkId": "api/cli#sharded-builds-for-large-sites"
}
],
"sources": [
{
"chunkId": "api/cli#sharded-builds-for-large-sites",
"url": "/docs/api/cli#sharded-builds-for-large-sites",
"anchor": "sharded-builds-for-large-sites"
}
],
"mode": "source-primary",
"terms": [
"sharded",
"builds",
"large",
"sites",
"sharding",
"removes",
"single",
"context",
"corpus",
"bound",
"splitting",
"along",
"slug",
"prefix",
"boundaries",
"distilling",
"shard",
"independently",
"fresh",
"merging",
"shards",
"digest",
"stable",
"incremental",
"editing",
"pends",
"only",
"owns",
"distillation",
"names",
"hash",
"came",
"stale",
"work",
"detected",
"skipped",
"plain",
"excerpts",
"merged",
"glossaries"
]
},
{
"id": "api/cli#where-it-runs",
"kind": "section",
"title": "CLI",
"heading": "Where it runs",
"group": "API",
"url": "/docs/api/cli#where-it-runs",
"summary": "Producer commands run locally or in CI with filesystem access, and the Astro integration also runs the build during astro build when a key is present, falling back to the committed artifact otherwise. The deployed site reads the committed digest through the virtual module with no filesystem access, and running the verify step on every build is the mechanical check that generated anchors still match Astro's rendered HTML.",
"facts": [
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/cli#where-it-runs"
},
{
"kind": "code",
"literal": "astro build",
"chunkId": "api/cli#where-it-runs"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "api/cli#where-it-runs"
},
{
"kind": "code",
"literal": "virtual:hev-ask/digest",
"chunkId": "api/cli#where-it-runs"
},
{
"kind": "code",
"literal": "ask digest verify",
"chunkId": "api/cli#where-it-runs"
}
],
"sources": [
{
"chunkId": "api/cli#where-it-runs",
"url": "/docs/api/cli#where-it-runs",
"anchor": "where-it-runs"
}
],
"mode": "source-primary",
"terms": [
"runs",
"producer",
"commands",
"locally",
"filesystem",
"access",
"astro",
"integration",
"also",
"build",
"during",
"present",
"falling",
"back",
"committed",
"artifact",
"otherwise",
"deployed",
"site",
"reads",
"digest",
"through",
"virtual",
"module",
"running",
"verify",
"step",
"every",
"mechanical",
"check",
"generated",
"anchors",
"still",
"match",
"rendered",
"html",
"anthropic",
"invokes",
"anthropicapikey",
"falls"
]
},
{
"id": "api/configuration",
"kind": "section",
"title": "Configuration",
"heading": null,
"group": "API",
"url": "/docs/api/configuration",
"summary": "The hevAsk integration is the default export of the package and takes a single options object where only the content collections setting is effectively required and everything else defaults. It configures collections, models, endpoint and base path, chunking depth, retrieval caps, and digest paths.",
"facts": [
{
"kind": "code",
"literal": "// astro.config.mjs\nimport hevAsk from \"@hevmind/ask\";\n\nexport default defineConfig({\n integrations: [\n hevAsk({\n collections: [\"docs\"],\n basePath: \"/docs/\",\n model: \"claude-haiku-4-5\",\n maxResults: 6,\n }),\n ],\n});",
"chunkId": "api/configuration"
},
{
"kind": "code",
"literal": "hevAsk()",
"chunkId": "api/configuration"
},
{
"kind": "code",
"literal": "@hevmind/ask",
"chunkId": "api/configuration"
},
{
"kind": "code",
"literal": "collections",
"chunkId": "api/configuration"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/configuration"
}
],
"sources": [
{
"chunkId": "api/configuration",
"url": "/docs/api/configuration",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"hevask",
"integration",
"default",
"export",
"package",
"takes",
"single",
"options",
"object",
"only",
"content",
"collections",
"setting",
"effectively",
"required",
"everything",
"else",
"defaults",
"configures",
"models",
"endpoint",
"base",
"path",
"chunking",
"depth",
"retrieval",
"caps",
"digest",
"paths",
"astro",
"config",
"import",
"hevmind",
"defineconfig",
"integrations",
"docs",
"basepath",
"model",
"claude",
"haiku"
]
},
{
"id": "api/configuration#options",
"kind": "section",
"title": "Configuration",
"heading": "Options",
"group": "API",
"url": "/docs/api/configuration#options",
"summary": "A full table of integration options with their types, defaults, and meaning, covering collections, base path, endpoint route, the loop and digest models, result and token caps, iteration and chunking limits, per-search and per-doc candidate caps, the digest path, and the content globs the offline builder reads. If you change the endpoint option you must pass the same value to the overlay's matching prop.",
"facts": [
{
"kind": "code",
"literal": "collections",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "string[]",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "basePath",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "'/docs/'",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "basePath + slug",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "#anchor",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "endpoint",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "'/api/ask'",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "model",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "'claude-haiku-4-5'",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "digestModel",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "'claude-opus-4-8'",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "maxResults",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "number",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "answerMaxTokens",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "1024",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "search",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "chunkHeadingDepth",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "##",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "###",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "candidatePerSearch",
"chunkId": "api/configuration#options"
},
{
"kind": "code",
"literal": "perDocCap",
"chunkId": "api/configuration#options"
}
],
"sources": [
{
"chunkId": "api/configuration#options",
"url": "/docs/api/configuration#options",
"anchor": "options"
}
],
"mode": "source-primary",
"terms": [
"options",
"full",
"table",
"integration",
"their",
"types",
"defaults",
"meaning",
"covering",
"collections",
"base",
"path",
"endpoint",
"route",
"loop",
"digest",
"models",
"result",
"token",
"caps",
"iteration",
"chunking",
"limits",
"search",
"candidate",
"content",
"globs",
"offline",
"builder",
"reads",
"change",
"option",
"must",
"pass",
"same",
"value",
"overlay",
"matching",
"prop",
"string"
]
},
{
"id": "api/configuration#tuning-notes",
"kind": "section",
"title": "Configuration",
"heading": "Tuning notes",
"group": "API",
"url": "/docs/api/configuration#tuning-notes",
"summary": "Guidance on tuning the knobs: raise or lower chunk heading depth for anchor granularity, lower iterations to cap agentic latency or raise it for multi-part questions, use the per-doc cap to stop one page dominating results, and raise candidates per search to trade more recall for more tokens.",
"facts": [
{
"kind": "code",
"literal": "chunkHeadingDepth",
"chunkId": "api/configuration#tuning-notes"
},
{
"kind": "code",
"literal": "###",
"chunkId": "api/configuration#tuning-notes"
},
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "api/configuration#tuning-notes"
},
{
"kind": "code",
"literal": "perDocCap",
"chunkId": "api/configuration#tuning-notes"
},
{
"kind": "code",
"literal": "candidatePerSearch",
"chunkId": "api/configuration#tuning-notes"
}
],
"sources": [
{
"chunkId": "api/configuration#tuning-notes",
"url": "/docs/api/configuration#tuning-notes",
"anchor": "tuning-notes"
}
],
"mode": "source-primary",
"terms": [
"tuning",
"notes",
"guidance",
"knobs",
"raise",
"lower",
"chunk",
"heading",
"depth",
"anchor",
"granularity",
"iterations",
"agentic",
"latency",
"multi",
"part",
"questions",
"stop",
"page",
"dominating",
"results",
"candidates",
"search",
"trade",
"more",
"recall",
"tokens",
"chunkheadingdepth",
"maxiterations",
"perdoccap",
"candidatepersearch",
"default",
"finer",
"section",
"anchors",
"long",
"pages",
"drop",
"sections",
"small"
]
},
{
"id": "api/configuration#typescript",
"kind": "section",
"title": "Configuration",
"heading": "TypeScript",
"group": "API",
"url": "/docs/api/configuration#typescript",
"summary": "The options type is exported so editors can offer help and you can type your config.",
"facts": [
{
"kind": "code",
"literal": "import type { HevAskOptions } from \"@hevmind/ask\";",
"chunkId": "api/configuration#typescript"
}
],
"sources": [
{
"chunkId": "api/configuration#typescript",
"url": "/docs/api/configuration#typescript",
"anchor": "typescript"
}
],
"mode": "source-primary",
"terms": [
"typescript",
"options",
"type",
"exported",
"editors",
"offer",
"help",
"config",
"import",
"hevaskoptions",
"hevmind",
"editor",
"typing"
]
},
{
"id": "api/configuration#what-the-integration-does",
"kind": "section",
"title": "Configuration",
"heading": "What the integration does",
"group": "API",
"url": "/docs/api/configuration#what-the-integration-does",
"summary": "At Astro startup the integration injects the on-demand endpoint route, registers the config and digest virtual modules, watches the digest file for dev reloads, and warns if no collections are set. At build start it runs the hash-gated digest build when a key is present, otherwise warns and proceeds with the committed artifact, and it never fails the build for a missing key.",
"facts": [
{
"kind": "code",
"literal": "astro:config:setup",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "endpoint",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "@hevmind/ask/endpoint",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "prerender: false",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "virtual:hev-ask/config",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "virtual:hev-ask/digest",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "digestPath",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "collections",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "astro:build:start",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "api/configuration#what-the-integration-does"
}
],
"sources": [
{
"chunkId": "api/configuration#what-the-integration-does",
"url": "/docs/api/configuration#what-the-integration-does",
"anchor": "what-the-integration-does"
}
],
"mode": "source-primary",
"terms": [
"integration",
"does",
"astro",
"startup",
"injects",
"demand",
"endpoint",
"route",
"registers",
"config",
"digest",
"virtual",
"modules",
"watches",
"file",
"reloads",
"warns",
"collections",
"build",
"start",
"runs",
"hash",
"gated",
"present",
"otherwise",
"proceeds",
"committed",
"artifact",
"never",
"fails",
"missing",
"setup",
"hevmind",
"prerender",
"false",
"digestpath",
"anthropic",
"starts",
"pointing",
"renders"
]
},
{
"id": "api/digest",
"kind": "section",
"title": "Digest format",
"heading": null,
"group": "API",
"url": "/docs/api/digest",
"summary": "The committed digest is a single JSON file built offline and committed to your repo, inlined into the build through a virtual module so the running site reads it without filesystem access. It is the agent's distilled, source-grounded view of your docs that the loop reads progressively, with every node linking back to a real page anchor.",
"facts": [
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/digest"
},
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/digest"
},
{
"kind": "code",
"literal": "kg",
"chunkId": "api/digest"
},
{
"kind": "code",
"literal": "virtual:hev-ask/digest",
"chunkId": "api/digest"
},
{
"kind": "code",
"literal": "url#anchor",
"chunkId": "api/digest"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/digest"
}
],
"sources": [
{
"chunkId": "api/digest",
"url": "/docs/api/digest",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"committed",
"digest",
"single",
"json",
"file",
"built",
"offline",
"repo",
"inlined",
"build",
"through",
"virtual",
"module",
"running",
"site",
"reads",
"without",
"filesystem",
"access",
"agent",
"distilled",
"source",
"grounded",
"view",
"docs",
"loop",
"progressively",
"every",
"node",
"linking",
"back",
"real",
"page",
"anchor",
"callout",
"astro",
"artifact",
"section",
"nodes",
"verbatim"
]
},
{
"id": "api/digest#degradation",
"kind": "section",
"title": "Digest format",
"heading": "Degradation",
"group": "API",
"url": "/docs/api/digest#degradation",
"summary": "The digest is read defensively: if it is missing, malformed, or an older node-less version, the integration uses it as-is, the agentic loop falls back to keyword-style search, and nothing hard-fails. Because it is committed JSON its deterministic structure shows up and is reviewable in pull requests, with only the distillation being model-authored.",
"facts": [
{
"kind": "code",
"literal": "summary",
"chunkId": "api/digest#degradation"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/digest#degradation"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/digest#degradation"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/digest#degradation"
}
],
"sources": [
{
"chunkId": "api/digest#degradation",
"url": "/docs/api/digest#degradation",
"anchor": "degradation"
}
],
"mode": "source-primary",
"terms": [
"degradation",
"digest",
"read",
"defensively",
"missing",
"malformed",
"older",
"node",
"less",
"version",
"integration",
"uses",
"agentic",
"loop",
"falls",
"back",
"keyword",
"style",
"search",
"nothing",
"hard",
"fails",
"because",
"committed",
"json",
"deterministic",
"structure",
"shows",
"reviewable",
"pull",
"requests",
"only",
"distillation",
"being",
"model",
"authored",
"summary",
"glossary",
"context",
"suggestions"
]
},
{
"id": "api/digest#digestnode",
"kind": "section",
"title": "Digest format",
"heading": "DigestNode",
"group": "API",
"url": "/docs/api/digest#digestnode",
"summary": "Describes the fields of a single distilled section node: its id mapping one-to-one to a real anchor, the model's summary the agent reasons from, deterministically extracted verbatim facts, provenance sources, a mode marking reference sections as source-primary, and distinctive terms used for the render-time link-support check.",
"facts": [
{
"kind": "code",
"literal": "DigestNode",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "id",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "Fact[]",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "sources",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "SourceRef[]",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "anchor",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "mode",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "'agent-primary' \\| 'source-primary'",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "source-primary",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "terms",
"chunkId": "api/digest#digestnode"
},
{
"kind": "code",
"literal": "string[]",
"chunkId": "api/digest#digestnode"
}
],
"sources": [
{
"chunkId": "api/digest#digestnode",
"url": "/docs/api/digest#digestnode",
"anchor": "digestnode"
}
],
"mode": "source-primary",
"terms": [
"digestnode",
"describes",
"fields",
"single",
"distilled",
"section",
"node",
"mapping",
"real",
"anchor",
"model",
"summary",
"agent",
"reasons",
"deterministically",
"extracted",
"verbatim",
"facts",
"provenance",
"sources",
"mode",
"marking",
"reference",
"sections",
"source",
"primary",
"distinctive",
"terms",
"render",
"time",
"link",
"support",
"check",
"string",
"fact",
"sourceref",
"field",
"type",
"description",
"equals"
]
},
{
"id": "api/digest#fields",
"kind": "section",
"title": "Digest format",
"heading": "Fields",
"group": "API",
"url": "/docs/api/digest#fields",
"summary": "Lists the top-level digest fields and their roles: schema version, build timestamp, the content hash freshness gate, compact context, the glossary, a deterministic section overview, model-authored suggestions, the array of distilled nodes, and a reserved-empty edges array.",
"facts": [
{
"kind": "code",
"literal": "version",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "generatedAt",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "contentHash",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "GlossaryEntry[]",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "string[]",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "nodes",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "DigestNode[]",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "edges",
"chunkId": "api/digest#fields"
},
{
"kind": "code",
"literal": "DigestEdge[]",
"chunkId": "api/digest#fields"
}
],
"sources": [
{
"chunkId": "api/digest#fields",
"url": "/docs/api/digest#fields",
"anchor": "fields"
}
],
"mode": "source-primary",
"terms": [
"fields",
"lists",
"level",
"digest",
"their",
"roles",
"schema",
"version",
"build",
"timestamp",
"content",
"hash",
"freshness",
"gate",
"compact",
"context",
"glossary",
"deterministic",
"section",
"overview",
"model",
"authored",
"suggestions",
"array",
"distilled",
"nodes",
"reserved",
"empty",
"edges",
"generatedat",
"string",
"contenthash",
"glossaryentry",
"digestnode",
"digestedge",
"field",
"type",
"description",
"stamped",
"node"
]
},
{
"id": "api/digest#how-each-field-is-used",
"kind": "section",
"title": "Digest format",
"heading": "How each field is used",
"group": "API",
"url": "/docs/api/digest#how-each-field-is-used",
"summary": "Explains how each field drives behavior: overview and nodes are injected and prompt-cached into the agentic loop, the glossary expands keyword queries, nodes also rank keyword results above incidental body mentions, terms back a render-time link-degradation check, suggestions populate the overlay, and the content hash gates whether the build calls the model.",
"facts": [
{
"kind": "code",
"literal": "overview",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "nodes",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "k8s",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "terms",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "GET",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "contentHash",
"chunkId": "api/digest#how-each-field-is-used"
},
{
"kind": "code",
"literal": "build",
"chunkId": "api/digest#how-each-field-is-used"
}
],
"sources": [
{
"chunkId": "api/digest#how-each-field-is-used",
"url": "/docs/api/digest#how-each-field-is-used",
"anchor": "how-each-field-is-used"
}
],
"mode": "source-primary",
"terms": [
"field",
"explains",
"drives",
"behavior",
"overview",
"nodes",
"injected",
"prompt",
"cached",
"agentic",
"loop",
"glossary",
"expands",
"keyword",
"queries",
"also",
"rank",
"results",
"above",
"incidental",
"body",
"mentions",
"terms",
"back",
"render",
"time",
"link",
"degradation",
"check",
"suggestions",
"populate",
"overlay",
"content",
"hash",
"gates",
"whether",
"build",
"calls",
"model",
"facts"
]
},
{
"id": "api/digest#regenerating",
"kind": "section",
"title": "Digest format",
"heading": "Regenerating",
"group": "API",
"url": "/docs/api/digest#regenerating",
"summary": "Rebuild and commit the digest after content changes; the hash gate makes this safe to run every build since it only spends model work when content actually changed. Build it with the keyless Claude Code skill or the bounded one-shot CLI, use the sharded flow for large sites that re-distills only touched shards, and run verify to gate anchors, coverage, and fidelity.",
"facts": [
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/digest#regenerating"
},
{
"kind": "code",
"literal": "astro build",
"chunkId": "api/digest#regenerating"
},
{
"kind": "code",
"literal": "ask digest verify",
"chunkId": "api/digest#regenerating"
}
],
"sources": [
{
"chunkId": "api/digest#regenerating",
"url": "/docs/api/digest#regenerating",
"anchor": "regenerating"
}
],
"mode": "source-primary",
"terms": [
"regenerating",
"rebuild",
"commit",
"digest",
"after",
"content",
"changes",
"hash",
"gate",
"makes",
"safe",
"every",
"build",
"since",
"only",
"spends",
"model",
"work",
"actually",
"changed",
"keyless",
"claude",
"code",
"skill",
"bounded",
"shot",
"sharded",
"flow",
"large",
"sites",
"distills",
"touched",
"shards",
"verify",
"anchors",
"coverage",
"fidelity",
"astro",
"result",
"bundled"
]
},
{
"id": "api/digest#shape",
"kind": "section",
"title": "Digest format",
"heading": "Shape",
"group": "API",
"url": "/docs/api/digest#shape",
"summary": "Shows a concrete example of the digest JSON, illustrating the top-level fields and the structure of a single node with its summary, facts, sources, mode, and terms.",
"facts": [],
"sources": [
{
"chunkId": "api/digest#shape",
"url": "/docs/api/digest#shape",
"anchor": "shape"
}
],
"mode": "source-primary",
"terms": [
"shape",
"shows",
"concrete",
"example",
"digest",
"json",
"illustrating",
"level",
"fields",
"structure",
"single",
"node",
"summary",
"facts",
"sources",
"mode",
"terms",
"version",
"generatedat",
"2026",
"30t12",
"000z",
"contenthash",
"a1b2c3",
"context",
"search",
"overlay",
"astro",
"docs",
"glossary",
"term",
"aliases",
"definition",
"offline",
"built",
"artifact",
"distilled",
"overview",
"kubernetes",
"autoscaling"
]
},
{
"id": "api/endpoint",
"kind": "section",
"title": "Search endpoint",
"heading": null,
"group": "API",
"url": "/docs/api/endpoint",
"summary": "The integration injects one on-demand route tree where the base route serves the overlay, returning JSON for keyword mode and streaming a grounded answer as Server-Sent Events for agentic mode. Keyless sub-routes expose the committed digest for CLIs, MCP servers, and generated clients, and an OpenAPI contract is published.",
"facts": [
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "api/endpoint"
},
{
"kind": "code",
"literal": "text/event-stream",
"chunkId": "api/endpoint"
},
{
"kind": "code",
"literal": "/openapi.yaml",
"chunkId": "api/endpoint"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/endpoint"
},
{
"kind": "value",
"literal": "3.1",
"chunkId": "api/endpoint"
},
{
"kind": "value",
"literal": "openapi.yaml",
"chunkId": "api/endpoint"
}
],
"sources": [
{
"chunkId": "api/endpoint",
"url": "/docs/api/endpoint",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"integration",
"injects",
"demand",
"route",
"tree",
"base",
"serves",
"overlay",
"returning",
"json",
"keyword",
"mode",
"streaming",
"grounded",
"answer",
"server",
"sent",
"events",
"agentic",
"keyless",
"routes",
"expose",
"committed",
"digest",
"clis",
"servers",
"generated",
"clients",
"openapi",
"contract",
"published",
"text",
"event",
"stream",
"yaml",
"callout",
"astro",
"suggestions",
"reads",
"selection"
]
},
{
"id": "api/endpoint#agentic-response-sse",
"kind": "section",
"title": "Search endpoint",
"heading": "Agentic response (SSE)",
"group": "API",
"url": "/docs/api/endpoint#agentic-response-sse",
"summary": "When a key is present and the mode is agentic, the endpoint streams the answer as named SSE frames: search events report context gathered, a one-time sources event sends the grounding set before any token, token events stream answer deltas, done ends the stream, and error reports a failure after streaming began. Sources carry no snippet because the prose carries the substance and links point at their URLs.",
"facts": [
{
"kind": "code",
"literal": "mode",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "agentic",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "content-type: text/event-stream",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "search",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ query }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "sources",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ sources: Source[], model, mode }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "token",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ text }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "done",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{}",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "error",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ error }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "200",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "Source",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ title, heading?, url, group? }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "snippet",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/endpoint#agentic-response-sse"
}
],
"sources": [
{
"chunkId": "api/endpoint#agentic-response-sse",
"url": "/docs/api/endpoint#agentic-response-sse",
"anchor": "agentic-response-sse"
}
],
"mode": "source-primary",
"terms": [
"agentic",
"response",
"present",
"mode",
"endpoint",
"streams",
"answer",
"named",
"frames",
"search",
"events",
"report",
"context",
"gathered",
"time",
"sources",
"event",
"sends",
"grounding",
"before",
"token",
"stream",
"deltas",
"done",
"ends",
"error",
"reports",
"failure",
"after",
"streaming",
"began",
"carry",
"snippet",
"because",
"prose",
"carries",
"substance",
"links",
"point",
"their"
]
},
{
"id": "api/endpoint#digest-reads-get",
"kind": "section",
"title": "Search endpoint",
"heading": "Digest reads (GET)",
"group": "API",
"url": "/docs/api/endpoint#digest-reads-get",
"summary": "A set of GET routes read the digest without ever calling a model or needing a key, returning the glossary, a single glossary entry by term or alias, section summaries optionally filtered by group, a full node by id, and the overview plus context. Section ids containing slashes or hashes must be URL-encoded in the path, and missing terms, ids, or unknown routes return a 404 JSON error.",
"facts": [
{
"kind": "code",
"literal": "{ \"error\": \"Not found.\" }",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "virtual:hev-ask/digest",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/glossary",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "{ \"terms\": GlossaryEntry[] }",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/glossary/{term}",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GlossaryEntry",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/sections",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "{ \"sections\": SectionSummary[] }",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/sections?group=API",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/sections/{id}",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "KnowledgeNode",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/overview",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "{ \"overview\": string, \"context\": string }",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "SectionSummary",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "{ id, title, heading, group, url }",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "/api/ask/sections/api%2Fcli%23flags",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "404",
"chunkId": "api/endpoint#digest-reads-get"
}
],
"sources": [
{
"chunkId": "api/endpoint#digest-reads-get",
"url": "/docs/api/endpoint#digest-reads-get",
"anchor": "digest-reads-get"
}
],
"mode": "source-primary",
"terms": [
"digest",
"reads",
"routes",
"read",
"without",
"ever",
"calling",
"model",
"needing",
"returning",
"glossary",
"single",
"entry",
"term",
"alias",
"section",
"summaries",
"optionally",
"filtered",
"group",
"full",
"node",
"overview",
"plus",
"context",
"containing",
"slashes",
"hashes",
"must",
"encoded",
"path",
"missing",
"terms",
"unknown",
"return",
"json",
"error",
"found",
"virtual",
"glossaryentry"
]
},
{
"id": "api/endpoint#errors",
"kind": "section",
"title": "Search endpoint",
"heading": "Errors",
"group": "API",
"url": "/docs/api/endpoint#errors",
"summary": "Documents the endpoint's error responses by status: invalid JSON body, not-found for missing read routes or terms or section ids, server error when the chunk index fails to build, and a special case where failures during the agentic stream arrive as a final SSE error event because the HTTP status is already a success.",
"facts": [
{
"kind": "code",
"literal": "400",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "{ \"error\": \"Invalid JSON body.\" }",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "404",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "{ \"error\": \"…\" }",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "500",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "event: error",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "200",
"chunkId": "api/endpoint#errors"
},
{
"kind": "code",
"literal": "error",
"chunkId": "api/endpoint#errors"
},
{
"kind": "value",
"literal": "e.g",
"chunkId": "api/endpoint#errors"
}
],
"sources": [
{
"chunkId": "api/endpoint#errors",
"url": "/docs/api/endpoint#errors",
"anchor": "errors"
}
],
"mode": "source-primary",
"terms": [
"errors",
"documents",
"endpoint",
"error",
"responses",
"status",
"invalid",
"json",
"body",
"found",
"missing",
"read",
"routes",
"terms",
"section",
"server",
"chunk",
"index",
"fails",
"build",
"special",
"case",
"failures",
"during",
"agentic",
"stream",
"arrive",
"final",
"event",
"because",
"http",
"already",
"success",
"cause",
"request",
"wasn",
"valid",
"digest",
"route",
"glossary"
]
},
{
"id": "api/endpoint#index-lifecycle",
"kind": "section",
"title": "Search endpoint",
"heading": "Index lifecycle",
"group": "API",
"url": "/docs/api/endpoint#index-lifecycle",
"summary": "The chunk index is built once per server instance on the first request and cached for the process lifetime. On that first request the endpoint also compares the live content hash against the digest's and logs a one-time warning if they differ, signaling that you should rebuild.",
"facts": [
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "api/endpoint#index-lifecycle"
}
],
"sources": [
{
"chunkId": "api/endpoint#index-lifecycle",
"url": "/docs/api/endpoint#index-lifecycle",
"anchor": "index-lifecycle"
}
],
"mode": "source-primary",
"terms": [
"index",
"lifecycle",
"chunk",
"built",
"once",
"server",
"instance",
"first",
"request",
"cached",
"process",
"lifetime",
"endpoint",
"also",
"compares",
"live",
"content",
"hash",
"against",
"digest",
"logs",
"time",
"warning",
"differ",
"signaling",
"should",
"rebuild",
"build"
]
},
{
"id": "api/endpoint#keyword-response-json",
"kind": "section",
"title": "Search endpoint",
"heading": "Keyword response (JSON)",
"group": "API",
"url": "/docs/api/endpoint#keyword-response-json",
"summary": "Keyword mode returns a success JSON envelope with ranked results, the echoed query, the configured model, the mode that ran, and an optional warning when agentic was requested but no key is configured. Each result's URL is the deep link carrying the section anchor, absent only for a document's intro chunk.",
"facts": [
{
"kind": "code",
"literal": "{\n \"results\": [\n {\n \"title\": \"Concepts\",\n \"heading\": \"The agentic search loop\",\n \"url\": \"/docs/concepts#the-agentic-search-loop\",\n \"group\": \"Overview\",\n \"snippet\": \"When the reader presses Enter, the query goes to a bounded loop…\"\n }\n ],\n \"query\": \"how does agentic search work\",\n \"model\": \"claude-haiku-4-5\",\n \"mode\": \"keyword\"\n}",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "200",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "results",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "Result[]",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "title",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "heading?",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "group?",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "snippet",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "query",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "model",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "mode",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "'keyword'",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "warning",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "string?",
"chunkId": "api/endpoint#keyword-response-json"
},
{
"kind": "code",
"literal": "#anchor",
"chunkId": "api/endpoint#keyword-response-json"
}
],
"sources": [
{
"chunkId": "api/endpoint#keyword-response-json",
"url": "/docs/api/endpoint#keyword-response-json",
"anchor": "keyword-response-json"
}
],
"mode": "source-primary",
"terms": [
"keyword",
"response",
"json",
"mode",
"returns",
"success",
"envelope",
"ranked",
"results",
"echoed",
"query",
"configured",
"model",
"optional",
"warning",
"agentic",
"requested",
"result",
"deep",
"link",
"carrying",
"section",
"anchor",
"absent",
"only",
"document",
"intro",
"chunk",
"title",
"concepts",
"heading",
"search",
"loop",
"docs",
"group",
"overview",
"snippet",
"reader",
"presses",
"enter"
]
},
{
"id": "api/endpoint#llm-tracing",
"kind": "section",
"title": "Search endpoint",
"heading": "LLM tracing",
"group": "API",
"url": "/docs/api/endpoint#llm-tracing",
"summary": "Setting a PostHog key in the same environment makes every agentic answer emit a generation trace with model, tokens, latency, and tool calls, with additional env vars to override the ingestion host and control how much prompt and answer text ships. With no key it is a no-op and the answer path never depends on telemetry.",
"facts": [
{
"kind": "code",
"literal": "POSTHOG_KEY",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "POSTHOG_API_KEY",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "$ai_generation",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "POSTHOG_HOST",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "POSTHOG_CAPTURE_CONTENT",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "off",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "redacted",
"chunkId": "api/endpoint#llm-tracing"
},
{
"kind": "code",
"literal": "full",
"chunkId": "api/endpoint#llm-tracing"
}
],
"sources": [
{
"chunkId": "api/endpoint#llm-tracing",
"url": "/docs/api/endpoint#llm-tracing",
"anchor": "llm-tracing"
}
],
"mode": "source-primary",
"terms": [
"tracing",
"setting",
"posthog",
"same",
"environment",
"makes",
"every",
"agentic",
"answer",
"emit",
"generation",
"trace",
"model",
"tokens",
"latency",
"tool",
"calls",
"additional",
"vars",
"override",
"ingestion",
"host",
"control",
"much",
"prompt",
"text",
"ships",
"path",
"never",
"depends",
"telemetry",
"capture",
"content",
"redacted",
"full",
"posthogkey",
"posthogapikey",
"emits",
"aigeneration",
"loop"
]
},
{
"id": "api/endpoint#mode-selection",
"kind": "section",
"title": "Search endpoint",
"heading": "Mode selection",
"group": "API",
"url": "/docs/api/endpoint#mode-selection",
"summary": "The endpoint chooses the path: an empty query returns an empty keyword result, keyword mode or a missing key returns keyword JSON, requesting agentic without a key downgrades to keyword JSON with a warning, and otherwise it streams the agentic answer. There is no AI-unavailable error path because a missing key simply downgrades to keyword results, and the overlay branches on the response content-type.",
"facts": [
{
"kind": "code",
"literal": "{ results: [], query: \"\", model, mode: \"keyword\" }",
"chunkId": "api/endpoint#mode-selection"
},
{
"kind": "code",
"literal": "mode: \"keyword\"",
"chunkId": "api/endpoint#mode-selection"
},
{
"kind": "code",
"literal": "mode: \"agentic\"",
"chunkId": "api/endpoint#mode-selection"
},
{
"kind": "code",
"literal": "warning",
"chunkId": "api/endpoint#mode-selection"
},
{
"kind": "code",
"literal": "content-type",
"chunkId": "api/endpoint#mode-selection"
}
],
"sources": [
{
"chunkId": "api/endpoint#mode-selection",
"url": "/docs/api/endpoint#mode-selection",
"anchor": "mode-selection"
}
],
"mode": "source-primary",
"terms": [
"mode",
"selection",
"endpoint",
"chooses",
"path",
"empty",
"query",
"returns",
"keyword",
"result",
"missing",
"json",
"requesting",
"agentic",
"without",
"downgrades",
"warning",
"otherwise",
"streams",
"answer",
"there",
"unavailable",
"error",
"because",
"simply",
"results",
"overlay",
"branches",
"response",
"content",
"type",
"model",
"decides",
"plus",
"stream",
"request",
"says",
"reader",
"still",
"gets"
]
},
{
"id": "api/endpoint#request",
"kind": "section",
"title": "Search endpoint",
"heading": "Request",
"group": "API",
"url": "/docs/api/endpoint#request",
"summary": "Requests are a POST with a JSON body carrying the query and an optional mode. An empty or whitespace query returns an empty result set, keyword forces the instant path, agentic requests the loop, and an omitted mode behaves like agentic when a key is present.",
"facts": [
{
"kind": "code",
"literal": "{\n \"query\": \"how does autoscaling work\",\n \"mode\": \"agentic\"\n}",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "POST",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "query",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "mode",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "'keyword' \\| 'agentic'",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "keyword",
"chunkId": "api/endpoint#request"
},
{
"kind": "code",
"literal": "agentic",
"chunkId": "api/endpoint#request"
}
],
"sources": [
{
"chunkId": "api/endpoint#request",
"url": "/docs/api/endpoint#request",
"anchor": "request"
}
],
"mode": "source-primary",
"terms": [
"request",
"requests",
"post",
"json",
"body",
"carrying",
"query",
"optional",
"mode",
"empty",
"whitespace",
"returns",
"result",
"keyword",
"forces",
"instant",
"path",
"agentic",
"loop",
"omitted",
"behaves",
"like",
"present",
"does",
"autoscaling",
"work",
"string",
"field",
"type",
"description",
"search"
]
},
{
"id": "api/endpoint#suggested-questions-get",
"kind": "section",
"title": "Search endpoint",
"heading": "Suggested questions (GET)",
"group": "API",
"url": "/docs/api/endpoint#suggested-questions-get",
"summary": "A GET on the base endpoint returns the digest's baked-in suggestions and the loop model with no query or model call. The overlay fetches this once on first open when AI is on, and an empty suggestions array simply means the overlay shows none.",
"facts": [
{
"kind": "code",
"literal": "{\n \"suggestions\": [\"How does the digest stay fresh?\"],\n \"model\": \"claude-haiku-4-5\"\n}",
"chunkId": "api/endpoint#suggested-questions-get"
},
{
"kind": "code",
"literal": "GET /api/ask",
"chunkId": "api/endpoint#suggested-questions-get"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/endpoint#suggested-questions-get"
}
],
"sources": [
{
"chunkId": "api/endpoint#suggested-questions-get",
"url": "/docs/api/endpoint#suggested-questions-get",
"anchor": "suggested-questions-get"
}
],
"mode": "source-primary",
"terms": [
"suggested",
"questions",
"base",
"endpoint",
"returns",
"digest",
"baked",
"suggestions",
"loop",
"model",
"query",
"call",
"overlay",
"fetches",
"once",
"first",
"open",
"empty",
"array",
"simply",
"means",
"shows",
"none",
"does",
"stay",
"fresh",
"claude",
"haiku",
"populate",
"graph",
"without",
"just"
]
},
{
"id": "api/endpoint#the-api-key",
"kind": "section",
"title": "Search endpoint",
"heading": "The API key",
"group": "API",
"url": "/docs/api/endpoint#the-api-key",
"summary": "The endpoint resolves the Anthropic API key in order from the adapter runtime env, then the process env, then the build-time import env. Set it wherever your host injects server secrets; it is never sent to the browser.",
"facts": [
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "api/endpoint#the-api-key"
},
{
"kind": "code",
"literal": "locals.runtime.env",
"chunkId": "api/endpoint#the-api-key"
},
{
"kind": "code",
"literal": "process.env",
"chunkId": "api/endpoint#the-api-key"
},
{
"kind": "code",
"literal": "import.meta.env",
"chunkId": "api/endpoint#the-api-key"
},
{
"kind": "value",
"literal": "e.g",
"chunkId": "api/endpoint#the-api-key"
}
],
"sources": [
{
"chunkId": "api/endpoint#the-api-key",
"url": "/docs/api/endpoint#the-api-key",
"anchor": "the-api-key"
}
],
"mode": "source-primary",
"terms": [
"endpoint",
"resolves",
"anthropic",
"order",
"adapter",
"runtime",
"process",
"build",
"time",
"import",
"wherever",
"host",
"injects",
"server",
"secrets",
"never",
"sent",
"browser",
"locals",
"meta",
"anthropicapikey",
"cloudflare"
]
},
{
"id": "api/mcp",
"kind": "section",
"title": "MCP server",
"heading": null,
"group": "API",
"url": "/docs/api/mcp",
"summary": "Running the MCP subcommand starts a stdio Model Context Protocol server over the same digest reads as the CLI and HTTP API. It is the zero-glue path for coding agents: point the agent at a checked-out repo's digest or a deployed endpoint and it gets structured tools for your docs.",
"facts": [
{
"kind": "code",
"literal": "ask mcp",
"chunkId": "api/mcp"
},
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/mcp"
},
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "api/mcp"
}
],
"sources": [
{
"chunkId": "api/mcp",
"url": "/docs/api/mcp",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"running",
"subcommand",
"starts",
"stdio",
"model",
"context",
"protocol",
"server",
"same",
"digest",
"reads",
"http",
"zero",
"glue",
"path",
"coding",
"agents",
"point",
"agent",
"checked",
"repo",
"deployed",
"endpoint",
"gets",
"structured",
"tools",
"docs",
"json",
"expose",
"committed",
"runs",
"graph"
]
},
{
"id": "api/mcp#configure",
"kind": "section",
"title": "MCP server",
"heading": "Configure",
"group": "API",
"url": "/docs/api/mcp#configure",
"summary": "Shows the MCP server configuration for local keyless digest reads versus a deployed site. Use the endpoint form when you want the freshest deployed digest or the answer tool, since local mode is fully offline and keyless but the answer tool errors without an endpoint.",
"facts": [
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"docs\": {\n \"command\": \"ask\",\n \"args\": [\"--digest-path\", \".hev-ask/digest.json\", \"mcp\"]\n }\n }\n}",
"chunkId": "api/mcp#configure"
},
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"hevask\": {\n \"command\": \"ask\",\n \"args\": [\"--endpoint\", \"https://hevask.com/api/ask\", \"mcp\"]\n }\n }\n}",
"chunkId": "api/mcp#configure"
},
{
"kind": "code",
"literal": "answer",
"chunkId": "api/mcp#configure"
},
{
"kind": "code",
"literal": "--endpoint",
"chunkId": "api/mcp#configure"
}
],
"sources": [
{
"chunkId": "api/mcp#configure",
"url": "/docs/api/mcp#configure",
"anchor": "configure"
}
],
"mode": "source-primary",
"terms": [
"configure",
"shows",
"server",
"configuration",
"local",
"keyless",
"digest",
"reads",
"versus",
"deployed",
"site",
"endpoint",
"form",
"want",
"freshest",
"answer",
"tool",
"since",
"mode",
"fully",
"offline",
"errors",
"without",
"mcpservers",
"docs",
"command",
"args",
"path",
"json",
"hevask",
"https",
"graph",
"returns",
"error",
"unless"
]
},
{
"id": "api/mcp#data-sources",
"kind": "section",
"title": "MCP server",
"heading": "Data sources",
"group": "API",
"url": "/docs/api/mcp#data-sources",
"summary": "The MCP server uses the same resolution as the CLI: an endpoint calls the deployed HTTP read API and streams the answer through the POST route, otherwise it reads the local digest path from disk. Local reads load the digest on each tool call so a just-rebuilt digest is visible without restarting the server.",
"facts": [
{
"kind": "code",
"literal": "ask mcp",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": "--endpoint <url>",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": "answer",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": "POST /api/ask",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": "--digest-path",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": "digest.json",
"chunkId": "api/mcp#data-sources"
}
],
"sources": [
{
"chunkId": "api/mcp#data-sources",
"url": "/docs/api/mcp#data-sources",
"anchor": "data-sources"
}
],
"mode": "source-primary",
"terms": [
"data",
"sources",
"server",
"uses",
"same",
"resolution",
"endpoint",
"calls",
"deployed",
"http",
"read",
"streams",
"answer",
"through",
"post",
"route",
"otherwise",
"reads",
"local",
"digest",
"path",
"disk",
"load",
"tool",
"call",
"just",
"rebuilt",
"visible",
"without",
"restarting",
"json",
"defaulting"
]
},
{
"id": "api/mcp#protocol-surface",
"kind": "section",
"title": "MCP server",
"heading": "Protocol surface",
"group": "API",
"url": "/docs/api/mcp#protocol-surface",
"summary": "The server speaks newline-delimited JSON-RPC over stdio, handling initialize, tools listing and calls, and the initialized notification, with unknown methods returning a protocol error and tool failures returning an error tool result. It stays small because all substantive behavior lives in the shared Go package used by the CLI, embeddable command group, and MCP server.",
"facts": [
{
"kind": "code",
"literal": "initialize",
"chunkId": "api/mcp#protocol-surface"
},
{
"kind": "code",
"literal": "tools/list",
"chunkId": "api/mcp#protocol-surface"
},
{
"kind": "code",
"literal": "tools/call",
"chunkId": "api/mcp#protocol-surface"
},
{
"kind": "code",
"literal": "isError: true",
"chunkId": "api/mcp#protocol-surface"
},
{
"kind": "code",
"literal": "pkg/ask",
"chunkId": "api/mcp#protocol-surface"
}
],
"sources": [
{
"chunkId": "api/mcp#protocol-surface",
"url": "/docs/api/mcp#protocol-surface",
"anchor": "protocol-surface"
}
],
"mode": "source-primary",
"terms": [
"protocol",
"surface",
"server",
"speaks",
"newline",
"delimited",
"json",
"stdio",
"handling",
"initialize",
"tools",
"listing",
"calls",
"initialized",
"notification",
"unknown",
"methods",
"returning",
"error",
"tool",
"failures",
"result",
"stays",
"small",
"because",
"substantive",
"behavior",
"lives",
"shared",
"package",
"embeddable",
"command",
"group",
"list",
"call",
"iserror",
"true",
"handles",
"plus",
"return"
]
},
{
"id": "api/mcp#tools",
"kind": "section",
"title": "MCP server",
"heading": "Tools",
"group": "API",
"url": "/docs/api/mcp#tools",
"summary": "Lists the MCP tools with their arguments and returns, covering glossary list and get, section list and get, overview, keyword search, and a collapsed agentic answer. Tool results include human-readable text plus the original machine shape in structured content so agents can read it or route it into later steps.",
"facts": [
{
"kind": "code",
"literal": "glossary_list",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ terms: GlossaryEntry[] }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "glossary_get",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ term }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "sections_list",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ group? }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ sections: SectionSummary[] }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "section_get",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ id }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ overview, context }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "search",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ query, maxResults? }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "answer",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "{ query }",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "content",
"chunkId": "api/mcp#tools"
},
{
"kind": "code",
"literal": "structuredContent",
"chunkId": "api/mcp#tools"
}
],
"sources": [
{
"chunkId": "api/mcp#tools",
"url": "/docs/api/mcp#tools",
"anchor": "tools"
}
],
"mode": "source-primary",
"terms": [
"tools",
"lists",
"their",
"arguments",
"returns",
"covering",
"glossary",
"list",
"section",
"overview",
"keyword",
"search",
"collapsed",
"agentic",
"answer",
"tool",
"results",
"include",
"human",
"readable",
"text",
"plus",
"original",
"machine",
"shape",
"structured",
"content",
"agents",
"read",
"route",
"later",
"steps",
"terms",
"glossaryentry",
"term",
"sections",
"group",
"sectionsummary",
"context",
"query"
]
},
{
"id": "api/search-overlay",
"kind": "section",
"title": "SearchOverlay component",
"heading": null,
"group": "API",
"url": "/docs/api/search-overlay",
"summary": "The SearchOverlay component renders the Cmd-K command palette and is added once in a global layout. It opens over the page and does not affect layout until opened.",
"facts": [
{
"kind": "code",
"literal": "---\nimport SearchOverlay from \"@hevmind/ask/components/SearchOverlay.astro\";\n---\n<SearchOverlay />",
"chunkId": "api/search-overlay"
},
{
"kind": "code",
"literal": "SearchOverlay.astro",
"chunkId": "api/search-overlay"
},
{
"kind": "code",
"literal": "⌘K",
"chunkId": "api/search-overlay"
},
{
"kind": "code",
"literal": "<dialog>",
"chunkId": "api/search-overlay"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/search-overlay"
}
],
"sources": [
{
"chunkId": "api/search-overlay",
"url": "/docs/api/search-overlay",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"searchoverlay",
"component",
"renders",
"command",
"palette",
"added",
"once",
"global",
"layout",
"opens",
"page",
"does",
"affect",
"until",
"opened",
"import",
"hevmind",
"components",
"astro",
"dialog",
"callout",
"props",
"data",
"open",
"opener",
"attribute",
"keyboard",
"model",
"mode",
"toggle",
"theming",
"through",
"variables",
"doesn"
]
},
{
"id": "api/search-overlay#keyboard-model",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Keyboard model",
"group": "API",
"url": "/docs/api/search-overlay#keyboard-model",
"summary": "The overlay is ask-first and uses the number of typed words to choose the path: suggestions on open, debounced keyless keyword search at one word with the first result auto-active, and a switch to ask mode once a space is typed so Enter sends the question to the agentic loop. Arrow keys move the active keyword result, Esc closes, and if no server key is present asking returns keyword results with a surfaced warning.",
"facts": [
{
"kind": "code",
"literal": "Tab",
"chunkId": "api/search-overlay#keyboard-model"
}
],
"sources": [
{
"chunkId": "api/search-overlay#keyboard-model",
"url": "/docs/api/search-overlay#keyboard-model",
"anchor": "keyboard-model"
}
],
"mode": "source-primary",
"terms": [
"keyboard",
"model",
"overlay",
"first",
"uses",
"number",
"typed",
"words",
"choose",
"path",
"suggestions",
"open",
"debounced",
"keyless",
"keyword",
"search",
"word",
"result",
"auto",
"active",
"switch",
"mode",
"once",
"space",
"enter",
"sends",
"question",
"agentic",
"loop",
"arrow",
"keys",
"move",
"closes",
"server",
"present",
"asking",
"returns",
"results",
"surfaced",
"warning"
]
},
{
"id": "api/search-overlay#keyword-results-and-deep-links",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Keyword results and deep links",
"group": "API",
"url": "/docs/api/search-overlay#keyword-results-and-deep-links",
"summary": "Each keyword result row shows the document title, an optional heading breadcrumb, and a one-line snippet. The row links to the chunk's URL which already carries the section anchor, so clicking lands on the exact heading.",
"facts": [
{
"kind": "code",
"literal": "Concepts › The agentic loop",
"chunkId": "api/search-overlay#keyword-results-and-deep-links"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/search-overlay#keyword-results-and-deep-links"
},
{
"kind": "code",
"literal": "#anchor",
"chunkId": "api/search-overlay#keyword-results-and-deep-links"
}
],
"sources": [
{
"chunkId": "api/search-overlay#keyword-results-and-deep-links",
"url": "/docs/api/search-overlay#keyword-results-and-deep-links",
"anchor": "keyword-results-and-deep-links"
}
],
"mode": "source-primary",
"terms": [
"keyword",
"results",
"deep",
"links",
"result",
"shows",
"document",
"title",
"optional",
"heading",
"breadcrumb",
"line",
"snippet",
"chunk",
"already",
"carries",
"section",
"anchor",
"clicking",
"lands",
"exact",
"concepts",
"agentic",
"loop",
"renders",
"link"
]
},
{
"id": "api/search-overlay#opening-the-overlay",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Opening the overlay",
"group": "API",
"url": "/docs/api/search-overlay#opening-the-overlay",
"summary": "The overlay opens two built-in ways: the Cmd-K or Ctrl-K shortcut bound automatically once the component is on the page, and any element carrying the opener attribute, of which you can wire up as many triggers as you like.",
"facts": [
{
"kind": "code",
"literal": "<button type=\"button\" data-hev-ask-open>\n Search <kbd>⌘K</kbd>\n</button>\n\n<a href=\"#\" data-hev-ask-open>Search the docs</a>",
"chunkId": "api/search-overlay#opening-the-overlay"
},
{
"kind": "code",
"literal": "⌘K",
"chunkId": "api/search-overlay#opening-the-overlay"
},
{
"kind": "code",
"literal": "Ctrl-K",
"chunkId": "api/search-overlay#opening-the-overlay"
},
{
"kind": "code",
"literal": "data-hev-ask-open",
"chunkId": "api/search-overlay#opening-the-overlay"
}
],
"sources": [
{
"chunkId": "api/search-overlay#opening-the-overlay",
"url": "/docs/api/search-overlay#opening-the-overlay",
"anchor": "opening-the-overlay"
}
],
"mode": "source-primary",
"terms": [
"opening",
"overlay",
"opens",
"built",
"ways",
"ctrl",
"shortcut",
"bound",
"automatically",
"once",
"component",
"page",
"element",
"carrying",
"opener",
"attribute",
"wire",
"many",
"triggers",
"like",
"button",
"type",
"data",
"open",
"search",
"href",
"docs",
"both",
"click",
"header",
"sidebar",
"inline",
"links"
]
},
{
"id": "api/search-overlay#props",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Props",
"group": "API",
"url": "/docs/api/search-overlay#props",
"summary": "Documents the overlay's props with defaults: the endpoint it posts to (which must match the integration's endpoint option), the input placeholder text, and the debounce delay before a keyword query is sent.",
"facts": [
{
"kind": "code",
"literal": "<SearchOverlay\n endpoint=\"/api/ask\"\n placeholder=\"Search hev ask…\"\n debounce={400}\n/>",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "endpoint",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "'/api/ask'",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "placeholder",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "'Search the docs…'",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "debounce",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "number",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "500",
"chunkId": "api/search-overlay#props"
}
],
"sources": [
{
"chunkId": "api/search-overlay#props",
"url": "/docs/api/search-overlay#props",
"anchor": "props"
}
],
"mode": "source-primary",
"terms": [
"props",
"documents",
"overlay",
"defaults",
"endpoint",
"posts",
"must",
"match",
"integration",
"option",
"input",
"placeholder",
"text",
"debounce",
"delay",
"before",
"keyword",
"query",
"sent",
"searchoverlay",
"search",
"string",
"docs",
"number",
"prop",
"type",
"default",
"description",
"queries",
"milliseconds",
"after",
"typing",
"stops"
]
},
{
"id": "api/search-overlay#suggested-questions",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Suggested questions",
"group": "API",
"url": "/docs/api/search-overlay#suggested-questions",
"summary": "When AI is on, the overlay fetches a short list of suggested questions from the endpoint the first time it opens and shows them in the empty state. They come from the digest's suggestions baked in at build time so there is no model call to render them, and if the digest has none the overlay shows nothing extra.",
"facts": [
{
"kind": "code",
"literal": "GET /api/ask",
"chunkId": "api/search-overlay#suggested-questions"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/search-overlay#suggested-questions"
}
],
"sources": [
{
"chunkId": "api/search-overlay#suggested-questions",
"url": "/docs/api/search-overlay#suggested-questions",
"anchor": "suggested-questions"
}
],
"mode": "source-primary",
"terms": [
"suggested",
"questions",
"overlay",
"fetches",
"short",
"list",
"endpoint",
"first",
"time",
"opens",
"shows",
"empty",
"state",
"come",
"digest",
"suggestions",
"baked",
"build",
"there",
"model",
"call",
"render",
"none",
"nothing",
"extra",
"simply",
"clicking",
"suggestion",
"fills",
"input",
"asks",
"immediately"
]
},
{
"id": "api/search-overlay#the-mode-toggle",
"kind": "section",
"title": "SearchOverlay component",
"heading": "The mode toggle",
"group": "API",
"url": "/docs/api/search-overlay#the-mode-toggle",
"summary": "The overlay persists an AI-on-Enter preference in localStorage so readers can flip it to keyword-only and never trigger a model call. In that mode a space just searches for a phrase, no suggested questions appear, and the choice survives reloads.",
"facts": [
{
"kind": "code",
"literal": "localStorage",
"chunkId": "api/search-overlay#the-mode-toggle"
},
{
"kind": "code",
"literal": "hev-ask:mode",
"chunkId": "api/search-overlay#the-mode-toggle"
},
{
"kind": "code",
"literal": "agentic",
"chunkId": "api/search-overlay#the-mode-toggle"
},
{
"kind": "code",
"literal": "keyword",
"chunkId": "api/search-overlay#the-mode-toggle"
}
],
"sources": [
{
"chunkId": "api/search-overlay#the-mode-toggle",
"url": "/docs/api/search-overlay#the-mode-toggle",
"anchor": "the-mode-toggle"
}
],
"mode": "source-primary",
"terms": [
"mode",
"toggle",
"overlay",
"persists",
"enter",
"preference",
"localstorage",
"readers",
"flip",
"keyword",
"only",
"never",
"trigger",
"model",
"call",
"space",
"just",
"searches",
"phrase",
"suggested",
"questions",
"appear",
"choice",
"survives",
"reloads",
"agentic",
"under",
"shown"
]
},
{
"id": "api/search-overlay#the-streamed-answer",
"kind": "section",
"title": "SearchOverlay component",
"heading": "The streamed answer",
"group": "API",
"url": "/docs/api/search-overlay#the-streamed-answer",
"summary": "Pressing Enter with a key configured replaces the keyword rows with an answer panel showing the model's live sub-queries, then the grounded answer streaming token-by-token with a blinking caret. Inline deep links point at the exact section anchor and a Sources row lists every section drawn from, with any link outside the streamed source set rendered as plain text so a hallucinated anchor can never become a clickable dead link.",
"facts": [
{
"kind": "code",
"literal": "searched: …",
"chunkId": "api/search-overlay#the-streamed-answer"
},
{
"kind": "code",
"literal": "/docs/page#anchor",
"chunkId": "api/search-overlay#the-streamed-answer"
}
],
"sources": [
{
"chunkId": "api/search-overlay#the-streamed-answer",
"url": "/docs/api/search-overlay#the-streamed-answer",
"anchor": "the-streamed-answer"
}
],
"mode": "source-primary",
"terms": [
"streamed",
"answer",
"pressing",
"enter",
"configured",
"replaces",
"keyword",
"rows",
"panel",
"showing",
"model",
"live",
"queries",
"grounded",
"streaming",
"token",
"blinking",
"caret",
"inline",
"deep",
"links",
"point",
"exact",
"section",
"anchor",
"sources",
"lists",
"every",
"drawn",
"link",
"outside",
"source",
"rendered",
"plain",
"text",
"hallucinated",
"never",
"become",
"clickable",
"dead"
]
},
{
"id": "api/search-overlay#theming",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Theming",
"group": "API",
"url": "/docs/api/search-overlay#theming",
"summary": "The overlay's markup uses a class prefix and reads your page's CSS custom properties, so defining a handful of color tokens on the root makes it inherit your palette. Because its scoped styles are keyed to those variables, matching your site's look usually requires no overlay CSS to override.",
"facts": [
{
"kind": "code",
"literal": ":root {\n --paper: #111111; /* overlay background */\n --ink: #fafaf5; /* primary text */\n --muted: #6b6b66; /* secondary text */\n --signal: #e25822; /* accent / active state */\n}",
"chunkId": "api/search-overlay#theming"
},
{
"kind": "code",
"literal": "as-",
"chunkId": "api/search-overlay#theming"
},
{
"kind": "code",
"literal": ":root",
"chunkId": "api/search-overlay#theming"
}
],
"sources": [
{
"chunkId": "api/search-overlay#theming",
"url": "/docs/api/search-overlay#theming",
"anchor": "theming"
}
],
"mode": "source-primary",
"terms": [
"theming",
"overlay",
"markup",
"uses",
"class",
"prefix",
"reads",
"page",
"custom",
"properties",
"defining",
"handful",
"color",
"tokens",
"root",
"makes",
"inherit",
"palette",
"because",
"scoped",
"styles",
"keyed",
"those",
"variables",
"matching",
"site",
"look",
"usually",
"requires",
"override",
"paper",
"111111",
"background",
"fafaf5",
"primary",
"text",
"muted",
"6b6b66",
"secondary",
"signal"
]
},
{
"id": "concepts",
"kind": "section",
"title": "Concepts",
"heading": null,
"group": "Overview",
"url": "/docs/concepts",
"summary": "hev ask is three parts: a heading-chunk index with real anchors, an offline ask digest that is a distilled source-grounded index of every section, and a bounded agentic loop that reads the digest progressively from primer to summaries to full source. The split that matters is that the digest is built offline with a strong model and committed to git while the index and loop run on demand at the edge, with no durable state in the running site.",
"facts": [
{
"kind": "value",
"literal": "Diagram.astro",
"chunkId": "concepts"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "concepts"
}
],
"sources": [
{
"chunkId": "concepts",
"url": "/docs/concepts",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"three",
"parts",
"heading",
"chunk",
"index",
"real",
"anchors",
"offline",
"digest",
"distilled",
"source",
"grounded",
"every",
"section",
"bounded",
"agentic",
"loop",
"reads",
"progressively",
"primer",
"summaries",
"full",
"split",
"matters",
"built",
"strong",
"model",
"committed",
"while",
"demand",
"edge",
"durable",
"state",
"running",
"site",
"diagram",
"astro",
"callout",
"works",
"indexing"
]
},
{
"id": "concepts#asking-is-the-default",
"kind": "section",
"title": "Concepts",
"heading": "Asking is the default",
"group": "Overview",
"url": "/docs/concepts#asking-is-the-default",
"summary": "The overlay is ask-first: a single word is a keyword lookup answered instantly from the index, and the moment the query grows past one word it switches to ask mode where Enter sends the question to the agentic loop. Suggested questions baked into the digest make asking the obvious move, but a reader can flip to keyword-only so a space just searches and the model is never called.",
"facts": [
{
"kind": "code",
"literal": "localStorage",
"chunkId": "concepts#asking-is-the-default"
}
],
"sources": [
{
"chunkId": "concepts#asking-is-the-default",
"url": "/docs/concepts#asking-is-the-default",
"anchor": "asking-is-the-default"
}
],
"mode": "agent-primary",
"terms": [
"asking",
"default",
"overlay",
"first",
"single",
"word",
"keyword",
"lookup",
"answered",
"instantly",
"index",
"moment",
"query",
"grows",
"past",
"switches",
"mode",
"enter",
"sends",
"question",
"agentic",
"loop",
"suggested",
"questions",
"baked",
"digest",
"make",
"obvious",
"move",
"reader",
"flip",
"only",
"space",
"just",
"searches",
"model",
"never",
"called",
"localstorage",
"treated"
]
},
{
"id": "concepts#chunks-and-anchors",
"kind": "section",
"title": "Concepts",
"heading": "Chunks and anchors",
"group": "Overview",
"url": "/docs/concepts#chunks-and-anchors",
"summary": "hev ask indexes sections rather than pages, splitting each document on its headings up to a configurable depth, with pre-heading content becoming an intro chunk whose URL is the page itself. Each chunk carries its heading, cleaned prose, and a URL whose anchor is generated by the same slugger Astro's renderer uses, and both the runtime index and the offline build chunk through one shared function so the anchors agree.",
"facts": [
{
"kind": "code",
"literal": "##",
"chunkId": "concepts#chunks-and-anchors"
},
{
"kind": "code",
"literal": "###",
"chunkId": "concepts#chunks-and-anchors"
},
{
"kind": "code",
"literal": "basePath + slug + #anchor",
"chunkId": "concepts#chunks-and-anchors"
},
{
"kind": "code",
"literal": "github-slugger",
"chunkId": "concepts#chunks-and-anchors"
},
{
"kind": "code",
"literal": "getCollection",
"chunkId": "concepts#chunks-and-anchors"
},
{
"kind": "value",
"literal": "github.com",
"chunkId": "concepts#chunks-and-anchors"
}
],
"sources": [
{
"chunkId": "concepts#chunks-and-anchors",
"url": "/docs/concepts#chunks-and-anchors",
"anchor": "chunks-and-anchors"
}
],
"mode": "agent-primary",
"terms": [
"chunks",
"anchors",
"indexes",
"sections",
"rather",
"pages",
"splitting",
"document",
"headings",
"configurable",
"depth",
"heading",
"content",
"becoming",
"intro",
"chunk",
"whose",
"page",
"itself",
"carries",
"cleaned",
"prose",
"anchor",
"generated",
"same",
"slugger",
"astro",
"renderer",
"uses",
"both",
"runtime",
"index",
"offline",
"build",
"through",
"shared",
"function",
"agree",
"basepath",
"slug"
]
},
{
"id": "concepts#degradation-by-design",
"kind": "section",
"title": "Concepts",
"heading": "Degradation, by design",
"group": "Overview",
"url": "/docs/concepts#degradation-by-design",
"summary": "hev ask keeps working as pieces drop away: no key at runtime falls back to keyword mode, no key at build keeps the committed digest with only a warning, a missing or node-less digest degrades the loop to keyword-style retrieval and ranking to raw token overlap, and a stale digest logs a warning but still serves. Everything still works.",
"facts": [
{
"kind": "code",
"literal": "digest.json",
"chunkId": "concepts#degradation-by-design"
}
],
"sources": [
{
"chunkId": "concepts#degradation-by-design",
"url": "/docs/concepts#degradation-by-design",
"anchor": "degradation-by-design"
}
],
"mode": "agent-primary",
"terms": [
"degradation",
"design",
"keeps",
"working",
"pieces",
"drop",
"away",
"runtime",
"falls",
"back",
"keyword",
"mode",
"build",
"committed",
"digest",
"only",
"warning",
"missing",
"node",
"less",
"degrades",
"loop",
"style",
"retrieval",
"ranking",
"token",
"overlap",
"stale",
"logs",
"still",
"serves",
"everything",
"works",
"json",
"built",
"keep",
"overlay",
"searches",
"kept",
"warns"
]
},
{
"id": "concepts#keyword-search-and-the-glossary",
"kind": "section",
"title": "Concepts",
"heading": "Keyword search and the glossary",
"group": "Overview",
"url": "/docs/concepts#keyword-search-and-the-glossary",
"summary": "On a single term the server runs a dependency-free prefilter: it expands the query with glossary aliases and matched-term tokens, scores by token overlap widened by the digest so sections it considers central rank above incidental body mentions, caps results per document, and excerpts around the first matched term. This instant path needs no key and no embeddings, and with no digest it degrades to plain token overlap so keyword search always works.",
"facts": [
{
"kind": "code",
"literal": "k8s",
"chunkId": "concepts#keyword-search-and-the-glossary"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "concepts#keyword-search-and-the-glossary"
},
{
"kind": "code",
"literal": "digest.json",
"chunkId": "concepts#keyword-search-and-the-glossary"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "concepts#keyword-search-and-the-glossary"
},
{
"kind": "code",
"literal": "terms",
"chunkId": "concepts#keyword-search-and-the-glossary"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "concepts#keyword-search-and-the-glossary"
}
],
"sources": [
{
"chunkId": "concepts#keyword-search-and-the-glossary",
"url": "/docs/concepts#keyword-search-and-the-glossary",
"anchor": "keyword-search-and-the-glossary"
}
],
"mode": "agent-primary",
"terms": [
"keyword",
"search",
"glossary",
"single",
"term",
"server",
"runs",
"dependency",
"free",
"prefilter",
"expands",
"query",
"aliases",
"matched",
"tokens",
"scores",
"token",
"overlap",
"widened",
"digest",
"sections",
"considers",
"central",
"rank",
"above",
"incidental",
"body",
"mentions",
"caps",
"results",
"document",
"excerpts",
"around",
"first",
"instant",
"path",
"needs",
"embeddings",
"degrades",
"plain"
]
},
{
"id": "concepts#the-agentic-search-loop",
"kind": "section",
"title": "Concepts",
"heading": "The agentic search loop",
"group": "Overview",
"url": "/docs/concepts#the-agentic-search-loop",
"summary": "On a multi-word ask with a key, the query goes to a bounded two-phase tool-use loop that is progressive disclosure over the digest. In the gather phase the model is given a map of every section and one tool to open sections it needs, citing only what it opened and stopping within a capped number of rounds; in the answer phase the accumulated sources are sent to the overlay and the model is called once more with no tools so it can only write a grounded, inline-linked answer constrained to the surfaced sections.",
"facts": [
{
"kind": "code",
"literal": "open_section({ id })",
"chunkId": "concepts#the-agentic-search-loop"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "concepts#the-agentic-search-loop"
},
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "concepts#the-agentic-search-loop"
},
{
"kind": "code",
"literal": "url",
"chunkId": "concepts#the-agentic-search-loop"
}
],
"sources": [
{
"chunkId": "concepts#the-agentic-search-loop",
"url": "/docs/concepts#the-agentic-search-loop",
"anchor": "the-agentic-search-loop"
}
],
"mode": "agent-primary",
"terms": [
"agentic",
"search",
"loop",
"multi",
"word",
"query",
"goes",
"bounded",
"phase",
"tool",
"progressive",
"disclosure",
"digest",
"gather",
"model",
"given",
"every",
"section",
"open",
"sections",
"needs",
"citing",
"only",
"opened",
"stopping",
"within",
"capped",
"number",
"rounds",
"answer",
"accumulated",
"sources",
"sent",
"overlay",
"called",
"once",
"more",
"tools",
"write",
"grounded"
]
},
{
"id": "concepts#the-ask-digest",
"kind": "section",
"title": "Concepts",
"heading": "The ask digest",
"group": "Overview",
"url": "/docs/concepts#the-ask-digest",
"summary": "The ask digest is built offline and committed as a reviewable artifact holding distilled section nodes with summaries, verbatim facts, and source links (reference sections marked source-primary), a deterministic overview, a compact context and glossary, and suggested questions. Only the summary, glossary, context, and suggestions are model-authored while the node structure, facts, overview, and content hash are derived deterministically, so the model supplies only the distillation.",
"facts": [
{
"kind": "code",
"literal": "digest.json",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "nodes",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "source",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "source-primary",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "context",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "concepts#the-ask-digest"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "concepts#the-ask-digest"
}
],
"sources": [
{
"chunkId": "concepts#the-ask-digest",
"url": "/docs/concepts#the-ask-digest",
"anchor": "the-ask-digest"
}
],
"mode": "agent-primary",
"terms": [
"digest",
"built",
"offline",
"committed",
"reviewable",
"artifact",
"holding",
"distilled",
"section",
"nodes",
"summaries",
"verbatim",
"facts",
"source",
"links",
"reference",
"sections",
"marked",
"primary",
"deterministic",
"overview",
"compact",
"context",
"glossary",
"suggested",
"questions",
"only",
"summary",
"suggestions",
"model",
"authored",
"while",
"node",
"structure",
"content",
"hash",
"derived",
"deterministically",
"supplies",
"distillation"
]
},
{
"id": "concepts#the-system-prompt-is-cached",
"kind": "section",
"title": "Concepts",
"heading": "The system prompt is cached",
"group": "Overview",
"url": "/docs/concepts#the-system-prompt-is-cached",
"summary": "The digest's section map and summaries are injected into the system prompt with a cache marker so across the gather rounds it is a prompt-cache hit rather than re-sent tokens. The answer turn changes the tool set so it cannot reuse that cache, but it is the last call anyway, and the loop model defaults to a Haiku model and is configurable.",
"facts": [
{
"kind": "code",
"literal": "cache_control",
"chunkId": "concepts#the-system-prompt-is-cached"
},
{
"kind": "value",
"literal": "4.5",
"chunkId": "concepts#the-system-prompt-is-cached"
}
],
"sources": [
{
"chunkId": "concepts#the-system-prompt-is-cached",
"url": "/docs/concepts#the-system-prompt-is-cached",
"anchor": "the-system-prompt-is-cached"
}
],
"mode": "agent-primary",
"terms": [
"system",
"prompt",
"cached",
"digest",
"section",
"summaries",
"injected",
"cache",
"marker",
"across",
"gather",
"rounds",
"rather",
"sent",
"tokens",
"answer",
"turn",
"changes",
"tool",
"cannot",
"reuse",
"last",
"call",
"anyway",
"loop",
"model",
"defaults",
"haiku",
"configurable",
"control",
"cachecontrol",
"none",
"search",
"claude"
]
},
{
"id": "concepts#two-ways-to-build-it",
"kind": "section",
"title": "Concepts",
"heading": "Two ways to build it",
"group": "Overview",
"url": "/docs/concepts#two-ways-to-build-it",
"summary": "The model step can run two ways that feed the same deterministic assembler: the recommended Claude Code skill that walks Claude through the corpus inside your subscription with no API key or per-build token spend, or the fallback one-shot CLI call to the default Opus model for CI or non-Claude-Code users. Either way the build is hash-gated so an unchanged committed digest does no model work, and the JSON is reviewed in pull requests.",
"facts": [
{
"kind": "code",
"literal": "digest.json",
"chunkId": "concepts#two-ways-to-build-it"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "concepts#two-ways-to-build-it"
},
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "concepts#two-ways-to-build-it"
},
{
"kind": "value",
"literal": "4.8",
"chunkId": "concepts#two-ways-to-build-it"
}
],
"sources": [
{
"chunkId": "concepts#two-ways-to-build-it",
"url": "/docs/concepts#two-ways-to-build-it",
"anchor": "two-ways-to-build-it"
}
],
"mode": "agent-primary",
"terms": [
"ways",
"build",
"model",
"step",
"feed",
"same",
"deterministic",
"assembler",
"recommended",
"claude",
"code",
"skill",
"walks",
"through",
"corpus",
"inside",
"subscription",
"token",
"spend",
"fallback",
"shot",
"call",
"default",
"opus",
"users",
"either",
"hash",
"gated",
"unchanged",
"committed",
"digest",
"does",
"work",
"json",
"reviewed",
"pull",
"requests",
"anthropic",
"both",
"reading"
]
},
{
"id": "index",
"kind": "section",
"title": "Introduction",
"heading": null,
"group": "Overview",
"url": "/docs",
"summary": "hev ask distills an Astro docs site into an ask digest, a token-efficient form of your docs that agents discover progressively through the ask CLI and readers reach through a Cmd-K overlay. Build the digest offline with the bundled skill and your Claude Code subscription, then serve single-turn Q&A over your docs for a few cents per query, suited to technical docs, internal wikis, and medium-sized corpora.",
"facts": [
{
"kind": "code",
"literal": "ask",
"chunkId": "index"
},
{
"kind": "code",
"literal": "⌘K",
"chunkId": "index"
},
{
"kind": "value",
"literal": "Diagram.astro",
"chunkId": "index"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "index"
},
{
"kind": "value",
"literal": "astro.build",
"chunkId": "index"
}
],
"sources": [
{
"chunkId": "index",
"url": "/docs",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"distills",
"astro",
"docs",
"site",
"digest",
"token",
"efficient",
"form",
"agents",
"discover",
"progressively",
"through",
"readers",
"reach",
"overlay",
"build",
"offline",
"bundled",
"skill",
"claude",
"code",
"subscription",
"serve",
"single",
"turn",
"cents",
"query",
"suited",
"technical",
"internal",
"wikis",
"medium",
"sized",
"corpora",
"diagram",
"callout",
"committed",
"serves",
"ways",
"answer"
]
},
{
"id": "index#build-it-with-your-coding-agent",
"kind": "section",
"title": "Introduction",
"heading": "Build it with your coding agent",
"group": "Overview",
"url": "/docs#build-it-with-your-coding-agent",
"summary": "The digest is built inside your coding agent: the bundled Claude Code skill generates it using your existing subscription, with no API key and no per-build token spend. Commit the JSON and drop the overlay into a layout to get instant keyword results plus a Claude answer loop on Enter, every result deep-linked, with no crawler or external index because the docs you render are the digest and the committed file is reviewable in every PR.",
"facts": [
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "index#build-it-with-your-coding-agent"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "index#build-it-with-your-coding-agent"
},
{
"kind": "code",
"literal": "SearchOverlay.astro",
"chunkId": "index#build-it-with-your-coding-agent"
},
{
"kind": "code",
"literal": "digest.json",
"chunkId": "index#build-it-with-your-coding-agent"
}
],
"sources": [
{
"chunkId": "index#build-it-with-your-coding-agent",
"url": "/docs#build-it-with-your-coding-agent",
"anchor": "build-it-with-your-coding-agent"
}
],
"mode": "agent-primary",
"terms": [
"build",
"coding",
"agent",
"digest",
"built",
"inside",
"bundled",
"claude",
"code",
"skill",
"generates",
"existing",
"subscription",
"token",
"spend",
"commit",
"json",
"drop",
"overlay",
"layout",
"instant",
"keyword",
"results",
"plus",
"answer",
"loop",
"enter",
"every",
"result",
"deep",
"linked",
"crawler",
"external",
"index",
"because",
"docs",
"render",
"committed",
"file",
"reviewable"
]
},
{
"id": "index#next-steps",
"kind": "section",
"title": "Introduction",
"heading": "Next steps",
"group": "Overview",
"url": "/docs#next-steps",
"summary": "Points to the next pages: Quick start to add search in five minutes, Concepts for chunks and the loop and digest, Tradeoffs and Limits for what you are choosing and what it does not do, and the CLI and API references.",
"facts": [
{
"kind": "code",
"literal": "ask",
"chunkId": "index#next-steps"
}
],
"sources": [
{
"chunkId": "index#next-steps",
"url": "/docs#next-steps",
"anchor": "next-steps"
}
],
"mode": "agent-primary",
"terms": [
"next",
"steps",
"points",
"pages",
"quick",
"start",
"search",
"five",
"minutes",
"concepts",
"chunks",
"loop",
"digest",
"tradeoffs",
"limits",
"choosing",
"does",
"references",
"site",
"anchors",
"agentic",
"deliberately",
"doesn",
"build",
"verify",
"query",
"reference",
"every",
"option",
"component",
"props",
"endpoint",
"contract"
]
},
{
"id": "index#who-this-is-for",
"kind": "section",
"title": "Introduction",
"heading": "Who this is for",
"group": "Overview",
"url": "/docs#who-this-is-for",
"summary": "The audience is anyone building or maintaining an Astro 5 docs site whose content lives in a Markdown or MDX content collection and who wants search that works without a service or crawler, deep-links to the right section, answers questions in the reader's own words, and is queryable by a coding agent. If you only need keyword search over a static site with no API key, Pagefind is a simpler and great fit.",
"facts": [
{
"kind": "value",
"literal": "docs.astro.build",
"chunkId": "index#who-this-is-for"
},
{
"kind": "value",
"literal": "pagefind.app",
"chunkId": "index#who-this-is-for"
}
],
"sources": [
{
"chunkId": "index#who-this-is-for",
"url": "/docs#who-this-is-for",
"anchor": "who-this-is-for"
}
],
"mode": "agent-primary",
"terms": [
"audience",
"anyone",
"building",
"maintaining",
"astro",
"docs",
"site",
"whose",
"content",
"lives",
"markdown",
"collection",
"wants",
"search",
"works",
"without",
"service",
"crawler",
"deep",
"links",
"right",
"section",
"answers",
"questions",
"reader",
"words",
"queryable",
"coding",
"agent",
"only",
"need",
"keyword",
"static",
"pagefind",
"simpler",
"great",
"build",
"want",
"work",
"standing"
]
},
{
"id": "limits",
"kind": "section",
"title": "Limits",
"heading": null,
"group": "Overview",
"url": "/docs/limits",
"summary": "These are the boundaries to know before adopting hev ask. None are bugs; they are the edges of what the current design covers.",
"facts": [
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "limits"
}
],
"sources": [
{
"chunkId": "limits",
"url": "/docs/limits",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"these",
"boundaries",
"know",
"before",
"adopting",
"none",
"bugs",
"edges",
"current",
"design",
"covers",
"callout",
"astro",
"hard",
"corpus",
"scope",
"recall",
"ceiling",
"digest",
"build",
"limits",
"frontmatter",
"parsing",
"latency",
"adapter",
"requirements",
"deliberately",
"does",
"should"
]
},
{
"id": "limits#a-server-route-is-required",
"kind": "section",
"title": "Limits",
"heading": "A server route is required",
"group": "Overview",
"url": "/docs/limits#a-server-route-is-required",
"summary": "The search endpoint renders on demand, so a fully static build cannot serve search and you need a server or hybrid adapter such as Node, Cloudflare, or Vercel. Static-only sites should use a static search tool instead.",
"facts": [
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "limits#a-server-route-is-required"
}
],
"sources": [
{
"chunkId": "limits#a-server-route-is-required",
"url": "/docs/limits#a-server-route-is-required",
"anchor": "a-server-route-is-required"
}
],
"mode": "agent-primary",
"terms": [
"server",
"route",
"required",
"search",
"endpoint",
"renders",
"demand",
"fully",
"static",
"build",
"cannot",
"serve",
"need",
"hybrid",
"adapter",
"such",
"node",
"cloudflare",
"vercel",
"only",
"sites",
"should",
"tool",
"instead",
"tradeoffs"
]
},
{
"id": "limits#agentic-search-adds-latency",
"kind": "section",
"title": "Limits",
"heading": "Agentic search adds latency",
"group": "Overview",
"url": "/docs/limits#agentic-search-adds-latency",
"summary": "The agentic path is bounded by a capped number of Claude round-trips, worst case a few seconds, so it is not instant by nature. The keyword path is the always-available instant lane, and lowering the iteration cap tightens the agentic ceiling.",
"facts": [
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "limits#agentic-search-adds-latency"
}
],
"sources": [
{
"chunkId": "limits#agentic-search-adds-latency",
"url": "/docs/limits#agentic-search-adds-latency",
"anchor": "agentic-search-adds-latency"
}
],
"mode": "agent-primary",
"terms": [
"agentic",
"search",
"adds",
"latency",
"path",
"bounded",
"capped",
"number",
"claude",
"round",
"trips",
"worst",
"case",
"seconds",
"instant",
"nature",
"keyword",
"always",
"available",
"lane",
"lowering",
"iteration",
"tightens",
"ceiling",
"maxiterations",
"default",
"considered",
"tune",
"down",
"need",
"tighter"
]
},
{
"id": "limits#anchors-depend-on-astros-slugger",
"kind": "section",
"title": "Limits",
"heading": "Anchors depend on Astro's slugger",
"group": "Overview",
"url": "/docs/limits#anchors-depend-on-astros-slugger",
"summary": "Deep links stay correct only while the heading slugs hev ask generates match Astro's rendered id attributes, which it ensures by using the same github-slugger. It ships a verify command that fails if any chunk anchor is missing from the built HTML, and wiring that into CI is what catches any future slugging change before a broken link ships.",
"facts": [
{
"kind": "code",
"literal": "id",
"chunkId": "limits#anchors-depend-on-astros-slugger"
},
{
"kind": "code",
"literal": "github-slugger",
"chunkId": "limits#anchors-depend-on-astros-slugger"
},
{
"kind": "code",
"literal": "ask digest verify",
"chunkId": "limits#anchors-depend-on-astros-slugger"
},
{
"kind": "code",
"literal": "verify",
"chunkId": "limits#anchors-depend-on-astros-slugger"
}
],
"sources": [
{
"chunkId": "limits#anchors-depend-on-astros-slugger",
"url": "/docs/limits#anchors-depend-on-astros-slugger",
"anchor": "anchors-depend-on-astros-slugger"
}
],
"mode": "agent-primary",
"terms": [
"anchors",
"depend",
"astro",
"slugger",
"deep",
"links",
"stay",
"correct",
"only",
"while",
"heading",
"slugs",
"generates",
"match",
"rendered",
"attributes",
"ensures",
"same",
"github",
"ships",
"verify",
"command",
"fails",
"chunk",
"anchor",
"missing",
"built",
"html",
"wiring",
"catches",
"future",
"slugging",
"change",
"before",
"broken",
"link",
"digest",
"long",
"uses",
"aligned"
]
},
{
"id": "limits#frontmatter-parsing-is-a-flat-yaml-subset",
"kind": "section",
"title": "Limits",
"heading": "Frontmatter parsing is a flat-YAML subset",
"group": "Overview",
"url": "/docs/limits#frontmatter-parsing-is-a-flat-yaml-subset",
"summary": "The offline build parses frontmatter with a small flat-YAML splitter rather than a full YAML parser, handling the common string and number docs schema but not nested structures. This affects only the offline build reading files from disk, since the runtime index uses Astro's own collection loader which honors your real schema.",
"facts": [
{
"kind": "code",
"literal": "getCollection",
"chunkId": "limits#frontmatter-parsing-is-a-flat-yaml-subset"
}
],
"sources": [
{
"chunkId": "limits#frontmatter-parsing-is-a-flat-yaml-subset",
"url": "/docs/limits#frontmatter-parsing-is-a-flat-yaml-subset",
"anchor": "frontmatter-parsing-is-a-flat-yaml-subset"
}
],
"mode": "agent-primary",
"terms": [
"frontmatter",
"parsing",
"flat",
"yaml",
"subset",
"offline",
"build",
"parses",
"small",
"splitter",
"rather",
"full",
"parser",
"handling",
"common",
"string",
"number",
"docs",
"schema",
"nested",
"structures",
"affects",
"only",
"reading",
"files",
"disk",
"since",
"runtime",
"index",
"uses",
"astro",
"collection",
"loader",
"honors",
"real",
"getcollection",
"handles",
"fields",
"aren",
"supported"
]
},
{
"id": "limits#recall-has-a-keyword-ceiling",
"kind": "section",
"title": "Limits",
"heading": "Recall has a keyword ceiling",
"group": "Overview",
"url": "/docs/limits#recall-has-a-keyword-ceiling",
"summary": "Retrieval is glossary-widened keyword token overlap, not embeddings, and the agentic loop can only ground in and link to what retrieval surfaces. The glossary recovers most synonym cases, but a query that shares no tokens with your docs and is not in the glossary may never enter the candidate pool; embeddings are the deferred known fix, with a richer glossary the cheaper lever until analytics show consistent misses.",
"facts": [
{
"kind": "code",
"literal": "k8s",
"chunkId": "limits#recall-has-a-keyword-ceiling"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "limits#recall-has-a-keyword-ceiling"
}
],
"sources": [
{
"chunkId": "limits#recall-has-a-keyword-ceiling",
"url": "/docs/limits#recall-has-a-keyword-ceiling",
"anchor": "recall-has-a-keyword-ceiling"
}
],
"mode": "agent-primary",
"terms": [
"recall",
"keyword",
"ceiling",
"retrieval",
"glossary",
"widened",
"token",
"overlap",
"embeddings",
"agentic",
"loop",
"only",
"ground",
"link",
"surfaces",
"recovers",
"most",
"synonym",
"cases",
"query",
"shares",
"tokens",
"docs",
"never",
"enter",
"candidate",
"pool",
"deferred",
"known",
"richer",
"cheaper",
"lever",
"until",
"analytics",
"show",
"consistent",
"misses",
"kubernetes",
"grounds",
"answer"
]
},
{
"id": "limits#secrets-live-server-side",
"kind": "section",
"title": "Limits",
"heading": "Secrets live server-side",
"group": "Overview",
"url": "/docs/limits#secrets-live-server-side",
"summary": "The agentic path needs the Anthropic API key in the server environment that runs the endpoint, and the key is never exposed to the browser. Without it at runtime the endpoint serves keyword results, so search degrades rather than breaks.",
"facts": [
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "limits#secrets-live-server-side"
},
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "limits#secrets-live-server-side"
}
],
"sources": [
{
"chunkId": "limits#secrets-live-server-side",
"url": "/docs/limits#secrets-live-server-side",
"anchor": "secrets-live-server-side"
}
],
"mode": "agent-primary",
"terms": [
"secrets",
"live",
"server",
"side",
"agentic",
"path",
"needs",
"anthropic",
"environment",
"runs",
"endpoint",
"never",
"exposed",
"browser",
"without",
"runtime",
"serves",
"keyword",
"results",
"search",
"degrades",
"rather",
"breaks",
"anthropicapikey",
"present",
"doesn",
"break"
]
},
{
"id": "limits#the-corpus-is-your-content-collection",
"kind": "section",
"title": "Limits",
"heading": "The corpus is your content collection",
"group": "Overview",
"url": "/docs/limits#the-corpus-is-your-content-collection",
"summary": "hev ask searches only the Astro content collections you configure and nothing else: there is no crawler, no sitemap ingestion, and no way to index non-collection pages such as hand-written Astro pages. Anything you want searchable must live in a configured collection.",
"facts": [
{
"kind": "code",
"literal": ".astro",
"chunkId": "limits#the-corpus-is-your-content-collection"
}
],
"sources": [
{
"chunkId": "limits#the-corpus-is-your-content-collection",
"url": "/docs/limits#the-corpus-is-your-content-collection",
"anchor": "the-corpus-is-your-content-collection"
}
],
"mode": "agent-primary",
"terms": [
"corpus",
"content",
"collection",
"searches",
"only",
"astro",
"collections",
"configure",
"nothing",
"else",
"there",
"crawler",
"sitemap",
"ingestion",
"index",
"pages",
"such",
"hand",
"written",
"anything",
"want",
"searchable",
"must",
"live",
"configured",
"external",
"aren",
"entries",
"example",
"appear",
"search"
]
},
{
"id": "limits#the-one-shot-digest-build-is-bounded-sharded-builds-are-not",
"kind": "section",
"title": "Limits",
"heading": "The one-shot digest build is bounded; sharded builds are not",
"group": "Overview",
"url": "/docs/limits#the-one-shot-digest-build-is-bounded-sharded-builds-are-not",
"summary": "The one-shot build sends the full cleaned corpus to the model in one call, which fits typical docs sites but fails loudly past a section-text size limit, whereas the sharded build splits the corpus into prefix-stable shards each distilled in its own context and merged deterministically, scaling to very large corpora and re-distilling only touched shards. The remaining scale consideration is the runtime prompt, since the agentic path inlines node summaries, so digests with tens of thousands of nodes are not yet a fit for the answer loop.",
"facts": [
{
"kind": "code",
"literal": "ask digest build",
"chunkId": "limits#the-one-shot-digest-build-is-bounded-sharded-builds-are-not"
}
],
"sources": [
{
"chunkId": "limits#the-one-shot-digest-build-is-bounded-sharded-builds-are-not",
"url": "/docs/limits#the-one-shot-digest-build-is-bounded-sharded-builds-are-not",
"anchor": "the-one-shot-digest-build-is-bounded-sharded-builds-are-not"
}
],
"mode": "agent-primary",
"terms": [
"shot",
"digest",
"build",
"bounded",
"sharded",
"builds",
"sends",
"full",
"cleaned",
"corpus",
"model",
"call",
"fits",
"typical",
"docs",
"sites",
"fails",
"loudly",
"past",
"section",
"text",
"size",
"limit",
"whereas",
"splits",
"prefix",
"stable",
"shards",
"distilled",
"context",
"merged",
"deterministically",
"scaling",
"very",
"large",
"corpora",
"distilling",
"only",
"touched",
"remaining"
]
},
{
"id": "quickstart",
"kind": "section",
"title": "Quick start",
"heading": null,
"group": "Overview",
"url": "/docs/quickstart",
"summary": "You can add search to an existing Astro 5 docs site whose content lives in a collection in about five minutes, getting keyword search working first and then adding an Anthropic API key to enable Claude-powered agentic answers. The overlay gives keyless instant keyword search that runs anywhere, and the same overlay runs the agentic loop on Enter once a server key is present.",
"facts": [
{
"kind": "code",
"literal": "src/content/docs",
"chunkId": "quickstart"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "quickstart"
},
{
"kind": "code",
"literal": "SearchOverlay.astro",
"chunkId": "quickstart"
},
{
"kind": "value",
"literal": "Steps.astro",
"chunkId": "quickstart"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "quickstart"
}
],
"sources": [
{
"chunkId": "quickstart",
"url": "/docs/quickstart",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"search",
"existing",
"astro",
"docs",
"site",
"whose",
"content",
"lives",
"collection",
"about",
"five",
"minutes",
"getting",
"keyword",
"working",
"first",
"adding",
"anthropic",
"enable",
"claude",
"powered",
"agentic",
"answers",
"overlay",
"gives",
"keyless",
"instant",
"runs",
"anywhere",
"same",
"loop",
"enter",
"once",
"server",
"present",
"searchoverlay",
"steps",
"callout",
"install",
"integration"
]
},
{
"id": "quickstart#1-install",
"kind": "section",
"title": "Quick start",
"heading": "1. Install",
"group": "Overview",
"url": "/docs/quickstart#1-install",
"summary": "Install the package from npm once published, or until then consume it straight from the package subdirectory on GitHub.",
"facts": [
{
"kind": "code",
"literal": "pnpm add @hevmind/ask",
"chunkId": "quickstart#1-install"
},
{
"kind": "code",
"literal": "pnpm add \"git+ssh://[email protected]/hev/ask.git#main&path:/packages/ui\"",
"chunkId": "quickstart#1-install"
}
],
"sources": [
{
"chunkId": "quickstart#1-install",
"url": "/docs/quickstart#1-install",
"anchor": "1-install"
}
],
"mode": "agent-primary",
"terms": [
"install",
"package",
"once",
"published",
"until",
"consume",
"straight",
"subdirectory",
"github",
"pnpm",
"hevmind",
"main",
"path",
"packages"
]
},
{
"id": "quickstart#2-register-the-integration",
"kind": "section",
"title": "Quick start",
"heading": "2. Register the integration",
"group": "Overview",
"url": "/docs/quickstart#2-register-the-integration",
"summary": "Register the integration in your Astro config, passing your content collection name(s) and a base path. Collections is the one option you must set; everything else has a default.",
"facts": [
{
"kind": "code",
"literal": "// astro.config.mjs\nimport { defineConfig } from \"astro/config\";\nimport hevAsk from \"@hevmind/ask\";\n\nexport default defineConfig({\n integrations: [\n hevAsk({\n collections: [\"docs\"], // your content collection name(s)\n basePath: \"/docs/\", // slug → URL prefix: basePath + slug\n }),\n ],\n});",
"chunkId": "quickstart#2-register-the-integration"
},
{
"kind": "code",
"literal": "collections",
"chunkId": "quickstart#2-register-the-integration"
}
],
"sources": [
{
"chunkId": "quickstart#2-register-the-integration",
"url": "/docs/quickstart#2-register-the-integration",
"anchor": "2-register-the-integration"
}
],
"mode": "agent-primary",
"terms": [
"register",
"integration",
"astro",
"config",
"passing",
"content",
"collection",
"name",
"base",
"path",
"collections",
"option",
"must",
"everything",
"else",
"default",
"import",
"defineconfig",
"hevask",
"hevmind",
"export",
"integrations",
"docs",
"basepath",
"slug",
"prefix",
"configuration",
"reference"
]
},
{
"id": "quickstart#3-add-a-server-adapter",
"kind": "section",
"title": "Quick start",
"heading": "3. Add a server adapter",
"group": "Overview",
"url": "/docs/quickstart#3-add-a-server-adapter",
"summary": "Because the search route renders on demand, add whichever server or hybrid adapter matches your host while existing pages stay prerendered and only the endpoint runs as a function.",
"facts": [
{
"kind": "code",
"literal": "// astro.config.mjs\nimport cloudflare from \"@astrojs/cloudflare\";\n\nexport default defineConfig({\n adapter: cloudflare({ platformProxy: { enabled: true } }),\n // ...integrations as above\n});",
"chunkId": "quickstart#3-add-a-server-adapter"
},
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "quickstart#3-add-a-server-adapter"
}
],
"sources": [
{
"chunkId": "quickstart#3-add-a-server-adapter",
"url": "/docs/quickstart#3-add-a-server-adapter",
"anchor": "3-add-a-server-adapter"
}
],
"mode": "agent-primary",
"terms": [
"server",
"adapter",
"because",
"search",
"route",
"renders",
"demand",
"whichever",
"hybrid",
"matches",
"host",
"while",
"existing",
"pages",
"stay",
"prerendered",
"only",
"endpoint",
"runs",
"function",
"astro",
"config",
"import",
"cloudflare",
"astrojs",
"export",
"default",
"defineconfig",
"platformproxy",
"enabled",
"true",
"integrations",
"above",
"site",
"uses"
]
},
{
"id": "quickstart#4-render-the-overlay",
"kind": "section",
"title": "Quick start",
"heading": "4. Render the overlay",
"group": "Overview",
"url": "/docs/quickstart#4-render-the-overlay",
"summary": "Add the overlay component once somewhere global like your base layout; any element with the opener attribute opens the palette and the Cmd-K shortcut is bound automatically. Keyword search then works in dev.",
"facts": [
{
"kind": "code",
"literal": "---\n// src/layouts/Base.astro\nimport SearchOverlay from \"@hevmind/ask/components/SearchOverlay.astro\";\n---\n<button type=\"button\" data-hev-ask-open>\n Search <kbd>⌘K</kbd>\n</button>\n\n<slot />\n\n<SearchOverlay />",
"chunkId": "quickstart#4-render-the-overlay"
},
{
"kind": "code",
"literal": "data-hev-ask-open",
"chunkId": "quickstart#4-render-the-overlay"
},
{
"kind": "code",
"literal": "⌘K",
"chunkId": "quickstart#4-render-the-overlay"
},
{
"kind": "code",
"literal": "astro dev",
"chunkId": "quickstart#4-render-the-overlay"
}
],
"sources": [
{
"chunkId": "quickstart#4-render-the-overlay",
"url": "/docs/quickstart#4-render-the-overlay",
"anchor": "4-render-the-overlay"
}
],
"mode": "agent-primary",
"terms": [
"render",
"overlay",
"component",
"once",
"somewhere",
"global",
"like",
"base",
"layout",
"element",
"opener",
"attribute",
"opens",
"palette",
"shortcut",
"bound",
"automatically",
"keyword",
"search",
"works",
"layouts",
"astro",
"import",
"searchoverlay",
"hevmind",
"components",
"button",
"type",
"data",
"open",
"slot",
"press"
]
},
{
"id": "quickstart#5-build-the-digest",
"kind": "section",
"title": "Quick start",
"heading": "5. Build the digest",
"group": "Overview",
"url": "/docs/quickstart#5-build-the-digest",
"summary": "The digest is an offline-built JSON file you commit that gives the agentic loop context, ranks keyword results, supplies the glossary, and holds the overlay's suggested questions. Build it with the recommended keyless Claude Code skill or the one-shot CLI for CI, then verify and commit; both paths are hash-gated and the integration also builds automatically during astro build when a key is present.",
"facts": [
{
"kind": "code",
"literal": "You: build the hev ask digest\n\nClaude runs:\n ask digest corpus # emits the sections to distil\n …writes context/glossary/summaries/suggestions…\n ask digest assemble # writes .hev-ask/digest.json",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "export ANTHROPIC_API_KEY=sk-ant-...\npnpm exec ask digest build # writes .hev-ask/digest.json",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "pnpm exec ask digest verify # builds the site, checks every anchor resolves\ngit add .hev-ask/digest.json",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "k8s",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "astro build",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "value",
"literal": "claude.com",
"chunkId": "quickstart#5-build-the-digest"
}
],
"sources": [
{
"chunkId": "quickstart#5-build-the-digest",
"url": "/docs/quickstart#5-build-the-digest",
"anchor": "5-build-the-digest"
}
],
"mode": "agent-primary",
"terms": [
"build",
"digest",
"offline",
"built",
"json",
"file",
"commit",
"gives",
"agentic",
"loop",
"context",
"ranks",
"keyword",
"results",
"supplies",
"glossary",
"holds",
"overlay",
"suggested",
"questions",
"recommended",
"keyless",
"claude",
"code",
"skill",
"shot",
"verify",
"both",
"paths",
"hash",
"gated",
"integration",
"also",
"builds",
"automatically",
"during",
"astro",
"present",
"runs",
"corpus"
]
},
{
"id": "quickstart#enable-agentic-search",
"kind": "section",
"title": "Quick start",
"heading": "Enable agentic search",
"group": "Overview",
"url": "/docs/quickstart#enable-agentic-search",
"summary": "Set the Anthropic API key in the server environment where the endpoint runs, via your host's secrets or a local env file. With a key present, pressing Enter runs the agentic loop with self-issued sub-queries, a grounded answer, and inline deep links; without one, Enter returns keyword results.",
"facts": [
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "quickstart#enable-agentic-search"
},
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "quickstart#enable-agentic-search"
},
{
"kind": "code",
"literal": ".env",
"chunkId": "quickstart#enable-agentic-search"
}
],
"sources": [
{
"chunkId": "quickstart#enable-agentic-search",
"url": "/docs/quickstart#enable-agentic-search",
"anchor": "enable-agentic-search"
}
],
"mode": "agent-primary",
"terms": [
"enable",
"agentic",
"search",
"anthropic",
"server",
"environment",
"endpoint",
"runs",
"host",
"secrets",
"local",
"file",
"present",
"pressing",
"enter",
"loop",
"self",
"issued",
"queries",
"grounded",
"answer",
"inline",
"deep",
"links",
"without",
"returns",
"keyword",
"results",
"anthropicapikey",
"overlay"
]
},
{
"id": "quickstart#prerequisites",
"kind": "section",
"title": "Quick start",
"heading": "Prerequisites",
"group": "Overview",
"url": "/docs/quickstart#prerequisites",
"summary": "Prerequisites are Astro 5 with at least one content collection, a server or hybrid adapter because the search route renders on demand, and an Anthropic API key to enable agentic search. Keyword search needs no key.",
"facts": [
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "quickstart#prerequisites"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "quickstart#prerequisites"
},
{
"kind": "value",
"literal": "docs.astro.build",
"chunkId": "quickstart#prerequisites"
}
],
"sources": [
{
"chunkId": "quickstart#prerequisites",
"url": "/docs/quickstart#prerequisites",
"anchor": "prerequisites"
}
],
"mode": "agent-primary",
"terms": [
"prerequisites",
"astro",
"least",
"content",
"collection",
"server",
"hybrid",
"adapter",
"because",
"search",
"route",
"renders",
"demand",
"anthropic",
"enable",
"agentic",
"keyword",
"needs",
"docs",
"build",
"node",
"cloudflare",
"vercel",
"fully",
"static",
"serve",
"anthropicapikey"
]
},
{
"id": "quickstart#set-up-keyword-search",
"kind": "section",
"title": "Quick start",
"heading": "Set up keyword search",
"group": "Overview",
"url": "/docs/quickstart#set-up-keyword-search",
"summary": "Section heading introducing the steps to set up keyword search.",
"facts": [
{
"kind": "value",
"literal": "astro.config.mjs",
"chunkId": "quickstart#set-up-keyword-search"
},
{
"kind": "value",
"literal": "SearchOverlay.astro",
"chunkId": "quickstart#set-up-keyword-search"
}
],
"sources": [
{
"chunkId": "quickstart#set-up-keyword-search",
"url": "/docs/quickstart#set-up-keyword-search",
"anchor": "set-up-keyword-search"
}
],
"mode": "agent-primary",
"terms": [
"keyword",
"search",
"section",
"heading",
"introducing",
"steps",
"astro",
"config",
"searchoverlay"
]
},
{
"id": "quickstart#verify-it-works",
"kind": "section",
"title": "Quick start",
"heading": "Verify it works",
"group": "Overview",
"url": "/docs/quickstart#verify-it-works",
"summary": "Verify keyword search by typing a single word from a heading and confirming the top result deep-links to that section, and verify agentic search by asking a multi-word question and confirming the sub-queries and a streamed, deep-linked answer appear. Also confirm the verify command exits non-zero if any chunk anchor is missing from the built HTML, and wire it into CI.",
"facts": [
{
"kind": "code",
"literal": "/docs/page#heading",
"chunkId": "quickstart#verify-it-works"
},
{
"kind": "code",
"literal": "ask digest verify",
"chunkId": "quickstart#verify-it-works"
}
],
"sources": [
{
"chunkId": "quickstart#verify-it-works",
"url": "/docs/quickstart#verify-it-works",
"anchor": "verify-it-works"
}
],
"mode": "agent-primary",
"terms": [
"verify",
"works",
"keyword",
"search",
"typing",
"single",
"word",
"heading",
"confirming",
"result",
"deep",
"links",
"section",
"agentic",
"asking",
"multi",
"question",
"queries",
"streamed",
"linked",
"answer",
"appear",
"also",
"confirm",
"command",
"exits",
"zero",
"chunk",
"anchor",
"missing",
"built",
"html",
"wire",
"docs",
"page",
"digest",
"type",
"should",
"link",
"click"
]
},
{
"id": "tradeoffs",
"kind": "section",
"title": "Tradeoffs",
"heading": null,
"group": "Overview",
"url": "/docs/tradeoffs",
"summary": "Every search tool makes choices, and this page is the honest account of what hev ask trades away to get what it gives so you can decide whether the trade fits your docs.",
"facts": [
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "tradeoffs"
}
],
"sources": [
{
"chunkId": "tradeoffs",
"url": "/docs/tradeoffs",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"every",
"search",
"tool",
"makes",
"choices",
"page",
"honest",
"account",
"trades",
"away",
"gives",
"decide",
"whether",
"trade",
"fits",
"docs",
"callout",
"astro",
"choosing",
"adopting",
"dependency",
"posture",
"committed",
"digest",
"cost",
"latency",
"agentic",
"compares",
"pagefind",
"algolia",
"orama",
"version"
]
},
{
"id": "tradeoffs#a-committed-digest",
"kind": "section",
"title": "Tradeoffs",
"heading": "A committed digest",
"group": "Overview",
"url": "/docs/tradeoffs#a-committed-digest",
"summary": "The digest is generated offline and committed to git as JSON rather than computed at runtime or hidden in a service, making it reviewable in pull requests, deterministic, free to read on the request path, and bundled into the edge worker with no runtime filesystem access. The cost is that it can go stale, since it only regenerates on content change plus a build; a warning fires when the live hash differs, and the cheap idempotent hash gate makes rebuild-on-every-content-change in CI the intended workflow.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#a-committed-digest",
"url": "/docs/tradeoffs#a-committed-digest",
"anchor": "a-committed-digest"
}
],
"mode": "agent-primary",
"terms": [
"committed",
"digest",
"generated",
"offline",
"json",
"rather",
"computed",
"runtime",
"hidden",
"service",
"making",
"reviewable",
"pull",
"requests",
"deterministic",
"free",
"read",
"request",
"path",
"bundled",
"edge",
"worker",
"filesystem",
"access",
"cost",
"stale",
"since",
"only",
"regenerates",
"content",
"change",
"plus",
"build",
"warning",
"fires",
"live",
"hash",
"differs",
"cheap",
"idempotent"
]
},
{
"id": "tradeoffs#cost-and-latency-of-agentic-search",
"kind": "section",
"title": "Tradeoffs",
"heading": "Cost and latency of agentic search",
"group": "Overview",
"url": "/docs/tradeoffs#cost-and-latency-of-agentic-search",
"summary": "The agentic path calls Claude, so it costs small real money and latency: worst-case latency is roughly the iteration cap of Haiku round-trips, with the keyword path staying instant and the iteration cap as the tightening knob. Cost is one bounded loop per submitted query on the default Haiku model with domain context prompt-cached, the Opus offline build is paid only when content changes thanks to the hash gate, and keyword-only is a first-class mode if you want no key in the loop.",
"facts": [
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "tradeoffs#cost-and-latency-of-agentic-search"
}
],
"sources": [
{
"chunkId": "tradeoffs#cost-and-latency-of-agentic-search",
"url": "/docs/tradeoffs#cost-and-latency-of-agentic-search",
"anchor": "cost-and-latency-of-agentic-search"
}
],
"mode": "agent-primary",
"terms": [
"cost",
"latency",
"agentic",
"search",
"path",
"calls",
"claude",
"costs",
"small",
"real",
"money",
"worst",
"case",
"roughly",
"iteration",
"haiku",
"round",
"trips",
"keyword",
"staying",
"instant",
"tightening",
"knob",
"bounded",
"loop",
"submitted",
"query",
"default",
"model",
"domain",
"context",
"prompt",
"cached",
"opus",
"offline",
"build",
"paid",
"only",
"content",
"changes"
]
},
{
"id": "tradeoffs#how-it-compares",
"kind": "section",
"title": "Tradeoffs",
"heading": "How it compares",
"group": "Overview",
"url": "/docs/tradeoffs#how-it-compares",
"summary": "A comparison table and guidance versus Pagefind, Algolia DocSearch, and Orama across retrieval, AI ranking, deep links, and hosting. Choose Pagefind for simple keyless static keyword search, Algolia for a managed crawler-based service, Orama for client-side vector search, and hev ask when your docs are Astro content collections and you want section-level deep links and a reader's question, not just keywords, to find the right section.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#how-it-compares",
"url": "/docs/tradeoffs#how-it-compares",
"anchor": "how-it-compares"
}
],
"mode": "agent-primary",
"terms": [
"compares",
"comparison",
"table",
"guidance",
"versus",
"pagefind",
"algolia",
"docsearch",
"orama",
"across",
"retrieval",
"ranking",
"deep",
"links",
"hosting",
"choose",
"simple",
"keyless",
"static",
"keyword",
"search",
"managed",
"crawler",
"based",
"service",
"client",
"side",
"vector",
"docs",
"astro",
"content",
"collections",
"want",
"section",
"level",
"reader",
"question",
"just",
"keywords",
"find"
]
},
{
"id": "tradeoffs#keyword-retrieval-not-embeddings",
"kind": "section",
"title": "Tradeoffs",
"heading": "Keyword retrieval, not embeddings",
"group": "Overview",
"url": "/docs/tradeoffs#keyword-retrieval-not-embeddings",
"summary": "Retrieval is dependency-free token overlap widened by the glossary with no embeddings or vector store, so there is nothing to host or keep in sync, it is edge-safe and instant, and the glossary recovers a lot of synonym recall. The cost is a paraphrase-recall ceiling since the agent can only ground in what keyword retrieval surfaced, and embeddings would do better for readers who search in words that share no tokens with your docs; that upgrade is deferred, not designed out.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#keyword-retrieval-not-embeddings",
"url": "/docs/tradeoffs#keyword-retrieval-not-embeddings",
"anchor": "keyword-retrieval-not-embeddings"
}
],
"mode": "agent-primary",
"terms": [
"keyword",
"retrieval",
"embeddings",
"dependency",
"free",
"token",
"overlap",
"widened",
"glossary",
"vector",
"store",
"there",
"nothing",
"host",
"keep",
"sync",
"edge",
"safe",
"instant",
"recovers",
"synonym",
"recall",
"cost",
"paraphrase",
"ceiling",
"since",
"agent",
"only",
"ground",
"surfaced",
"would",
"better",
"readers",
"search",
"words",
"share",
"tokens",
"docs",
"upgrade",
"deferred"
]
},
{
"id": "tradeoffs#one-dependency-deliberately",
"kind": "section",
"title": "Tradeoffs",
"heading": "One dependency, deliberately",
"group": "Overview",
"url": "/docs/tradeoffs#one-dependency-deliberately",
"summary": "hev ask aims to be near zero-dependency with one deliberate exception: github-slugger, a tiny pure-JS edge-safe library. Generating heading anchors by hand risks drifting from Astro's renderer and shipping links that 404, so using the same slugger guarantees byte-identical anchors.",
"facts": [
{
"kind": "code",
"literal": "github-slugger",
"chunkId": "tradeoffs#one-dependency-deliberately"
},
{
"kind": "value",
"literal": "github.com",
"chunkId": "tradeoffs#one-dependency-deliberately"
}
],
"sources": [
{
"chunkId": "tradeoffs#one-dependency-deliberately",
"url": "/docs/tradeoffs#one-dependency-deliberately",
"anchor": "one-dependency-deliberately"
}
],
"mode": "agent-primary",
"terms": [
"dependency",
"deliberately",
"aims",
"near",
"zero",
"deliberate",
"exception",
"github",
"slugger",
"tiny",
"pure",
"edge",
"safe",
"library",
"generating",
"heading",
"anchors",
"hand",
"risks",
"drifting",
"astro",
"renderer",
"shipping",
"links",
"same",
"guarantees",
"byte",
"identical",
"close",
"link",
"404s",
"page",
"uses",
"took",
"purpose"
]
},
{
"id": "tradeoffs#two-paths-instead-of-one",
"kind": "section",
"title": "Tradeoffs",
"heading": "Two paths instead of one",
"group": "Overview",
"url": "/docs/tradeoffs#two-paths-instead-of-one",
"summary": "hev ask runs an instant keyword path and an agentic path and asks the reader to choose by pressing Enter, keeping the common one-or-two-word case instant and keyless while hard questions get a smarter ranker. The cost is a slightly more complex interaction model where readers must learn that Enter means ask AI, judged the right trade for docs where queries split into jumping to a known thing versus finding a thing you cannot name.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#two-paths-instead-of-one",
"url": "/docs/tradeoffs#two-paths-instead-of-one",
"anchor": "two-paths-instead-of-one"
}
],
"mode": "agent-primary",
"terms": [
"paths",
"instead",
"runs",
"instant",
"keyword",
"path",
"agentic",
"asks",
"reader",
"choose",
"pressing",
"enter",
"keeping",
"common",
"word",
"case",
"keyless",
"while",
"hard",
"questions",
"smarter",
"ranker",
"cost",
"slightly",
"more",
"complex",
"interaction",
"model",
"readers",
"must",
"learn",
"means",
"judged",
"right",
"trade",
"docs",
"queries",
"split",
"jumping",
"known"
]
}
],
"edges": []
}