Repository navigation
Releases: dgesteves/ondocs
Release list
starlight-ondocs@0.9.0
starlight-ondocs@0.10.0
ondocs@0.9.0
Minor Changes
-
#84
9276df9Thanks @dgesteves! - One name per option across the endpoint, the dialog, the script tag, the plugins and the CLI. The old names still work, and say once what they are called now, until 0.10 removes them. Upgrading has the table, old name to new.launcherreplacesbuttonLabelinmountAskDialog,window.Ondocs.mount()and the plugins'dialogoptions, each locale's included, asAskDialogalready called it. It takestrue, a label, orfalse. On the script tag,data-launcherreplacesdata-button-label.theme: 'auto'replacestheme: 'system'onAskDialog, the name the plugins and the script tag use.retrieval.maxContextCharsreplacesmaxContextCharsoncreateAskHandler, next totopK. The answer cache keeps its keys.ondocs init --site-namereplaces--name, assiteNamenames it in the handlers.
Two defaults of
AskDialogchange to match the plugins and the script tag. It opens with ⌘I or Ctrl+I, so ⌘K stays with the site's search;shortcut="k"keeps ⌘K. Its default theme,auto, followsdata-theme="light"or"dark"on<html>when the page sets one, and the system's setting otherwise, as before.
Patch Changes
-
#96
9b882eeThanks @dgesteves! - Fixes from following the docs on a fresh install:ondocs index --llms-txtresolves the relative links and images in Markdown files from each file's folder, so they work from the page's.mdcopy and fromllms-full.txt. Before,content/index.md, copied to/docs.md, kept./setup.mdas written, which pointed at/setup.mdthere instead of/docs/setup.md. A link to another page's file goes to that page's copy. An HTMLindex.htmlpage's links are now resolved from its folder too.ondocs initno longer takes adocusaurus deployscript for GitHub Pages: every new Docusaurus site has one, wherever it is hosted. With no host config, init asks, as the docs say. Thegh-pagespackage, a script that runs it, and a Pages workflow still count.- For GitHub Pages, init asks for the site's URL when the config has a template's placeholder, such as
https://your-docusaurus-site.example.com, and warns when it keeps one: the Worker reads the index from that URL. - When the site's config already adds the ondocs plugin, init's next steps no longer say to add it. On GitHub Pages they say which options to give it.
- On a site with no config to detect, the error now says how to name a plain HTML site's folder, as in
npx ondocs init --out public, and names the folder when it finds one with HTML files. - For a site indexed with
ondocs index(Next.js and static sites), init says that a keyword-only index needs-e nonewhen there is no key. The plugins build one without a key, but the CLI stops.
-
#87
5409b87Thanks @dgesteves! -ondocs index, andloadDirectorywithframework: 'next'or'auto', now cite Fumadocs and Nextra pages at the URLs those frameworks serve. On any Next.js site,page.mdxandIndex.mdxin a content folder are pages of their own, and anappfolder is read as Next.js routes it: onlypage.mdxfiles, without_privatefolders. Nextra keeps(group)folders in the URL, and a## Title [#id]heading is cited at#id.frameworkUrlis unchanged. -
#76
153760bThanks @dgesteves! -ondocs initon a static site (Hugo, Jekyll, MkDocs, Eleventy or plain HTML) on Vercel, Netlify or Cloudflare now lists the packages its functions import,ondocs ai @ai-sdk/openai, in its next steps. A site with nopackage.jsongetsnpm init -y && npm i ondocs ai @ai-sdk/openai, since the host installs the functions' packages from one. Before, the steps left outaiand@ai-sdk/openai, or said nothing without apackage.json, and the functions failed to build. -
#81
7858807Thanks @dgesteves! -docusaurus-plugin-ondocsandstarlight-ondocsnow publish to npm, at the same version asondocs. They re-exportondocs/docusaurusandondocs/starlightunder the names Docusaurus and Starlight users search for, as the 0.7.0 release notes and the migration guide said, but until now they were left out of the publish, sonpm i docusaurus-plugin-ondocsornpm i starlight-ondocsfound nothing.
ondocs@0.10.0
Minor Changes
- #107
c675e01Thanks @dgesteves! -ondocs indexnow cites Nextra and Fumadocs headings at the ids those sites render (a mixed-case[#id]in a Nextraapppage is lowercased, and footnote references such as[^1]are left out of the anchor and the heading's text, as on Docusaurus), resolves relative links in the.mdcopy of a page in a Nextra(group)folder from that folder, andframeworkUrltakes an optionalrouting, so it gives the URLloadDirectorygives for a content folder'spage.mdx.
Patch Changes
- #106
900f368Thanks @dgesteves! - The Ask dialog no longer lists sources under an answer that cites none of them, shows a model reply of only "I don't know" as a refusal (the endpoint now marks it as one at the end of its stream), shows the question over an error, and shows a long question from its start in the input once it is asked.
docusaurus-plugin-ondocs@0.9.0
docusaurus-plugin-ondocs@0.10.0
ondocs@0.8.0
Minor Changes
-
#69
bbe0f87Thanks @dgesteves! - New entry,ondocs/integration: the build helpers the Docusaurus, Astro and Starlight plugins are made of, for a plugin for another framework. It reads the pages a build wrote (readBuiltHtml,loadBuiltPage), builds the embedding model (buildEmbedding), writes the index with the previous build's vectors (writeSiteIndex,indexCache) and the llms files (writeLlmsFiles), and adds the launcher to every page (launcherScript,LAUNCHER_STYLESHEETS). The plugins now build with it alone. See "Writing an integration" in the docs. -
#73
4daccdfThanks @dgesteves! - The Docusaurus, Astro, Starlight and VitePress plugins link each page to its Markdown copy. After the build, every page that has a.mdcopy gets<link rel="alternate" type="text/markdown" href="…">in its<head>, with the site's base path and the page's locale, so an agent that fetches the page finds the copy. A page whose head already links a Markdown copy keeps its own, and no page is linked whenllmsTxtturns the copies off or another plugin writes them. Each page's HTML is replaced in one step, so a Docusaurus plugin reading it in its ownpostBuildat the same time reads all of it. Inondocs/integration,writeLlmsFilestakeslinkPagesto do the same for another framework. -
#71
d8a3e65Thanks @dgesteves! -createAskHandlertakes two retrieval hooks.retrieval.rerank(question, hits, { signal, index })puts the candidates in a new order beforetopKis applied, with the AI SDK'srerank()and a reranking model, or to boost sections.retrieval.retrieve(query, search, context)finds the candidates instead of the built-in retrieval, withsearchto call it. The relevance gate decides after both: each hit's chunk is measured again against the question, so a hook cannot make an off-topic page count. A hook that throws is reported toonErrorand skipped. Without hooks, retrieval is unchanged.gateHits, the gate on hits from anywhere, is exported fromondocs. -
#74
55772baThanks @dgesteves! - An optional bot check for the ask endpoint, with Cloudflare Turnstile, off by default.createAskHandlertakeschallenge: turnstile({ secretKey }), withturnstilefromondocs/server. Each question must then carry a Turnstile token aschallengein its body, which the endpoint checks with Turnstile's siteverify after the rate limit and before the answer cache, the embedding and the model. A question without a token gets a 403 with codechallenge_required, and one with a bad or used token a 403 withchallenge_failed. When Turnstile cannot be reached, the endpoint answers 503, or answers anyway withrateLimitFailure: 'open'. Feedback posts and the MCP endpoint are not checked.The dialog solves the check with
challenge: { turnstile: '<site key>' }: onAskDialog,mountAskDialog, and thedialogoptions of the Docusaurus, Astro, Starlight and VitePress plugins, or withdata-turnstile-site-keyon the script tag. When the dialog opens, it loads Turnstile's script from challenges.cloudflare.com and solves a token, invisibly unless Turnstile asks the visitor to click, and it sends a fresh token with each question. Pages load nothing of Turnstile until then. Two new labels,challengeRequiredandchallengeFailed, say when the check did not load or failed.useAsktakeschallengeToken, for a widget of your own.The Astro integration's own ask route checks tokens when
dialog.challenge.turnstileis set, with the secret inTURNSTILE_SECRET_KEY. The endpointsondocs initwrites, and the Cloudflare Worker template, turn the check on onceTURNSTILE_SECRET_KEYis set. -
#70
4773192Thanks @dgesteves! - New VitePress plugin,ondocs/vitepress: wrap the config inwithOndocs(defineConfig({ ... }))and, aftervitepress build, it indexes the pages at the URLs VitePress serves (withbase,cleanUrls,rewrites,srcExclude, dynamic routes and an index per locale, leaving out pages withsearch: false), writesllms.txt,llms-full.txtand a Markdown copy of each page, and adds the "Ask AI" button and ⌘I to every page: about 2 KB of JavaScript, in VitePress's colors and dark mode, with the dialog loaded the first time it is wanted. No theme file is needed.npx ondocs initnow recognizes VitePress sites and writes their endpoint for the index the plugin builds, andondocs devfinds.vitepress/dist/ask-index.json.ondocs/integrationaddsquietUseClient, andlauncherScripttakesspa: truefor a site that moves between pages without loading them.
Patch Changes
-
#67
98d1021Thanks @dgesteves! - The Cloudflare Worker thatondocs initwrites, andtemplates/cloudflare-worker, now allow the install scripts of esbuild and workerd inpackage.json(allowScripts) and decline fsevents. npm 12 runs no install scripts unless they are allowed, so a fresh install no longer warns that Wrangler's binaries were blocked. -
#72
5dbe809Thanks @dgesteves! - The website moved to ondocs.vercel.app, and the README links point there. The old address redirects, so links in earlier versions keep working.
ondocs@0.7.0
Minor Changes
-
#61
a7fc5d3Thanks @dgesteves! - Follow-up questions. The dialog keeps the thread and sends it with each question as{ messages }; the handler rewrites a follow-up that leans on the conversation ("and on Netlify?") into a question that stands on its own, with one short model call, before retrieval, the relevance gate, the answer cache and the answer. A question that already stands on its own is not rewritten. The rewrite counts againstbudget, can use a model of its own (followUps.model), andfollowUps: falsekeeps the single-question behavior;onFinishgets the rewritten question asfollowUp. In the dialog, earlier questions and answers stay above the current one with their own citations, typing offers "Follow up", and "New question" starts over.useAskreturns the thread asturns. -
#59
2321172Thanks @dgesteves! -npx ondocs initwrites the ask endpoint and the MCP endpoint for your site and its host: Vercel Functions, Netlify Functions, Cloudflare Pages Functions, or a Cloudflare Worker with static assets. Each has a rate limit on the host's client IP header, a daily budget, the answer cache, the CORS preflight answered, and the index bundled the way the host needs. For GitHub Pages and other hosts that only serve files, it writes a Cloudflare Worker of its own that reads the index from the live site, with CORS for the site's origin only. It detects Docusaurus, Starlight, Astro, Next.js, VitePress, Hugo, MkDocs, Jekyll and Eleventy, prints what it wrote and the environment variables to set, asks before it overwrites a file that differs, has--dry-run, and never deploys anything or reads secrets.On an Astro or Starlight site with an SSR adapter, the integration now serves
POST /api/askand/api/mcpitself withinjectRoute, from the index it builds, so there is no route file to write. It answers withopenai:gpt-5.4-miniby default, under a rate limit and a daily budget. A route file the site already has at either path answers instead;routesets the model and the limits, androute: falseturns the routes off and keeps the previous behavior.remoteIndex(url)fromondocs/serverfetches an index over HTTP, keeps it in memory and checks it again every five minutes with its ETag, for an endpoint deployed apart from its site. -
#63
1950ef2Thanks @dgesteves! - Labels and locales. Every string the dialog and its button show or announce is a label:labelsonAskDialog,dialog.labelsin the plugins, anddata-labels(a JSON object) ordata-label-<name>on the script tag, over English defaults;DEFAULT_LABELSlists them. The endpoint's own messages show as it sends them unless a label for them is given. The plugins take options per locale (dialog.locales), from Docusaurus's i18n and from the page's path in Starlight and Astro, and the dialog sends the page'slocalewith each question;createAskHandleranswers it fromindexes[locale], the index the plugins already build per locale. The routes the Astro integration serves, and the endpointsondocs initwrites, wire each locale's index.useAsktakeslocale, and anAskErrorhas areason. -
#62
eefb00cThanks @dgesteves! - The quality loop.ondocs eval <questions.yaml>scores retrieval against questions whose answers you know, hit@1 and hit@3, and refusal precision and recall for questions marked unanswerable, question by question, embedding each question as the index was and calling no language model; it exits 1 under its thresholds, for CI. WithonFeedback, the dialog asks "Was this helpful?" under each answer, with thumbs up and down and a comment, posted to the endpoint with the answer's id, whichonFinishnow gets too.onFinishalso getslowConfidence, true when the model answered without citing its sources, sorefused || lowConfidenceis the log of the questions the docs do not answer. Nothing leaves the site unless you wire it.useAskhasrate(), andondocs devprints ratings. -
#66
e3c5e30Thanks @dgesteves! -ask-my-siteis nowondocs, and this is its first release under that name. The options, the endpoints and their paths,ask-index.jsonand its format are unchanged, and so is what the dialog and the endpoint send each other. What had the old name moves, and the old names in your code keep working until you rename them (migration guide):- Package and command:
npm install ondocs, imports fromondocs/server,ondocs/react,ondocs/docusaurus,ondocs/astro,ondocs/starlight,ondocs/embedand the stylesheets under the same paths, andnpx ondocs index,init,devandeval. Theask-my-sitepackage gets no new releases. - Script tag:
https://cdn.jsdelivr.net/npm/ondocs@0.7/dist/embed.global.js. Its global iswindow.Ondocs;window.AskMySitestill works, and says once in the console to use the new name. - Docusaurus: the theme components are
@theme/Ondocsand@theme/OndocsMcp.@theme/AskMySiteand@theme/AskMySiteMcpstill work, and say once, while the site builds or indocusaurus start, to import the new names. The plugin warns about a swizzledsrc/theme/AskMySite, which itsRootno longer renders. The plugin's name, foruseAllPluginInstancesData, isondocs. - Types:
OndocsOptions,OndocsDialogOptions,OndocsStarlightOptions,OndocsGlobalDataandOndocsTheme. TheAskMySite…names are deprecated aliases. - Plugins under their own names:
docusaurus-plugin-ondocsandstarlight-ondocs. They were prepared in the repository asdocusaurus-plugin-ask-my-siteandstarlight-ask-my-site, and never published under those names. - Smaller things: the button's class is
.ondocs-launcherand the script tag's container.ondocs; log lines start with[ondocs]and errors withondocs:; the Astro integration and the Starlight plugin are namedondocs, and so is the MCP server ininitializeunless you passname. The plugins keep the previous build's index innode_modules/.cache/ondocs, and the first build after the upgrade reuses the vectors innode_modules/.cache/ask-my-site, so it embeds only what changed. - Unchanged on purpose: the index's format id (
ask-my-site/index@1), the key under which the endpoint sends each source's title, and the store keys ofbudgetandanswerCache(ask-my-site:budget:,ask-my-site:answer:,ask-my-site:mcp-budget:), so indexes, dialogs and shared stores carry over.
- Package and command:
-
#60
0510866Thanks @dgesteves! - A Cloudflare Worker that answers any static docs site with Workers AI, with no API key:npx ondocs init --host github-pagesnow writes it by default (--provider openaikeeps OpenAI), andtemplates/cloudflare-workeris the same Worker as a template fornpm create cloudflare. It reads the index from the live site, embeds questions with the Workers AI model the index records (or searches by keywords), answers withCHAT_MODEL, caps itself near the free daily allowance, and runs its tests in workerd with stand-ins, offline.-e workers-ai:@cf/<model>(andembedding: 'workers-ai:…'in the plugins) builds an index with a Workers AI embedding model over Cloudflare's REST API, withCLOUDFLARE_ACCOUNT_IDandCLOUDFLARE_API_TOKEN;ondocs devembeds questions for such an index the same way.An index embedded with
@cf/baai/bge-small-en-v1.5gets a relevance gate of 0.65 by default, measured on docusaurus.io's docs, instead of the 0.25 set for OpenAI's models, which would let every question through.
Patch Changes
- #64
1d742bbThanks @dgesteves! - The repository gains two packages under the names people search for,docusaurus-plugin-ondocsandstarlight-ondocs. Each re-exportsondocs/docusaurusorondocs/starlight, is versioned withondocs, and asks for the peer dependencies that entry needs. The main package gains thechatbotanduikeywords.
ask-my-site@0.6.0
Minor Changes
-
#41
1e6ceb5Thanks @dgesteves! - Addlinks: 'sources'to the dialog (<AskDialog links="sources">,<AskAnswer links="sources">,dialog: { links: 'sources' }in the plugins,data-links="sources"on the script tag): a Markdown link in an answer then stays a link only when it points at one of the answer's source pages, and any other shows as its text, so text injected into indexed content cannot get the model to show visitors another site's link. Citations link to their sources either way; the default,'all', is unchanged. The Docusaurus launcher's shortcut hint now reaches 4.5:1 contrast in light and dark mode (it was 3.97:1 in light mode), using Infima's emphasis colors instead of opacity. -
#40
2e8d08bThanks @dgesteves! - The Docusaurus, Astro and Starlight plugins now build their default model, OpenAI'stext-embedding-3-small, at 512 dimensions instead of its full 1,536: a third of the index size, as the README's figures assume. Passdimensions(orembeddingProviderOptions) for another size; a model you name withembeddingkeeps its own size unless you give one.createAskHandlerreads the vector size from the index for OpenAI'stext-embedding-3models, directly or through AI Gateway, so the endpoint no longer repeatsembeddingProviderOptions: { openai: { dimensions } }, and indexes built at 1,536 keep working. If your endpoint runs on an older ask-my-site than your site's build, either upgrade it or pindimensions: 1536in the plugin.ask-my-site devalso findsdist/client/ask-index.json, where Astro writes the index for a site with an adapter, and the Astro integration's build log names the file it wrote from the project root. -
#36
12b4be8Thanks @dgesteves! -createAskHandlernow rate-limits by default: without arateLimit, each client IP gets 10 questions a minute throughmemoryRateLimit(), keyed by the lastX-Forwarded-Forentry as on Vercel. Pass your own limiter to change it (for examplememoryRateLimit({ trustedHeader: 'cf-connecting-ip' })on Cloudflare), orrateLimit: falseto turn it off when something in front of the endpoint already limits it. Requests without anX-Forwarded-Forheader share one bucket, so on a platform that does not set it the default is a single limit for all visitors, and the handler reports the first such request toonErrorwith the setting to change.ask-my-site devanswers up to 30 questions a minute. The Vercel and Cloudflare recipes in the README now show their rate limit, as the Netlify one did. -
#38
1493ad3Thanks @dgesteves! -ask-my-site devnow answers only pages on your machine. Before, it allowed any origin, so withOPENAI_API_KEYset any site you visited could spend your key through it. Requests from an origin other than localhost, 127.0.0.1 or [::1] (any port) get a 403 unless--allow-originnames it (repeatable, or*for any;--originstill works). Requests whoseHostis not one of those names get a 403, which stops DNS rebinding. Request bodies over 64 KiB get a 413 as soon as they pass the limit, instead of being read into memory first. -
#46
8c47324Thanks @dgesteves! - Load the dialog on first use. A page now carries only the dialog's button and shortcut, and the dialog itself (Radix Dialog, cmdk and the answer) loads the first time it is wanted: a pointer over or focus on its button or trigger, the shortcut, or opening it. A shortcut pressed while it loads still opens it, with focus in its input, and focus goes back where it was when it closes. Measured on the example sites, ask-my-site's JavaScript per page goes from about 22 KB to 3 KB gzipped with Docusaurus, from 88 KB to under 2 KB with Starlight, and from 91 KB to 2.4 KB with the script tag.AskDialogkeeps its props;loadAskDialog()loads it sooner.mountAskDialogfromask-my-site/embedno longer loads React until the dialog is wanted. The script tag'sembed.global.jsnow loadsembed-dialog.global.jsfrom next to it: copy both when you host the script yourself, or setdata-dialog-src. -
#45
d6d93d6Thanks @dgesteves! - Writellms.txt,llms-full.txtand a Markdown copy of each page at build time, from the pages the index is built from. The Docusaurus, Astro and Starlight plugins write them into the build output by default:llms.txtas llmstxt.org describes it, linking each page's copy at its URL plus.md(/docs/intro.md), and naming the MCP endpoint when themcpoption is set. The copies, read from the built HTML, keep links, emphasis, code languages, numbered and nested lists, tables and quotes; the index is unchanged. The plugins never replace a file the build already has, and leave whatdocusaurus-plugin-llms,docusaurus-plugin-llms-txt,docusaurus-plugin-copy-page-button,starlight-llms-txt,starlight-page-actionsandstarlight-llm-actionswrite to them.llmsTxt: falseturns all three off, or{ index, full, markdown }one at a time. The CLI writes them withask-my-site index --llms-txt <dir>, andbuildLlmsFilesfromask-my-sitebuilds them anywhere. Pages read from Markdown or HTML now carry theirdescription. -
#44
31ef143Thanks @dgesteves! - Serve the index to agents as an MCP server.createMcpHandlerfromask-my-site/serveris a Web-standard(Request) => Promise<Response>, mounted like the ask endpoint, with three read-only tools:search(ranked sections with a snippet and a URL to the anchor),fetch(a page or section as Markdown) andlist_pages. It never calls a language model, and without anembeddingModelit calls no model at all. It speaks MCP 2026-07-28 (server/discover, no session) and, for clients that start withinitialize, 2025-11-25 back to 2024-11-05, statelessly. Tool calls are rate-limited (60 a minute per client IP by default) and can take a dailybudget.The Docusaurus, Astro and Starlight plugins take an
mcpoption with the endpoint's URL, for an "Add to Cursor / VS Code / Claude" block on a docs page:<AskMySiteMcp />from@theme/AskMySiteMcp, orask-my-site/astro/McpInstall.astro.McpInstallfromask-my-site/reactandmcpInstallLinksfromask-my-sitedo the same anywhere.ask-my-site devserves the index at/api/mcptoo. -
#35
213d8daThanks @dgesteves! - Add spend controls tocreateAskHandler.budget: { requestsPerDay, tokensPerDay }caps the whole endpoint per UTC day, counting model tokens from each answer'susageand reserving an answer's worst case before the model is called, so concurrent answers cannot overshoot it; once it is spent, questions get a 429 with codebudget_exceeded.answerCache: trueanswers a repeated question (compared after normalizing case, spacing and trailing punctuation) without embedding it or calling the model, keyed by the index's content hash so a rebuilt index starts fresh. Both keep their counts and answers in memory by default, and take a shared store:upstashBudgetStoreandupstashAnswerCacheadapt@upstash/rediswithout a dependency on it. Rate-limit keys now bucket an IPv6 client by its /64, so rotating addresses within one subscriber's network no longer gets a fresh limit each time, anduseAskerrors carry the server'scode.
Patch Changes
-
#37
a8b97c5Thanks @dgesteves! - The Docusaurus, Astro and Starlight plugins now post toASK_ENDPOINTwhenever it is set as the site builds or starts, even when the config setsendpoint. Before, anendpointin the config won, so following the README (a config withendpoint: '/api/ask', thenASK_ENDPOINT=http://localhost:8787/api/ask npm start) left the dialog posting to a path the dev server does not serve. The README's plugin snippets no longer setendpoint, since/api/askis the default. -
#39
6ff0ccbThanks @dgesteves! - Read heading ids written as MDX comments,## Title {/* #custom-id */}, which is how Docusaurus spells{#custom-id}in MDX. The MDX loader used to drop the comment and slug the heading text instead, so the CLI's citations missed the page's anchor for every such heading whose id is not its slug: 141 of the 702 indexed sections in docusaurus.io's own docs. And refuse to index a page whose URL is not a path o...
ask-my-site@0.5.3
Patch Changes
- #33
054c7caThanks @dgesteves! - The README on npm opens with the demo animated, the same one GitHub plays as a video, instead of a still image.