NLWeb
leadtype/nlweb makes your docs site answer NLWeb
natural-language queries. It has two halves:
- Runtime:
createAskHandler()mounts a Web-standard/askendpoint over the generated artifacts — list-mode answers backed by the same search index the docs MCP server uses. No LLM, no new content surface. - Generate-time: with
agents.nlweb.enabled,leadtype generateemits a schema.org JSONL feed (/feeds/schema.jsonl), a/schema-map.xmlthat lists it, and aSchemamap:directive in robots.txt so retrieval systems can find the feeds.
Mount the /ask endpoint
// app/ask/route.ts (Next App Router)
import { createAskHandler } from "leadtype/nlweb";
const handler = createAskHandler({ artifacts: "./public" });
export const GET = handler;
export const POST = handler;The handler accepts the NLWeb request shapes — ?query= params, a flat JSON
body, or the { query: { text }, prefer: { streaming } } document — and
answers with:
{
"query_id": "…",
"_meta": { "response_type": "answer", "version": "0.55" },
"results": [
{
"url": "https://example.com/docs/quickstart",
"name": "Quickstart",
"site": "example.com",
"score": 12.4,
"description": "Install and configure the package.",
"schema_object": { "@type": "TechArticle", "…": "…" }
}
]
}Streaming is opt-in: request it with prefer.streaming: true, ?streaming=1,
or an Accept: text/event-stream header and the handler responds with SSE
start / result / complete events. (NLWeb defaults to streaming; leadtype
defaults to the JSON document so plain fetches and scanners get what they
expect.)
mode=summarize / mode=generate need an LLM and are not implemented —
queries always answer in list mode.
Emit the schema feeds
// docs/docs.config.ts
agents: {
nlweb: { enabled: true },
},leadtype generate then writes /feeds/schema.jsonl (one schema.org
TechArticle per docs page), /schema-map.xml listing the feed, and adds
Schemamap: <baseUrl>/schema-map.xml after the Sitemap: line in robots.txt.
The root llms.txt also links the /ask endpoint under ## Agent Interfaces. Set agents.nlweb.endpoint if you mount the handler somewhere
other than /ask.
Hosts that regenerate robots.txt at request time pass the directive through
createRobotsTxtResponse({ schemamapUrlPath: "/schema-map.xml" }).