// 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
hev ask (@hev/ask) is a ⌘K search overlay for Astro docs sites. It distills the site's content collection into an ask digest — a token-efficient, committed JSON form of the docs — and serves it to readers (an answer overlay) and coding agents (the ask CLI and an MCP server).
Core ideas users ask about:
- Ask digest (
.hev-ask/digest.json): offline-built, committed, reviewable. Nodes hold model-authored summaries plus deterministically extracted verbatim facts; only the distillation is model work, and a content-hash gate skips rebuilds when docs are unchanged. (kgis the digest's historical name, kept in the CLI command group, the path flag, and the virtual module id.) - Progressive disclosure: the agentic loop holds a primer and section map in its prompt, opens only the sections it needs, and reads full source text only for reference sections.
- Two search paths: instant keyless keyword search (token overlap widened by the glossary), and on Enter a bounded Claude loop that streams a grounded answer over SSE with inline deep links.
- Deep links: every result and citation lands on an exact heading anchor generated with the same slugger Astro uses; a verify command gates drift in CI.
- Degradation: no key → keyword mode; no digest → plain token overlap; nothing hard-fails.
- Building: the bundled build-digest skill runs inside a Claude Code subscription (no API key, no token spend on your own key);
ask kg buildis the one-call fallback for CI.
Users phrase questions as: how do I add search to my Astro site, how does the AI answer work, what happens without an API key, how do I rebuild or verify the digest, how does it compare to Pagefind/Algolia/Orama, what are the limits.
Glossary 15 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 graphdigest.jsonThe committed JSON artifact distilling every doc section — summaries, verbatim facts, glossary, overview, and suggested questions — that the agentic loop reads progressively.
-
agentic search
agentic loopask modeAI searchanswer loopsearch loopThe bounded Claude tool-use loop that opens digest sections and streams a grounded, deep-linked answer over SSE.
-
keyword search
keyword modeinstant searchprefilterThe keyless instant path: token-overlap scoring over heading chunks, widened by the glossary and the digest's per-section signal.
-
progressive disclosure
progressiveThe loop's reading pattern — primer and section map up front, distilled summaries on open, full source text only for reference sections.
-
chunk
heading chunksectionA heading-bounded slice of a document; the unit of indexing, retrieval, and deep linking.
-
anchor
deep linkheading anchorThe URL fragment generated with the same slugger Astro uses, so results land on the exact rendered heading.
-
glossary
aliasesquery expansionDigest terms with aliases that widen keyword queries (k8s finds kubernetes) and one-line definitions agents can read.
-
SearchOverlay
overlaycommand palettecmd-kctrl-kThe Astro component rendering the ask-first ⌘K search palette; add it once in a global layout.
-
ask CLI
askCLIask binaryThe binary with consumer verbs for reading the digest progressively and producer verbs under the kg group for building and verifying it.
-
MCP server
ask mcpMCPModel Context ProtocolThe stdio MCP server exposing digest reads, search, and answers as structured tools for coding agents.
-
endpoint
/api/asksearch endpointAPI routeThe injected on-demand route serving keyword JSON, agentic SSE, suggested questions, and keyless digest reads.
-
content hash
hash gatefreshnessstaleThe sha256 of chunk text that lets builds skip model work when docs are unchanged and flags staleness at runtime.
-
build-digest skill
build-kgClaude Code skillbundled skillThe bundled skill that distills the digest inside a Claude Code subscription, costing no API tokens on the user's own key.
-
verify
ask kg verifyanchor verificationCI gateThe command that builds the site and fails on anchor drift, warning on digest coverage and literal fidelity.
-
degradation
fallbackno API keykeylessThe design rule that every missing piece downgrades — no key means keyword mode, no digest means plain token overlap — and nothing hard-fails.
Sections 86 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 binary has two command groups: consumer verbs that read the committed digest progressively (skim, find, open, ask, or serve it all to an agent) and producer verbs under the kg group — the digest's historical name — that build and verify it. A deprecated alias binary forwards to the new group with a one-line migration notice.facts · quoted verbatim
@hev/askaskoverviewglossarysearchsectionssection getanswermcpask kgkgbuildcorpusassembleverifyhev-ask-kgask kg ...Callout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Building the digest referenceProducer commands run from the site root: a hash-gated one-shot build, a corpus emitter for keyless distillation, an assembler that turns a distillation into the digest, and a verifier for anchors, coverage, and fidelity. The model authors only context, glossary, summaries, and suggestions; chunking, facts, overview, sources, and the content hash are computed in code.facts · quoted verbatim
ask kg build # one-shot build; needs ANTHROPIC_API_KEY only when stale ask kg corpus # emit sections for a keyless skill/model distillation ask kg assemble # assemble .hev-ask/digest.json from that distillation ask kg verify # build the site and verify anchors, coverage, fidelityask kg build.hev-ask/digest.jsonask kg corpus.hev-ask/kg-input.jsonask kg assemble.hev-ask/kg-distill.jsoncontextglossarysummariessuggestionsask kg verify--skip-build--strictReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Claude Code skill referenceThe bundled skill builds the digest inside a Claude Code subscription, so it costs no API tokens on the user's own key. It runs the same deterministic corpus-distill-assemble seam and produces the same artifact shape under the same hash gate.facts · quoted verbatim
ask kg corpus -> .hev-ask/kg-input.json ...writes .hev-ask/kg-distill.json... ask kg assemble -> .hev-ask/digest.jsonbuild-digestANTHROPIC_API_KEYdigest.jsonask kg buildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Distribution referenceThe npm package ships two bins: the main v3 CLI and a deprecated alias that forwards to the kg command group. The launcher resolves an environment override first, then a platform-specific binary package, then checked-out Go source for development.facts · quoted verbatim
askhev-ask-kgask kg ...HEV_ASK_BINARYReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Flags referenceReference table of global flags covering the digest path, remote endpoint, JSON output, result caps, collection and base-path selection, content globs, chunk heading depth, the build model, producer input and output paths, the verify build command, skip-build, and strict mode. Global flags come before the command.facts · quoted verbatim
ask --kg-path .hev-ask/digest.json --json search "openapi" ask --endpoint https://askhev.com/api/ask mcp ask kg build --collection docs --collection guides --chunk-heading-depth 2 ask kg verify --skip-build--kg-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>--kg-model <model>claude-opus-4-8ask kg build--out <path>.hev-ask/kg-input.jsonask kg corpus--input <path>.hev-ask/kg-distill.jsonask kg assemble--build-command <cmd>Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Go library referenceA reusable Go API offers pure helpers and an embeddable, dependency-free command group for mounting the same verbs in another CLI. Helpers cover loading the digest, glossary and section reads, search, an endpoint client, building, anchor verification, and MCP serving.facts · quoted verbatim
group := ask.NewCommandGroup(ask.CommandOptions{ KGPath: ".hev-ask/digest.json", }) err := group.Run(ctx, []string{"search", "read endpoints"}, os.Stdin, os.Stdout, os.Stderr)pkg/askLoadGraphListGlossaryGetSectionSearchGraphNewEndpointClientBuildKnowledgeGraphVerifyAnchorsServeMCPReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - MCP referenceThe CLI runs a stdio MCP server over the same read and search surface. Point it at a local digest for checked-out repos, or at a deployed endpoint when the agent needs the remote digest or streamed answers.facts · quoted verbatim
{ "mcpServers": { "docs": { "command": "ask", "args": ["--kg-path", ".hev-ask/digest.json", "mcp"] } } }{ "mcpServers": { "askhev": { "command": "ask", "args": ["--endpoint", "https://askhev.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 referenceSites typically wrap the build and verify commands in package scripts. Scripts calling the deprecated alias keep working through the forward, but new scripts should use the kg command group.facts · quoted verbatim
{ "scripts": { "kg:build": "ask kg build", "kg:verify": "ask kg verify" } }ask kghev-ask-kg buildhev-ask-kg verifyReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Reading the digest referenceBy default the CLI reads the committed digest from the current repo; an endpoint flag switches reads to a deployed site's HTTP API. The answer verb requires the endpoint because it uses the deployed agentic SSE path; local search is the keyless alternative.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://askhev.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 ↗ - Where it runs referenceProducer commands need filesystem access and run locally or in CI; the Astro integration also triggers the hash-gated build during the site build when a key is present, falling back to the committed artifact. The deployed site reads the digest through a virtual module, and wiring verify into CI is the mechanical guard for anchor correctness.facts · quoted verbatim
ask kg buildastro buildANTHROPIC_API_KEYvirtual:hev-ask/kgask kg verifyReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Configuration referenceThe integration is the package's default export and takes one options object. Only the collection list is effectively required; everything else has a default.facts · quoted verbatim
// astro.config.mjs import hevAsk from "@hev/ask"; export default defineConfig({ integrations: [ hevAsk({ collections: ["docs"], basePath: "/docs/", model: "claude-haiku-4-5", maxResults: 6, }), ], });hevAsk()@hev/askcollectionsCallout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Options referenceReference table of every option: collections, base path, endpoint route, the loop and digest-build models, result and answer-token caps, iteration and chunk-depth limits, per-search candidates, the per-document cap, the digest path, and content globs. A changed endpoint must match the overlay component's endpoint prop.facts · quoted verbatim
collectionsstring[]basePathstring'/docs/'basePath + slug#anchorendpoint'/api/ask'model'claude-haiku-4-5'kgModel'claude-opus-4-8'maxResultsnumberanswerMaxTokens1024maxIterationssearchchunkHeadingDepth#####candidatePerSearchperDocCapReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Tuning notes referencePractical knobs: heading depth trades finer anchors against too-small sections, the iteration cap bounds agentic latency, the per-document cap controls result spread, and candidates per search trade recall against 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 for editor help and typed configuration.facts · quoted verbatim
import type { HevAskOptions } from "@hev/ask";Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - What the integration does referenceAt startup the integration injects the on-demand endpoint route, registers virtual modules for the resolved config and the inlined digest, watches the digest path so dev reloads on changes, and warns when collections are missing. At build it runs the hash-gated digest build when a key is present, otherwise warns and keeps the committed artifact — never failing for lack of a key.facts · quoted verbatim
astro:config:setupendpoint@hev/ask/endpointprerender: falsevirtual:hev-ask/configvirtual:hev-ask/kgkgPathcollectionsastro:build:startANTHROPIC_API_KEYReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Search endpoint referenceOne injected on-demand route tree serves the overlay: keyword mode returns JSON, agentic mode streams a grounded answer over Server-Sent Events, and keyless sub-routes expose the digest to CLIs, MCP servers, and generated clients. An OpenAPI 3.1 contract is published alongside.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) referenceWith a key and agentic mode the endpoint streams named SSE frames: search activity lines, a one-time sources set sent before any token so clients can validate links, token deltas of the Markdown answer, a done marker, and an error frame for failures after streaming began. Sources carry the deep-link URL; the answer prose carries the substance.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) referenceKeyless GET routes read the inlined digest and never call a model: glossary listing and term lookup, section summaries with an optional group filter, full section nodes by id, and the overview-plus-context pair. IDs containing slashes or hashes are URL-encoded in the path, and misses return a JSON 404.facts · quoted verbatim
{ "error": "Not found." }virtual:hev-ask/kgGET /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 referenceInvalid JSON bodies return 400, missing read routes, glossary terms, or section ids return 404, and a failed chunk-index build returns 500. Failures during an agentic stream arrive as a final SSE error event because the HTTP status is already committed.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 builds once per server instance on the first request and is cached for the process lifetime. That first request also compares the live content hash against the digest's and logs a one-time staleness warning — the cue to rebuild.facts · quoted verbatim
ask kg buildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Keyword response (JSON) referenceKeyword mode returns a JSON envelope of ranked results — title, optional heading and group, the deep-link URL, and a snippet — plus the echoed query, the configured model, the mode that ran, and a warning when an agentic request was downgraded for lack of a key.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 makes every agentic answer emit a generation trace with model, tokens, latency, and the loop's tool calls; the ingestion host and how much prompt text ships are configurable. Without a key tracing 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 decides the path: empty queries return empty keyword JSON, keyword mode or a missing key returns keyword JSON (with a downgrade warning when agentic was requested), otherwise the agentic SSE stream runs. There is no AI-unavailable error path, 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 JSON POST with a query and an optional mode. Empty queries return an empty result set, and omitting the 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 keyless GET on the base route returns the digest's baked-in suggested questions and the loop model — no query, no model call. The overlay fetches it once on first open, and an empty list simply means no suggestions are shown.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 key from the adapter runtime environment first, then the process environment, then the import-time environment. It lives wherever the host injects server secrets and 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 ↗ - Digest format referenceThe ask digest is a single committed JSON file, built offline and inlined into the site through a virtual module so the running site reads it without filesystem access. It is the agent's view of the docs — a distilled, source-grounded index read progressively — and every node deep-links back to its real section. The kg name survives only in the CLI group, the path flag, and the virtual module id.facts · quoted verbatim
.hev-ask/digest.jsonask kg buildkg--kg-pathvirtual:hev-ask/kgurl#anchorCallout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Degradation referenceThe digest is read defensively: a missing, malformed, or node-less file degrades the agentic loop to keyword-style search while keyword mode keeps working, and nothing hard-fails. Because it is committed JSON, the deterministic structure reviews in pull requests; only the distillation is model-authored, which is why that step can run inside a Claude Code skill.facts · quoted verbatim
summaryglossarycontextsuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Fields referenceTop-level fields: a schema version, a generation timestamp, the content hash that gates freshness, a compact context used as the degradation fallback, the alias-bearing glossary, a deterministic overview map, model-authored suggested questions, the distilled section nodes, and a reserved edges array that ships empty.facts · quoted verbatim
versiongeneratedAtstringcontentHashcontextglossaryGlossaryEntry[]overviewsuggestionsstring[]nodesKnowledgeNode[]edgesKnowledgeEdge[]Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - How each field is used referenceThe overview and nodes are prompt-cached into the loop's system prompt; the glossary widens keyword queries; nodes also lift keyword ranking above incidental mentions; terms back a render-time link-support check; suggestions feed the overlay's empty state; and the content hash lets the build skip model work when nothing changed.facts · quoted verbatim
overviewnodesfactsglossaryk8skubernetessummarytermssuggestionsGETcontentHashbuildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - KnowledgeNode referenceEach node pairs the chunk id — mapping one-to-one to a real anchor — with the model's paraphrase, deterministically extracted verbatim facts the model never authors, provenance sources, a mode that marks reference sections as source-primary so the agent reads their source text, and distinctive terms for link validation.facts · quoted verbatim
KnowledgeNodeidstringsummaryfactsFact[]sourcesSourceRef[]urlanchormode'agent-primary' \| 'source-primary'source-primarytermsstring[]Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Regenerating referenceRebuild after content changes and commit the result; the hash gate makes this safe to run on every build because model work only happens when content actually changed. Build with the bundled skill or one API call, and run the verifier to gate anchors, coverage, and literal fidelity.facts · quoted verbatim
ask kg buildastro buildask kg verifyReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Shape referenceA worked example of the artifact: version, timestamp, content hash, context, glossary, overview, suggested questions, one fully populated section node with facts and sources, and the empty edges array.no verbatim facts in this section
Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - MCP server referenceThe MCP command runs a stdio Model Context Protocol server over the same digest reads as the CLI and HTTP API — the zero-glue way to hand a coding agent structured tools for the docs, from a checked-out repo's digest file or a deployed endpoint.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 referenceTwo configurations: local keyless reads pointing at the repo's digest file, or a deployed endpoint when the freshest digest or the answer tool matters. Local mode is fully offline, but its answer tool returns an error unless an endpoint is set.facts · quoted verbatim
{ "mcpServers": { "docs": { "command": "ask", "args": ["--kg-path", ".hev-ask/digest.json", "mcp"] } } }{ "mcpServers": { "askhev": { "command": "ask", "args": ["--endpoint", "https://askhev.com/api/ask", "mcp"] } } }answer--endpointReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Data sources referenceResolution mirrors the CLI: an endpoint flag routes reads and answers through the deployed HTTP API, otherwise the digest path is read from disk on every tool call — so a just-rebuilt digest is visible without restarting the server.facts · quoted verbatim
ask mcp--endpoint <url>answerPOST /api/ask--kg-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 initialization, tool listing, and tool calls. Unknown methods return protocol errors while tool-level failures return MCP error results, and all substantive behavior lives in the shared Go package.facts · quoted verbatim
initializetools/listtools/callisError: truepkg/askReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Tools referenceTools mirror the read surface: glossary listing and lookup, section listing and retrieval, the overview, keyword search, and a streamed answer collapsed into one tool result. Results carry human-readable text plus the original machine shape in structured content.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 overlay component renders the ⌘K command palette. Add it once in a global layout; it opens over the page and doesn't affect layout until opened.facts · quoted verbatim
--- import SearchOverlay from "@hev/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 word count picks the path: one word runs debounced keyword search with an auto-active first result, a second word switches to ask mode where Enter sends the question to the loop, and arrow keys move keyword selection. Without a server key, asking returns keyword results with a surfaced warning instead of breaking.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 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 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 referenceTwo built-in ways to open the palette: the keyboard shortcut binds automatically once the component is on the page, and any element with the opener data attribute opens it on click — wire up as many triggers as needed.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 referenceThree props: the endpoint the overlay posts to (which must match the integration's endpoint option), the input placeholder, and the debounce in milliseconds 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 referenceWith AI on, the overlay fetches suggested questions from the endpoint on first open and shows them in the empty state. They come from the digest at build time so rendering costs no model call, and clicking one fills the input and asks immediately.facts · quoted verbatim
GET /api/asksuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - The mode toggle referenceAn AI-on-Enter preference persists in localStorage. Readers who flip to keyword-only never trigger a model call — a space just searches a phrase, no suggestions are shown, 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 referenceAsking replaces the keyword rows with an answer panel: the model's sub-queries appear as faint activity lines, then the grounded answer streams token-by-token with accent-styled inline deep links and a sources chip row. Links are validated against the streamed source set, so a hallucinated anchor renders as plain text instead of a 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 reads the page's CSS custom properties for background, text, muted, and accent colors. Because its scoped styles key off those variables, matching a site's look is usually just defining the tokens — 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 distilling every section, and a bounded agentic loop that reads the digest progressively — primer first, summaries next, full source only when needed. The digest builds offline with a strong model and commits to git; the index and loop run on demand at the edge with no durable state.
- Asking is the default summaryThe overlay treats a single word as an instant keyword lookup; a second word switches to ask mode, where Enter sends the question to the agentic loop, and suggested questions baked into the digest make asking the obvious move. Readers can flip to keyword-only, persisted in localStorage, so the model is never called.
- Chunks and anchors summaryDocuments are split on headings into section chunks whose URLs carry real anchors, generated with the same slugger Astro's renderer uses so links land on headings that exist. Both the runtime index and the offline build chunk through the same function, so the anchors always agree.facts · quoted verbatimopen section ↗
#####basePath + slug + #anchorgithub-sluggergetCollectiongithub.com - Degradation, by design summaryEvery missing piece degrades instead of failing: no runtime key means keyword-only search, no build key keeps the committed digest with a warning, a missing or node-less digest falls back to plain retrieval with no suggestions, and a stale digest logs a one-line warning but still serves.
- Keyword search and the glossary summaryThe instant path is a dependency-free prefilter: query terms expand through glossary aliases, chunks score by token overlap widened by the digest's summaries, terms, and facts, results are capped per document, and snippets excerpt around the first match. It needs no key and no embeddings, and with no digest it degrades to plain token overlap.
- The agentic search loop summaryAsking sends the query to a bounded tool-use loop that is progressive disclosure over the digest: the primer and section map come free in the prompt, and the model opens only the sections it needs — reading summaries, verbatim facts, and source text for reference sections — up to an iteration cap. The final call drops all tools so the model must stream a grounded answer, citing only sections it opened.
- The ask digest summaryThe digest is an offline-built, committed artifact holding distilled section nodes with verbatim facts and source links, a deterministic overview map, a compact context and glossary, and suggested questions. Only the distillation is model-authored — structure, facts, overview, and the hash derive in code — which is exactly why the model step fits a Claude Code skill.facts · quoted verbatimopen section ↗
digest.jsonnodessummaryfactssourcesource-primaryoverviewcontextglossarysuggestions - The system prompt is cached summaryThe digest's map and section summaries are injected into the system prompt with a cache marker, so search rounds hit the prompt cache instead of re-sending tokens. The toolless answer turn can't reuse that cache but is the last call anyway, and the loop model defaults to Haiku.
- Two ways to build it summaryThe distillation runs two ways into the same deterministic assembler: the recommended Claude Code skill inside an existing subscription with no API key, or a one-call CLI build with Opus for CI. Both are hash-gated so unchanged content does no model work, and the JSON reviews in pull requests like any other change.
- Introduction summaryhev ask distills an Astro docs site into an ask digest — a token-efficient form of the docs that agents discover progressively through the CLI and readers search through a ⌘K overlay. Build the digest offline with the bundled skill and your subscription, then serve single-turn Q&A for a few cents per query — suited to technical docs, internal wikis, and other medium-sized corpora.
- Build it with your coding agent summaryThe bundled Claude Code skill generates the digest inside an existing coding subscription — no API key, no per-build token spend. Commit the JSON, drop the overlay into a layout, and the site has instant keyword search plus a Claude answer loop, every result deep-linked. The corpus is only the configured collections: no crawler, no external index, nothing to sync.facts · quoted verbatimopen section ↗
.hev-ask/digest.jsonANTHROPIC_API_KEYSearchOverlay.astrodigest.json - Next steps summaryPointers onward: the five-minute quick start, the concepts page, tradeoffs and limits, the CLI reference, and the full API reference.
- Who this is for summaryFor maintainers of Astro 5 docs sites with content collections who want search that works without standing up a service, deep-links to the right section, answers questions phrased in the reader's words, and is queryable by coding agents. Static-only keyword needs are better served by Pagefind.
- Limits summaryThe hard boundaries of the current design — corpus scope, recall ceiling, single-call digest build, frontmatter parsing, latency, and adapter requirements — stated as edges of what it covers, not bugs.
- A server route is required summaryThe search endpoint renders on demand, so a fully static build cannot serve it; a server or hybrid adapter is required, and static-only sites should use a static search tool instead.
- Agentic search adds latency summaryThe agentic path costs up to the iteration cap in Claude round-trips — a few seconds worst case — by nature. The keyword path is the always-available instant lane, and lowering the cap tightens the ceiling.
- Anchors depend on Astro's slugger summaryDeep links are correct only while generated slugs match Astro's rendered ids. Using the same slugger keeps them aligned, and the verify command fails when any chunk anchor is missing from the built HTML — wire it into CI so a slugging change is caught before a broken link ships.
- Frontmatter parsing is a flat-YAML subset summaryThe offline build parses frontmatter with a small flat-YAML splitter that handles common string and number fields but not nested structures. This only affects disk reads during the offline digest build; the runtime index uses Astro's own collection loader and honors the real schema.
- Recall has a keyword ceiling summaryRetrieval is keyword token overlap widened by the glossary, not embeddings, and the loop cannot ground in what retrieval missed. The glossary recovers most synonym cases, but a query sharing no tokens with the docs can miss entirely; embeddings are the known fix, deliberately unbuilt, and a richer glossary is the cheaper lever.
- Secrets live server-side summaryThe agentic path needs the Anthropic key in the server environment that runs the endpoint; it is never exposed to the browser, and without it the endpoint serves keyword results — search degrades rather than breaks.
- The corpus is your content collection summarySearch covers only the configured content collections — no crawler, no sitemap ingestion, and no way to index pages that aren't collection entries. Anything that should be searchable belongs in a collection.
- The digest build is a single model call summaryThe offline build sends the full cleaned corpus to the model in one call, which fits typical docs sites comfortably but would overflow on a very large corpus. A map-reduce builder is a noted follow-up, not implemented; assume the corpus fits one call.no verbatim facts in this section open section ↗
- Quick start summaryAdd search to an existing Astro 5 collection-based docs site in about five minutes: keyword search first, then an API key to enable agentic answers. The overlay alone gives keyless instant search; adding a server key upgrades Enter into the answer loop, and skipping the key just ships the search UI.facts · quoted verbatimopen section ↗
src/content/docsANTHROPIC_API_KEYSearchOverlay.astroSteps.astroCallout.astro - 1. Install summaryInstall from npm once published, or until then consume the package straight from its subdirectory on GitHub.facts · quoted verbatimopen section ↗
pnpm add @hev/askpnpm add "git+ssh://[email protected]/hev/ask.git#main&path:/packages/ui" - 2. Register the integration summaryRegister the integration in the Astro config with the content collection name(s) — the one required option — and the base path that maps slugs to URLs. Everything else has defaults covered in the configuration reference.facts · quoted verbatimopen section ↗
// astro.config.mjs import { defineConfig } from "astro/config"; import hevAsk from "@hev/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 summaryThe search route renders on demand, so add the adapter matching the host. Existing pages stay prerendered; only the search route 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 the base layout. Any element with the opener attribute opens the palette, the keyboard shortcut binds automatically, and keyword search works from there.facts · quoted verbatimopen section ↗
--- // src/layouts/Base.astro import SearchOverlay from "@hev/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: it gives the loop context, ranks keyword results, supplies the glossary, and holds the suggested questions. The recommended path is the bundled Claude Code skill — built inside the subscription, no API key — with a one-call CLI build for CI; both are hash-gated, then verify and commit.facts · quoted verbatimopen section ↗
You: build the hev ask digest Claude runs: ask kg corpus # emits the sections to distil …writes context/glossary/summaries/suggestions… ask kg assemble # writes .hev-ask/digest.jsonexport ANTHROPIC_API_KEY=sk-ant-... pnpm exec ask kg build # writes .hev-ask/digest.jsonpnpm exec ask kg verify # builds the site, checks every anchor resolves git add .hev-ask/digest.jsonk8skubernetesastro buildclaude.com - Enable agentic search summarySet the Anthropic key in the server environment where the endpoint runs. With it, Enter runs the agentic loop — self-issued sub-queries, a grounded answer, inline deep links; without it, Enter returns keyword results.
- Prerequisites summaryAstro 5 with at least one content collection, a server or hybrid adapter for the on-demand route, and an Anthropic key only if agentic search is wanted — keyword search needs none.
- Set up keyword search summaryThe keyword path is set up by the install, register, adapter, and overlay steps that follow.
- Verify it works summarySanity checks: a single heading word should deep-link to its section, a multi-word question should stream a grounded answer with the sub-queries visible, and the verify command — which exits non-zero on any missing anchor — belongs in CI.
- Tradeoffs summaryEvery search tool makes choices; this page states honestly what hev ask trades away — its dependency posture, the committed digest, agentic cost and latency — and how it compares to Pagefind, Algolia, and Orama.
- A committed digest summaryGenerating the digest offline and committing it makes it reviewable in pull requests, deterministic at runtime, free on the request path, and bundleable at the edge with no filesystem access. The cost is staleness when a rebuild is forgotten; the runtime warns on hash divergence, and the hash gate makes rebuild-on-every-change the cheap, intended workflow.no verbatim facts in this section open section ↗
- Cost and latency of agentic search summaryThe agentic path costs real but small money and a few seconds of latency: one bounded loop per query on the default Haiku model with prompt-cached context, plus an Opus-powered offline digest build paid only when content changes. Keyword-only is a first-class mode for keyless deployments, not a fallback afterthought.
- How it compares summaryA comparison against Pagefind, Algolia DocSearch, and Orama across retrieval, AI ranking, deep links, and hosting. Choose Pagefind for static keyword simplicity, Algolia for a managed service with a crawler, Orama for client-side vector search, and hev ask when docs live in Astro collections and a reader's question — not just keywords — should find the right section.no verbatim facts in this section open section ↗
- Keyword retrieval, not embeddings summaryToken-overlap retrieval widened by the glossary means nothing to host, nothing to sync, edge-safe, and instant — but paraphrase recall has a ceiling, and the agent grounds only in what retrieval surfaced. Embeddings would do better for token-free phrasing; that upgrade is deferred, not designed out.no verbatim facts in this section open section ↗
- One dependency, deliberately summaryThe package keeps close to zero dependencies with one deliberate exception: the same tiny, edge-safe slugger Astro uses. Hand-rolling anchors risks drifting from the renderer and shipping links that 404 to the top of the page; sharing the slugger guarantees byte-identical anchors.
- Two paths instead of one summaryRunning an instant keyword path beside an agentic path keeps the common case instant and keyless while hard questions get a smarter ranker. The cost is a slightly more complex interaction — readers learn that Enter means asking AI — which fits docs, where queries split between jumping to known things and finding the unnameable.no verbatim facts in this section open section ↗
Raw digest.json artifact
{
"version": 2,
"generatedAt": "2026-06-05T01:49:16.438Z",
"contentHash": "b8987e737da2dbe8c58216407c6b667d64f24ac18d0997e682cfc450347bef2d",
"context": "## hev ask\n\nhev ask (`@hev/ask`) is a ⌘K search overlay for Astro docs sites. It distills the site's content collection into an **ask digest** — a token-efficient, committed JSON form of the docs — and serves it to readers (an answer overlay) and coding agents (the ask CLI and an MCP server).\n\nCore ideas users ask about:\n- **Ask digest (`.hev-ask/digest.json`)**: offline-built, committed, reviewable. Nodes hold model-authored summaries plus deterministically extracted verbatim facts; only the distillation is model work, and a content-hash gate skips rebuilds when docs are unchanged. (`kg` is the digest's historical name, kept in the CLI command group, the path flag, and the virtual module id.)\n- **Progressive disclosure**: the agentic loop holds a primer and section map in its prompt, opens only the sections it needs, and reads full source text only for reference sections.\n- **Two search paths**: instant keyless keyword search (token overlap widened by the glossary), and on Enter a bounded Claude loop that streams a grounded answer over SSE with inline deep links.\n- **Deep links**: every result and citation lands on an exact heading anchor generated with the same slugger Astro uses; a verify command gates drift in CI.\n- **Degradation**: no key → keyword mode; no digest → plain token overlap; nothing hard-fails.\n- **Building**: the bundled build-digest skill runs inside a Claude Code subscription (no API key, no token spend on your own key); `ask kg build` is the one-call fallback for CI.\n\nUsers phrase questions as: how do I add search to my Astro site, how does the AI answer work, what happens without an API key, how do I rebuild or verify the digest, how does it compare to Pagefind/Algolia/Orama, what are the limits.",
"glossary": [
{
"term": "ask digest",
"aliases": [
"digest",
"kg",
"knowledge graph",
"digest.json"
],
"definition": "The committed JSON artifact distilling every doc section — summaries, verbatim facts, glossary, overview, and suggested questions — that the agentic loop reads progressively."
},
{
"term": "agentic search",
"aliases": [
"agentic loop",
"ask mode",
"AI search",
"answer loop",
"search loop"
],
"definition": "The bounded Claude tool-use loop that opens digest sections and streams a grounded, deep-linked answer over SSE."
},
{
"term": "keyword search",
"aliases": [
"keyword mode",
"instant search",
"prefilter"
],
"definition": "The keyless instant path: token-overlap scoring over heading chunks, widened by the glossary and the digest's per-section signal."
},
{
"term": "progressive disclosure",
"aliases": [
"progressive"
],
"definition": "The loop's reading pattern — primer and section map up front, distilled summaries on open, full source text only for reference sections."
},
{
"term": "chunk",
"aliases": [
"heading chunk",
"section"
],
"definition": "A heading-bounded slice of a document; the unit of indexing, retrieval, and deep linking."
},
{
"term": "anchor",
"aliases": [
"deep link",
"heading anchor"
],
"definition": "The URL fragment generated with the same slugger Astro uses, so results land on the exact rendered heading."
},
{
"term": "glossary",
"aliases": [
"aliases",
"query expansion"
],
"definition": "Digest terms with aliases that widen keyword queries (k8s finds kubernetes) and one-line definitions agents can read."
},
{
"term": "SearchOverlay",
"aliases": [
"overlay",
"command palette",
"cmd-k",
"ctrl-k"
],
"definition": "The Astro component rendering the ask-first ⌘K search palette; add it once in a global layout."
},
{
"term": "ask CLI",
"aliases": [
"ask",
"CLI",
"ask binary"
],
"definition": "The binary with consumer verbs for reading the digest progressively and producer verbs under the kg group for building and verifying it."
},
{
"term": "MCP server",
"aliases": [
"ask mcp",
"MCP",
"Model Context Protocol"
],
"definition": "The stdio MCP server exposing digest reads, search, and answers as structured tools for coding agents."
},
{
"term": "endpoint",
"aliases": [
"/api/ask",
"search endpoint",
"API route"
],
"definition": "The injected on-demand route serving keyword JSON, agentic SSE, suggested questions, and keyless digest reads."
},
{
"term": "content hash",
"aliases": [
"hash gate",
"freshness",
"stale"
],
"definition": "The sha256 of chunk text that lets builds skip model work when docs are unchanged and flags staleness at runtime."
},
{
"term": "build-digest skill",
"aliases": [
"build-kg",
"Claude Code skill",
"bundled skill"
],
"definition": "The bundled skill that distills the digest inside a Claude Code subscription, costing no API tokens on the user's own key."
},
{
"term": "verify",
"aliases": [
"ask kg verify",
"anchor verification",
"CI gate"
],
"definition": "The command that builds the site and fails on anchor drift, warning on digest coverage and literal fidelity."
},
{
"term": "degradation",
"aliases": [
"fallback",
"no API key",
"keyless"
],
"definition": "The design rule that every missing piece downgrades — no key means keyword mode, no digest means plain token overlap — and nothing hard-fails."
}
],
"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- 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- 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- Digest format — `api/knowledge-graph`\n- Degradation — `api/knowledge-graph#degradation`\n- Fields — `api/knowledge-graph#fields`\n- How each field is used — `api/knowledge-graph#how-each-field-is-used`\n- KnowledgeNode — `api/knowledge-graph#knowledgenode`\n- Regenerating — `api/knowledge-graph#regenerating`\n- Shape — `api/knowledge-graph#shape`\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 digest build is a single model call — `limits#the-digest-build-is-a-single-model-call`\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 docs site?",
"How does the ask digest stay fresh after docs change?",
"What happens if I don't set an API key?",
"How does hev ask compare to Pagefind or Algolia?",
"How does the agentic answer loop stay grounded?"
],
"nodes": [
{
"id": "api/cli",
"kind": "section",
"title": "CLI",
"heading": null,
"group": "API",
"url": "/docs/api/cli",
"summary": "The ask binary has two command groups: consumer verbs that read the committed digest progressively (skim, find, open, ask, or serve it all to an agent) and producer verbs under the kg group — the digest's historical name — that build and verify it. A deprecated alias binary forwards to the new group with a one-line migration notice.",
"facts": [
{
"kind": "code",
"literal": "@hev/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 kg",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "kg",
"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": "hev-ask-kg",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "ask kg ...",
"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": [
"binary",
"command",
"groups",
"consumer",
"verbs",
"read",
"committed",
"digest",
"progressively",
"skim",
"find",
"open",
"serve",
"agent",
"producer",
"under",
"group",
"historical",
"name",
"build",
"verify",
"deprecated",
"alias",
"forwards",
"line",
"migration",
"notice",
"overview",
"glossary",
"search",
"sections",
"section",
"answer",
"corpus",
"assemble",
"callout",
"astro",
"reads",
"builds",
"verifies"
]
},
{
"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 site root: a hash-gated one-shot build, a corpus emitter for keyless distillation, an assembler that turns a distillation into the digest, and a verifier for anchors, coverage, and fidelity. The model authors only context, glossary, summaries, and suggestions; chunking, facts, overview, sources, and the content hash are computed in code.",
"facts": [
{
"kind": "code",
"literal": "ask kg build # one-shot build; needs ANTHROPIC_API_KEY only when stale\nask kg corpus # emit sections for a keyless skill/model distillation\nask kg assemble # assemble .hev-ask/digest.json from that distillation\nask kg verify # build the site and verify anchors, coverage, fidelity",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "ask kg build",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "ask kg corpus",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/kg-input.json",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "ask kg assemble",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": ".hev-ask/kg-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"
},
{
"kind": "code",
"literal": "ask kg verify",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "--skip-build",
"chunkId": "api/cli#building-the-digest"
},
{
"kind": "code",
"literal": "--strict",
"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",
"site",
"root",
"hash",
"gated",
"shot",
"build",
"corpus",
"emitter",
"keyless",
"distillation",
"assembler",
"turns",
"verifier",
"anchors",
"coverage",
"fidelity",
"model",
"authors",
"only",
"context",
"glossary",
"summaries",
"suggestions",
"chunking",
"facts",
"overview",
"sources",
"content",
"computed",
"code",
"needs",
"anthropic",
"stale",
"emit",
"sections",
"skill"
]
},
{
"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 skill builds the digest inside a Claude Code subscription, so it costs no API tokens on the user's own key. It runs the same deterministic corpus-distill-assemble seam and produces the same artifact shape under the same hash gate.",
"facts": [
{
"kind": "code",
"literal": "ask kg corpus -> .hev-ask/kg-input.json\n...writes .hev-ask/kg-distill.json...\nask kg assemble -> .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 kg 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",
"builds",
"digest",
"inside",
"subscription",
"costs",
"tokens",
"user",
"runs",
"same",
"deterministic",
"corpus",
"distill",
"assemble",
"seam",
"produces",
"artifact",
"shape",
"under",
"hash",
"gate",
"input",
"json",
"writes",
"build",
"anthropic",
"without",
"anthropicapikey",
"producer",
"because",
"model",
"step",
"resulting",
"output",
"applies"
]
},
{
"id": "api/cli#distribution",
"kind": "section",
"title": "CLI",
"heading": "Distribution",
"group": "API",
"url": "/docs/api/cli#distribution",
"summary": "The npm package ships two bins: the main v3 CLI and a deprecated alias that forwards to the kg command group. The launcher resolves an environment override first, then a platform-specific binary package, then checked-out Go source for development.",
"facts": [
{
"kind": "code",
"literal": "ask",
"chunkId": "api/cli#distribution"
},
{
"kind": "code",
"literal": "hev-ask-kg",
"chunkId": "api/cli#distribution"
},
{
"kind": "code",
"literal": "ask kg ...",
"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",
"ships",
"bins",
"main",
"deprecated",
"alias",
"forwards",
"command",
"group",
"launcher",
"resolves",
"environment",
"override",
"first",
"platform",
"specific",
"binary",
"checked",
"source",
"development",
"exposes",
"purpose",
"hevaskbinary",
"optional",
"installed",
"monorepo",
"fallback",
"published",
"installs",
"packaged",
"path"
]
},
{
"id": "api/cli#flags",
"kind": "section",
"title": "CLI",
"heading": "Flags",
"group": "API",
"url": "/docs/api/cli#flags",
"summary": "Reference table of global flags covering the digest path, remote endpoint, JSON output, result caps, collection and base-path selection, content globs, chunk heading depth, the build model, producer input and output paths, the verify build command, skip-build, and strict mode. Global flags come before the command.",
"facts": [
{
"kind": "code",
"literal": "ask --kg-path .hev-ask/digest.json --json search \"openapi\"\nask --endpoint https://askhev.com/api/ask mcp\nask kg build --collection docs --collection guides --chunk-heading-depth 2\nask kg verify --skip-build",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--kg-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": "--kg-model <model>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "claude-opus-4-8",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "ask kg build",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--out <path>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": ".hev-ask/kg-input.json",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "ask kg corpus",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--input <path>",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": ".hev-ask/kg-distill.json",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "ask kg assemble",
"chunkId": "api/cli#flags"
},
{
"kind": "code",
"literal": "--build-command <cmd>",
"chunkId": "api/cli#flags"
}
],
"sources": [
{
"chunkId": "api/cli#flags",
"url": "/docs/api/cli#flags",
"anchor": "flags"
}
],
"mode": "source-primary",
"terms": [
"flags",
"reference",
"table",
"global",
"covering",
"digest",
"path",
"remote",
"endpoint",
"json",
"output",
"result",
"caps",
"collection",
"base",
"selection",
"content",
"globs",
"chunk",
"heading",
"depth",
"build",
"model",
"producer",
"input",
"paths",
"verify",
"command",
"skip",
"strict",
"mode",
"come",
"before",
"search",
"openapi",
"https",
"askhev",
"docs",
"guides",
"answer"
]
},
{
"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 offers pure helpers and an embeddable, dependency-free command group for mounting the same verbs in another CLI. Helpers cover loading the digest, glossary and section reads, search, an endpoint client, building, anchor verification, and MCP serving.",
"facts": [
{
"kind": "code",
"literal": "group := ask.NewCommandGroup(ask.CommandOptions{\n\tKGPath: \".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": "LoadGraph",
"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": "SearchGraph",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "NewEndpointClient",
"chunkId": "api/cli#go-library"
},
{
"kind": "code",
"literal": "BuildKnowledgeGraph",
"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",
"offers",
"pure",
"helpers",
"embeddable",
"dependency",
"free",
"command",
"group",
"mounting",
"same",
"verbs",
"another",
"cover",
"loading",
"digest",
"glossary",
"section",
"reads",
"search",
"endpoint",
"client",
"building",
"anchor",
"verification",
"serving",
"newcommandgroup",
"commandoptions",
"kgpath",
"json",
"string",
"read",
"endpoints",
"stdin",
"stdout",
"stderr",
"loadgraph",
"listglossary",
"getsection"
]
},
{
"id": "api/cli#mcp",
"kind": "section",
"title": "CLI",
"heading": "MCP",
"group": "API",
"url": "/docs/api/cli#mcp",
"summary": "The CLI runs a stdio MCP server over the same read and search surface. Point it at a local digest for checked-out repos, or at a deployed endpoint when the agent needs the remote digest or streamed answers.",
"facts": [
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"docs\": {\n \"command\": \"ask\",\n \"args\": [\"--kg-path\", \".hev-ask/digest.json\", \"mcp\"]\n }\n }\n}",
"chunkId": "api/cli#mcp"
},
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"askhev\": {\n \"command\": \"ask\",\n \"args\": [\"--endpoint\", \"https://askhev.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": [
"runs",
"stdio",
"server",
"same",
"read",
"search",
"surface",
"point",
"local",
"digest",
"checked",
"repos",
"deployed",
"endpoint",
"agent",
"needs",
"remote",
"streamed",
"answers",
"mcpservers",
"docs",
"command",
"args",
"path",
"json",
"askhev",
"https",
"glossary",
"list",
"sections",
"section",
"overview",
"answer",
"glossarylist",
"glossaryget",
"sectionslist",
"sectionget",
"reads",
"page",
"tool"
]
},
{
"id": "api/cli#package-scripts",
"kind": "section",
"title": "CLI",
"heading": "Package scripts",
"group": "API",
"url": "/docs/api/cli#package-scripts",
"summary": "Sites typically wrap the build and verify commands in package scripts. Scripts calling the deprecated alias keep working through the forward, but new scripts should use the kg command group.",
"facts": [
{
"kind": "code",
"literal": "{\n \"scripts\": {\n \"kg:build\": \"ask kg build\",\n \"kg:verify\": \"ask kg verify\"\n }\n}",
"chunkId": "api/cli#package-scripts"
},
{
"kind": "code",
"literal": "ask kg",
"chunkId": "api/cli#package-scripts"
},
{
"kind": "code",
"literal": "hev-ask-kg build",
"chunkId": "api/cli#package-scripts"
},
{
"kind": "code",
"literal": "hev-ask-kg verify",
"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",
"sites",
"typically",
"wrap",
"build",
"verify",
"commands",
"calling",
"deprecated",
"alias",
"keep",
"working",
"through",
"forward",
"should",
"command",
"group",
"site",
"existing",
"call"
]
},
{
"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 committed digest from the current repo; an endpoint flag switches reads to a deployed site's HTTP API. The answer verb requires the endpoint because it uses the deployed agentic SSE path; local search is the keyless alternative.",
"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://askhev.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",
"committed",
"current",
"repo",
"endpoint",
"flag",
"switches",
"deployed",
"site",
"http",
"answer",
"verb",
"requires",
"because",
"uses",
"agentic",
"path",
"local",
"search",
"keyless",
"alternative",
"glossary",
"list",
"sections",
"group",
"section",
"overview",
"read",
"endpoints",
"https",
"askhev",
"routes",
"exist",
"json",
"pass",
"instead",
"retrieval"
]
},
{
"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 need filesystem access and run locally or in CI; the Astro integration also triggers the hash-gated build during the site build when a key is present, falling back to the committed artifact. The deployed site reads the digest through a virtual module, and wiring verify into CI is the mechanical guard for anchor correctness.",
"facts": [
{
"kind": "code",
"literal": "ask kg 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/kg",
"chunkId": "api/cli#where-it-runs"
},
{
"kind": "code",
"literal": "ask kg 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",
"need",
"filesystem",
"access",
"locally",
"astro",
"integration",
"also",
"triggers",
"hash",
"gated",
"build",
"during",
"site",
"present",
"falling",
"back",
"committed",
"artifact",
"deployed",
"reads",
"digest",
"through",
"virtual",
"module",
"wiring",
"verify",
"mechanical",
"guard",
"anchor",
"correctness",
"anthropic",
"invokes",
"anthropicapikey",
"falls",
"command",
"cannot",
"does"
]
},
{
"id": "api/configuration",
"kind": "section",
"title": "Configuration",
"heading": null,
"group": "API",
"url": "/docs/api/configuration",
"summary": "The integration is the package's default export and takes one options object. Only the collection list is effectively required; everything else has a default.",
"facts": [
{
"kind": "code",
"literal": "// astro.config.mjs\nimport hevAsk from \"@hev/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": "@hev/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": [
"integration",
"package",
"default",
"export",
"takes",
"options",
"object",
"only",
"collection",
"list",
"effectively",
"required",
"everything",
"else",
"astro",
"config",
"import",
"hevask",
"defineconfig",
"integrations",
"collections",
"docs",
"basepath",
"model",
"claude",
"haiku",
"maxresults",
"callout",
"every",
"option",
"models",
"endpoint",
"chunking",
"depth",
"retrieval",
"caps",
"digest",
"paths",
"defaults"
]
},
{
"id": "api/configuration#options",
"kind": "section",
"title": "Configuration",
"heading": "Options",
"group": "API",
"url": "/docs/api/configuration#options",
"summary": "Reference table of every option: collections, base path, endpoint route, the loop and digest-build models, result and answer-token caps, iteration and chunk-depth limits, per-search candidates, the per-document cap, the digest path, and content globs. A changed endpoint must match the overlay component's endpoint 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": "kgModel",
"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",
"reference",
"table",
"every",
"option",
"collections",
"base",
"path",
"endpoint",
"route",
"loop",
"digest",
"build",
"models",
"result",
"answer",
"token",
"caps",
"iteration",
"chunk",
"depth",
"limits",
"search",
"candidates",
"document",
"content",
"globs",
"changed",
"must",
"match",
"overlay",
"component",
"prop",
"string",
"basepath",
"docs",
"slug",
"anchor",
"model",
"claude"
]
},
{
"id": "api/configuration#tuning-notes",
"kind": "section",
"title": "Configuration",
"heading": "Tuning notes",
"group": "API",
"url": "/docs/api/configuration#tuning-notes",
"summary": "Practical knobs: heading depth trades finer anchors against too-small sections, the iteration cap bounds agentic latency, the per-document cap controls result spread, and candidates per search trade recall against 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",
"practical",
"knobs",
"heading",
"depth",
"trades",
"finer",
"anchors",
"against",
"small",
"sections",
"iteration",
"bounds",
"agentic",
"latency",
"document",
"controls",
"result",
"spread",
"candidates",
"search",
"trade",
"recall",
"tokens",
"chunkheadingdepth",
"maxiterations",
"perdoccap",
"candidatepersearch",
"chunk",
"granularity",
"raise",
"default",
"section",
"long",
"pages",
"drop",
"stand",
"alone",
"results"
]
},
{
"id": "api/configuration#typescript",
"kind": "section",
"title": "Configuration",
"heading": "TypeScript",
"group": "API",
"url": "/docs/api/configuration#typescript",
"summary": "The options type is exported for editor help and typed configuration.",
"facts": [
{
"kind": "code",
"literal": "import type { HevAskOptions } from \"@hev/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",
"editor",
"help",
"typed",
"configuration",
"import",
"hevaskoptions",
"config",
"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 startup the integration injects the on-demand endpoint route, registers virtual modules for the resolved config and the inlined digest, watches the digest path so dev reloads on changes, and warns when collections are missing. At build it runs the hash-gated digest build when a key is present, otherwise warns and keeps the committed artifact — never failing for lack of a 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": "@hev/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/kg",
"chunkId": "api/configuration#what-the-integration-does"
},
{
"kind": "code",
"literal": "kgPath",
"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",
"startup",
"injects",
"demand",
"endpoint",
"route",
"registers",
"virtual",
"modules",
"resolved",
"config",
"inlined",
"digest",
"watches",
"path",
"reloads",
"changes",
"warns",
"collections",
"missing",
"build",
"runs",
"hash",
"gated",
"present",
"otherwise",
"keeps",
"committed",
"artifact",
"never",
"failing",
"lack",
"astro",
"setup",
"prerender",
"false",
"kgpath",
"start",
"anthropic"
]
},
{
"id": "api/endpoint",
"kind": "section",
"title": "Search endpoint",
"heading": null,
"group": "API",
"url": "/docs/api/endpoint",
"summary": "One injected on-demand route tree serves the overlay: keyword mode returns JSON, agentic mode streams a grounded answer over Server-Sent Events, and keyless sub-routes expose the digest to CLIs, MCP servers, and generated clients. An OpenAPI 3.1 contract is published alongside.",
"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": [
"injected",
"demand",
"route",
"tree",
"serves",
"overlay",
"keyword",
"mode",
"returns",
"json",
"agentic",
"streams",
"grounded",
"answer",
"server",
"sent",
"events",
"keyless",
"routes",
"expose",
"digest",
"clis",
"servers",
"generated",
"clients",
"openapi",
"contract",
"published",
"alongside",
"text",
"event",
"stream",
"yaml",
"callout",
"astro",
"suggestions",
"reads",
"selection",
"error",
"responses"
]
},
{
"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": "With a key and agentic mode the endpoint streams named SSE frames: search activity lines, a one-time sources set sent before any token so clients can validate links, token deltas of the Markdown answer, a done marker, and an error frame for failures after streaming began. Sources carry the deep-link URL; the answer prose carries the substance.",
"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",
"mode",
"endpoint",
"streams",
"named",
"frames",
"search",
"activity",
"lines",
"time",
"sources",
"sent",
"before",
"token",
"clients",
"validate",
"links",
"deltas",
"markdown",
"answer",
"done",
"marker",
"error",
"frame",
"failures",
"after",
"streaming",
"began",
"carry",
"deep",
"link",
"prose",
"carries",
"substance",
"content",
"type",
"text",
"event",
"stream"
]
},
{
"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": "Keyless GET routes read the inlined digest and never call a model: glossary listing and term lookup, section summaries with an optional group filter, full section nodes by id, and the overview-plus-context pair. IDs containing slashes or hashes are URL-encoded in the path, and misses return a JSON 404.",
"facts": [
{
"kind": "code",
"literal": "{ \"error\": \"Not found.\" }",
"chunkId": "api/endpoint#digest-reads-get"
},
{
"kind": "code",
"literal": "virtual:hev-ask/kg",
"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",
"keyless",
"routes",
"read",
"inlined",
"never",
"call",
"model",
"glossary",
"listing",
"term",
"lookup",
"section",
"summaries",
"optional",
"group",
"filter",
"full",
"nodes",
"overview",
"plus",
"context",
"pair",
"containing",
"slashes",
"hashes",
"encoded",
"path",
"misses",
"return",
"json",
"error",
"found",
"virtual",
"terms",
"glossaryentry",
"sections",
"sectionsummary",
"knowledgenode"
]
},
{
"id": "api/endpoint#errors",
"kind": "section",
"title": "Search endpoint",
"heading": "Errors",
"group": "API",
"url": "/docs/api/endpoint#errors",
"summary": "Invalid JSON bodies return 400, missing read routes, glossary terms, or section ids return 404, and a failed chunk-index build returns 500. Failures during an agentic stream arrive as a final SSE error event because the HTTP status is already committed.",
"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",
"invalid",
"json",
"bodies",
"return",
"missing",
"read",
"routes",
"glossary",
"terms",
"section",
"failed",
"chunk",
"index",
"build",
"returns",
"failures",
"during",
"agentic",
"stream",
"arrive",
"final",
"error",
"event",
"because",
"http",
"status",
"already",
"committed",
"body",
"cause",
"request",
"wasn",
"valid",
"digest",
"route",
"term",
"found",
"misconfigured",
"collection"
]
},
{
"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 builds once per server instance on the first request and is cached for the process lifetime. That first request also compares the live content hash against the digest's and logs a one-time staleness warning — the cue to rebuild.",
"facts": [
{
"kind": "code",
"literal": "ask kg 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",
"builds",
"once",
"server",
"instance",
"first",
"request",
"cached",
"process",
"lifetime",
"also",
"compares",
"live",
"content",
"hash",
"against",
"digest",
"logs",
"time",
"staleness",
"warning",
"rebuild",
"build",
"built",
"endpoint",
"differ"
]
},
{
"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 JSON envelope of ranked results — title, optional heading and group, the deep-link URL, and a snippet — plus the echoed query, the configured model, the mode that ran, and a warning when an agentic request was downgraded for lack of a key.",
"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",
"envelope",
"ranked",
"results",
"title",
"optional",
"heading",
"group",
"deep",
"link",
"snippet",
"plus",
"echoed",
"query",
"configured",
"model",
"warning",
"agentic",
"request",
"downgraded",
"lack",
"concepts",
"search",
"loop",
"docs",
"overview",
"reader",
"presses",
"enter",
"goes",
"bounded",
"does",
"work",
"claude",
"haiku",
"result"
]
},
{
"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 makes every agentic answer emit a generation trace with model, tokens, latency, and the loop's tool calls; the ingestion host and how much prompt text ships are configurable. Without a key tracing 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",
"makes",
"every",
"agentic",
"answer",
"emit",
"generation",
"trace",
"model",
"tokens",
"latency",
"loop",
"tool",
"calls",
"ingestion",
"host",
"much",
"prompt",
"text",
"ships",
"configurable",
"without",
"path",
"never",
"depends",
"telemetry",
"capture",
"content",
"redacted",
"full",
"posthogkey",
"posthogapikey",
"same",
"environment",
"emits",
"aigeneration",
"posthoghost",
"overrides"
]
},
{
"id": "api/endpoint#mode-selection",
"kind": "section",
"title": "Search endpoint",
"heading": "Mode selection",
"group": "API",
"url": "/docs/api/endpoint#mode-selection",
"summary": "The endpoint decides the path: empty queries return empty keyword JSON, keyword mode or a missing key returns keyword JSON (with a downgrade warning when agentic was requested), otherwise the agentic SSE stream runs. There is no AI-unavailable error path, 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",
"decides",
"path",
"empty",
"queries",
"return",
"keyword",
"json",
"missing",
"returns",
"downgrade",
"warning",
"agentic",
"requested",
"otherwise",
"stream",
"runs",
"there",
"unavailable",
"error",
"overlay",
"branches",
"response",
"content",
"type",
"results",
"query",
"model",
"plus",
"downgrades",
"request",
"says",
"reader",
"still",
"gets",
"handles",
"both",
"shapes"
]
},
{
"id": "api/endpoint#request",
"kind": "section",
"title": "Search endpoint",
"heading": "Request",
"group": "API",
"url": "/docs/api/endpoint#request",
"summary": "Requests are a JSON POST with a query and an optional mode. Empty queries return an empty result set, and omitting the 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",
"json",
"post",
"query",
"optional",
"mode",
"empty",
"queries",
"return",
"result",
"omitting",
"behaves",
"like",
"agentic",
"present",
"does",
"autoscaling",
"work",
"string",
"keyword",
"body",
"field",
"type",
"description",
"search",
"whitespace",
"returns",
"forces",
"instant",
"path",
"loop",
"omitted"
]
},
{
"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 keyless GET on the base route returns the digest's baked-in suggested questions and the loop model — no query, no model call. The overlay fetches it once on first open, and an empty list simply means no suggestions are shown.",
"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",
"keyless",
"base",
"route",
"returns",
"digest",
"baked",
"loop",
"model",
"query",
"call",
"overlay",
"fetches",
"once",
"first",
"open",
"empty",
"list",
"simply",
"means",
"suggestions",
"shown",
"does",
"stay",
"fresh",
"claude",
"haiku",
"populate",
"array",
"graph",
"without",
"just",
"shows",
"none"
]
},
{
"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 key from the adapter runtime environment first, then the process environment, then the import-time environment. It lives wherever the host injects server secrets and 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",
"adapter",
"runtime",
"environment",
"first",
"process",
"import",
"time",
"lives",
"wherever",
"host",
"injects",
"server",
"secrets",
"never",
"sent",
"browser",
"locals",
"meta",
"anthropicapikey",
"order",
"cloudflare"
]
},
{
"id": "api/knowledge-graph",
"kind": "section",
"title": "Digest format",
"heading": null,
"group": "API",
"url": "/docs/api/knowledge-graph",
"summary": "The ask digest is a single committed JSON file, built offline and inlined into the site through a virtual module so the running site reads it without filesystem access. It is the agent's view of the docs — a distilled, source-grounded index read progressively — and every node deep-links back to its real section. The kg name survives only in the CLI group, the path flag, and the virtual module id.",
"facts": [
{
"kind": "code",
"literal": ".hev-ask/digest.json",
"chunkId": "api/knowledge-graph"
},
{
"kind": "code",
"literal": "ask kg build",
"chunkId": "api/knowledge-graph"
},
{
"kind": "code",
"literal": "kg",
"chunkId": "api/knowledge-graph"
},
{
"kind": "code",
"literal": "--kg-path",
"chunkId": "api/knowledge-graph"
},
{
"kind": "code",
"literal": "virtual:hev-ask/kg",
"chunkId": "api/knowledge-graph"
},
{
"kind": "code",
"literal": "url#anchor",
"chunkId": "api/knowledge-graph"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/knowledge-graph"
}
],
"sources": [
{
"chunkId": "api/knowledge-graph",
"url": "/docs/api/knowledge-graph",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"digest",
"single",
"committed",
"json",
"file",
"built",
"offline",
"inlined",
"site",
"through",
"virtual",
"module",
"running",
"reads",
"without",
"filesystem",
"access",
"agent",
"view",
"docs",
"distilled",
"source",
"grounded",
"index",
"read",
"progressively",
"every",
"node",
"deep",
"links",
"back",
"real",
"section",
"name",
"survives",
"only",
"group",
"path",
"flag",
"build"
]
},
{
"id": "api/knowledge-graph#degradation",
"kind": "section",
"title": "Digest format",
"heading": "Degradation",
"group": "API",
"url": "/docs/api/knowledge-graph#degradation",
"summary": "The digest is read defensively: a missing, malformed, or node-less file degrades the agentic loop to keyword-style search while keyword mode keeps working, and nothing hard-fails. Because it is committed JSON, the deterministic structure reviews in pull requests; only the distillation is model-authored, which is why that step can run inside a Claude Code skill.",
"facts": [
{
"kind": "code",
"literal": "summary",
"chunkId": "api/knowledge-graph#degradation"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/knowledge-graph#degradation"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/knowledge-graph#degradation"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/knowledge-graph#degradation"
}
],
"sources": [
{
"chunkId": "api/knowledge-graph#degradation",
"url": "/docs/api/knowledge-graph#degradation",
"anchor": "degradation"
}
],
"mode": "source-primary",
"terms": [
"degradation",
"digest",
"read",
"defensively",
"missing",
"malformed",
"node",
"less",
"file",
"degrades",
"agentic",
"loop",
"keyword",
"style",
"search",
"while",
"mode",
"keeps",
"working",
"nothing",
"hard",
"fails",
"because",
"committed",
"json",
"deterministic",
"structure",
"reviews",
"pull",
"requests",
"only",
"distillation",
"model",
"authored",
"step",
"inside",
"claude",
"code",
"skill",
"summary"
]
},
{
"id": "api/knowledge-graph#fields",
"kind": "section",
"title": "Digest format",
"heading": "Fields",
"group": "API",
"url": "/docs/api/knowledge-graph#fields",
"summary": "Top-level fields: a schema version, a generation timestamp, the content hash that gates freshness, a compact context used as the degradation fallback, the alias-bearing glossary, a deterministic overview map, model-authored suggested questions, the distilled section nodes, and a reserved edges array that ships empty.",
"facts": [
{
"kind": "code",
"literal": "version",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "generatedAt",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "contentHash",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "GlossaryEntry[]",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "string[]",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "nodes",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "KnowledgeNode[]",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "edges",
"chunkId": "api/knowledge-graph#fields"
},
{
"kind": "code",
"literal": "KnowledgeEdge[]",
"chunkId": "api/knowledge-graph#fields"
}
],
"sources": [
{
"chunkId": "api/knowledge-graph#fields",
"url": "/docs/api/knowledge-graph#fields",
"anchor": "fields"
}
],
"mode": "source-primary",
"terms": [
"fields",
"level",
"schema",
"version",
"generation",
"timestamp",
"content",
"hash",
"gates",
"freshness",
"compact",
"context",
"degradation",
"fallback",
"alias",
"bearing",
"glossary",
"deterministic",
"overview",
"model",
"authored",
"suggested",
"questions",
"distilled",
"section",
"nodes",
"reserved",
"edges",
"array",
"ships",
"empty",
"generatedat",
"string",
"contenthash",
"glossaryentry",
"suggestions",
"knowledgenode",
"knowledgeedge",
"field",
"type"
]
},
{
"id": "api/knowledge-graph#how-each-field-is-used",
"kind": "section",
"title": "Digest format",
"heading": "How each field is used",
"group": "API",
"url": "/docs/api/knowledge-graph#how-each-field-is-used",
"summary": "The overview and nodes are prompt-cached into the loop's system prompt; the glossary widens keyword queries; nodes also lift keyword ranking above incidental mentions; terms back a render-time link-support check; suggestions feed the overlay's empty state; and the content hash lets the build skip model work when nothing changed.",
"facts": [
{
"kind": "code",
"literal": "overview",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "nodes",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "k8s",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "terms",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "GET",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "contentHash",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
},
{
"kind": "code",
"literal": "build",
"chunkId": "api/knowledge-graph#how-each-field-is-used"
}
],
"sources": [
{
"chunkId": "api/knowledge-graph#how-each-field-is-used",
"url": "/docs/api/knowledge-graph#how-each-field-is-used",
"anchor": "how-each-field-is-used"
}
],
"mode": "source-primary",
"terms": [
"field",
"overview",
"nodes",
"prompt",
"cached",
"loop",
"system",
"glossary",
"widens",
"keyword",
"queries",
"also",
"lift",
"ranking",
"above",
"incidental",
"mentions",
"terms",
"back",
"render",
"time",
"link",
"support",
"check",
"suggestions",
"feed",
"overlay",
"empty",
"state",
"content",
"hash",
"lets",
"build",
"skip",
"model",
"work",
"nothing",
"changed",
"facts",
"kubernetes"
]
},
{
"id": "api/knowledge-graph#knowledgenode",
"kind": "section",
"title": "Digest format",
"heading": "KnowledgeNode",
"group": "API",
"url": "/docs/api/knowledge-graph#knowledgenode",
"summary": "Each node pairs the chunk id — mapping one-to-one to a real anchor — with the model's paraphrase, deterministically extracted verbatim facts the model never authors, provenance sources, a mode that marks reference sections as source-primary so the agent reads their source text, and distinctive terms for link validation.",
"facts": [
{
"kind": "code",
"literal": "KnowledgeNode",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "id",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "Fact[]",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "sources",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "SourceRef[]",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "anchor",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "mode",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "'agent-primary' \\| 'source-primary'",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "source-primary",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "terms",
"chunkId": "api/knowledge-graph#knowledgenode"
},
{
"kind": "code",
"literal": "string[]",
"chunkId": "api/knowledge-graph#knowledgenode"
}
],
"sources": [
{
"chunkId": "api/knowledge-graph#knowledgenode",
"url": "/docs/api/knowledge-graph#knowledgenode",
"anchor": "knowledgenode"
}
],
"mode": "source-primary",
"terms": [
"knowledgenode",
"node",
"pairs",
"chunk",
"mapping",
"real",
"anchor",
"model",
"paraphrase",
"deterministically",
"extracted",
"verbatim",
"facts",
"never",
"authors",
"provenance",
"sources",
"mode",
"marks",
"reference",
"sections",
"source",
"primary",
"agent",
"reads",
"their",
"text",
"distinctive",
"terms",
"link",
"validation",
"string",
"summary",
"fact",
"sourceref",
"field",
"type",
"description",
"equals",
"maps"
]
},
{
"id": "api/knowledge-graph#regenerating",
"kind": "section",
"title": "Digest format",
"heading": "Regenerating",
"group": "API",
"url": "/docs/api/knowledge-graph#regenerating",
"summary": "Rebuild after content changes and commit the result; the hash gate makes this safe to run on every build because model work only happens when content actually changed. Build with the bundled skill or one API call, and run the verifier to gate anchors, coverage, and literal fidelity.",
"facts": [
{
"kind": "code",
"literal": "ask kg build",
"chunkId": "api/knowledge-graph#regenerating"
},
{
"kind": "code",
"literal": "astro build",
"chunkId": "api/knowledge-graph#regenerating"
},
{
"kind": "code",
"literal": "ask kg verify",
"chunkId": "api/knowledge-graph#regenerating"
}
],
"sources": [
{
"chunkId": "api/knowledge-graph#regenerating",
"url": "/docs/api/knowledge-graph#regenerating",
"anchor": "regenerating"
}
],
"mode": "source-primary",
"terms": [
"regenerating",
"rebuild",
"after",
"content",
"changes",
"commit",
"result",
"hash",
"gate",
"makes",
"safe",
"every",
"build",
"because",
"model",
"work",
"only",
"happens",
"actually",
"changed",
"bundled",
"skill",
"call",
"verifier",
"anchors",
"coverage",
"literal",
"fidelity",
"astro",
"verify",
"spends",
"claude",
"code",
"integration",
"also",
"runs",
"during",
"present"
]
},
{
"id": "api/knowledge-graph#shape",
"kind": "section",
"title": "Digest format",
"heading": "Shape",
"group": "API",
"url": "/docs/api/knowledge-graph#shape",
"summary": "A worked example of the artifact: version, timestamp, content hash, context, glossary, overview, suggested questions, one fully populated section node with facts and sources, and the empty edges array.",
"facts": [],
"sources": [
{
"chunkId": "api/knowledge-graph#shape",
"url": "/docs/api/knowledge-graph#shape",
"anchor": "shape"
}
],
"mode": "source-primary",
"terms": [
"shape",
"worked",
"example",
"artifact",
"version",
"timestamp",
"content",
"hash",
"context",
"glossary",
"overview",
"suggested",
"questions",
"fully",
"populated",
"section",
"node",
"facts",
"sources",
"empty",
"edges",
"array",
"generatedat",
"2026",
"30t12",
"000z",
"contenthash",
"a1b2c3",
"search",
"overlay",
"astro",
"docs",
"term",
"digest",
"aliases",
"definition",
"offline",
"built",
"distilled",
"kubernetes"
]
},
{
"id": "api/mcp",
"kind": "section",
"title": "MCP server",
"heading": null,
"group": "API",
"url": "/docs/api/mcp",
"summary": "The MCP command runs a stdio Model Context Protocol server over the same digest reads as the CLI and HTTP API — the zero-glue way to hand a coding agent structured tools for the docs, from a checked-out repo's digest file or a deployed endpoint.",
"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": [
"command",
"runs",
"stdio",
"model",
"context",
"protocol",
"server",
"same",
"digest",
"reads",
"http",
"zero",
"glue",
"hand",
"coding",
"agent",
"structured",
"tools",
"docs",
"checked",
"repo",
"file",
"deployed",
"endpoint",
"json",
"expose",
"committed",
"agents",
"graph",
"path",
"point",
"gets"
]
},
{
"id": "api/mcp#configure",
"kind": "section",
"title": "MCP server",
"heading": "Configure",
"group": "API",
"url": "/docs/api/mcp#configure",
"summary": "Two configurations: local keyless reads pointing at the repo's digest file, or a deployed endpoint when the freshest digest or the answer tool matters. Local mode is fully offline, but its answer tool returns an error unless an endpoint is set.",
"facts": [
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"docs\": {\n \"command\": \"ask\",\n \"args\": [\"--kg-path\", \".hev-ask/digest.json\", \"mcp\"]\n }\n }\n}",
"chunkId": "api/mcp#configure"
},
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"askhev\": {\n \"command\": \"ask\",\n \"args\": [\"--endpoint\", \"https://askhev.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",
"configurations",
"local",
"keyless",
"reads",
"pointing",
"repo",
"digest",
"file",
"deployed",
"endpoint",
"freshest",
"answer",
"tool",
"matters",
"mode",
"fully",
"offline",
"returns",
"error",
"unless",
"mcpservers",
"docs",
"command",
"args",
"path",
"json",
"askhev",
"https",
"graph",
"site",
"form",
"want"
]
},
{
"id": "api/mcp#data-sources",
"kind": "section",
"title": "MCP server",
"heading": "Data sources",
"group": "API",
"url": "/docs/api/mcp#data-sources",
"summary": "Resolution mirrors the CLI: an endpoint flag routes reads and answers through the deployed HTTP API, otherwise the digest path is read from disk on every 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": "--kg-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",
"resolution",
"mirrors",
"endpoint",
"flag",
"routes",
"reads",
"answers",
"through",
"deployed",
"http",
"otherwise",
"digest",
"path",
"read",
"disk",
"every",
"tool",
"call",
"just",
"rebuilt",
"visible",
"without",
"restarting",
"server",
"answer",
"post",
"json",
"uses",
"same",
"calls",
"streams",
"defaulting",
"local",
"load"
]
},
{
"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 initialization, tool listing, and tool calls. Unknown methods return protocol errors while tool-level failures return MCP error results, and all substantive behavior lives in the shared Go package.",
"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",
"initialization",
"tool",
"listing",
"calls",
"unknown",
"methods",
"return",
"errors",
"while",
"level",
"failures",
"error",
"results",
"substantive",
"behavior",
"lives",
"shared",
"package",
"initialize",
"tools",
"list",
"call",
"iserror",
"true",
"handles",
"plus",
"initialized",
"notification",
"result",
"keeps",
"small"
]
},
{
"id": "api/mcp#tools",
"kind": "section",
"title": "MCP server",
"heading": "Tools",
"group": "API",
"url": "/docs/api/mcp#tools",
"summary": "Tools mirror the read surface: glossary listing and lookup, section listing and retrieval, the overview, keyword search, and a streamed answer collapsed into one tool result. Results carry human-readable text plus the original machine shape in structured content.",
"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",
"mirror",
"read",
"surface",
"glossary",
"listing",
"lookup",
"section",
"retrieval",
"overview",
"keyword",
"search",
"streamed",
"answer",
"collapsed",
"tool",
"result",
"results",
"carry",
"human",
"readable",
"text",
"plus",
"original",
"machine",
"shape",
"structured",
"content",
"list",
"terms",
"glossaryentry",
"term",
"sections",
"group",
"sectionsummary",
"context",
"query",
"maxresults",
"structuredcontent",
"arguments"
]
},
{
"id": "api/search-overlay",
"kind": "section",
"title": "SearchOverlay component",
"heading": null,
"group": "API",
"url": "/docs/api/search-overlay",
"summary": "The overlay component renders the ⌘K command palette. Add it once in a global layout; it opens over the page and doesn't affect layout until opened.",
"facts": [
{
"kind": "code",
"literal": "---\nimport SearchOverlay from \"@hev/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": [
"overlay",
"component",
"renders",
"command",
"palette",
"once",
"global",
"layout",
"opens",
"page",
"doesn",
"affect",
"until",
"opened",
"import",
"searchoverlay",
"components",
"astro",
"dialog",
"callout",
"props",
"data",
"open",
"opener",
"attribute",
"keyboard",
"model",
"mode",
"toggle",
"theming",
"through",
"variables"
]
},
{
"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 word count picks the path: one word runs debounced keyword search with an auto-active first result, a second word switches to ask mode where Enter sends the question to the loop, and arrow keys move keyword selection. Without a server key, asking returns keyword results with a surfaced warning instead of breaking.",
"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",
"word",
"count",
"picks",
"path",
"runs",
"debounced",
"keyword",
"search",
"auto",
"active",
"result",
"second",
"switches",
"mode",
"enter",
"sends",
"question",
"loop",
"arrow",
"keys",
"move",
"selection",
"without",
"server",
"asking",
"returns",
"results",
"surfaced",
"warning",
"instead",
"breaking",
"number",
"words",
"typed",
"decides",
"open"
]
},
{
"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 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 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",
"shows",
"document",
"title",
"optional",
"heading",
"breadcrumb",
"line",
"snippet",
"chunk",
"already",
"carries",
"anchor",
"clicking",
"lands",
"exact",
"concepts",
"agentic",
"loop",
"result",
"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": "Two built-in ways to open the palette: the keyboard shortcut binds automatically once the component is on the page, and any element with the opener data attribute opens it on click — wire up as many triggers as needed.",
"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",
"built",
"ways",
"open",
"palette",
"keyboard",
"shortcut",
"binds",
"automatically",
"once",
"component",
"page",
"element",
"opener",
"data",
"attribute",
"opens",
"click",
"wire",
"many",
"triggers",
"needed",
"button",
"type",
"search",
"href",
"docs",
"ctrl",
"both",
"bound",
"like",
"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": "Three props: the endpoint the overlay posts to (which must match the integration's endpoint option), the input placeholder, and the debounce in milliseconds 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",
"three",
"endpoint",
"overlay",
"posts",
"must",
"match",
"integration",
"option",
"input",
"placeholder",
"debounce",
"milliseconds",
"before",
"keyword",
"query",
"sent",
"searchoverlay",
"search",
"string",
"docs",
"number",
"prop",
"type",
"default",
"description",
"queries",
"text",
"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": "With AI on, the overlay fetches suggested questions from the endpoint on first open and shows them in the empty state. They come from the digest at build time so rendering costs no model call, and clicking one fills the input and asks immediately.",
"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",
"endpoint",
"first",
"open",
"shows",
"empty",
"state",
"come",
"digest",
"build",
"time",
"rendering",
"costs",
"model",
"call",
"clicking",
"fills",
"input",
"asks",
"immediately",
"suggestions",
"short",
"list",
"opens",
"baked",
"there",
"render",
"none",
"simply",
"nothing",
"extra",
"suggestion"
]
},
{
"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": "An AI-on-Enter preference persists in localStorage. Readers who flip to keyword-only never trigger a model call — a space just searches a phrase, no suggestions are shown, 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",
"enter",
"preference",
"persists",
"localstorage",
"readers",
"flip",
"keyword",
"only",
"never",
"trigger",
"model",
"call",
"space",
"just",
"searches",
"phrase",
"suggestions",
"shown",
"choice",
"survives",
"reloads",
"agentic",
"overlay",
"under",
"suggested",
"questions"
]
},
{
"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": "Asking replaces the keyword rows with an answer panel: the model's sub-queries appear as faint activity lines, then the grounded answer streams token-by-token with accent-styled inline deep links and a sources chip row. Links are validated against the streamed source set, so a hallucinated anchor renders as plain text instead of a 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",
"asking",
"replaces",
"keyword",
"rows",
"panel",
"model",
"queries",
"appear",
"faint",
"activity",
"lines",
"grounded",
"streams",
"token",
"accent",
"styled",
"inline",
"deep",
"links",
"sources",
"chip",
"validated",
"against",
"source",
"hallucinated",
"anchor",
"renders",
"plain",
"text",
"instead",
"dead",
"link",
"searched",
"docs",
"page",
"pressing",
"enter",
"configured"
]
},
{
"id": "api/search-overlay#theming",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Theming",
"group": "API",
"url": "/docs/api/search-overlay#theming",
"summary": "The overlay reads the page's CSS custom properties for background, text, muted, and accent colors. Because its scoped styles key off those variables, matching a site's look is usually just defining the tokens — 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",
"reads",
"page",
"custom",
"properties",
"background",
"text",
"muted",
"accent",
"colors",
"because",
"scoped",
"styles",
"those",
"variables",
"matching",
"site",
"look",
"usually",
"just",
"defining",
"tokens",
"override",
"root",
"paper",
"111111",
"fafaf5",
"primary",
"6b6b66",
"secondary",
"signal",
"e25822",
"active",
"state",
"markup",
"uses",
"class",
"prefix",
"define"
]
},
{
"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 distilling every section, and a bounded agentic loop that reads the digest progressively — primer first, summaries next, full source only when needed. The digest builds offline with a strong model and commits to git; the index and loop run on demand at the edge with no durable state.",
"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",
"distilling",
"every",
"section",
"bounded",
"agentic",
"loop",
"reads",
"progressively",
"primer",
"first",
"summaries",
"next",
"full",
"source",
"only",
"needed",
"builds",
"strong",
"model",
"commits",
"demand",
"edge",
"durable",
"state",
"diagram",
"astro",
"callout",
"works",
"indexing",
"keyword",
"prefiltering"
]
},
{
"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 treats a single word as an instant keyword lookup; a second word switches to ask mode, where Enter sends the question to the agentic loop, and suggested questions baked into the digest make asking the obvious move. Readers can flip to keyword-only, persisted in localStorage, so 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",
"treats",
"single",
"word",
"instant",
"keyword",
"lookup",
"second",
"switches",
"mode",
"enter",
"sends",
"question",
"agentic",
"loop",
"suggested",
"questions",
"baked",
"digest",
"make",
"obvious",
"move",
"readers",
"flip",
"only",
"persisted",
"localstorage",
"model",
"never",
"called",
"first",
"treated",
"answered",
"instantly",
"index",
"moment",
"query",
"grows"
]
},
{
"id": "concepts#chunks-and-anchors",
"kind": "section",
"title": "Concepts",
"heading": "Chunks and anchors",
"group": "Overview",
"url": "/docs/concepts#chunks-and-anchors",
"summary": "Documents are split on headings into section chunks whose URLs carry real anchors, generated with the same slugger Astro's renderer uses so links land on headings that exist. Both the runtime index and the offline build chunk through the same function, so the anchors always 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",
"documents",
"split",
"headings",
"section",
"whose",
"urls",
"carry",
"real",
"generated",
"same",
"slugger",
"astro",
"renderer",
"uses",
"links",
"land",
"exist",
"both",
"runtime",
"index",
"offline",
"build",
"chunk",
"through",
"function",
"always",
"agree",
"basepath",
"slug",
"anchor",
"github",
"getcollection",
"does",
"pages",
"indexes",
"sections",
"document",
"configurable"
]
},
{
"id": "concepts#degradation-by-design",
"kind": "section",
"title": "Concepts",
"heading": "Degradation, by design",
"group": "Overview",
"url": "/docs/concepts#degradation-by-design",
"summary": "Every missing piece degrades instead of failing: no runtime key means keyword-only search, no build key keeps the committed digest with a warning, a missing or node-less digest falls back to plain retrieval with no suggestions, and a stale digest logs a one-line warning but still serves.",
"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",
"every",
"missing",
"piece",
"degrades",
"instead",
"failing",
"runtime",
"means",
"keyword",
"only",
"search",
"build",
"keeps",
"committed",
"digest",
"warning",
"node",
"less",
"falls",
"back",
"plain",
"retrieval",
"suggestions",
"stale",
"logs",
"line",
"still",
"serves",
"json",
"built",
"keep",
"working",
"pieces",
"drop",
"away",
"mode",
"overlay",
"searches"
]
},
{
"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": "The instant path is a dependency-free prefilter: query terms expand through glossary aliases, chunks score by token overlap widened by the digest's summaries, terms, and facts, results are capped per document, and snippets excerpt around the first match. It needs no key and no embeddings, and with no digest it degrades to plain token overlap.",
"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",
"instant",
"path",
"dependency",
"free",
"prefilter",
"query",
"terms",
"expand",
"through",
"aliases",
"chunks",
"score",
"token",
"overlap",
"widened",
"digest",
"summaries",
"facts",
"results",
"capped",
"document",
"snippets",
"excerpt",
"around",
"first",
"match",
"needs",
"embeddings",
"degrades",
"plain",
"kubernetes",
"json",
"summary",
"reader",
"types",
"single",
"term"
]
},
{
"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": "Asking sends the query to a bounded tool-use loop that is progressive disclosure over the digest: the primer and section map come free in the prompt, and the model opens only the sections it needs — reading summaries, verbatim facts, and source text for reference sections — up to an iteration cap. The final call drops all tools so the model must stream a grounded answer, citing only sections it opened.",
"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",
"asking",
"sends",
"query",
"bounded",
"tool",
"progressive",
"disclosure",
"digest",
"primer",
"section",
"come",
"free",
"prompt",
"model",
"opens",
"only",
"sections",
"needs",
"reading",
"summaries",
"verbatim",
"facts",
"source",
"text",
"reference",
"iteration",
"final",
"call",
"drops",
"tools",
"must",
"stream",
"grounded",
"answer",
"citing",
"opened",
"open"
]
},
{
"id": "concepts#the-ask-digest",
"kind": "section",
"title": "Concepts",
"heading": "The ask digest",
"group": "Overview",
"url": "/docs/concepts#the-ask-digest",
"summary": "The digest is an offline-built, committed artifact holding distilled section nodes with verbatim facts and source links, a deterministic overview map, a compact context and glossary, and suggested questions. Only the distillation is model-authored — structure, facts, overview, and the hash derive in code — which is exactly why the model step fits a Claude Code skill.",
"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",
"offline",
"built",
"committed",
"artifact",
"holding",
"distilled",
"section",
"nodes",
"verbatim",
"facts",
"source",
"links",
"deterministic",
"overview",
"compact",
"context",
"glossary",
"suggested",
"questions",
"only",
"distillation",
"model",
"authored",
"structure",
"hash",
"derive",
"code",
"exactly",
"step",
"fits",
"claude",
"skill",
"json",
"summary",
"primary",
"suggestions",
"repo",
"reviewable",
"agent"
]
},
{
"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 map and section summaries are injected into the system prompt with a cache marker, so search rounds hit the prompt cache instead of re-sending tokens. The toolless answer turn can't reuse that cache but is the last call anyway, and the loop model defaults to Haiku.",
"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",
"search",
"rounds",
"instead",
"sending",
"tokens",
"toolless",
"answer",
"turn",
"reuse",
"last",
"call",
"anyway",
"loop",
"model",
"defaults",
"haiku",
"control",
"cachecontrol",
"across",
"rather",
"sent",
"changes",
"tool",
"none",
"claude",
"configurable"
]
},
{
"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 distillation runs two ways into the same deterministic assembler: the recommended Claude Code skill inside an existing subscription with no API key, or a one-call CLI build with Opus for CI. Both are hash-gated so unchanged content does no model work, and the JSON reviews in pull requests like any other change.",
"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 kg 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",
"distillation",
"runs",
"same",
"deterministic",
"assembler",
"recommended",
"claude",
"code",
"skill",
"inside",
"existing",
"subscription",
"call",
"opus",
"both",
"hash",
"gated",
"unchanged",
"content",
"does",
"model",
"work",
"json",
"reviews",
"pull",
"requests",
"like",
"other",
"change",
"digest",
"anthropic",
"step",
"feed",
"walks",
"through",
"reading",
"corpus",
"writing"
]
},
{
"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 the docs that agents discover progressively through the CLI and readers search through a ⌘K overlay. Build the digest offline with the bundled skill and your subscription, then serve single-turn Q&A for a few cents per query — suited to technical docs, internal wikis, and other 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",
"search",
"overlay",
"build",
"offline",
"bundled",
"skill",
"subscription",
"serve",
"single",
"turn",
"cents",
"query",
"suited",
"technical",
"internal",
"wikis",
"other",
"medium",
"sized",
"corpora",
"diagram",
"callout",
"committed",
"serves",
"ways",
"answer",
"server"
]
},
{
"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 bundled Claude Code skill generates the digest inside an existing coding subscription — no API key, no per-build token spend. Commit the JSON, drop the overlay into a layout, and the site has instant keyword search plus a Claude answer loop, every result deep-linked. The corpus is only the configured collections: no crawler, no external index, nothing to sync.",
"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",
"bundled",
"claude",
"code",
"skill",
"generates",
"digest",
"inside",
"existing",
"subscription",
"token",
"spend",
"commit",
"json",
"drop",
"overlay",
"layout",
"site",
"instant",
"keyword",
"search",
"plus",
"answer",
"loop",
"every",
"result",
"deep",
"linked",
"corpus",
"only",
"configured",
"collections",
"crawler",
"external",
"index",
"nothing",
"sync",
"anthropic"
]
},
{
"id": "index#next-steps",
"kind": "section",
"title": "Introduction",
"heading": "Next steps",
"group": "Overview",
"url": "/docs#next-steps",
"summary": "Pointers onward: the five-minute quick start, the concepts page, tradeoffs and limits, the CLI reference, and the full API reference.",
"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",
"pointers",
"onward",
"five",
"minute",
"quick",
"start",
"concepts",
"page",
"tradeoffs",
"limits",
"reference",
"full",
"search",
"site",
"minutes",
"chunks",
"anchors",
"agentic",
"loop",
"digest",
"choosing",
"deliberately",
"doesn",
"build",
"verify",
"query",
"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": "For maintainers of Astro 5 docs sites with content collections who want search that works without standing up a service, deep-links to the right section, answers questions phrased in the reader's words, and is queryable by coding agents. Static-only keyword needs are better served by Pagefind.",
"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": [
"maintainers",
"astro",
"docs",
"sites",
"content",
"collections",
"want",
"search",
"works",
"without",
"standing",
"service",
"deep",
"links",
"right",
"section",
"answers",
"questions",
"phrased",
"reader",
"words",
"queryable",
"coding",
"agents",
"static",
"only",
"keyword",
"needs",
"better",
"served",
"pagefind",
"build",
"building",
"maintaining",
"site",
"whose",
"lives",
"collection",
"markdown",
"work"
]
},
{
"id": "limits",
"kind": "section",
"title": "Limits",
"heading": null,
"group": "Overview",
"url": "/docs/limits",
"summary": "The hard boundaries of the current design — corpus scope, recall ceiling, single-call digest build, frontmatter parsing, latency, and adapter requirements — stated as edges of what it covers, not bugs.",
"facts": [
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "limits"
}
],
"sources": [
{
"chunkId": "limits",
"url": "/docs/limits",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"hard",
"boundaries",
"current",
"design",
"corpus",
"scope",
"recall",
"ceiling",
"single",
"call",
"digest",
"build",
"frontmatter",
"parsing",
"latency",
"adapter",
"requirements",
"stated",
"edges",
"covers",
"bugs",
"callout",
"astro",
"deliberately",
"does",
"these",
"should",
"know",
"before",
"adopting",
"none"
]
},
{
"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 it; a server or hybrid adapter is required, and 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",
"hybrid",
"adapter",
"only",
"sites",
"should",
"tool",
"instead",
"need",
"node",
"cloudflare",
"vercel",
"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 costs up to the iteration cap in Claude round-trips — a few seconds worst case — by nature. The keyword path is the always-available instant lane, and lowering the cap tightens the 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",
"costs",
"iteration",
"claude",
"round",
"trips",
"seconds",
"worst",
"case",
"nature",
"keyword",
"always",
"available",
"instant",
"lane",
"lowering",
"tightens",
"ceiling",
"maxiterations",
"bounded",
"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 are correct only while generated slugs match Astro's rendered ids. Using the same slugger keeps them aligned, and the verify command fails when any chunk anchor is missing from the built HTML — wire it into CI so a slugging change is caught 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 kg 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",
"correct",
"only",
"while",
"generated",
"slugs",
"match",
"rendered",
"same",
"keeps",
"aligned",
"verify",
"command",
"fails",
"chunk",
"anchor",
"missing",
"built",
"html",
"wire",
"slugging",
"change",
"caught",
"before",
"broken",
"link",
"ships",
"github",
"long",
"heading",
"generates",
"attributes",
"uses",
"stay",
"ever"
]
},
{
"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 that handles common string and number fields but not nested structures. This only affects disk reads during the offline digest build; the runtime index uses Astro's own collection loader and honors the 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",
"handles",
"common",
"string",
"number",
"fields",
"nested",
"structures",
"only",
"affects",
"disk",
"reads",
"during",
"digest",
"runtime",
"index",
"uses",
"astro",
"collection",
"loader",
"honors",
"real",
"schema",
"getcollection",
"full",
"parser",
"docs",
"aren",
"supported",
"time",
"reading"
]
},
{
"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 keyword token overlap widened by the glossary, not embeddings, and the loop cannot ground in what retrieval missed. The glossary recovers most synonym cases, but a query sharing no tokens with the docs can miss entirely; embeddings are the known fix, deliberately unbuilt, and a richer glossary is the cheaper lever.",
"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",
"token",
"overlap",
"widened",
"glossary",
"embeddings",
"loop",
"cannot",
"ground",
"missed",
"recovers",
"most",
"synonym",
"cases",
"query",
"sharing",
"tokens",
"docs",
"miss",
"entirely",
"known",
"deliberately",
"unbuilt",
"richer",
"cheaper",
"lever",
"kubernetes",
"agentic",
"grounds",
"answer",
"surfaces",
"link",
"practice",
"abbreviations",
"product",
"aliases",
"reader"
]
},
{
"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 key in the server environment that runs the endpoint; it is never exposed to the browser, and without it the endpoint serves keyword results — 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",
"serves",
"keyword",
"results",
"search",
"degrades",
"rather",
"breaks",
"anthropicapikey",
"present",
"runtime",
"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": "Search covers only the configured content collections — no crawler, no sitemap ingestion, and no way to index pages that aren't collection entries. Anything that should be searchable belongs in a 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",
"search",
"covers",
"only",
"configured",
"collections",
"crawler",
"sitemap",
"ingestion",
"index",
"pages",
"aren",
"entries",
"anything",
"should",
"searchable",
"belongs",
"astro",
"searches",
"configure",
"nothing",
"else",
"there",
"external",
"hand",
"written",
"example",
"appear",
"want"
]
},
{
"id": "limits#the-digest-build-is-a-single-model-call",
"kind": "section",
"title": "Limits",
"heading": "The digest build is a single model call",
"group": "Overview",
"url": "/docs/limits#the-digest-build-is-a-single-model-call",
"summary": "The offline build sends the full cleaned corpus to the model in one call, which fits typical docs sites comfortably but would overflow on a very large corpus. A map-reduce builder is a noted follow-up, not implemented; assume the corpus fits one call.",
"facts": [],
"sources": [
{
"chunkId": "limits#the-digest-build-is-a-single-model-call",
"url": "/docs/limits#the-digest-build-is-a-single-model-call",
"anchor": "the-digest-build-is-a-single-model-call"
}
],
"mode": "agent-primary",
"terms": [
"digest",
"build",
"single",
"model",
"call",
"offline",
"sends",
"full",
"cleaned",
"corpus",
"fits",
"typical",
"docs",
"sites",
"comfortably",
"would",
"overflow",
"very",
"large",
"reduce",
"builder",
"noted",
"follow",
"implemented",
"assume",
"site",
"dozens",
"pages",
"exceed",
"context",
"window",
"summaries",
"merged",
"graph",
"today"
]
},
{
"id": "quickstart",
"kind": "section",
"title": "Quick start",
"heading": null,
"group": "Overview",
"url": "/docs/quickstart",
"summary": "Add search to an existing Astro 5 collection-based docs site in about five minutes: keyword search first, then an API key to enable agentic answers. The overlay alone gives keyless instant search; adding a server key upgrades Enter into the answer loop, and skipping the key just ships the search UI.",
"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",
"collection",
"based",
"docs",
"site",
"about",
"five",
"minutes",
"keyword",
"first",
"enable",
"agentic",
"answers",
"overlay",
"alone",
"gives",
"keyless",
"instant",
"adding",
"server",
"upgrades",
"enter",
"answer",
"loop",
"skipping",
"just",
"ships",
"content",
"anthropic",
"searchoverlay",
"steps",
"callout",
"install",
"integration",
"drop",
"build",
"digest",
"whose"
]
},
{
"id": "quickstart#1-install",
"kind": "section",
"title": "Quick start",
"heading": "1. Install",
"group": "Overview",
"url": "/docs/quickstart#1-install",
"summary": "Install from npm once published, or until then consume the package straight from its subdirectory on GitHub.",
"facts": [
{
"kind": "code",
"literal": "pnpm add @hev/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",
"once",
"published",
"until",
"consume",
"package",
"straight",
"subdirectory",
"github",
"pnpm",
"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 the Astro config with the content collection name(s) — the one required option — and the base path that maps slugs to URLs. Everything else has defaults covered in the configuration reference.",
"facts": [
{
"kind": "code",
"literal": "// astro.config.mjs\nimport { defineConfig } from \"astro/config\";\nimport hevAsk from \"@hev/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",
"content",
"collection",
"name",
"required",
"option",
"base",
"path",
"maps",
"slugs",
"urls",
"everything",
"else",
"defaults",
"covered",
"configuration",
"reference",
"import",
"defineconfig",
"hevask",
"export",
"default",
"integrations",
"collections",
"docs",
"basepath",
"slug",
"prefix",
"must"
]
},
{
"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": "The search route renders on demand, so add the adapter matching the host. Existing pages stay prerendered; only the search route 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",
"search",
"route",
"renders",
"demand",
"matching",
"host",
"existing",
"pages",
"stay",
"prerendered",
"only",
"runs",
"function",
"astro",
"config",
"import",
"cloudflare",
"astrojs",
"export",
"default",
"defineconfig",
"platformproxy",
"enabled",
"true",
"integrations",
"above",
"whichever",
"matches",
"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 the base layout. Any element with the opener attribute opens the palette, the keyboard shortcut binds automatically, and keyword search works from there.",
"facts": [
{
"kind": "code",
"literal": "---\n// src/layouts/Base.astro\nimport SearchOverlay from \"@hev/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",
"keyboard",
"shortcut",
"binds",
"automatically",
"keyword",
"search",
"works",
"there",
"layouts",
"astro",
"import",
"searchoverlay",
"components",
"button",
"type",
"data",
"open",
"slot",
"bound",
"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: it gives the loop context, ranks keyword results, supplies the glossary, and holds the suggested questions. The recommended path is the bundled Claude Code skill — built inside the subscription, no API key — with a one-call CLI build for CI; both are hash-gated, then verify and commit.",
"facts": [
{
"kind": "code",
"literal": "You: build the hev ask digest\n\nClaude runs:\n ask kg corpus # emits the sections to distil\n …writes context/glossary/summaries/suggestions…\n ask kg assemble # writes .hev-ask/digest.json",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "export ANTHROPIC_API_KEY=sk-ant-...\npnpm exec ask kg build # writes .hev-ask/digest.json",
"chunkId": "quickstart#5-build-the-digest"
},
{
"kind": "code",
"literal": "pnpm exec ask kg 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",
"loop",
"context",
"ranks",
"keyword",
"results",
"supplies",
"glossary",
"holds",
"suggested",
"questions",
"recommended",
"path",
"bundled",
"claude",
"code",
"skill",
"inside",
"subscription",
"call",
"both",
"hash",
"gated",
"verify",
"runs",
"corpus",
"emits",
"sections",
"distil",
"writes",
"summaries",
"suggestions",
"assemble"
]
},
{
"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 key in the server environment where the endpoint runs. With it, Enter runs the agentic loop — self-issued sub-queries, a grounded answer, inline deep links; without it, 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",
"enter",
"loop",
"self",
"issued",
"queries",
"grounded",
"answer",
"inline",
"deep",
"links",
"without",
"returns",
"keyword",
"results",
"anthropicapikey",
"host",
"secrets",
"local",
"present",
"pressing",
"overlay"
]
},
{
"id": "quickstart#prerequisites",
"kind": "section",
"title": "Quick start",
"heading": "Prerequisites",
"group": "Overview",
"url": "/docs/quickstart#prerequisites",
"summary": "Astro 5 with at least one content collection, a server or hybrid adapter for the on-demand route, and an Anthropic key only if agentic search is wanted — keyword search needs none.",
"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",
"demand",
"route",
"anthropic",
"only",
"agentic",
"search",
"wanted",
"keyword",
"needs",
"none",
"docs",
"build",
"node",
"cloudflare",
"vercel",
"renders",
"fully",
"static",
"serve",
"anthropicapikey",
"enable"
]
},
{
"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": "The keyword path is set up by the install, register, adapter, and overlay steps that follow.",
"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",
"path",
"install",
"register",
"adapter",
"overlay",
"steps",
"follow",
"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": "Sanity checks: a single heading word should deep-link to its section, a multi-word question should stream a grounded answer with the sub-queries visible, and the verify command — which exits non-zero on any missing anchor — belongs in CI.",
"facts": [
{
"kind": "code",
"literal": "/docs/page#heading",
"chunkId": "quickstart#verify-it-works"
},
{
"kind": "code",
"literal": "ask kg 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",
"sanity",
"checks",
"single",
"heading",
"word",
"should",
"deep",
"link",
"section",
"multi",
"question",
"stream",
"grounded",
"answer",
"queries",
"visible",
"command",
"exits",
"zero",
"missing",
"anchor",
"belongs",
"docs",
"page",
"keyword",
"type",
"result",
"agentic",
"click",
"suggested",
"press",
"enter",
"footer",
"shows",
"model",
"streams",
"inline",
"links"
]
},
{
"id": "tradeoffs",
"kind": "section",
"title": "Tradeoffs",
"heading": null,
"group": "Overview",
"url": "/docs/tradeoffs",
"summary": "Every search tool makes choices; this page states honestly what hev ask trades away — its dependency posture, the committed digest, agentic cost and latency — and how it compares to Pagefind, Algolia, and Orama.",
"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",
"states",
"honestly",
"trades",
"away",
"dependency",
"posture",
"committed",
"digest",
"agentic",
"cost",
"latency",
"compares",
"pagefind",
"algolia",
"orama",
"callout",
"astro",
"choosing",
"adopting",
"honest",
"version",
"gives",
"decide",
"whether",
"trade",
"fits",
"docs"
]
},
{
"id": "tradeoffs#a-committed-digest",
"kind": "section",
"title": "Tradeoffs",
"heading": "A committed digest",
"group": "Overview",
"url": "/docs/tradeoffs#a-committed-digest",
"summary": "Generating the digest offline and committing it makes it reviewable in pull requests, deterministic at runtime, free on the request path, and bundleable at the edge with no filesystem access. The cost is staleness when a rebuild is forgotten; the runtime warns on hash divergence, and the hash gate makes rebuild-on-every-change the cheap, 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",
"generating",
"offline",
"committing",
"makes",
"reviewable",
"pull",
"requests",
"deterministic",
"runtime",
"free",
"request",
"path",
"bundleable",
"edge",
"filesystem",
"access",
"cost",
"staleness",
"rebuild",
"forgotten",
"warns",
"hash",
"divergence",
"gate",
"every",
"change",
"cheap",
"intended",
"workflow",
"generated",
"json",
"rather",
"computed",
"hidden",
"service",
"upside",
"read",
"model"
]
},
{
"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 costs real but small money and a few seconds of latency: one bounded loop per query on the default Haiku model with prompt-cached context, plus an Opus-powered offline digest build paid only when content changes. Keyword-only is a first-class mode for keyless deployments, not a fallback afterthought.",
"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",
"costs",
"real",
"small",
"money",
"seconds",
"bounded",
"loop",
"query",
"default",
"haiku",
"model",
"prompt",
"cached",
"context",
"plus",
"opus",
"powered",
"offline",
"digest",
"build",
"paid",
"only",
"content",
"changes",
"keyword",
"first",
"class",
"mode",
"keyless",
"deployments",
"fallback",
"afterthought",
"maxiterations",
"calls",
"claude"
]
},
{
"id": "tradeoffs#how-it-compares",
"kind": "section",
"title": "Tradeoffs",
"heading": "How it compares",
"group": "Overview",
"url": "/docs/tradeoffs#how-it-compares",
"summary": "A comparison against Pagefind, Algolia DocSearch, and Orama across retrieval, AI ranking, deep links, and hosting. Choose Pagefind for static keyword simplicity, Algolia for a managed service with a crawler, Orama for client-side vector search, and hev ask when docs live in Astro collections and a reader's question — not just keywords — should 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",
"against",
"pagefind",
"algolia",
"docsearch",
"orama",
"across",
"retrieval",
"ranking",
"deep",
"links",
"hosting",
"choose",
"static",
"keyword",
"simplicity",
"managed",
"service",
"crawler",
"client",
"side",
"vector",
"search",
"docs",
"live",
"astro",
"collections",
"reader",
"question",
"just",
"keywords",
"should",
"find",
"right",
"section",
"tool",
"glossary",
"enter",
"heading"
]
},
{
"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": "Token-overlap retrieval widened by the glossary means nothing to host, nothing to sync, edge-safe, and instant — but paraphrase recall has a ceiling, and the agent grounds only in what retrieval surfaced. Embeddings would do better for token-free phrasing; 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",
"token",
"overlap",
"widened",
"glossary",
"means",
"nothing",
"host",
"sync",
"edge",
"safe",
"instant",
"paraphrase",
"recall",
"ceiling",
"agent",
"grounds",
"only",
"surfaced",
"would",
"better",
"free",
"phrasing",
"upgrade",
"deferred",
"designed",
"dependency",
"vector",
"store",
"upside",
"keep",
"recovers",
"synonym",
"give",
"cost",
"answers",
"well",
"ground"
]
},
{
"id": "tradeoffs#one-dependency-deliberately",
"kind": "section",
"title": "Tradeoffs",
"heading": "One dependency, deliberately",
"group": "Overview",
"url": "/docs/tradeoffs#one-dependency-deliberately",
"summary": "The package keeps close to zero dependencies with one deliberate exception: the same tiny, edge-safe slugger Astro uses. Hand-rolling anchors risks drifting from the renderer and shipping links that 404 to the top of the page; sharing the 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",
"package",
"keeps",
"close",
"zero",
"dependencies",
"deliberate",
"exception",
"same",
"tiny",
"edge",
"safe",
"slugger",
"astro",
"uses",
"hand",
"rolling",
"anchors",
"risks",
"drifting",
"renderer",
"shipping",
"links",
"page",
"sharing",
"guarantees",
"byte",
"identical",
"github",
"aims",
"pure",
"generating",
"heading",
"link",
"404s",
"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": "Running an instant keyword path beside an agentic path keeps the common case instant and keyless while hard questions get a smarter ranker. The cost is a slightly more complex interaction — readers learn that Enter means asking AI — which fits docs, where queries split between jumping to known things and finding the unnameable.",
"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",
"running",
"instant",
"keyword",
"path",
"beside",
"agentic",
"keeps",
"common",
"case",
"keyless",
"while",
"hard",
"questions",
"smarter",
"ranker",
"cost",
"slightly",
"more",
"complex",
"interaction",
"readers",
"learn",
"enter",
"means",
"asking",
"fits",
"docs",
"queries",
"split",
"between",
"jumping",
"known",
"things",
"finding",
"unnameable",
"runs",
"asks",
"reader"
]
}
],
"edges": []
}