// what the agent sees
Knowledge graph
When you press ⌘K and ask a question, the agent doesn't read
these pages — it reads this. It's committed as
.hev-ask/kg.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 turns the site's content collection into a committed knowledge graph — one distilled, source-grounded entry per heading section, plus a glossary — and serves it to humans (an answer overlay) and coding agents (a CLI and MCP server). Core concepts users talk about: - **Knowledge graph (kg.json)**: an offline-built, committed JSON artifact. Nodes hold model-authored summaries and deterministically-extracted verbatim facts; only the distillation is model work, and a content-hash gate skips rebuilds when docs are unchanged. - **Two search paths**: instant keyless keyword search (token overlap widened by the glossary), and an agentic path — a bounded Claude tool-use loop that opens sections from the graph and streams a grounded, deep-linked answer over SSE. - **Deep links**: every result and citation lands on an exact heading anchor, generated with the same slugger Astro uses; a verify command gates anchor drift in CI. - **Degradation**: no API key → keyword mode; no graph → plain token overlap; nothing hard-fails. - **Surfaces**: the Astro integration + SearchOverlay component for readers; the ask CLI, an HTTP read API, and an MCP server for agents. Building the graph can run inside a Claude Code subscription via a bundled skill, costing no API tokens. 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 knowledge graph, how does it compare to Pagefind/Algolia/Orama, what are the limits.
Glossary 24 terms
Aliases that widen a reader's query before retrieval — so k8s finds kubernetes. List the terms; open one for its aliases and definition.
-
knowledge graph
kgkg.jsongraphThe committed JSON artifact distilling every doc section — summaries, verbatim facts, glossary, overview, and suggestions — that both search paths read.
-
agentic search
ask modeAI answeragentic loopanswer loopA bounded Claude tool-use loop that opens knowledge-graph sections, then streams a grounded answer with inline deep links over SSE.
-
keyword search
instant searchkeyless searchtype-aheadThe instant, keyless path: token-overlap scoring over heading chunks, widened by the glossary and ranked by the knowledge graph.
-
chunk
sectionheading chunkA heading-level slice of a doc; each chunk carries its prose and a URL with a real rendered anchor.
-
anchor
deep linkslugheading idThe #fragment generated with the same slugger Astro uses, so links land on the exact rendered heading.
-
SearchOverlay
overlaycommand palettesearch boxcmd-k⌘KThe Astro component rendering the ⌘K palette: keyword results as you type, AI answers on Enter.
-
hash gate
content hashfreshness gateupToDateA sha256 of the chunk text; if the committed graph already matches, builds skip all model work.
-
Claude Code skill
build-kg skillbundled skillsubscription buildThe bundled skill that distils the graph inside a Claude Code subscription, so building costs no API tokens on your own key.
-
MCP server
mcpmodel context protocolA stdio server run by the CLI exposing graph reads, search, and answer as structured tools for coding agents.
-
endpoint
/api/asksearch endpointAPI routeThe on-demand route the integration injects: keyword JSON, agentic SSE, suggestions, and keyless knowledge-graph reads.
-
SSE
server-sent eventsevent streamstreamingThe streaming format of agentic answers: search, sources, token, and done events on one response.
-
degradation
fallbackgraceful degradationdowngradeThe design rule that missing pieces (key, graph, nodes) downgrade behavior — keyword mode, plain ranking — instead of failing.
-
verify
kg verifyanchor checkdrift checkThe CI gate that builds the site and fails if any chunk anchor is missing from the rendered HTML.
-
content collection
collectioncorpusdocs collectionThe Astro collection(s) hev ask indexes — the entire corpus; no crawler and no external pages.
-
suggested questions
suggestionsexample questionsModel-authored questions baked into the graph and shown in the overlay's empty state, served without a model call.
-
source-primary
agent-primarynode modeA node mode marking reference sections the agent reads verbatim from source text rather than from a paraphrase.
-
facts
verbatim factsliteralsDeterministically extracted literals (flags, code, identifiers) on each node, so the agent quotes exact strings without re-reading the page.
-
Pagefind
algoliadocsearchoramaalternativesAlternative docs-search tools hev ask compares itself to; Pagefind is the recommended choice for static keyword-only sites.
-
server adapter
hybrid adapteron-demand renderingprerender falseA Node/Cloudflare/Vercel-style adapter required because the search endpoint renders on demand; static-only builds can't serve it.
-
ANTHROPIC_API_KEY
api keyanthropic keyserver secretThe server-side secret enabling agentic answers and unattended graph builds; never sent to the browser, and optional everywhere.
-
glossary
aliasesquery expansionsynonymsGraph-held terms with aliases that widen keyword queries, so k8s finds kubernetes sections.
-
overview
section mapA deterministic grouped map of every section, injected into the agent's prompt so it knows what it can open.
-
ask CLI
askask binhev-ask-kgcliThe bundled binary: read/search/answer verbs, an MCP server, and producer commands that build and verify the graph.
-
LLM tracing
posthogtelemetryobservabilityOptional PostHog tracing of every agentic answer — model, tokens, latency, tool calls — enabled by an environment key.
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 graph (glossary, sections, overview, search, answer, an MCP server) and producer verbs under the kg group that build and verify it. The old binary name is kept one minor cycle as a deprecated alias that forwards and prints a migration notice.facts · quoted verbatim
@hev/askaskglossarysectionssection getoverviewsearchanswermcpask kgbuildcorpusassembleverifyhev-ask-kgask kg ...Callout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Building the graph referenceProducer commands run from the Astro site root: a one-shot hash-gated build that only calls the model when content changed, plus a corpus/assemble pair exposing the deterministic seam the Claude Code skill uses — the model authors only context, glossary, summaries, and suggestions, while chunking, facts, overview, and the hash are computed in code. Verify builds the site and checks anchors (always fatal on drift), coverage, and literal fidelity (warnings unless strict).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/kg.json from that distillation ask kg verify # build the site and verify anchors, coverage, fidelityask kg build.hev-ask/kg.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 build-kg skill builds the graph without an API key by running the deterministic producer seam — emit corpus, write the distillation inside your Claude Code subscription, assemble. The output has the same shape as a CLI build and the same hash gate applies.facts · quoted verbatim
ask kg corpus -> .hev-ask/kg-input.json ...writes .hev-ask/kg-distill.json... ask kg assemble -> .hev-ask/kg.jsonbuild-kgANTHROPIC_API_KEYkg.jsonask kg buildReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Distribution referenceThe npm package exposes the main CLI bin plus a deprecated alias bin. The launcher resolves an env-var override first, then a platform-specific optional binary package, then the checked-out Go source in the monorepo (a development fallback; published installs use the packaged binary).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: graph path, remote endpoint base URL, JSON output, result caps, collection and base-path and content-glob selection, chunk heading depth, the KG build model, corpus/assemble file paths, and verify's build-command, skip-build, and strict options. Global flags come before the command.facts · quoted verbatim
ask --kg-path .hev-ask/kg.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/kg.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 lets you embed the CLI's behavior: mount a dependency-free command group in your own CLI, or call lower-level helpers for loading the graph, glossary and section reads, search, an endpoint client, building, verifying anchors, and serving MCP.facts · quoted verbatim
group := ask.NewCommandGroup(ask.CommandOptions{ KGPath: ".hev-ask/kg.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/search surface — glossary, sections, overview, search, and answer tools. Configure it with a local graph path for checked-out repos, or a deployed endpoint URL when the agent needs the remote graph or the answer tool.facts · quoted verbatim
{ "mcpServers": { "docs": { "command": "ask", "args": ["--kg-path", ".hev-ask/kg.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 can wire the kg build and verify commands into package scripts. Existing scripts using the deprecated alias keep working, 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 graph referenceBy default the CLI reads the committed graph file in the current repo; an endpoint flag switches reads to a deployed site's HTTP API. The answer verb uses the deployed endpoint's agentic SSE path so it requires the endpoint flag; keyless local retrieval uses the search verb instead.facts · quoted verbatim
ask glossary list ask glossary get "knowledge graph" ask sections list --group API ask section get api/endpoint#knowledge-graph-reads-get ask overview ask search "read endpoints" ask --endpoint https://askhev.com/api/ask answer "what read routes exist?" ask mcpask.hev-ask/kg.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 run locally or in CI with filesystem access; the Astro integration also runs the build during the site build when a key is present, falling back to the committed artifact. The deployed site reads the graph through a virtual module with no filesystem access. Running verify on every build is the mechanical check that generated slugs still match what Astro renders.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 a single options object. Only the collections list is effectively required; every other option 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 integration option: collections to index, the slug-to-URL base path, the endpoint route, loop and KG-build models, result and token and iteration caps, chunk heading depth, per-search candidate and per-document caps, and the knowledge-graph path and content globs. Changing the endpoint route requires passing the same value to the overlay component.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 referenceTuning guidance: chunk depth trades finer anchors against too-small sections; the iteration cap bounds agentic latency; the per-document cap stops one long page from filling results; the per-search candidate count trades 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 configs.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 config setup the integration injects the on-demand endpoint route, registers virtual modules for the resolved config and the inlined knowledge graph, watches the graph file for dev reloads, and warns on an empty collections list. At build start it runs the hash-gated KG build when a key is present, otherwise warns and proceeds with the committed artifact — the build never fails 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 referenceThe integration injects one on-demand route tree. The base route serves the overlay — keyword mode returns JSON, agentic mode streams SSE — and keyless sub-routes expose the committed knowledge graph for CLIs, MCP servers, and generated clients. An OpenAPI 3.1 contract is published on the site.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 present and agentic mode, the endpoint streams named SSE frames: search events for each sub-query or opened section, a single sources event carrying the grounding set before any prose, token events with answer deltas, then done. Errors after streaming begins arrive as an error event since the status is already 200. Sources carry title, optional heading, url, and group — no snippet.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 ↗ - Errors referenceError contract: 400 for invalid JSON bodies, 404 for missing graph-read routes, glossary terms, or section IDs, 500 when the chunk index fails to build, and an SSE error event for failures during an already-started agentic stream.facts · quoted verbatim
400{ "error": "Invalid JSON body." }404{ "error": "…" }500event: error200errore.gReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Index lifecycle referenceThe chunk index is built on the first request per server instance and cached for the process lifetime. The first request also compares the live content hash to the graph's and logs a one-time warning on mismatch — the cue to rebuild the graph.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, deep-link URL, group, snippet) plus the echoed query, the configured model, and the mode that ran. A warning field appears when an agentic request was downgraded for lack of a key. Result URLs carry the section anchor; only a document's intro chunk lacks one.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 ↗ - Knowledge graph reads (GET) referenceKeyless GET sub-routes read the committed graph without any model call: list and fetch glossary entries by term or alias, list section summaries (optionally filtered by group), fetch one full knowledge node by ID, and fetch the overview and context. Section IDs containing slashes or hashes must be URL-encoded in the path; misses return 404 with a JSON error.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 ↗ - LLM tracing referenceSetting a PostHog key in the endpoint's environment makes every agentic answer emit a generation trace — model, tokens, latency, and tool calls. Companion variables override the ingestion host and control how much prompt and answer text ships. Without a key telemetry is a no-op; the answer path never depends on it.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: an empty query returns an empty keyword JSON; explicit keyword mode or a missing key runs keyword; an agentic request without a key downgrades to keyword JSON with a warning; otherwise it streams the agentic SSE. There is no 'AI unavailable' error — 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 referenceThe base route takes a POST with a JSON body holding the query string and an optional mode that forces the instant keyword path or requests the agentic loop; omitting it behaves agentically when a key is present. Empty or whitespace queries return an empty result set.facts · quoted verbatim
{ "query": "how does autoscaling work", "mode": "agentic" }POSTquerystringmode'keyword' \| 'agentic'keywordagenticReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Suggested questions (GET) referenceA GET on the base route returns the graph's baked-in suggested questions and the loop model with no model call. The overlay fetches this once on first open to populate its empty state; an absent or empty list just means no suggestions are shown.facts · quoted verbatim
{ "suggestions": ["How does the knowledge graph 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 (such as Cloudflare's), then the process environment, then the build-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 ↗ - Knowledge graph format referenceThe knowledge graph is a single committed JSON file built offline and inlined into the build through a virtual module, so the running site reads it without filesystem access. It is the agent's distilled, source-grounded 'shadow site': humans read the rendered pages, the loop reads the graph, and every node links back to its real page and anchor. The site renders its own graph at /kg.facts · quoted verbatim
.hev-ask/kg.jsonask kg buildvirtual:hev-ask/kgurl#anchorCallout.astroReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Degradation referenceThe graph is read defensively: missing, malformed, or older node-less artifacts still work — the agentic loop falls back to keyword-style search and keyword mode keeps working. Because it's committed JSON, its deterministic structure is reviewable in pull requests; only the distillation is model-authored, which is what lets the model step move into 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, generation timestamp, the content hash that gates freshness, the orientation context (also the no-nodes fallback), the glossary that widens keyword search, the deterministic overview map injected into the agent's prompt, model-authored suggestions for the overlay, the nodes that form the shadow site, and an edges array reserved for a future node-to-node graph.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 injected into the loop's prompt-cached system prompt; the glossary expands keyword queries with aliases; nodes also lift keyword ranking when a term hits a section's summary, terms, or facts; node terms back a render-time check that downgrades unsupported cited links to plain text; suggestions feed the overlay's empty state; and the content hash lets builds skip the model 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's ID equals its chunk ID so it maps one-to-one to a real anchor. It carries the model's summary the agent reasons from, deterministically extracted verbatim facts the model never authors, provenance back to the source chunk, a mode marking reference sections as source-primary so the agent reads them verbatim, and distinctive terms used by the render-time link-support check.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 running on every build safe because model work is only spent when content actually changed. Build with the bundled Claude Code skill (no API key) or a one-call CLI build, and run verify 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 JSON example of the full graph shape: version, timestamp, content hash, context, glossary entries, the overview map, suggestions, one complete node with facts, sources, mode, and terms, 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 CLI's MCP command runs a stdio Model Context Protocol server over the same graph reads as the CLI and HTTP API — the zero-glue path for coding agents, pointed at either a checked-out repo's graph file or a deployed endpoint.facts · quoted verbatim
ask mcp.hev-ask/kg.json/api/askReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Configure referenceTwo configurations: a local graph path for keyless, fully offline reads in checked-out repos, or a deployed endpoint URL for the freshest remote graph. The answer tool requires the endpoint form and returns a tool error in local mode.facts · quoted verbatim
{ "mcpServers": { "docs": { "command": "ask", "args": ["--kg-path", ".hev-ask/kg.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 referenceThe MCP server resolves data like the CLI: an endpoint flag routes reads to the deployed HTTP API and streams answers through the POST route, otherwise it reads the local graph path. Local reads load the graph on each tool call, so a just-rebuilt graph is visible without restarting the server.facts · quoted verbatim
ask mcp--endpoint <url>answerPOST /api/ask--kg-path.hev-ask/kg.jsonkg.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 tool results flagged as errors. All substantive behavior lives in the shared Go package so the CLI, embeddable command group, and MCP server use the same helpers.facts · quoted verbatim
initializetools/listtools/callisError: truepkg/askReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Tools referenceThe tool set mirrors the read surface: list and fetch glossary entries, list sections optionally by group, fetch one full node, fetch the overview, run keyword search with an optional result cap, and an answer tool that collapses the streamed endpoint answer into one 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. It's added once in a global layout, opens over the page as a dialog, 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 driven: one word runs debounced keyword search with the first result active; a second word switches to ask mode where Enter sends the question to the agentic loop; arrow keys move the active result and Escape closes. Suggested questions appear on open with AI on, and the first can be dropped into the input with Tab. Without a server key, asking returns keyword results with a surfaced warning.facts · quoted verbatim
TabReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Keyword results and deep links referenceEach keyword result row shows the document title, an optional heading breadcrumb, and a one-line snippet. The row links to the chunk's URL, which already carries the 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 keyboard shortcut is bound automatically once the component is on the page, and any element carrying the opener data attribute opens it on click, so you can wire as many triggers as you like.facts · quoted verbatim
<button type="button" data-hev-ask-open> Search <kbd>⌘K</kbd> </button> <a href="#" data-hev-ask-open>Search the docs</a>⌘KCtrl-Kdata-hev-ask-openReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Props referenceThree props: the endpoint the overlay posts to (which must match the integration's endpoint option), the input placeholder text, and the debounce delay before a keyword query is sent.facts · quoted verbatim
<SearchOverlay endpoint="/api/ask" placeholder="Search hev ask…" debounce={400} />endpointstring'/api/ask'placeholder'Search the docs…'debouncenumber500Reference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Suggested questions referenceWith AI on, the overlay fetches suggested questions from the endpoint once on first open and shows them in the empty state. They come from the graph's baked-in suggestions so no model call is needed; clicking one fills the input and asks immediately, and a graph without them just shows nothing extra.facts · quoted verbatim
GET /api/asksuggestionsReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - The mode toggle referenceThe overlay persists an AI-on-Enter preference in localStorage. Readers who flip it to keyword-only never trigger a model call — a space just searches a phrase and no suggested questions show — and the choice survives reloads.facts · quoted verbatim
localStoragehev-ask:modeagentickeywordReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - The streamed answer referencePressing Enter replaces the keyword rows with an answer panel: the model's sub-queries appear live as a faint activity line, then the grounded answer streams in with a blinking caret. Inline deep links point at exact section anchors with hover breadcrumbs, a Sources chip row lists every grounding section, and any link outside the streamed source set renders as plain text so a hallucinated anchor can never become a clickable dead link.facts · quoted verbatim
searched: …/docs/page#anchorReference section — on open, the agent also receives this section's source text verbatim.
open section ↗ - Theming referenceThe overlay reads the page's CSS custom properties for background, text, muted, and accent colors, and ships scoped styles keyed to those variables — matching your site's look is usually just defining the tokens, with 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, a bounded agentic loop that navigates a knowledge graph, and that offline graph — a distilled, source-grounded shadow site. The split that matters: the graph is built offline with a strong model and committed to git, while the index and loop run on demand at the edge with no durable state in the running site.
- Asking is the default summaryThe overlay is ask-first: one word is an instant keyword lookup, and the moment a query grows past one word it switches to ask mode where Enter sends the question to the agentic loop. Suggested questions baked into the graph appear on open to make asking the obvious move, and readers can flip to keyword-only, persisted across reloads, so the model is never called.
- Chunks and anchors summaryDocuments are split on headings to a configurable depth rather than indexed as pages, with pre-heading content becoming an intro chunk. Anchors are generated with the same slugger Astro's renderer uses, so section links land on headings that actually exist. Both the runtime index and the offline build chunk through one shared function, so their slugs always agree.facts · quoted verbatimopen section ↗
#####basePath + slug + #anchorgithub-sluggergetCollectiongithub.com - Degradation, by design summaryEvery missing piece downgrades instead of failing: no runtime key means keyword-only; no key at build keeps the committed graph with a warning; a missing or node-less graph drops the loop to keyword-style retrieval and ranking to raw token overlap; a stale graph logs a one-line hash-mismatch warning but still serves.
- Keyword search and the glossary summaryThe instant path is a dependency-free prefilter: expand each query term with its glossary aliases, score chunks by token overlap — counting hits against a section's graph summary, terms, and facts so central sections outrank incidental mentions — cap results per document, and excerpt around the first match. It needs no key and no embeddings, and without a graph it degrades to plain token overlap.
- The agentic search loop summaryAsking runs a bounded two-phase tool-use loop. In the gather phase the model gets a map of every section up front plus one tool that opens a section's summary, verbatim facts, and (for reference sections) source text, bounded by an iteration cap. In the answer phase the accumulated sources go to the overlay and the model is called once more with no tools, so it can only write prose — grounded in opened sections, linking only to provided URLs.
- The knowledge graph summaryThe graph is built offline and committed as a reviewable artifact: distilled per-heading nodes with verbatim facts and source links, a deterministic overview map, an orientation context and alias glossary, and suggested questions. Only the distillation is model-authored; structure, facts, overview, and the hash are derived in code — which is exactly why the model step fits in a Claude Code skill.facts · quoted verbatimopen section ↗
kg.jsonnodessummaryfactssourcesource-primaryoverviewcontextglossarysuggestions - The system prompt is cached summaryThe graph's map and summaries are injected into the system prompt with a cache marker, so across search rounds they're a prompt-cache hit rather than re-sent tokens. The final answer turn changes the tool set so it can't reuse that cache, but it's the last call anyway. The loop model defaults to Claude Haiku 4.5 and is configurable.
- Two ways to build it summaryThe model step runs two ways feeding the same deterministic assembler: the recommended Claude Code skill, which distils inside your existing subscription with no API key or per-build token spend, or a one-call CLI build with an API key for CI and non-Claude-Code users. Both are hash-gated so unchanged content does no model work, and the JSON is reviewed in pull requests.
- Introduction summaryhev ask turns an Astro docs site into a small knowledge graph — one distilled, source-grounded entry per heading section plus a glossary — and serves it to whoever needs the docs: a human pressing ⌘K or a coding agent in the repo. The graph is built offline and committed as reviewable JSON, the single source everything else reads.
- Build it with your coding agent summaryThe bundled Claude Code skill generates the graph inside your 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 content collections: no crawler, no external index, nothing to keep in sync.
- Next steps summaryA map of where to go next: the quick start for five-minute setup, Concepts for how it works, Tradeoffs and Limits for what you're choosing and what it deliberately doesn't do, and the CLI and API reference for the full surface.
- Who this is for summaryFor maintainers of Astro 5 docs sites with content in collections who want search that works without standing up a service, deep-links to the right section, answers questions in the reader's own words, and is queryable by coding agents. If you only need keyword search on a static site with no key, Pagefind is simpler and a great fit.
- Limits summaryThe hard boundaries to know before adopting: corpus scope, recall ceiling, single-call graph build, frontmatter parsing, latency, and adapter requirements. None are bugs — they're the edges of the current design.
- A server route is required summaryThe search endpoint renders on demand, so a fully static build can't serve search — you need a server or hybrid adapter. Static-only sites should use a static search tool instead.
- Agentic search adds latency summaryThe agentic path is bounded by the iteration cap of Claude round-trips — worst case a few seconds, not instant by nature. The keyword path is the always-available instant lane; lower the iteration cap for a tighter ceiling.
- Anchors depend on Astro's slugger summaryDeep links stay correct only while generated heading slugs match Astro's rendered IDs. hev ask uses the same slugger to stay aligned and ships a verify command that fails when any chunk anchor is missing from 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 handling common string and number fields; nested structures aren't supported at build time. This only affects the offline graph build reading from disk — the runtime index uses Astro's own collection loading, which honors the real schema.
- Recall has a keyword ceiling summaryRetrieval is keyword token-overlap widened by the glossary, not embeddings, and the loop can't ground in what retrieval missed. The glossary recovers most synonym cases, but a query sharing no tokens with the docs may never surface the right section. Embeddings are the known fix and deliberately not built yet; a richer glossary is the cheaper lever until analytics show consistent misses.
- Secrets live server-side summaryThe agentic path needs the Anthropic key in the server environment running the endpoint; it's never exposed to the browser. Without it the endpoint serves keyword results — search degrades, it doesn't break.
- The corpus is your content collection summaryhev ask searches only the configured Astro content collections — no crawler, no sitemap ingestion, no way to index non-collection pages like hand-written Astro files. Put what you want searchable in a collection.
- The knowledge-graph build is a single model call summaryThe offline build sends the full cleaned corpus to the model in one call, which fits comfortably for typical docs sites of dozens of pages but would exceed a single context window for a very large corpus. A map-reduce builder is noted as a follow-up but not implemented.no verbatim facts in this section open section ↗
- Quick start summaryAdd search to an existing Astro 5 docs site in about five minutes: keyword search works first, keyless; adding a server-side Anthropic key turns on Claude-powered agentic answers on Enter. Skipping the key just ships the search UI.facts · quoted verbatimopen section ↗
src/content/docsANTHROPIC_API_KEYSearchOverlay.astroSteps.astroCallout.astro - 1. Install summaryInstall the package from npm once published, or until then consume it straight from the package subdirectory of the GitHub repo.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 your content collection name(s) and the slug-to-URL base path. The collections list is the one required option; everything else defaults.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 whichever server adapter matches your host — existing pages stay prerendered and only the search route runs as a function. The docs site itself uses Cloudflare.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 data attribute opens the palette and the keyboard shortcut binds automatically — keyword search then works in dev immediately.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 knowledge graph summaryBuild the committed graph that gives the loop context, ranks keyword results, supplies the glossary, and holds suggested questions. Recommended: the bundled Claude Code skill, which builds inside your subscription with no API key; or one CLI call for CI. Then verify anchors and commit the JSON — both paths are hash-gated and the integration also builds automatically when a key is present.facts · quoted verbatimopen section ↗
You: build the hev ask knowledge graph Claude runs: ask kg corpus # emits the sections to distil …writes context/glossary/summaries/suggestions… ask kg assemble # writes .hev-ask/kg.jsonexport ANTHROPIC_API_KEY=sk-ant-... pnpm exec ask kg build # writes .hev-ask/kg.jsonpnpm exec ask kg verify # builds the site, checks every anchor resolves git add .hev-ask/kg.jsonk8skubernetesastro buildclaude.com - Enable agentic search summarySet the Anthropic key in the server environment where the search route runs. With it, Enter runs the agentic loop with sub-queries, a grounded answer, and inline deep links; without it, Enter returns keyword results.
- Prerequisites summaryYou need Astro 5 with at least one content collection, a server or hybrid adapter because the search route renders on demand, and an Anthropic key only if you want agentic search — keyword search needs none.
- Set up keyword search summaryThe keyword-search setup phase: the steps that follow install the package, register the integration, add an adapter, and render the overlay.
- Verify it works summaryThree checks: a single heading word should deep-link its top keyword result to that section; a multi-word question on Enter should show the model's sub-queries and stream a grounded answer; and the verify command exits non-zero if any chunk anchor is missing from built HTML — wire it into CI.
- Tradeoffs summaryEvery search tool makes choices; this page is the honest version of what hev ask trades away to get what it gives — dependency posture, the committed graph, agentic cost and latency, and comparisons to Pagefind, Algolia, and Orama.
- A committed knowledge graph summaryThe graph is generated offline and committed as JSON rather than computed at runtime or hidden in a service: reviewable in pull requests, deterministic, free to read, and bundled into the edge worker. The cost is staleness — a forgotten rebuild means a slightly outdated glossary — so the hash gate makes 'rebuild on every content change in CI' the intended, cheap, idempotent workflow.no verbatim facts in this section open section ↗
- Cost and latency of agentic search summaryThe agentic path costs real if small money and latency: worst case a few seconds of Haiku round-trips bounded by the iteration cap, one bounded loop per submitted query with the domain context prompt-cached, and an Opus-powered offline graph build paid only when content changes. Keyword-only is a first-class mode for anyone who doesn't want a key in the loop.
- How it compares summaryA comparison table against Pagefind, Algolia DocSearch, and Orama across retrieval, AI ranking, deep links, and hosting. Choose Pagefind for static keyword search with zero services; Algolia for a managed crawler-based service; Orama for client-side vector search; hev ask when docs are Astro collections and you want section deep links plus answers to questions, not just keywords.no verbatim facts in this section open section ↗
- Keyword retrieval, not embeddings summaryRetrieval is dependency-free token overlap widened by the glossary — nothing to host, edge-safe, instant — and the glossary recovers much of the synonym recall embeddings would give. The cost is a paraphrase-recall ceiling: the agent can only ground in what keyword retrieval surfaced. The embeddings upgrade is deferred, not designed out.no verbatim facts in this section open section ↗
- One dependency, deliberately summaryThe package aims for near-zero dependencies with one deliberate exception: the same small, pure-JS, edge-safe slugger Astro uses, because hand-generating anchors risks drifting from the renderer and shipping links that land at the top of the page.
- Two paths instead of one summaryRunning an instant keyword path and an agentic path keeps the common one-or-two-word case instant and keyless while hard questions get a smarter ranker. The cost is a slightly more complex interaction model — readers learn that Enter means ask AI — a trade that fits docs, where queries split into jumping to a known thing and finding a thing you can't name.no verbatim facts in this section open section ↗
Raw kg.json artifact
{
"version": 2,
"generatedAt": "2026-06-04T13:27:10.834Z",
"contentHash": "be65bde22082559f5237a931ad2c64a5e455d204f6355592d63432926556b95d",
"context": "## hev ask\n\nhev ask (`@hev/ask`) is a ⌘K search overlay for Astro docs sites. It turns the site's content collection into a committed knowledge graph — one distilled, source-grounded entry per heading section, plus a glossary — and serves it to humans (an answer overlay) and coding agents (a CLI and MCP server).\n\nCore concepts users talk about:\n- **Knowledge graph (kg.json)**: an offline-built, committed JSON artifact. Nodes hold model-authored summaries and deterministically-extracted verbatim facts; only the distillation is model work, and a content-hash gate skips rebuilds when docs are unchanged.\n- **Two search paths**: instant keyless keyword search (token overlap widened by the glossary), and an agentic path — a bounded Claude tool-use loop that opens sections from the graph and streams a grounded, deep-linked answer over SSE.\n- **Deep links**: every result and citation lands on an exact heading anchor, generated with the same slugger Astro uses; a verify command gates anchor drift in CI.\n- **Degradation**: no API key → keyword mode; no graph → plain token overlap; nothing hard-fails.\n- **Surfaces**: the Astro integration + SearchOverlay component for readers; the ask CLI, an HTTP read API, and an MCP server for agents. Building the graph can run inside a Claude Code subscription via a bundled skill, costing no API tokens.\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 knowledge graph, how does it compare to Pagefind/Algolia/Orama, what are the limits.",
"glossary": [
{
"term": "knowledge graph",
"aliases": [
"kg",
"kg.json",
"graph"
],
"definition": "The committed JSON artifact distilling every doc section — summaries, verbatim facts, glossary, overview, and suggestions — that both search paths read."
},
{
"term": "agentic search",
"aliases": [
"ask mode",
"AI answer",
"agentic loop",
"answer loop"
],
"definition": "A bounded Claude tool-use loop that opens knowledge-graph sections, then streams a grounded answer with inline deep links over SSE."
},
{
"term": "keyword search",
"aliases": [
"instant search",
"keyless search",
"type-ahead"
],
"definition": "The instant, keyless path: token-overlap scoring over heading chunks, widened by the glossary and ranked by the knowledge graph."
},
{
"term": "chunk",
"aliases": [
"section",
"heading chunk"
],
"definition": "A heading-level slice of a doc; each chunk carries its prose and a URL with a real rendered anchor."
},
{
"term": "anchor",
"aliases": [
"deep link",
"slug",
"heading id"
],
"definition": "The #fragment generated with the same slugger Astro uses, so links land on the exact rendered heading."
},
{
"term": "SearchOverlay",
"aliases": [
"overlay",
"command palette",
"search box",
"cmd-k",
"⌘K"
],
"definition": "The Astro component rendering the ⌘K palette: keyword results as you type, AI answers on Enter."
},
{
"term": "hash gate",
"aliases": [
"content hash",
"freshness gate",
"upToDate"
],
"definition": "A sha256 of the chunk text; if the committed graph already matches, builds skip all model work."
},
{
"term": "Claude Code skill",
"aliases": [
"build-kg skill",
"bundled skill",
"subscription build"
],
"definition": "The bundled skill that distils the graph inside a Claude Code subscription, so building costs no API tokens on your own key."
},
{
"term": "MCP server",
"aliases": [
"mcp",
"model context protocol"
],
"definition": "A stdio server run by the CLI exposing graph reads, search, and answer as structured tools for coding agents."
},
{
"term": "endpoint",
"aliases": [
"/api/ask",
"search endpoint",
"API route"
],
"definition": "The on-demand route the integration injects: keyword JSON, agentic SSE, suggestions, and keyless knowledge-graph reads."
},
{
"term": "SSE",
"aliases": [
"server-sent events",
"event stream",
"streaming"
],
"definition": "The streaming format of agentic answers: search, sources, token, and done events on one response."
},
{
"term": "degradation",
"aliases": [
"fallback",
"graceful degradation",
"downgrade"
],
"definition": "The design rule that missing pieces (key, graph, nodes) downgrade behavior — keyword mode, plain ranking — instead of failing."
},
{
"term": "verify",
"aliases": [
"kg verify",
"anchor check",
"drift check"
],
"definition": "The CI gate that builds the site and fails if any chunk anchor is missing from the rendered HTML."
},
{
"term": "content collection",
"aliases": [
"collection",
"corpus",
"docs collection"
],
"definition": "The Astro collection(s) hev ask indexes — the entire corpus; no crawler and no external pages."
},
{
"term": "suggested questions",
"aliases": [
"suggestions",
"example questions"
],
"definition": "Model-authored questions baked into the graph and shown in the overlay's empty state, served without a model call."
},
{
"term": "source-primary",
"aliases": [
"agent-primary",
"node mode"
],
"definition": "A node mode marking reference sections the agent reads verbatim from source text rather than from a paraphrase."
},
{
"term": "facts",
"aliases": [
"verbatim facts",
"literals"
],
"definition": "Deterministically extracted literals (flags, code, identifiers) on each node, so the agent quotes exact strings without re-reading the page."
},
{
"term": "Pagefind",
"aliases": [
"algolia",
"docsearch",
"orama",
"alternatives"
],
"definition": "Alternative docs-search tools hev ask compares itself to; Pagefind is the recommended choice for static keyword-only sites."
},
{
"term": "server adapter",
"aliases": [
"hybrid adapter",
"on-demand rendering",
"prerender false"
],
"definition": "A Node/Cloudflare/Vercel-style adapter required because the search endpoint renders on demand; static-only builds can't serve it."
},
{
"term": "ANTHROPIC_API_KEY",
"aliases": [
"api key",
"anthropic key",
"server secret"
],
"definition": "The server-side secret enabling agentic answers and unattended graph builds; never sent to the browser, and optional everywhere."
},
{
"term": "glossary",
"aliases": [
"aliases",
"query expansion",
"synonyms"
],
"definition": "Graph-held terms with aliases that widen keyword queries, so k8s finds kubernetes sections."
},
{
"term": "overview",
"aliases": [
"section map"
],
"definition": "A deterministic grouped map of every section, injected into the agent's prompt so it knows what it can open."
},
{
"term": "ask CLI",
"aliases": [
"ask",
"ask bin",
"hev-ask-kg",
"cli"
],
"definition": "The bundled binary: read/search/answer verbs, an MCP server, and producer commands that build and verify the graph."
},
{
"term": "LLM tracing",
"aliases": [
"posthog",
"telemetry",
"observability"
],
"definition": "Optional PostHog tracing of every agentic answer — model, tokens, latency, tool calls — enabled by an environment key."
}
],
"overview": "## API\n- CLI — `api/cli`\n- Building the graph — `api/cli#building-the-graph`\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 graph — `api/cli#reading-the-graph`\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- Errors — `api/endpoint#errors`\n- Index lifecycle — `api/endpoint#index-lifecycle`\n- Keyword response (JSON) — `api/endpoint#keyword-response-json`\n- Knowledge graph reads (GET) — `api/endpoint#knowledge-graph-reads-get`\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- Knowledge graph 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 knowledge graph — `concepts#the-knowledge-graph`\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 knowledge-graph build is a single model call — `limits#the-knowledge-graph-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 knowledge graph — `quickstart#5-build-the-knowledge-graph`\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 knowledge graph — `tradeoffs#a-committed-knowledge-graph`\n- Cost and latency of agentic search — `tradeoffs#cost-and-latency-of-agentic-search`\n- How it compares — `tradeoffs#how-it-compares`\n- Keyword retrieval, not embeddings — `tradeoffs#keyword-retrieval-not-embeddings`\n- One dependency, deliberately — `tradeoffs#one-dependency-deliberately`\n- Two paths instead of one — `tradeoffs#two-paths-instead-of-one`",
"suggestions": [
"How do I add hev ask to my Astro site?",
"What happens if I don't set an API key?",
"How does the knowledge graph stay up to date?",
"How is hev ask different from Pagefind or Algolia?",
"Can my coding agent query the docs through MCP?"
],
"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 graph (glossary, sections, overview, search, answer, an MCP server) and producer verbs under the kg group that build and verify it. The old binary name is kept one minor cycle as a deprecated alias that forwards and prints a migration notice.",
"facts": [
{
"kind": "code",
"literal": "@hev/ask",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "ask",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "sections",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "section get",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "api/cli"
},
{
"kind": "code",
"literal": "search",
"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": "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",
"graph",
"glossary",
"sections",
"overview",
"search",
"answer",
"server",
"producer",
"under",
"group",
"build",
"verify",
"name",
"kept",
"minor",
"cycle",
"deprecated",
"alias",
"forwards",
"prints",
"migration",
"notice",
"section",
"corpus",
"assemble",
"callout",
"astro",
"reads",
"builds",
"verifies",
"serves",
"knowledge",
"agents"
]
},
{
"id": "api/cli#building-the-graph",
"kind": "section",
"title": "CLI",
"heading": "Building the graph",
"group": "API",
"url": "/docs/api/cli#building-the-graph",
"summary": "Producer commands run from the Astro site root: a one-shot hash-gated build that only calls the model when content changed, plus a corpus/assemble pair exposing the deterministic seam the Claude Code skill uses — the model authors only context, glossary, summaries, and suggestions, while chunking, facts, overview, and the hash are computed in code. Verify builds the site and checks anchors (always fatal on drift), coverage, and literal fidelity (warnings unless strict).",
"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/kg.json from that distillation\nask kg verify # build the site and verify anchors, coverage, fidelity",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "ask kg build",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": ".hev-ask/kg.json",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "ask kg corpus",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": ".hev-ask/kg-input.json",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "ask kg assemble",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": ".hev-ask/kg-distill.json",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "context",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "summaries",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "ask kg verify",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "--skip-build",
"chunkId": "api/cli#building-the-graph"
},
{
"kind": "code",
"literal": "--strict",
"chunkId": "api/cli#building-the-graph"
}
],
"sources": [
{
"chunkId": "api/cli#building-the-graph",
"url": "/docs/api/cli#building-the-graph",
"anchor": "building-the-graph"
}
],
"mode": "source-primary",
"terms": [
"building",
"graph",
"producer",
"commands",
"astro",
"site",
"root",
"shot",
"hash",
"gated",
"build",
"only",
"calls",
"model",
"content",
"changed",
"plus",
"corpus",
"assemble",
"pair",
"exposing",
"deterministic",
"seam",
"claude",
"code",
"skill",
"uses",
"authors",
"context",
"glossary",
"summaries",
"suggestions",
"while",
"chunking",
"facts",
"overview",
"computed",
"verify",
"builds",
"checks"
]
},
{
"id": "api/cli#claude-code-skill",
"kind": "section",
"title": "CLI",
"heading": "Claude Code skill",
"group": "API",
"url": "/docs/api/cli#claude-code-skill",
"summary": "The bundled build-kg skill builds the graph without an API key by running the deterministic producer seam — emit corpus, write the distillation inside your Claude Code subscription, assemble. The output has the same shape as a CLI build and the same hash gate applies.",
"facts": [
{
"kind": "code",
"literal": "ask kg corpus -> .hev-ask/kg-input.json\n...writes .hev-ask/kg-distill.json...\nask kg assemble -> .hev-ask/kg.json",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "build-kg",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "ANTHROPIC_API_KEY",
"chunkId": "api/cli#claude-code-skill"
},
{
"kind": "code",
"literal": "kg.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",
"build",
"builds",
"graph",
"without",
"running",
"deterministic",
"producer",
"seam",
"emit",
"corpus",
"write",
"distillation",
"inside",
"subscription",
"assemble",
"output",
"same",
"shape",
"hash",
"gate",
"applies",
"input",
"json",
"writes",
"distill",
"anthropic",
"anthropicapikey",
"runs",
"because",
"model",
"step",
"costs",
"tokens",
"resulting"
]
},
{
"id": "api/cli#distribution",
"kind": "section",
"title": "CLI",
"heading": "Distribution",
"group": "API",
"url": "/docs/api/cli#distribution",
"summary": "The npm package exposes the main CLI bin plus a deprecated alias bin. The launcher resolves an env-var override first, then a platform-specific optional binary package, then the checked-out Go source in the monorepo (a development fallback; published installs use the packaged binary).",
"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",
"exposes",
"main",
"plus",
"deprecated",
"alias",
"launcher",
"resolves",
"override",
"first",
"platform",
"specific",
"optional",
"binary",
"checked",
"source",
"monorepo",
"development",
"fallback",
"published",
"installs",
"packaged",
"bins",
"purpose",
"forwards",
"hevaskbinary",
"installed",
"path"
]
},
{
"id": "api/cli#flags",
"kind": "section",
"title": "CLI",
"heading": "Flags",
"group": "API",
"url": "/docs/api/cli#flags",
"summary": "Reference table of global flags: graph path, remote endpoint base URL, JSON output, result caps, collection and base-path and content-glob selection, chunk heading depth, the KG build model, corpus/assemble file paths, and verify's build-command, skip-build, and strict options. Global flags come before the command.",
"facts": [
{
"kind": "code",
"literal": "ask --kg-path .hev-ask/kg.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/kg.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",
"graph",
"path",
"remote",
"endpoint",
"base",
"json",
"output",
"result",
"caps",
"collection",
"content",
"glob",
"selection",
"chunk",
"heading",
"depth",
"build",
"model",
"corpus",
"assemble",
"file",
"paths",
"verify",
"command",
"skip",
"strict",
"options",
"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 lets you embed the CLI's behavior: mount a dependency-free command group in your own CLI, or call lower-level helpers for loading the graph, glossary and section reads, search, an endpoint client, building, verifying anchors, and serving MCP.",
"facts": [
{
"kind": "code",
"literal": "group := ask.NewCommandGroup(ask.CommandOptions{\n\tKGPath: \".hev-ask/kg.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",
"lets",
"embed",
"behavior",
"mount",
"dependency",
"free",
"command",
"group",
"call",
"lower",
"level",
"helpers",
"loading",
"graph",
"glossary",
"section",
"reads",
"search",
"endpoint",
"client",
"building",
"verifying",
"anchors",
"serving",
"newcommandgroup",
"commandoptions",
"kgpath",
"json",
"string",
"read",
"endpoints",
"stdin",
"stdout",
"stderr",
"loadgraph",
"listglossary",
"getsection",
"searchgraph"
]
},
{
"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/search surface — glossary, sections, overview, search, and answer tools. Configure it with a local graph path for checked-out repos, or a deployed endpoint URL when the agent needs the remote graph or the answer tool.",
"facts": [
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"docs\": {\n \"command\": \"ask\",\n \"args\": [\"--kg-path\", \".hev-ask/kg.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",
"glossary",
"sections",
"overview",
"answer",
"tools",
"configure",
"local",
"graph",
"path",
"checked",
"repos",
"deployed",
"endpoint",
"agent",
"needs",
"remote",
"tool",
"mcpservers",
"docs",
"command",
"args",
"json",
"askhev",
"https",
"list",
"section",
"glossarylist",
"glossaryget",
"sectionslist",
"sectionget",
"reads",
"page",
"schemas"
]
},
{
"id": "api/cli#package-scripts",
"kind": "section",
"title": "CLI",
"heading": "Package scripts",
"group": "API",
"url": "/docs/api/cli#package-scripts",
"summary": "Sites can wire the kg build and verify commands into package scripts. Existing scripts using the deprecated alias keep working, 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",
"wire",
"build",
"verify",
"commands",
"existing",
"deprecated",
"alias",
"keep",
"working",
"should",
"command",
"group",
"site",
"call",
"through"
]
},
{
"id": "api/cli#reading-the-graph",
"kind": "section",
"title": "CLI",
"heading": "Reading the graph",
"group": "API",
"url": "/docs/api/cli#reading-the-graph",
"summary": "By default the CLI reads the committed graph file in the current repo; an endpoint flag switches reads to a deployed site's HTTP API. The answer verb uses the deployed endpoint's agentic SSE path so it requires the endpoint flag; keyless local retrieval uses the search verb instead.",
"facts": [
{
"kind": "code",
"literal": "ask glossary list\nask glossary get \"knowledge graph\"\nask sections list --group API\nask section get api/endpoint#knowledge-graph-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-graph"
},
{
"kind": "code",
"literal": "ask",
"chunkId": "api/cli#reading-the-graph"
},
{
"kind": "code",
"literal": ".hev-ask/kg.json",
"chunkId": "api/cli#reading-the-graph"
},
{
"kind": "code",
"literal": "--endpoint <url>",
"chunkId": "api/cli#reading-the-graph"
},
{
"kind": "code",
"literal": "ask answer",
"chunkId": "api/cli#reading-the-graph"
},
{
"kind": "code",
"literal": "--endpoint",
"chunkId": "api/cli#reading-the-graph"
},
{
"kind": "code",
"literal": "ask search",
"chunkId": "api/cli#reading-the-graph"
}
],
"sources": [
{
"chunkId": "api/cli#reading-the-graph",
"url": "/docs/api/cli#reading-the-graph",
"anchor": "reading-the-graph"
}
],
"mode": "source-primary",
"terms": [
"reading",
"graph",
"default",
"reads",
"committed",
"file",
"current",
"repo",
"endpoint",
"flag",
"switches",
"deployed",
"site",
"http",
"answer",
"verb",
"uses",
"agentic",
"path",
"requires",
"keyless",
"local",
"retrieval",
"search",
"instead",
"glossary",
"list",
"knowledge",
"sections",
"group",
"section",
"overview",
"read",
"endpoints",
"https",
"askhev",
"routes",
"exist",
"json",
"pass"
]
},
{
"id": "api/cli#where-it-runs",
"kind": "section",
"title": "CLI",
"heading": "Where it runs",
"group": "API",
"url": "/docs/api/cli#where-it-runs",
"summary": "Producer commands run locally or in CI with filesystem access; the Astro integration also runs the build during the site build when a key is present, falling back to the committed artifact. The deployed site reads the graph through a virtual module with no filesystem access. Running verify on every build is the mechanical check that generated slugs still match what Astro renders.",
"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",
"locally",
"filesystem",
"access",
"astro",
"integration",
"also",
"build",
"during",
"site",
"present",
"falling",
"back",
"committed",
"artifact",
"deployed",
"reads",
"graph",
"through",
"virtual",
"module",
"running",
"verify",
"every",
"mechanical",
"check",
"generated",
"slugs",
"still",
"match",
"renders",
"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 a single options object. Only the collections list is effectively required; every other option 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",
"single",
"options",
"object",
"only",
"collections",
"list",
"effectively",
"required",
"every",
"other",
"option",
"astro",
"config",
"import",
"hevask",
"defineconfig",
"integrations",
"docs",
"basepath",
"model",
"claude",
"haiku",
"maxresults",
"callout",
"models",
"endpoint",
"chunking",
"depth",
"retrieval",
"caps",
"knowledge",
"graph",
"paths",
"defaults",
"everything"
]
},
{
"id": "api/configuration#options",
"kind": "section",
"title": "Configuration",
"heading": "Options",
"group": "API",
"url": "/docs/api/configuration#options",
"summary": "Reference table of every integration option: collections to index, the slug-to-URL base path, the endpoint route, loop and KG-build models, result and token and iteration caps, chunk heading depth, per-search candidate and per-document caps, and the knowledge-graph path and content globs. Changing the endpoint route requires passing the same value to the overlay component.",
"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",
"integration",
"option",
"collections",
"index",
"slug",
"base",
"path",
"endpoint",
"route",
"loop",
"build",
"models",
"result",
"token",
"iteration",
"caps",
"chunk",
"heading",
"depth",
"search",
"candidate",
"document",
"knowledge",
"graph",
"content",
"globs",
"changing",
"requires",
"passing",
"same",
"value",
"overlay",
"component",
"string",
"basepath",
"docs"
]
},
{
"id": "api/configuration#tuning-notes",
"kind": "section",
"title": "Configuration",
"heading": "Tuning notes",
"group": "API",
"url": "/docs/api/configuration#tuning-notes",
"summary": "Tuning guidance: chunk depth trades finer anchors against too-small sections; the iteration cap bounds agentic latency; the per-document cap stops one long page from filling results; the per-search candidate count trades 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",
"guidance",
"chunk",
"depth",
"trades",
"finer",
"anchors",
"against",
"small",
"sections",
"iteration",
"bounds",
"agentic",
"latency",
"document",
"stops",
"long",
"page",
"filling",
"results",
"search",
"candidate",
"count",
"recall",
"tokens",
"chunkheadingdepth",
"maxiterations",
"perdoccap",
"candidatepersearch",
"granularity",
"raise",
"default",
"section",
"pages",
"drop",
"stand",
"alone",
"lower",
"round"
]
},
{
"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 configs.",
"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",
"configs",
"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 config setup the integration injects the on-demand endpoint route, registers virtual modules for the resolved config and the inlined knowledge graph, watches the graph file for dev reloads, and warns on an empty collections list. At build start it runs the hash-gated KG build when a key is present, otherwise warns and proceeds with the committed artifact — the build never fails 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",
"config",
"setup",
"injects",
"demand",
"endpoint",
"route",
"registers",
"virtual",
"modules",
"resolved",
"inlined",
"knowledge",
"graph",
"watches",
"file",
"reloads",
"warns",
"empty",
"collections",
"list",
"build",
"start",
"runs",
"hash",
"gated",
"present",
"otherwise",
"proceeds",
"committed",
"artifact",
"never",
"fails",
"lack",
"astro",
"prerender",
"false",
"kgpath",
"anthropic"
]
},
{
"id": "api/endpoint",
"kind": "section",
"title": "Search endpoint",
"heading": null,
"group": "API",
"url": "/docs/api/endpoint",
"summary": "The integration injects one on-demand route tree. The base route serves the overlay — keyword mode returns JSON, agentic mode streams SSE — and keyless sub-routes expose the committed knowledge graph for CLIs, MCP servers, and generated clients. An OpenAPI 3.1 contract is published on the site.",
"facts": [
{
"kind": "code",
"literal": "/api/ask",
"chunkId": "api/endpoint"
},
{
"kind": "code",
"literal": "text/event-stream",
"chunkId": "api/endpoint"
},
{
"kind": "code",
"literal": "/openapi.yaml",
"chunkId": "api/endpoint"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "api/endpoint"
},
{
"kind": "value",
"literal": "3.1",
"chunkId": "api/endpoint"
},
{
"kind": "value",
"literal": "openapi.yaml",
"chunkId": "api/endpoint"
}
],
"sources": [
{
"chunkId": "api/endpoint",
"url": "/docs/api/endpoint",
"anchor": null
}
],
"mode": "source-primary",
"terms": [
"integration",
"injects",
"demand",
"route",
"tree",
"base",
"serves",
"overlay",
"keyword",
"mode",
"returns",
"json",
"agentic",
"streams",
"keyless",
"routes",
"expose",
"committed",
"knowledge",
"graph",
"clis",
"servers",
"generated",
"clients",
"openapi",
"contract",
"published",
"site",
"text",
"event",
"stream",
"yaml",
"callout",
"astro",
"suggestions",
"reads",
"selection",
"error",
"responses",
"default"
]
},
{
"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 present and agentic mode, the endpoint streams named SSE frames: search events for each sub-query or opened section, a single sources event carrying the grounding set before any prose, token events with answer deltas, then done. Errors after streaming begins arrive as an error event since the status is already 200. Sources carry title, optional heading, url, and group — no snippet.",
"facts": [
{
"kind": "code",
"literal": "mode",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "agentic",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "content-type: text/event-stream",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "search",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ query }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "sources",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ sources: Source[], model, mode }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "token",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ text }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "done",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{}",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "error",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ error }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "200",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "Source",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "{ title, heading?, url, group? }",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "snippet",
"chunkId": "api/endpoint#agentic-response-sse"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/endpoint#agentic-response-sse"
}
],
"sources": [
{
"chunkId": "api/endpoint#agentic-response-sse",
"url": "/docs/api/endpoint#agentic-response-sse",
"anchor": "agentic-response-sse"
}
],
"mode": "source-primary",
"terms": [
"agentic",
"response",
"present",
"mode",
"endpoint",
"streams",
"named",
"frames",
"search",
"events",
"query",
"opened",
"section",
"single",
"sources",
"event",
"carrying",
"grounding",
"before",
"prose",
"token",
"answer",
"deltas",
"done",
"errors",
"after",
"streaming",
"begins",
"arrive",
"error",
"since",
"status",
"already",
"carry",
"title",
"optional",
"heading",
"group",
"snippet",
"content"
]
},
{
"id": "api/endpoint#errors",
"kind": "section",
"title": "Search endpoint",
"heading": "Errors",
"group": "API",
"url": "/docs/api/endpoint#errors",
"summary": "Error contract: 400 for invalid JSON bodies, 404 for missing graph-read routes, glossary terms, or section IDs, 500 when the chunk index fails to build, and an SSE error event for failures during an already-started agentic stream.",
"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",
"error",
"contract",
"invalid",
"json",
"bodies",
"missing",
"graph",
"read",
"routes",
"glossary",
"terms",
"section",
"chunk",
"index",
"fails",
"build",
"event",
"failures",
"during",
"already",
"started",
"agentic",
"stream",
"body",
"status",
"cause",
"request",
"wasn",
"valid",
"knowledge",
"route",
"term",
"found",
"failed",
"misconfigured",
"collection",
"failure",
"http",
"arrive"
]
},
{
"id": "api/endpoint#index-lifecycle",
"kind": "section",
"title": "Search endpoint",
"heading": "Index lifecycle",
"group": "API",
"url": "/docs/api/endpoint#index-lifecycle",
"summary": "The chunk index is built on the first request per server instance and cached for the process lifetime. The first request also compares the live content hash to the graph's and logs a one-time warning on mismatch — the cue to rebuild the graph.",
"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",
"built",
"first",
"request",
"server",
"instance",
"cached",
"process",
"lifetime",
"also",
"compares",
"live",
"content",
"hash",
"graph",
"logs",
"time",
"warning",
"mismatch",
"rebuild",
"build",
"once",
"endpoint",
"against",
"knowledge",
"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, deep-link URL, group, snippet) plus the echoed query, the configured model, and the mode that ran. A warning field appears when an agentic request was downgraded for lack of a key. Result URLs carry the section anchor; only a document's intro chunk lacks one.",
"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",
"deep",
"link",
"group",
"snippet",
"plus",
"echoed",
"query",
"configured",
"model",
"warning",
"field",
"appears",
"agentic",
"request",
"downgraded",
"lack",
"result",
"urls",
"carry",
"section",
"anchor",
"only",
"document",
"intro",
"chunk",
"lacks",
"concepts",
"search",
"loop"
]
},
{
"id": "api/endpoint#knowledge-graph-reads-get",
"kind": "section",
"title": "Search endpoint",
"heading": "Knowledge graph reads (GET)",
"group": "API",
"url": "/docs/api/endpoint#knowledge-graph-reads-get",
"summary": "Keyless GET sub-routes read the committed graph without any model call: list and fetch glossary entries by term or alias, list section summaries (optionally filtered by group), fetch one full knowledge node by ID, and fetch the overview and context. Section IDs containing slashes or hashes must be URL-encoded in the path; misses return 404 with a JSON error.",
"facts": [
{
"kind": "code",
"literal": "{ \"error\": \"Not found.\" }",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "virtual:hev-ask/kg",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/glossary",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "{ \"terms\": GlossaryEntry[] }",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/glossary/{term}",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GlossaryEntry",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/sections",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "{ \"sections\": SectionSummary[] }",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/sections?group=API",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/sections/{id}",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "KnowledgeNode",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "GET /api/ask/overview",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "{ \"overview\": string, \"context\": string }",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "SectionSummary",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "{ id, title, heading, group, url }",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "/api/ask/sections/api%2Fcli%23flags",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
},
{
"kind": "code",
"literal": "404",
"chunkId": "api/endpoint#knowledge-graph-reads-get"
}
],
"sources": [
{
"chunkId": "api/endpoint#knowledge-graph-reads-get",
"url": "/docs/api/endpoint#knowledge-graph-reads-get",
"anchor": "knowledge-graph-reads-get"
}
],
"mode": "source-primary",
"terms": [
"knowledge",
"graph",
"reads",
"keyless",
"routes",
"read",
"committed",
"without",
"model",
"call",
"list",
"fetch",
"glossary",
"entries",
"term",
"alias",
"section",
"summaries",
"optionally",
"filtered",
"group",
"full",
"node",
"overview",
"context",
"containing",
"slashes",
"hashes",
"must",
"encoded",
"path",
"misses",
"return",
"json",
"error",
"found",
"virtual",
"terms",
"glossaryentry",
"sections"
]
},
{
"id": "api/endpoint#llm-tracing",
"kind": "section",
"title": "Search endpoint",
"heading": "LLM tracing",
"group": "API",
"url": "/docs/api/endpoint#llm-tracing",
"summary": "Setting a PostHog key in the endpoint's environment makes every agentic answer emit a generation trace — model, tokens, latency, and tool calls. Companion variables override the ingestion host and control how much prompt and answer text ships. Without a key telemetry is a no-op; the answer path never depends on it.",
"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",
"endpoint",
"environment",
"makes",
"every",
"agentic",
"answer",
"emit",
"generation",
"trace",
"model",
"tokens",
"latency",
"tool",
"calls",
"companion",
"variables",
"override",
"ingestion",
"host",
"control",
"much",
"prompt",
"text",
"ships",
"without",
"telemetry",
"path",
"never",
"depends",
"capture",
"content",
"redacted",
"full",
"posthogkey",
"posthogapikey",
"same",
"emits"
]
},
{
"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: an empty query returns an empty keyword JSON; explicit keyword mode or a missing key runs keyword; an agentic request without a key downgrades to keyword JSON with a warning; otherwise it streams the agentic SSE. There is no 'AI unavailable' error — 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",
"query",
"returns",
"keyword",
"json",
"explicit",
"missing",
"runs",
"agentic",
"request",
"without",
"downgrades",
"warning",
"otherwise",
"streams",
"there",
"unavailable",
"error",
"overlay",
"branches",
"response",
"content",
"type",
"results",
"model",
"plus",
"stream",
"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": "The base route takes a POST with a JSON body holding the query string and an optional mode that forces the instant keyword path or requests the agentic loop; omitting it behaves agentically when a key is present. Empty or whitespace queries return an empty result set.",
"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",
"base",
"route",
"takes",
"post",
"json",
"body",
"holding",
"query",
"string",
"optional",
"mode",
"forces",
"instant",
"keyword",
"path",
"requests",
"agentic",
"loop",
"omitting",
"behaves",
"agentically",
"present",
"empty",
"whitespace",
"queries",
"return",
"result",
"does",
"autoscaling",
"work",
"field",
"type",
"description",
"search",
"returns",
"omitted",
"like"
]
},
{
"id": "api/endpoint#suggested-questions-get",
"kind": "section",
"title": "Search endpoint",
"heading": "Suggested questions (GET)",
"group": "API",
"url": "/docs/api/endpoint#suggested-questions-get",
"summary": "A GET on the base route returns the graph's baked-in suggested questions and the loop model with no model call. The overlay fetches this once on first open to populate its empty state; an absent or empty list just means no suggestions are shown.",
"facts": [
{
"kind": "code",
"literal": "{\n \"suggestions\": [\"How does the knowledge graph stay fresh?\"],\n \"model\": \"claude-haiku-4-5\"\n}",
"chunkId": "api/endpoint#suggested-questions-get"
},
{
"kind": "code",
"literal": "GET /api/ask",
"chunkId": "api/endpoint#suggested-questions-get"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/endpoint#suggested-questions-get"
}
],
"sources": [
{
"chunkId": "api/endpoint#suggested-questions-get",
"url": "/docs/api/endpoint#suggested-questions-get",
"anchor": "suggested-questions-get"
}
],
"mode": "source-primary",
"terms": [
"suggested",
"questions",
"base",
"route",
"returns",
"graph",
"baked",
"loop",
"model",
"call",
"overlay",
"fetches",
"once",
"first",
"open",
"populate",
"empty",
"state",
"absent",
"list",
"just",
"means",
"suggestions",
"shown",
"does",
"knowledge",
"stay",
"fresh",
"claude",
"haiku",
"query",
"array",
"without",
"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 (such as Cloudflare's), then the process environment, then the build-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",
"such",
"cloudflare",
"process",
"build",
"time",
"lives",
"wherever",
"host",
"injects",
"server",
"secrets",
"never",
"sent",
"browser",
"locals",
"import",
"meta",
"anthropicapikey",
"order"
]
},
{
"id": "api/knowledge-graph",
"kind": "section",
"title": "Knowledge graph format",
"heading": null,
"group": "API",
"url": "/docs/api/knowledge-graph",
"summary": "The knowledge graph is a single committed JSON file built offline and inlined into the build through a virtual module, so the running site reads it without filesystem access. It is the agent's distilled, source-grounded 'shadow site': humans read the rendered pages, the loop reads the graph, and every node links back to its real page and anchor. The site renders its own graph at /kg.",
"facts": [
{
"kind": "code",
"literal": ".hev-ask/kg.json",
"chunkId": "api/knowledge-graph"
},
{
"kind": "code",
"literal": "ask kg build",
"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": [
"knowledge",
"graph",
"single",
"committed",
"json",
"file",
"built",
"offline",
"inlined",
"build",
"through",
"virtual",
"module",
"running",
"site",
"reads",
"without",
"filesystem",
"access",
"agent",
"distilled",
"source",
"grounded",
"shadow",
"humans",
"read",
"rendered",
"pages",
"loop",
"every",
"node",
"links",
"back",
"real",
"page",
"anchor",
"renders",
"callout",
"astro",
"artifact"
]
},
{
"id": "api/knowledge-graph#degradation",
"kind": "section",
"title": "Knowledge graph format",
"heading": "Degradation",
"group": "API",
"url": "/docs/api/knowledge-graph#degradation",
"summary": "The graph is read defensively: missing, malformed, or older node-less artifacts still work — the agentic loop falls back to keyword-style search and keyword mode keeps working. Because it's committed JSON, its deterministic structure is reviewable in pull requests; only the distillation is model-authored, which is what lets the model step move into 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",
"graph",
"read",
"defensively",
"missing",
"malformed",
"older",
"node",
"less",
"artifacts",
"still",
"work",
"agentic",
"loop",
"falls",
"back",
"keyword",
"style",
"search",
"mode",
"keeps",
"working",
"because",
"committed",
"json",
"deterministic",
"structure",
"reviewable",
"pull",
"requests",
"only",
"distillation",
"model",
"authored",
"lets",
"step",
"move",
"claude",
"code",
"skill"
]
},
{
"id": "api/knowledge-graph#fields",
"kind": "section",
"title": "Knowledge graph format",
"heading": "Fields",
"group": "API",
"url": "/docs/api/knowledge-graph#fields",
"summary": "Top-level fields: a schema version, generation timestamp, the content hash that gates freshness, the orientation context (also the no-nodes fallback), the glossary that widens keyword search, the deterministic overview map injected into the agent's prompt, model-authored suggestions for the overlay, the nodes that form the shadow site, and an edges array reserved for a future node-to-node graph.",
"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",
"orientation",
"context",
"also",
"nodes",
"fallback",
"glossary",
"widens",
"keyword",
"search",
"deterministic",
"overview",
"injected",
"agent",
"prompt",
"model",
"authored",
"suggestions",
"overlay",
"form",
"shadow",
"site",
"edges",
"array",
"reserved",
"future",
"node",
"graph",
"generatedat",
"string",
"contenthash"
]
},
{
"id": "api/knowledge-graph#how-each-field-is-used",
"kind": "section",
"title": "Knowledge graph 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 injected into the loop's prompt-cached system prompt; the glossary expands keyword queries with aliases; nodes also lift keyword ranking when a term hits a section's summary, terms, or facts; node terms back a render-time check that downgrades unsupported cited links to plain text; suggestions feed the overlay's empty state; and the content hash lets builds skip the model 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",
"injected",
"loop",
"prompt",
"cached",
"system",
"glossary",
"expands",
"keyword",
"queries",
"aliases",
"also",
"lift",
"ranking",
"term",
"hits",
"section",
"summary",
"terms",
"facts",
"node",
"back",
"render",
"time",
"check",
"downgrades",
"unsupported",
"cited",
"links",
"plain",
"text",
"suggestions",
"feed",
"overlay",
"empty",
"state",
"content",
"hash"
]
},
{
"id": "api/knowledge-graph#knowledgenode",
"kind": "section",
"title": "Knowledge graph format",
"heading": "KnowledgeNode",
"group": "API",
"url": "/docs/api/knowledge-graph#knowledgenode",
"summary": "Each node's ID equals its chunk ID so it maps one-to-one to a real anchor. It carries the model's summary the agent reasons from, deterministically extracted verbatim facts the model never authors, provenance back to the source chunk, a mode marking reference sections as source-primary so the agent reads them verbatim, and distinctive terms used by the render-time link-support check.",
"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",
"equals",
"chunk",
"maps",
"real",
"anchor",
"carries",
"model",
"summary",
"agent",
"reasons",
"deterministically",
"extracted",
"verbatim",
"facts",
"never",
"authors",
"provenance",
"back",
"source",
"mode",
"marking",
"reference",
"sections",
"primary",
"reads",
"distinctive",
"terms",
"render",
"time",
"link",
"support",
"check",
"string",
"fact",
"sources",
"sourceref",
"field",
"type"
]
},
{
"id": "api/knowledge-graph#regenerating",
"kind": "section",
"title": "Knowledge graph format",
"heading": "Regenerating",
"group": "API",
"url": "/docs/api/knowledge-graph#regenerating",
"summary": "Rebuild after content changes and commit the result; the hash gate makes running on every build safe because model work is only spent when content actually changed. Build with the bundled Claude Code skill (no API key) or a one-call CLI build, and run verify 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",
"running",
"every",
"build",
"safe",
"because",
"model",
"work",
"only",
"spent",
"actually",
"changed",
"bundled",
"claude",
"code",
"skill",
"call",
"verify",
"anchors",
"coverage",
"literal",
"fidelity",
"astro",
"spends",
"integration",
"also",
"runs",
"during",
"present"
]
},
{
"id": "api/knowledge-graph#shape",
"kind": "section",
"title": "Knowledge graph format",
"heading": "Shape",
"group": "API",
"url": "/docs/api/knowledge-graph#shape",
"summary": "A worked JSON example of the full graph shape: version, timestamp, content hash, context, glossary entries, the overview map, suggestions, one complete node with facts, sources, mode, and terms, 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",
"json",
"example",
"full",
"graph",
"version",
"timestamp",
"content",
"hash",
"context",
"glossary",
"entries",
"overview",
"suggestions",
"complete",
"node",
"facts",
"sources",
"mode",
"terms",
"empty",
"edges",
"array",
"generatedat",
"2026",
"30t12",
"000z",
"contenthash",
"a1b2c3",
"search",
"overlay",
"astro",
"docs",
"term",
"knowledge",
"aliases",
"definition",
"offline",
"built"
]
},
{
"id": "api/mcp",
"kind": "section",
"title": "MCP server",
"heading": null,
"group": "API",
"url": "/docs/api/mcp",
"summary": "The CLI's MCP command runs a stdio Model Context Protocol server over the same graph reads as the CLI and HTTP API — the zero-glue path for coding agents, pointed at either a checked-out repo's graph file or a deployed endpoint.",
"facts": [
{
"kind": "code",
"literal": "ask mcp",
"chunkId": "api/mcp"
},
{
"kind": "code",
"literal": ".hev-ask/kg.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",
"graph",
"reads",
"http",
"zero",
"glue",
"path",
"coding",
"agents",
"pointed",
"either",
"checked",
"repo",
"file",
"deployed",
"endpoint",
"json",
"expose",
"committed",
"knowledge",
"tools",
"point",
"agent",
"gets",
"structured",
"docs"
]
},
{
"id": "api/mcp#configure",
"kind": "section",
"title": "MCP server",
"heading": "Configure",
"group": "API",
"url": "/docs/api/mcp#configure",
"summary": "Two configurations: a local graph path for keyless, fully offline reads in checked-out repos, or a deployed endpoint URL for the freshest remote graph. The answer tool requires the endpoint form and returns a tool error in local mode.",
"facts": [
{
"kind": "code",
"literal": "{\n \"mcpServers\": {\n \"docs\": {\n \"command\": \"ask\",\n \"args\": [\"--kg-path\", \".hev-ask/kg.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",
"graph",
"path",
"keyless",
"fully",
"offline",
"reads",
"checked",
"repos",
"deployed",
"endpoint",
"freshest",
"remote",
"answer",
"tool",
"requires",
"form",
"returns",
"error",
"mode",
"mcpservers",
"docs",
"command",
"args",
"json",
"askhev",
"https",
"site",
"want",
"unless"
]
},
{
"id": "api/mcp#data-sources",
"kind": "section",
"title": "MCP server",
"heading": "Data sources",
"group": "API",
"url": "/docs/api/mcp#data-sources",
"summary": "The MCP server resolves data like the CLI: an endpoint flag routes reads to the deployed HTTP API and streams answers through the POST route, otherwise it reads the local graph path. Local reads load the graph on each tool call, so a just-rebuilt graph 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/kg.json",
"chunkId": "api/mcp#data-sources"
},
{
"kind": "code",
"literal": "kg.json",
"chunkId": "api/mcp#data-sources"
}
],
"sources": [
{
"chunkId": "api/mcp#data-sources",
"url": "/docs/api/mcp#data-sources",
"anchor": "data-sources"
}
],
"mode": "source-primary",
"terms": [
"data",
"sources",
"server",
"resolves",
"like",
"endpoint",
"flag",
"routes",
"reads",
"deployed",
"http",
"streams",
"answers",
"through",
"post",
"route",
"otherwise",
"local",
"graph",
"path",
"load",
"tool",
"call",
"just",
"rebuilt",
"visible",
"without",
"restarting",
"answer",
"json",
"uses",
"same",
"resolution",
"calls",
"read",
"disk",
"defaulting"
]
},
{
"id": "api/mcp#protocol-surface",
"kind": "section",
"title": "MCP server",
"heading": "Protocol surface",
"group": "API",
"url": "/docs/api/mcp#protocol-surface",
"summary": "The server speaks newline-delimited JSON-RPC over stdio, handling initialization, tool listing, and tool calls. Unknown methods return protocol errors while tool-level failures return MCP tool results flagged as errors. All substantive behavior lives in the shared Go package so the CLI, embeddable command group, and MCP server use the same helpers.",
"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",
"results",
"flagged",
"substantive",
"behavior",
"lives",
"shared",
"package",
"embeddable",
"command",
"group",
"same",
"helpers",
"initialize",
"tools",
"list",
"call",
"iserror",
"true",
"handles",
"plus"
]
},
{
"id": "api/mcp#tools",
"kind": "section",
"title": "MCP server",
"heading": "Tools",
"group": "API",
"url": "/docs/api/mcp#tools",
"summary": "The tool set mirrors the read surface: list and fetch glossary entries, list sections optionally by group, fetch one full node, fetch the overview, run keyword search with an optional result cap, and an answer tool that collapses the streamed endpoint answer into one 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",
"tool",
"mirrors",
"read",
"surface",
"list",
"fetch",
"glossary",
"entries",
"sections",
"optionally",
"group",
"full",
"node",
"overview",
"keyword",
"search",
"optional",
"result",
"answer",
"collapses",
"streamed",
"endpoint",
"results",
"carry",
"human",
"readable",
"text",
"plus",
"original",
"machine",
"shape",
"structured",
"content",
"terms",
"glossaryentry",
"term",
"sectionsummary",
"section",
"context"
]
},
{
"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. It's added once in a global layout, opens over the page as a dialog, 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",
"added",
"once",
"global",
"layout",
"opens",
"page",
"dialog",
"doesn",
"affect",
"until",
"opened",
"import",
"searchoverlay",
"components",
"astro",
"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 driven: one word runs debounced keyword search with the first result active; a second word switches to ask mode where Enter sends the question to the agentic loop; arrow keys move the active result and Escape closes. Suggested questions appear on open with AI on, and the first can be dropped into the input with Tab. Without a server key, asking returns keyword results with a surfaced warning.",
"facts": [
{
"kind": "code",
"literal": "Tab",
"chunkId": "api/search-overlay#keyboard-model"
}
],
"sources": [
{
"chunkId": "api/search-overlay#keyboard-model",
"url": "/docs/api/search-overlay#keyboard-model",
"anchor": "keyboard-model"
}
],
"mode": "source-primary",
"terms": [
"keyboard",
"model",
"overlay",
"first",
"word",
"count",
"driven",
"runs",
"debounced",
"keyword",
"search",
"result",
"active",
"second",
"switches",
"mode",
"enter",
"sends",
"question",
"agentic",
"loop",
"arrow",
"keys",
"move",
"escape",
"closes",
"suggested",
"questions",
"appear",
"open",
"dropped",
"input",
"without",
"server",
"asking",
"returns",
"results",
"surfaced",
"warning",
"number"
]
},
{
"id": "api/search-overlay#keyword-results-and-deep-links",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Keyword results and deep links",
"group": "API",
"url": "/docs/api/search-overlay#keyword-results-and-deep-links",
"summary": "Each keyword result row shows the document title, an optional heading breadcrumb, and a one-line snippet. The row links to the chunk's URL, which already carries the anchor, so clicking lands on the exact heading.",
"facts": [
{
"kind": "code",
"literal": "Concepts › The agentic loop",
"chunkId": "api/search-overlay#keyword-results-and-deep-links"
},
{
"kind": "code",
"literal": "url",
"chunkId": "api/search-overlay#keyword-results-and-deep-links"
},
{
"kind": "code",
"literal": "#anchor",
"chunkId": "api/search-overlay#keyword-results-and-deep-links"
}
],
"sources": [
{
"chunkId": "api/search-overlay#keyword-results-and-deep-links",
"url": "/docs/api/search-overlay#keyword-results-and-deep-links",
"anchor": "keyword-results-and-deep-links"
}
],
"mode": "source-primary",
"terms": [
"keyword",
"results",
"deep",
"links",
"result",
"shows",
"document",
"title",
"optional",
"heading",
"breadcrumb",
"line",
"snippet",
"chunk",
"already",
"carries",
"anchor",
"clicking",
"lands",
"exact",
"concepts",
"agentic",
"loop",
"renders",
"link"
]
},
{
"id": "api/search-overlay#opening-the-overlay",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Opening the overlay",
"group": "API",
"url": "/docs/api/search-overlay#opening-the-overlay",
"summary": "Two built-in ways to open: the keyboard shortcut is bound automatically once the component is on the page, and any element carrying the opener data attribute opens it on click, so you can wire as many triggers as you like.",
"facts": [
{
"kind": "code",
"literal": "<button type=\"button\" data-hev-ask-open>\n Search <kbd>⌘K</kbd>\n</button>\n\n<a href=\"#\" data-hev-ask-open>Search the docs</a>",
"chunkId": "api/search-overlay#opening-the-overlay"
},
{
"kind": "code",
"literal": "⌘K",
"chunkId": "api/search-overlay#opening-the-overlay"
},
{
"kind": "code",
"literal": "Ctrl-K",
"chunkId": "api/search-overlay#opening-the-overlay"
},
{
"kind": "code",
"literal": "data-hev-ask-open",
"chunkId": "api/search-overlay#opening-the-overlay"
}
],
"sources": [
{
"chunkId": "api/search-overlay#opening-the-overlay",
"url": "/docs/api/search-overlay#opening-the-overlay",
"anchor": "opening-the-overlay"
}
],
"mode": "source-primary",
"terms": [
"opening",
"overlay",
"built",
"ways",
"open",
"keyboard",
"shortcut",
"bound",
"automatically",
"once",
"component",
"page",
"element",
"carrying",
"opener",
"data",
"attribute",
"opens",
"click",
"wire",
"many",
"triggers",
"like",
"button",
"type",
"search",
"href",
"docs",
"ctrl",
"both",
"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 text, and the debounce delay before a keyword query is sent.",
"facts": [
{
"kind": "code",
"literal": "<SearchOverlay\n endpoint=\"/api/ask\"\n placeholder=\"Search hev ask…\"\n debounce={400}\n/>",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "endpoint",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "string",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "'/api/ask'",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "placeholder",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "'Search the docs…'",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "debounce",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "number",
"chunkId": "api/search-overlay#props"
},
{
"kind": "code",
"literal": "500",
"chunkId": "api/search-overlay#props"
}
],
"sources": [
{
"chunkId": "api/search-overlay#props",
"url": "/docs/api/search-overlay#props",
"anchor": "props"
}
],
"mode": "source-primary",
"terms": [
"props",
"three",
"endpoint",
"overlay",
"posts",
"must",
"match",
"integration",
"option",
"input",
"placeholder",
"text",
"debounce",
"delay",
"before",
"keyword",
"query",
"sent",
"searchoverlay",
"search",
"string",
"docs",
"number",
"prop",
"type",
"default",
"description",
"queries",
"milliseconds",
"after",
"typing",
"stops"
]
},
{
"id": "api/search-overlay#suggested-questions",
"kind": "section",
"title": "SearchOverlay component",
"heading": "Suggested questions",
"group": "API",
"url": "/docs/api/search-overlay#suggested-questions",
"summary": "With AI on, the overlay fetches suggested questions from the endpoint once on first open and shows them in the empty state. They come from the graph's baked-in suggestions so no model call is needed; clicking one fills the input and asks immediately, and a graph without them just shows nothing extra.",
"facts": [
{
"kind": "code",
"literal": "GET /api/ask",
"chunkId": "api/search-overlay#suggested-questions"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "api/search-overlay#suggested-questions"
}
],
"sources": [
{
"chunkId": "api/search-overlay#suggested-questions",
"url": "/docs/api/search-overlay#suggested-questions",
"anchor": "suggested-questions"
}
],
"mode": "source-primary",
"terms": [
"suggested",
"questions",
"overlay",
"fetches",
"endpoint",
"once",
"first",
"open",
"shows",
"empty",
"state",
"come",
"graph",
"baked",
"suggestions",
"model",
"call",
"needed",
"clicking",
"fills",
"input",
"asks",
"immediately",
"without",
"just",
"nothing",
"extra",
"short",
"list",
"time",
"opens",
"knowledge",
"build",
"there",
"render",
"none",
"simply",
"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": "The overlay persists an AI-on-Enter preference in localStorage. Readers who flip it to keyword-only never trigger a model call — a space just searches a phrase and no suggested questions show — and the choice survives reloads.",
"facts": [
{
"kind": "code",
"literal": "localStorage",
"chunkId": "api/search-overlay#the-mode-toggle"
},
{
"kind": "code",
"literal": "hev-ask:mode",
"chunkId": "api/search-overlay#the-mode-toggle"
},
{
"kind": "code",
"literal": "agentic",
"chunkId": "api/search-overlay#the-mode-toggle"
},
{
"kind": "code",
"literal": "keyword",
"chunkId": "api/search-overlay#the-mode-toggle"
}
],
"sources": [
{
"chunkId": "api/search-overlay#the-mode-toggle",
"url": "/docs/api/search-overlay#the-mode-toggle",
"anchor": "the-mode-toggle"
}
],
"mode": "source-primary",
"terms": [
"mode",
"toggle",
"overlay",
"persists",
"enter",
"preference",
"localstorage",
"readers",
"flip",
"keyword",
"only",
"never",
"trigger",
"model",
"call",
"space",
"just",
"searches",
"phrase",
"suggested",
"questions",
"show",
"choice",
"survives",
"reloads",
"agentic",
"under",
"shown"
]
},
{
"id": "api/search-overlay#the-streamed-answer",
"kind": "section",
"title": "SearchOverlay component",
"heading": "The streamed answer",
"group": "API",
"url": "/docs/api/search-overlay#the-streamed-answer",
"summary": "Pressing Enter replaces the keyword rows with an answer panel: the model's sub-queries appear live as a faint activity line, then the grounded answer streams in with a blinking caret. Inline deep links point at exact section anchors with hover breadcrumbs, a Sources chip row lists every grounding section, and any link outside the streamed source set renders as plain text so a hallucinated anchor can never become a clickable dead link.",
"facts": [
{
"kind": "code",
"literal": "searched: …",
"chunkId": "api/search-overlay#the-streamed-answer"
},
{
"kind": "code",
"literal": "/docs/page#anchor",
"chunkId": "api/search-overlay#the-streamed-answer"
}
],
"sources": [
{
"chunkId": "api/search-overlay#the-streamed-answer",
"url": "/docs/api/search-overlay#the-streamed-answer",
"anchor": "the-streamed-answer"
}
],
"mode": "source-primary",
"terms": [
"streamed",
"answer",
"pressing",
"enter",
"replaces",
"keyword",
"rows",
"panel",
"model",
"queries",
"appear",
"live",
"faint",
"activity",
"line",
"grounded",
"streams",
"blinking",
"caret",
"inline",
"deep",
"links",
"point",
"exact",
"section",
"anchors",
"hover",
"breadcrumbs",
"sources",
"chip",
"lists",
"every",
"grounding",
"link",
"outside",
"source",
"renders",
"plain",
"text",
"hallucinated"
]
},
{
"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, and ships scoped styles keyed to those variables — matching your site's look is usually just defining the tokens, with 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",
"ships",
"scoped",
"styles",
"keyed",
"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"
]
},
{
"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, a bounded agentic loop that navigates a knowledge graph, and that offline graph — a distilled, source-grounded shadow site. The split that matters: the graph is built offline with a strong model and committed to git, while the index and loop run on demand at the edge with no durable state in the running site.",
"facts": [
{
"kind": "value",
"literal": "Diagram.astro",
"chunkId": "concepts"
},
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "concepts"
}
],
"sources": [
{
"chunkId": "concepts",
"url": "/docs/concepts",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"three",
"parts",
"heading",
"chunk",
"index",
"real",
"anchors",
"bounded",
"agentic",
"loop",
"navigates",
"knowledge",
"graph",
"offline",
"distilled",
"source",
"grounded",
"shadow",
"site",
"split",
"matters",
"built",
"strong",
"model",
"committed",
"while",
"demand",
"edge",
"durable",
"state",
"running",
"diagram",
"astro",
"callout",
"works",
"indexing",
"keyword",
"prefiltering",
"widened",
"glossary"
]
},
{
"id": "concepts#asking-is-the-default",
"kind": "section",
"title": "Concepts",
"heading": "Asking is the default",
"group": "Overview",
"url": "/docs/concepts#asking-is-the-default",
"summary": "The overlay is ask-first: one word is an instant keyword lookup, and the moment a query grows past one word it switches to ask mode where Enter sends the question to the agentic loop. Suggested questions baked into the graph appear on open to make asking the obvious move, and readers can flip to keyword-only, persisted across reloads, 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",
"first",
"word",
"instant",
"keyword",
"lookup",
"moment",
"query",
"grows",
"past",
"switches",
"mode",
"enter",
"sends",
"question",
"agentic",
"loop",
"suggested",
"questions",
"baked",
"graph",
"appear",
"open",
"make",
"obvious",
"move",
"readers",
"flip",
"only",
"persisted",
"across",
"reloads",
"model",
"never",
"called",
"localstorage",
"single",
"treated"
]
},
{
"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 to a configurable depth rather than indexed as pages, with pre-heading content becoming an intro chunk. Anchors are generated with the same slugger Astro's renderer uses, so section links land on headings that actually exist. Both the runtime index and the offline build chunk through one shared function, so their slugs 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",
"configurable",
"depth",
"rather",
"indexed",
"pages",
"heading",
"content",
"becoming",
"intro",
"chunk",
"generated",
"same",
"slugger",
"astro",
"renderer",
"uses",
"section",
"links",
"land",
"actually",
"exist",
"both",
"runtime",
"index",
"offline",
"build",
"through",
"shared",
"function",
"their",
"slugs",
"always",
"agree",
"basepath",
"slug"
]
},
{
"id": "concepts#degradation-by-design",
"kind": "section",
"title": "Concepts",
"heading": "Degradation, by design",
"group": "Overview",
"url": "/docs/concepts#degradation-by-design",
"summary": "Every missing piece downgrades instead of failing: no runtime key means keyword-only; no key at build keeps the committed graph with a warning; a missing or node-less graph drops the loop to keyword-style retrieval and ranking to raw token overlap; a stale graph logs a one-line hash-mismatch warning but still serves.",
"facts": [
{
"kind": "code",
"literal": "kg.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",
"downgrades",
"instead",
"failing",
"runtime",
"means",
"keyword",
"only",
"build",
"keeps",
"committed",
"graph",
"warning",
"node",
"less",
"drops",
"loop",
"style",
"retrieval",
"ranking",
"token",
"overlap",
"stale",
"logs",
"line",
"hash",
"mismatch",
"still",
"serves",
"json",
"built",
"keep",
"working",
"pieces",
"drop",
"away"
]
},
{
"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: expand each query term with its glossary aliases, score chunks by token overlap — counting hits against a section's graph summary, terms, and facts so central sections outrank incidental mentions — cap results per document, and excerpt around the first match. It needs no key and no embeddings, and without a graph 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": "kg.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",
"expand",
"query",
"term",
"aliases",
"score",
"chunks",
"token",
"overlap",
"counting",
"hits",
"against",
"section",
"graph",
"summary",
"terms",
"facts",
"central",
"sections",
"outrank",
"incidental",
"mentions",
"results",
"document",
"excerpt",
"around",
"first",
"match",
"needs",
"embeddings",
"without",
"degrades",
"plain"
]
},
{
"id": "concepts#the-agentic-search-loop",
"kind": "section",
"title": "Concepts",
"heading": "The agentic search loop",
"group": "Overview",
"url": "/docs/concepts#the-agentic-search-loop",
"summary": "Asking runs a bounded two-phase tool-use loop. In the gather phase the model gets a map of every section up front plus one tool that opens a section's summary, verbatim facts, and (for reference sections) source text, bounded by an iteration cap. In the answer phase the accumulated sources go to the overlay and the model is called once more with no tools, so it can only write prose — grounded in opened sections, linking only to provided URLs.",
"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",
"runs",
"bounded",
"phase",
"tool",
"gather",
"model",
"gets",
"every",
"section",
"front",
"plus",
"opens",
"summary",
"verbatim",
"facts",
"reference",
"sections",
"source",
"text",
"iteration",
"answer",
"accumulated",
"sources",
"overlay",
"called",
"once",
"more",
"tools",
"only",
"write",
"prose",
"grounded",
"opened",
"linking",
"provided",
"urls"
]
},
{
"id": "concepts#the-knowledge-graph",
"kind": "section",
"title": "Concepts",
"heading": "The knowledge graph",
"group": "Overview",
"url": "/docs/concepts#the-knowledge-graph",
"summary": "The graph is built offline and committed as a reviewable artifact: distilled per-heading nodes with verbatim facts and source links, a deterministic overview map, an orientation context and alias glossary, and suggested questions. Only the distillation is model-authored; structure, facts, overview, and the hash are derived in code — which is exactly why the model step fits in a Claude Code skill.",
"facts": [
{
"kind": "code",
"literal": "kg.json",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "nodes",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "summary",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "facts",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "source",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "source-primary",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "overview",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "context",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "glossary",
"chunkId": "concepts#the-knowledge-graph"
},
{
"kind": "code",
"literal": "suggestions",
"chunkId": "concepts#the-knowledge-graph"
}
],
"sources": [
{
"chunkId": "concepts#the-knowledge-graph",
"url": "/docs/concepts#the-knowledge-graph",
"anchor": "the-knowledge-graph"
}
],
"mode": "agent-primary",
"terms": [
"knowledge",
"graph",
"built",
"offline",
"committed",
"reviewable",
"artifact",
"distilled",
"heading",
"nodes",
"verbatim",
"facts",
"source",
"links",
"deterministic",
"overview",
"orientation",
"context",
"alias",
"glossary",
"suggested",
"questions",
"only",
"distillation",
"model",
"authored",
"structure",
"hash",
"derived",
"code",
"exactly",
"step",
"fits",
"claude",
"skill",
"json",
"summary",
"primary",
"suggestions",
"repo"
]
},
{
"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 graph's map and summaries are injected into the system prompt with a cache marker, so across search rounds they're a prompt-cache hit rather than re-sent tokens. The final answer turn changes the tool set so it can't reuse that cache, but it's the last call anyway. The loop model defaults to Claude Haiku 4.5 and is configurable.",
"facts": [
{
"kind": "code",
"literal": "cache_control",
"chunkId": "concepts#the-system-prompt-is-cached"
},
{
"kind": "value",
"literal": "4.5",
"chunkId": "concepts#the-system-prompt-is-cached"
}
],
"sources": [
{
"chunkId": "concepts#the-system-prompt-is-cached",
"url": "/docs/concepts#the-system-prompt-is-cached",
"anchor": "the-system-prompt-is-cached"
}
],
"mode": "agent-primary",
"terms": [
"system",
"prompt",
"cached",
"graph",
"summaries",
"injected",
"cache",
"marker",
"across",
"search",
"rounds",
"rather",
"sent",
"tokens",
"final",
"answer",
"turn",
"changes",
"tool",
"reuse",
"last",
"call",
"anyway",
"loop",
"model",
"defaults",
"claude",
"haiku",
"configurable",
"control",
"knowledge",
"section",
"cachecontrol",
"none"
]
},
{
"id": "concepts#two-ways-to-build-it",
"kind": "section",
"title": "Concepts",
"heading": "Two ways to build it",
"group": "Overview",
"url": "/docs/concepts#two-ways-to-build-it",
"summary": "The model step runs two ways feeding the same deterministic assembler: the recommended Claude Code skill, which distils inside your existing subscription with no API key or per-build token spend, or a one-call CLI build with an API key for CI and non-Claude-Code users. Both are hash-gated so unchanged content does no model work, and the JSON is reviewed in pull requests.",
"facts": [
{
"kind": "code",
"literal": "kg.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",
"model",
"step",
"runs",
"feeding",
"same",
"deterministic",
"assembler",
"recommended",
"claude",
"code",
"skill",
"distils",
"inside",
"existing",
"subscription",
"token",
"spend",
"call",
"users",
"both",
"hash",
"gated",
"unchanged",
"content",
"does",
"work",
"json",
"reviewed",
"pull",
"requests",
"anthropic",
"feed",
"walks",
"through",
"reading",
"corpus",
"writing",
"distillation"
]
},
{
"id": "index",
"kind": "section",
"title": "Introduction",
"heading": null,
"group": "Overview",
"url": "/docs",
"summary": "hev ask turns an Astro docs site into a small knowledge graph — one distilled, source-grounded entry per heading section plus a glossary — and serves it to whoever needs the docs: a human pressing ⌘K or a coding agent in the repo. The graph is built offline and committed as reviewable JSON, the single source everything else reads.",
"facts": [
{
"kind": "code",
"literal": "⌘K",
"chunkId": "index"
},
{
"kind": "code",
"literal": ".hev-ask/kg.json",
"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": [
"turns",
"astro",
"docs",
"site",
"small",
"knowledge",
"graph",
"distilled",
"source",
"grounded",
"entry",
"heading",
"section",
"plus",
"glossary",
"serves",
"whoever",
"needs",
"human",
"pressing",
"coding",
"agent",
"repo",
"built",
"offline",
"committed",
"reviewable",
"json",
"single",
"everything",
"else",
"reads",
"diagram",
"callout",
"build",
"builds",
"ways",
"answer",
"overlay",
"readers"
]
},
{
"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 graph inside your 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 content collections: no crawler, no external index, nothing to keep in sync.",
"facts": [
{
"kind": "code",
"literal": ".hev-ask/kg.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": "kg.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",
"graph",
"inside",
"existing",
"subscription",
"token",
"spend",
"commit",
"json",
"drop",
"overlay",
"layout",
"site",
"instant",
"keyword",
"search",
"plus",
"answer",
"loop",
"every",
"result",
"deep",
"linked",
"corpus",
"only",
"configured",
"content",
"collections",
"crawler",
"external",
"index",
"nothing",
"keep"
]
},
{
"id": "index#next-steps",
"kind": "section",
"title": "Introduction",
"heading": "Next steps",
"group": "Overview",
"url": "/docs#next-steps",
"summary": "A map of where to go next: the quick start for five-minute setup, Concepts for how it works, Tradeoffs and Limits for what you're choosing and what it deliberately doesn't do, and the CLI and API reference for the full surface.",
"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",
"quick",
"start",
"five",
"minute",
"setup",
"concepts",
"works",
"tradeoffs",
"limits",
"choosing",
"deliberately",
"doesn",
"reference",
"full",
"surface",
"search",
"site",
"minutes",
"chunks",
"anchors",
"agentic",
"loop",
"knowledge",
"graph",
"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 in collections who want search that works without standing up a service, deep-links to the right section, answers questions in the reader's own words, and is queryable by coding agents. If you only need keyword search on a static site with no key, Pagefind is simpler and a great fit.",
"facts": [
{
"kind": "value",
"literal": "docs.astro.build",
"chunkId": "index#who-this-is-for"
},
{
"kind": "value",
"literal": "pagefind.app",
"chunkId": "index#who-this-is-for"
}
],
"sources": [
{
"chunkId": "index#who-this-is-for",
"url": "/docs#who-this-is-for",
"anchor": "who-this-is-for"
}
],
"mode": "agent-primary",
"terms": [
"maintainers",
"astro",
"docs",
"sites",
"content",
"collections",
"want",
"search",
"works",
"without",
"standing",
"service",
"deep",
"links",
"right",
"section",
"answers",
"questions",
"reader",
"words",
"queryable",
"coding",
"agents",
"only",
"need",
"keyword",
"static",
"site",
"pagefind",
"simpler",
"great",
"build",
"building",
"maintaining",
"whose",
"lives",
"collection",
"markdown",
"work",
"running"
]
},
{
"id": "limits",
"kind": "section",
"title": "Limits",
"heading": null,
"group": "Overview",
"url": "/docs/limits",
"summary": "The hard boundaries to know before adopting: corpus scope, recall ceiling, single-call graph build, frontmatter parsing, latency, and adapter requirements. None are bugs — they're the edges of the current design.",
"facts": [
{
"kind": "value",
"literal": "Callout.astro",
"chunkId": "limits"
}
],
"sources": [
{
"chunkId": "limits",
"url": "/docs/limits",
"anchor": null
}
],
"mode": "agent-primary",
"terms": [
"hard",
"boundaries",
"know",
"before",
"adopting",
"corpus",
"scope",
"recall",
"ceiling",
"single",
"call",
"graph",
"build",
"frontmatter",
"parsing",
"latency",
"adapter",
"requirements",
"none",
"bugs",
"edges",
"current",
"design",
"callout",
"astro",
"knowledge",
"deliberately",
"does",
"these",
"should",
"covers"
]
},
{
"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 can't serve search — you need a server or hybrid adapter. 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",
"serve",
"need",
"hybrid",
"adapter",
"only",
"sites",
"should",
"tool",
"instead",
"cannot",
"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 is bounded by the iteration cap of Claude round-trips — worst case a few seconds, not instant by nature. The keyword path is the always-available instant lane; lower the iteration cap for a tighter ceiling.",
"facts": [
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "limits#agentic-search-adds-latency"
}
],
"sources": [
{
"chunkId": "limits#agentic-search-adds-latency",
"url": "/docs/limits#agentic-search-adds-latency",
"anchor": "agentic-search-adds-latency"
}
],
"mode": "agent-primary",
"terms": [
"agentic",
"search",
"adds",
"latency",
"path",
"bounded",
"iteration",
"claude",
"round",
"trips",
"worst",
"case",
"seconds",
"instant",
"nature",
"keyword",
"always",
"available",
"lane",
"lower",
"tighter",
"ceiling",
"maxiterations",
"default",
"considered",
"tune",
"down",
"need"
]
},
{
"id": "limits#anchors-depend-on-astros-slugger",
"kind": "section",
"title": "Limits",
"heading": "Anchors depend on Astro's slugger",
"group": "Overview",
"url": "/docs/limits#anchors-depend-on-astros-slugger",
"summary": "Deep links stay correct only while generated heading slugs match Astro's rendered IDs. hev ask uses the same slugger to stay aligned and ships a verify command that fails when any chunk anchor is missing from 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",
"stay",
"correct",
"only",
"while",
"generated",
"heading",
"slugs",
"match",
"rendered",
"uses",
"same",
"aligned",
"ships",
"verify",
"command",
"fails",
"chunk",
"anchor",
"missing",
"built",
"html",
"wire",
"slugging",
"change",
"caught",
"before",
"broken",
"link",
"github",
"long",
"generates",
"attributes",
"ever",
"changes"
]
},
{
"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 handling common string and number fields; nested structures aren't supported at build time. This only affects the offline graph build reading from disk — the runtime index uses Astro's own collection loading, which 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",
"handling",
"common",
"string",
"number",
"fields",
"nested",
"structures",
"aren",
"supported",
"time",
"only",
"affects",
"graph",
"reading",
"disk",
"runtime",
"index",
"uses",
"astro",
"collection",
"loading",
"honors",
"real",
"schema",
"getcollection",
"full",
"parser",
"handles",
"docs",
"knowledge"
]
},
{
"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 can't ground in what retrieval missed. The glossary recovers most synonym cases, but a query sharing no tokens with the docs may never surface the right section. Embeddings are the known fix and deliberately not built yet; a richer glossary is the cheaper lever until analytics show consistent misses.",
"facts": [
{
"kind": "code",
"literal": "k8s",
"chunkId": "limits#recall-has-a-keyword-ceiling"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "limits#recall-has-a-keyword-ceiling"
}
],
"sources": [
{
"chunkId": "limits#recall-has-a-keyword-ceiling",
"url": "/docs/limits#recall-has-a-keyword-ceiling",
"anchor": "recall-has-a-keyword-ceiling"
}
],
"mode": "agent-primary",
"terms": [
"recall",
"keyword",
"ceiling",
"retrieval",
"token",
"overlap",
"widened",
"glossary",
"embeddings",
"loop",
"ground",
"missed",
"recovers",
"most",
"synonym",
"cases",
"query",
"sharing",
"tokens",
"docs",
"never",
"surface",
"right",
"section",
"known",
"deliberately",
"built",
"richer",
"cheaper",
"lever",
"until",
"analytics",
"show",
"consistent",
"misses",
"kubernetes",
"agentic",
"grounds",
"answer",
"surfaces"
]
},
{
"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 running the endpoint; it's never exposed to the browser. Without it the endpoint serves keyword results — search degrades, it doesn't break.",
"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",
"running",
"endpoint",
"never",
"exposed",
"browser",
"without",
"serves",
"keyword",
"results",
"search",
"degrades",
"doesn",
"break",
"anthropicapikey",
"runs",
"present",
"runtime"
]
},
{
"id": "limits#the-corpus-is-your-content-collection",
"kind": "section",
"title": "Limits",
"heading": "The corpus is your content collection",
"group": "Overview",
"url": "/docs/limits#the-corpus-is-your-content-collection",
"summary": "hev ask searches only the configured Astro content collections — no crawler, no sitemap ingestion, no way to index non-collection pages like hand-written Astro files. Put what you want searchable 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",
"searches",
"only",
"configured",
"astro",
"collections",
"crawler",
"sitemap",
"ingestion",
"index",
"pages",
"like",
"hand",
"written",
"files",
"want",
"searchable",
"configure",
"nothing",
"else",
"there",
"external",
"aren",
"entries",
"example",
"appear",
"search"
]
},
{
"id": "limits#the-knowledge-graph-build-is-a-single-model-call",
"kind": "section",
"title": "Limits",
"heading": "The knowledge-graph build is a single model call",
"group": "Overview",
"url": "/docs/limits#the-knowledge-graph-build-is-a-single-model-call",
"summary": "The offline build sends the full cleaned corpus to the model in one call, which fits comfortably for typical docs sites of dozens of pages but would exceed a single context window for a very large corpus. A map-reduce builder is noted as a follow-up but not implemented.",
"facts": [],
"sources": [
{
"chunkId": "limits#the-knowledge-graph-build-is-a-single-model-call",
"url": "/docs/limits#the-knowledge-graph-build-is-a-single-model-call",
"anchor": "the-knowledge-graph-build-is-a-single-model-call"
}
],
"mode": "agent-primary",
"terms": [
"knowledge",
"graph",
"build",
"single",
"model",
"call",
"offline",
"sends",
"full",
"cleaned",
"corpus",
"fits",
"comfortably",
"typical",
"docs",
"sites",
"dozens",
"pages",
"would",
"exceed",
"context",
"window",
"very",
"large",
"reduce",
"builder",
"noted",
"follow",
"implemented",
"site",
"summaries",
"merged",
"today",
"assume"
]
},
{
"id": "quickstart",
"kind": "section",
"title": "Quick start",
"heading": null,
"group": "Overview",
"url": "/docs/quickstart",
"summary": "Add search to an existing Astro 5 docs site in about five minutes: keyword search works first, keyless; adding a server-side Anthropic key turns on Claude-powered agentic answers on Enter. 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",
"docs",
"site",
"about",
"five",
"minutes",
"keyword",
"works",
"first",
"keyless",
"adding",
"server",
"side",
"anthropic",
"turns",
"claude",
"powered",
"agentic",
"answers",
"enter",
"skipping",
"just",
"ships",
"content",
"searchoverlay",
"steps",
"callout",
"install",
"integration",
"drop",
"overlay",
"build",
"knowledge",
"graph",
"enable",
"whose",
"lives",
"collection"
]
},
{
"id": "quickstart#1-install",
"kind": "section",
"title": "Quick start",
"heading": "1. Install",
"group": "Overview",
"url": "/docs/quickstart#1-install",
"summary": "Install the package from npm once published, or until then consume it straight from the package subdirectory of the GitHub repo.",
"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",
"package",
"once",
"published",
"until",
"consume",
"straight",
"subdirectory",
"github",
"repo",
"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 your content collection name(s) and the slug-to-URL base path. The collections list is the one required option; everything else defaults.",
"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",
"slug",
"base",
"path",
"collections",
"list",
"required",
"option",
"everything",
"else",
"defaults",
"import",
"defineconfig",
"hevask",
"export",
"default",
"integrations",
"docs",
"basepath",
"prefix",
"must",
"configuration",
"reference"
]
},
{
"id": "quickstart#3-add-a-server-adapter",
"kind": "section",
"title": "Quick start",
"heading": "3. Add a server adapter",
"group": "Overview",
"url": "/docs/quickstart#3-add-a-server-adapter",
"summary": "The search route renders on demand, so add whichever server adapter matches your host — existing pages stay prerendered and only the search route runs as a function. The docs site itself uses Cloudflare.",
"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",
"whichever",
"matches",
"host",
"existing",
"pages",
"stay",
"prerendered",
"only",
"runs",
"function",
"docs",
"site",
"itself",
"uses",
"cloudflare",
"astro",
"config",
"import",
"astrojs",
"export",
"default",
"defineconfig",
"platformproxy",
"enabled",
"true",
"integrations",
"above"
]
},
{
"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 data attribute opens the palette and the keyboard shortcut binds automatically — keyword search then works in dev immediately.",
"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",
"data",
"attribute",
"opens",
"palette",
"keyboard",
"shortcut",
"binds",
"automatically",
"keyword",
"search",
"works",
"immediately",
"layouts",
"astro",
"import",
"searchoverlay",
"components",
"button",
"type",
"open",
"slot",
"bound",
"press"
]
},
{
"id": "quickstart#5-build-the-knowledge-graph",
"kind": "section",
"title": "Quick start",
"heading": "5. Build the knowledge graph",
"group": "Overview",
"url": "/docs/quickstart#5-build-the-knowledge-graph",
"summary": "Build the committed graph that gives the loop context, ranks keyword results, supplies the glossary, and holds suggested questions. Recommended: the bundled Claude Code skill, which builds inside your subscription with no API key; or one CLI call for CI. Then verify anchors and commit the JSON — both paths are hash-gated and the integration also builds automatically when a key is present.",
"facts": [
{
"kind": "code",
"literal": "You: build the hev ask knowledge graph\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/kg.json",
"chunkId": "quickstart#5-build-the-knowledge-graph"
},
{
"kind": "code",
"literal": "export ANTHROPIC_API_KEY=sk-ant-...\npnpm exec ask kg build # writes .hev-ask/kg.json",
"chunkId": "quickstart#5-build-the-knowledge-graph"
},
{
"kind": "code",
"literal": "pnpm exec ask kg verify # builds the site, checks every anchor resolves\ngit add .hev-ask/kg.json",
"chunkId": "quickstart#5-build-the-knowledge-graph"
},
{
"kind": "code",
"literal": "k8s",
"chunkId": "quickstart#5-build-the-knowledge-graph"
},
{
"kind": "code",
"literal": "kubernetes",
"chunkId": "quickstart#5-build-the-knowledge-graph"
},
{
"kind": "code",
"literal": "astro build",
"chunkId": "quickstart#5-build-the-knowledge-graph"
},
{
"kind": "value",
"literal": "claude.com",
"chunkId": "quickstart#5-build-the-knowledge-graph"
}
],
"sources": [
{
"chunkId": "quickstart#5-build-the-knowledge-graph",
"url": "/docs/quickstart#5-build-the-knowledge-graph",
"anchor": "5-build-the-knowledge-graph"
}
],
"mode": "agent-primary",
"terms": [
"build",
"knowledge",
"graph",
"committed",
"gives",
"loop",
"context",
"ranks",
"keyword",
"results",
"supplies",
"glossary",
"holds",
"suggested",
"questions",
"recommended",
"bundled",
"claude",
"code",
"skill",
"builds",
"inside",
"subscription",
"call",
"verify",
"anchors",
"commit",
"json",
"both",
"paths",
"hash",
"gated",
"integration",
"also",
"automatically",
"present",
"runs",
"corpus",
"emits",
"sections"
]
},
{
"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 search route runs. With it, Enter runs the agentic loop with sub-queries, a grounded answer, and 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",
"route",
"runs",
"enter",
"loop",
"queries",
"grounded",
"answer",
"inline",
"deep",
"links",
"without",
"returns",
"keyword",
"results",
"anthropicapikey",
"host",
"secrets",
"local",
"present",
"pressing",
"overlay",
"self",
"issued"
]
},
{
"id": "quickstart#prerequisites",
"kind": "section",
"title": "Quick start",
"heading": "Prerequisites",
"group": "Overview",
"url": "/docs/quickstart#prerequisites",
"summary": "You need Astro 5 with at least one content collection, a server or hybrid adapter because the search route renders on demand, and an Anthropic key only if you want agentic search — 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",
"need",
"astro",
"least",
"content",
"collection",
"server",
"hybrid",
"adapter",
"because",
"search",
"route",
"renders",
"demand",
"anthropic",
"only",
"want",
"agentic",
"keyword",
"needs",
"none",
"docs",
"build",
"node",
"cloudflare",
"vercel",
"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-search setup phase: the steps that follow install the package, register the integration, add an adapter, and render the overlay.",
"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",
"setup",
"phase",
"steps",
"follow",
"install",
"package",
"register",
"integration",
"adapter",
"render",
"overlay",
"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": "Three checks: a single heading word should deep-link its top keyword result to that section; a multi-word question on Enter should show the model's sub-queries and stream a grounded answer; and the verify command exits non-zero if any chunk anchor is missing from built HTML — wire it into 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",
"three",
"checks",
"single",
"heading",
"word",
"should",
"deep",
"link",
"keyword",
"result",
"section",
"multi",
"question",
"enter",
"show",
"model",
"queries",
"stream",
"grounded",
"answer",
"command",
"exits",
"zero",
"chunk",
"anchor",
"missing",
"built",
"html",
"wire",
"docs",
"page",
"type",
"agentic",
"click",
"suggested",
"press",
"footer",
"shows"
]
},
{
"id": "tradeoffs",
"kind": "section",
"title": "Tradeoffs",
"heading": null,
"group": "Overview",
"url": "/docs/tradeoffs",
"summary": "Every search tool makes choices; this page is the honest version of what hev ask trades away to get what it gives — dependency posture, the committed graph, agentic cost and latency, and comparisons 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",
"honest",
"version",
"trades",
"away",
"gives",
"dependency",
"posture",
"committed",
"graph",
"agentic",
"cost",
"latency",
"comparisons",
"pagefind",
"algolia",
"orama",
"callout",
"astro",
"choosing",
"adopting",
"knowledge",
"compares",
"decide",
"whether",
"trade",
"fits",
"docs"
]
},
{
"id": "tradeoffs#a-committed-knowledge-graph",
"kind": "section",
"title": "Tradeoffs",
"heading": "A committed knowledge graph",
"group": "Overview",
"url": "/docs/tradeoffs#a-committed-knowledge-graph",
"summary": "The graph is generated offline and committed as JSON rather than computed at runtime or hidden in a service: reviewable in pull requests, deterministic, free to read, and bundled into the edge worker. The cost is staleness — a forgotten rebuild means a slightly outdated glossary — so the hash gate makes 'rebuild on every content change in CI' the intended, cheap, idempotent workflow.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#a-committed-knowledge-graph",
"url": "/docs/tradeoffs#a-committed-knowledge-graph",
"anchor": "a-committed-knowledge-graph"
}
],
"mode": "agent-primary",
"terms": [
"committed",
"knowledge",
"graph",
"generated",
"offline",
"json",
"rather",
"computed",
"runtime",
"hidden",
"service",
"reviewable",
"pull",
"requests",
"deterministic",
"free",
"read",
"bundled",
"edge",
"worker",
"cost",
"staleness",
"forgotten",
"rebuild",
"means",
"slightly",
"outdated",
"glossary",
"hash",
"gate",
"makes",
"every",
"content",
"change",
"intended",
"cheap",
"idempotent",
"workflow",
"upside",
"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 if small money and latency: worst case a few seconds of Haiku round-trips bounded by the iteration cap, one bounded loop per submitted query with the domain context prompt-cached, and an Opus-powered offline graph build paid only when content changes. Keyword-only is a first-class mode for anyone who doesn't want a key in the loop.",
"facts": [
{
"kind": "code",
"literal": "maxIterations",
"chunkId": "tradeoffs#cost-and-latency-of-agentic-search"
}
],
"sources": [
{
"chunkId": "tradeoffs#cost-and-latency-of-agentic-search",
"url": "/docs/tradeoffs#cost-and-latency-of-agentic-search",
"anchor": "cost-and-latency-of-agentic-search"
}
],
"mode": "agent-primary",
"terms": [
"cost",
"latency",
"agentic",
"search",
"path",
"costs",
"real",
"small",
"money",
"worst",
"case",
"seconds",
"haiku",
"round",
"trips",
"bounded",
"iteration",
"loop",
"submitted",
"query",
"domain",
"context",
"prompt",
"cached",
"opus",
"powered",
"offline",
"graph",
"build",
"paid",
"only",
"content",
"changes",
"keyword",
"first",
"class",
"mode",
"anyone",
"doesn",
"want"
]
},
{
"id": "tradeoffs#how-it-compares",
"kind": "section",
"title": "Tradeoffs",
"heading": "How it compares",
"group": "Overview",
"url": "/docs/tradeoffs#how-it-compares",
"summary": "A comparison table against Pagefind, Algolia DocSearch, and Orama across retrieval, AI ranking, deep links, and hosting. Choose Pagefind for static keyword search with zero services; Algolia for a managed crawler-based service; Orama for client-side vector search; hev ask when docs are Astro collections and you want section deep links plus answers to questions, not just keywords.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#how-it-compares",
"url": "/docs/tradeoffs#how-it-compares",
"anchor": "how-it-compares"
}
],
"mode": "agent-primary",
"terms": [
"compares",
"comparison",
"table",
"against",
"pagefind",
"algolia",
"docsearch",
"orama",
"across",
"retrieval",
"ranking",
"deep",
"links",
"hosting",
"choose",
"static",
"keyword",
"search",
"zero",
"services",
"managed",
"crawler",
"based",
"service",
"client",
"side",
"vector",
"docs",
"astro",
"collections",
"want",
"section",
"plus",
"answers",
"questions",
"just",
"keywords",
"tool",
"glossary",
"enter"
]
},
{
"id": "tradeoffs#keyword-retrieval-not-embeddings",
"kind": "section",
"title": "Tradeoffs",
"heading": "Keyword retrieval, not embeddings",
"group": "Overview",
"url": "/docs/tradeoffs#keyword-retrieval-not-embeddings",
"summary": "Retrieval is dependency-free token overlap widened by the glossary — nothing to host, edge-safe, instant — and the glossary recovers much of the synonym recall embeddings would give. The cost is a paraphrase-recall ceiling: the agent can only ground in what keyword retrieval surfaced. The embeddings upgrade is deferred, not designed out.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#keyword-retrieval-not-embeddings",
"url": "/docs/tradeoffs#keyword-retrieval-not-embeddings",
"anchor": "keyword-retrieval-not-embeddings"
}
],
"mode": "agent-primary",
"terms": [
"keyword",
"retrieval",
"embeddings",
"dependency",
"free",
"token",
"overlap",
"widened",
"glossary",
"nothing",
"host",
"edge",
"safe",
"instant",
"recovers",
"much",
"synonym",
"recall",
"would",
"give",
"cost",
"paraphrase",
"ceiling",
"agent",
"only",
"ground",
"surfaced",
"upgrade",
"deferred",
"designed",
"vector",
"store",
"upside",
"keep",
"sync",
"answers",
"well",
"readers",
"routinely",
"search"
]
},
{
"id": "tradeoffs#one-dependency-deliberately",
"kind": "section",
"title": "Tradeoffs",
"heading": "One dependency, deliberately",
"group": "Overview",
"url": "/docs/tradeoffs#one-dependency-deliberately",
"summary": "The package aims for near-zero dependencies with one deliberate exception: the same small, pure-JS, edge-safe slugger Astro uses, because hand-generating anchors risks drifting from the renderer and shipping links that land at the top of the page.",
"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",
"aims",
"near",
"zero",
"dependencies",
"deliberate",
"exception",
"same",
"small",
"pure",
"edge",
"safe",
"slugger",
"astro",
"uses",
"because",
"hand",
"generating",
"anchors",
"risks",
"drifting",
"renderer",
"shipping",
"links",
"land",
"page",
"github",
"close",
"heading",
"link",
"404s",
"guarantees",
"byte",
"identical",
"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 and an agentic path keeps the common one-or-two-word case instant and keyless while hard questions get a smarter ranker. The cost is a slightly more complex interaction model — readers learn that Enter means ask AI — a trade that fits docs, where queries split into jumping to a known thing and finding a thing you can't name.",
"facts": [],
"sources": [
{
"chunkId": "tradeoffs#two-paths-instead-of-one",
"url": "/docs/tradeoffs#two-paths-instead-of-one",
"anchor": "two-paths-instead-of-one"
}
],
"mode": "agent-primary",
"terms": [
"paths",
"instead",
"running",
"instant",
"keyword",
"path",
"agentic",
"keeps",
"common",
"word",
"case",
"keyless",
"while",
"hard",
"questions",
"smarter",
"ranker",
"cost",
"slightly",
"more",
"complex",
"interaction",
"model",
"readers",
"learn",
"enter",
"means",
"trade",
"fits",
"docs",
"queries",
"split",
"jumping",
"known",
"thing",
"finding",
"name",
"runs",
"asks",
"reader"
]
}
],
"edges": []
}