// 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.

version
2
sections
86
glossary
24
generated
2026-06-04
content hash
be65bde22082
  1. 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.

  2. 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.

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 reference
    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 · quoted verbatim
    @hev/askaskglossarysectionssection getoverviewsearchanswermcpask kgbuildcorpusassembleverifyhev-ask-kgask kg ...Callout.astro

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Building the graph reference
    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 · 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--strict

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Claude Code skill reference
    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 · 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 build

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Distribution reference
    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 · quoted verbatim
    askhev-ask-kgask kg ...HEV_ASK_BINARY

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Flags reference
    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 · 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 reference
    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 · 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/askLoadGraphListGlossaryGetSectionSearchGraphNewEndpointClientBuildKnowledgeGraphVerifyAnchorsServeMCP

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • MCP reference
    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 · 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_getoverviewsearchanswer

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Package scripts reference
    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 · quoted verbatim
    { "scripts": { "kg:build": "ask kg build", "kg:verify": "ask kg verify" } }ask kghev-ask-kg buildhev-ask-kg verify

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Reading the graph reference
    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 · 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 search

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Where it runs reference
    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 · quoted verbatim
    ask kg buildastro buildANTHROPIC_API_KEYvirtual:hev-ask/kgask kg verify

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Configuration reference
    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 · 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.astro

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Options reference
    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 · quoted verbatim
    collectionsstring[]basePathstring'/docs/'basePath + slug#anchorendpoint'/api/ask'model'claude-haiku-4-5'kgModel'claude-opus-4-8'maxResultsnumberanswerMaxTokens1024maxIterationssearchchunkHeadingDepth#####candidatePerSearchperDocCap

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Tuning notes reference
    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 · quoted verbatim
    chunkHeadingDepth###maxIterationsperDocCapcandidatePerSearch

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • TypeScript reference
    The 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 reference
    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 · quoted verbatim
    astro:config:setupendpoint@hev/ask/endpointprerender: falsevirtual:hev-ask/configvirtual:hev-ask/kgkgPathcollectionsastro:build:startANTHROPIC_API_KEY

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Search endpoint reference
    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 · quoted verbatim
    /api/asktext/event-stream/openapi.yamlCallout.astro3.1openapi.yaml

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Agentic response (SSE) reference
    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 · quoted verbatim
    modeagenticcontent-type: text/event-streamsearch{ query }sources{ sources: Source[], model, mode }token{ text }done{}error{ error }200Source{ title, heading?, url, group? }snippeturl

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Errors reference
    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 · quoted verbatim
    400{ "error": "Invalid JSON body." }404{ "error": "…" }500event: error200errore.g

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Index lifecycle reference
    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 · quoted verbatim
    ask kg build

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Keyword response (JSON) reference
    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 · 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?#anchor

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Knowledge graph reads (GET) reference
    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 · 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%23flags404

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • LLM tracing reference
    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 · quoted verbatim
    POSTHOG_KEYPOSTHOG_API_KEY$ai_generationPOSTHOG_HOSTPOSTHOG_CAPTURE_CONTENToffredactedfull

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Mode selection reference
    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 · quoted verbatim
    { results: [], query: "", model, mode: "keyword" }mode: "keyword"mode: "agentic"warningcontent-type

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Request reference
    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 · quoted verbatim
    { "query": "how does autoscaling work", "mode": "agentic" }POSTquerystringmode'keyword' \| 'agentic'keywordagentic

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Suggested questions (GET) reference
    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 · quoted verbatim
    { "suggestions": ["How does the knowledge graph stay fresh?"], "model": "claude-haiku-4-5" }GET /api/asksuggestions

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • The API key reference
    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 · quoted verbatim
    ANTHROPIC_API_KEYlocals.runtime.envprocess.envimport.meta.enve.g

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Knowledge graph format reference
    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 · quoted verbatim
    .hev-ask/kg.jsonask kg buildvirtual:hev-ask/kgurl#anchorCallout.astro

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Degradation reference
    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 · quoted verbatim
    summaryglossarycontextsuggestions

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Fields reference
    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 · 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 reference
    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 · quoted verbatim
    overviewnodesfactsglossaryk8skubernetessummarytermssuggestionsGETcontentHashbuild

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • KnowledgeNode reference
    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 · 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 reference
    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 · quoted verbatim
    ask kg buildastro buildask kg verify

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Shape reference
    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.
    no verbatim facts in this section

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • MCP server reference
    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 · quoted verbatim
    ask mcp.hev-ask/kg.json/api/ask

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Configure reference
    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 · 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--endpoint

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Data sources reference
    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 · quoted verbatim
    ask mcp--endpoint <url>answerPOST /api/ask--kg-path.hev-ask/kg.jsonkg.json

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Protocol surface reference
    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 · quoted verbatim
    initializetools/listtools/callisError: truepkg/ask

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Tools reference
    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 · 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 }contentstructuredContent

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • SearchOverlay component reference
    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 · quoted verbatim
    --- import SearchOverlay from "@hev/ask/components/SearchOverlay.astro"; --- <SearchOverlay />SearchOverlay.astro⌘K<dialog>Callout.astro

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Keyboard model reference
    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 · quoted verbatim
    Tab

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Keyword results and deep links reference
    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 · quoted verbatim
    Concepts › The agentic loopurl#anchor

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Opening the overlay reference
    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 · 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-open

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Props reference
    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 · quoted verbatim
    <SearchOverlay endpoint="/api/ask" placeholder="Search hev ask…" debounce={400} />endpointstring'/api/ask'placeholder'Search the docs…'debouncenumber500

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Suggested questions reference
    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 · quoted verbatim
    GET /api/asksuggestions

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • The mode toggle reference
    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 · quoted verbatim
    localStoragehev-ask:modeagentickeyword

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • The streamed answer reference
    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 · quoted verbatim
    searched: …/docs/page#anchor

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗
  • Theming reference
    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 · quoted verbatim
    :root { --paper: #111111; /* overlay background */ --ink: #fafaf5; /* primary text */ --muted: #6b6b66; /* secondary text */ --signal: #e25822; /* accent / active state */ }as-:root

    Reference section — on open, the agent also receives this section's source text verbatim.

    open section ↗

Overview

  • 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 · quoted verbatim
    Diagram.astroCallout.astro
    open section ↗
  • 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 · quoted verbatim
    localStorage
    open section ↗
  • 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 · quoted verbatim
    #####basePath + slug + #anchorgithub-sluggergetCollectiongithub.com
    open section ↗
  • 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 · quoted verbatim
    kg.json
    open section ↗
  • 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 · quoted verbatim
    k8skuberneteskg.jsonsummarytermsfacts
    open section ↗
  • 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 · quoted verbatim
    open_section({ id })factsmaxIterationsurl
    open section ↗
  • 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 · quoted verbatim
    kg.jsonnodessummaryfactssourcesource-primaryoverviewcontextglossarysuggestions
    open section ↗
  • 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 · quoted verbatim
    cache_control4.5
    open section ↗
  • 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 · quoted verbatim
    kg.jsonANTHROPIC_API_KEYask kg build4.8
    open section ↗
  • Introduction 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 · quoted verbatim
    ⌘K.hev-ask/kg.jsonDiagram.astroCallout.astroastro.build
    open section ↗
  • 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 · quoted verbatim
    .hev-ask/kg.jsonANTHROPIC_API_KEYSearchOverlay.astrokg.json
    open section ↗
  • 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 · quoted verbatim
    ask
    open section ↗
  • 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 · quoted verbatim
    docs.astro.buildpagefind.app
    open section ↗
  • 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 · quoted verbatim
    Callout.astro
    open section ↗
  • 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 · quoted verbatim
    /api/ask
    open section ↗
  • 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 · quoted verbatim
    maxIterations
    open section ↗
  • Anchors depend on Astro's 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 · quoted verbatim
    idgithub-sluggerask kg verifyverify
    open section ↗
  • 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 · quoted verbatim
    getCollection
    open section ↗
  • 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 · quoted verbatim
    k8skubernetes
    open section ↗
  • 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 · quoted verbatim
    ANTHROPIC_API_KEY/api/ask
    open section ↗
  • 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 · quoted verbatim
    .astro
    open section ↗
  • 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.
    no verbatim facts in this section open section ↗
  • Quick start 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 · quoted verbatim
    src/content/docsANTHROPIC_API_KEYSearchOverlay.astroSteps.astroCallout.astro
    open section ↗
  • 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 · quoted verbatim
    pnpm add @hev/askpnpm add "git+ssh://[email protected]/hev/ask.git#main&path:/packages/ui"
    open section ↗
  • 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 · quoted verbatim
    // 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
    open section ↗
  • 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 · quoted verbatim
    // astro.config.mjs import cloudflare from "@astrojs/cloudflare"; export default defineConfig({ adapter: cloudflare({ platformProxy: { enabled: true } }), // ...integrations as above });/api/ask
    open section ↗
  • 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 · quoted verbatim
    --- // 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
    open section ↗
  • 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 · quoted verbatim
    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
    open section ↗
  • 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 · quoted verbatim
    ANTHROPIC_API_KEY/api/ask.env
    open section ↗
  • 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 · quoted verbatim
    /api/askANTHROPIC_API_KEYdocs.astro.build
    open section ↗
  • 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 · quoted verbatim
    astro.config.mjsSearchOverlay.astro
    open section ↗
  • 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 · quoted verbatim
    /docs/page#headingask kg verify
    open section ↗
  • 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 · quoted verbatim
    Callout.astro
    open section ↗
  • 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.
    no verbatim facts in this section open section ↗
  • 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 · quoted verbatim
    maxIterations
    open section ↗
  • 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.
    no verbatim facts in this section open section ↗
  • 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.
    no verbatim facts in this section open section ↗
  • 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 · quoted verbatim
    github-sluggergithub.com
    open section ↗
  • 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.
    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": []
}
esc