Closes [OSS-882](https://linear.app/copilotkit/issue/OSS-882/add-to-existing-journeys-reach-for-the-v1-compat-copilotkit-wrapper). ## The failure The v1-compatible `<CopilotKit>` provider pins `useSingleEndpoint` to `true` ([`copilotkit.tsx:108`](https://github.com/CopilotKit/CopilotKit/blob/main/packages/react-core/src/components/copilot-provider/copilotkit.tsx#L108)), so its startup handshake POSTs `{ method: "info" }` at the base path. A multi-route runtime — the default — matches no route for that path and answered a bare `{"error":"Not found"}`, indistinguishable from a wrong `basePath` or an unmounted handler. Two independent onboarding validation runs hit this on their first browser attempt and each had to guess the cause. Both were *add-to-existing-app* journeys; the greenfield one reached for `CopilotKitProvider` and never saw it. ## What changed **The runtime says what happened.** `detectSingleRouteEnvelope` recognises a POST whose JSON body carries a `method` the single-route endpoint accepts, and the multi-route handler uses it at the one point routing gives up. The 404 now carries a `code` and a message naming the prop, plus a `logger.warn` so it lands in the dev-server terminal too. Deliberately conservative — wrong verb, non-JSON, unknown method, or a JSON POST that isn't an envelope all stay ordinary 404s, unchanged in status and shape. **The client stops discarding it.** All four `/info` callers (two in `agent-registry.ts`, two in `agent.ts`) threw away the response body and reported only the status, so a server-side diagnosis reached nobody. They now go through `runtimeInfoError`, which folds a string `message` from the body into the thrown error. Any future server-side diagnosis reaches the developer for free. **Docs.** Five pages paired a v2 multi-route handler with `<CopilotKit>` and never mentioned the prop. Rather than a warning under a snippet that is still wrong to copy, the snippets themselves now pass `useSingleEndpoint={false}`, with a short callout linking to the provider/handler mapping. Two pages were deliberately left alone: `backend/runtime-endpoints.mdx` already documents the pairing in full, and `cookbook/arcade.mdx` uses `mode: "single-route"` on purpose and already explains it. `backend/copilot-runtime.mdx` keeps its snippet as-is — it pairs with the v1 endpoint, where the default is correct — and gains the caveat only on its "switch to v2 handlers" note. Option 3 in the issue (reconsidering the compat default) is **not** in this PR. ## Testing ### Both halves connect, end to end Real `createCopilotRuntimeHandler` + real `CopilotKitCore` configured the way the v1 wrapper configures it — no mocks on either side: ``` code : runtime_info_fetch_failed message: Runtime info request failed with status 404: Received a single-route request envelope ({ method: "..." }) but this runtime is mounted in multi-route mode, so the request matched no route. If the frontend uses <CopilotKit> from @copilotkit/react-core/v2, pass useSingleEndpoint={false} — that provider defaults it to true. Otherwise mount the runtime with mode: "single-route" to serve this envelope. PASS — the diagnostic reached the client ``` The server-side `logger.warn` fired in the same run, carrying `{ url, path, method: 'info' }`. ### Unit tests `packages/runtime` — `single-route-envelope-diagnostic.test.ts` (2 positive, 5 control): ``` ✓ src/v2/runtime/__tests__/single-route-envelope-diagnostic.test.ts (7 tests) 26ms Tests 7 passed (7) ``` `packages/core` — `runtime-info-error-detail.test.ts` (2 positive, 5 control): ``` ✓ src/__tests__/runtime-info-error-detail.test.ts (7 tests) 267ms Tests 7 passed (7) ``` ### Mutation checks Every new test was verified to fail when its mechanism is broken, in both directions. Detector forced to `return null` — the two positives die, the four controls hold: ``` × names useSingleEndpoint when the envelope is an info call × diagnoses every method the single-route envelope accepts ✓ leaves an ordinary unmatched route as a plain 404 ✓ leaves a JSON POST that is not an envelope as a plain 404 ✓ leaves an unrecognized method name as a plain 404 ✓ does not diagnose a non-JSON POST ``` Detector forced to `return "info"` — the controls die instead, proving they are not vacuous: ``` ✓ names useSingleEndpoint when the envelope is an info call ✓ diagnoses every method the single-route envelope accepts × leaves an ordinary unmatched route as a plain 404 × leaves a JSON POST that is not an envelope as a plain 404 × leaves an unrecognized method name as a plain 404 × does not diagnose a non-JSON POST ``` `runtimeInfoError` with the detail dropped, then with the `typeof message === "string"` guard removed — each kills a different pair: ``` mutation: detail dropped → 2 failed | 5 passed mutation: accept any message field → 2 failed | 5 passed restored → 7 passed ``` ### Full suites, builds, docs | Check | Result | |---|---| | `packages/core` full suite | `Test Files 60 passed (60)` / `Tests 662 passed (662)` | | `packages/runtime` full suite | `Test Files 142 passed (142)` / `Tests 2067 passed (2067)` | | `packages/core` `tsc --noEmit` | clean | | `packages/runtime` `tsdown` | `416 files` — build complete | | MDX compile, 5 edited pages | all `OK` | | pre-commit `nx run-many -t test,publint,attw` | passed across affected projects | | CI on `f94d1ab0` | 72 pass, 3 skipping, 0 fail | Both suites are fully green. An earlier revision of this description reported 6 runtime failures as pre-existing on `main`; they were not. They were artifacts of a worktree whose `node_modules` had been assembled by hand, and a proper `pnpm install` cleared all of them along with the inspector-metadata failures from a stale `@copilotkit/shared` dist. `main` is clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Shell Docs
showcase/shell-docs is the Next.js app that builds and serves
docs.copilotkit.ai. Author CopilotKit product documentation here, not in the retired
top-level docs/ app.
Run Locally
Shell-docs is a standalone npm-based app. You do not need a root install just to run the docs app locally.
cd showcase/scripts
npm install
cd ../shell-docs
npm install
npm run dev
The local dev server runs on port 3003.
http://localhost:3003
The shell-docs npm lifecycle generates registry, demo-content, setup-content, and search
data before dev, build, and typecheck.
Validate Changes
Run these from showcase/shell-docs:
npm run build
npm run typecheck
npm run test
For repo-level CI parity, prefer Nx when a shell-docs target is available in the current checkout and root dependencies are installed. For normal shell-docs local development, the npm commands above are the canonical path.
Authoring Recipes
Showcase-Driven Framework Docs
Showcase-driven frameworks use docs_mode: generated. The docs are assembled from showcase
registry/generated data, demos, source regions, shared/root MDX, snippets, and sparse
framework overrides.
To update showcase-driven docs:
- Edit the showcase source of truth: manifests, demos, feature coverage, source regions, or registry inputs.
- Edit shared/root MDX only when the change applies across generated frameworks.
- Add sparse framework overrides only for real framework-specific differences.
- Do not hand-edit generated files under
src/data/frameworks/. - Validate routes, sidebar state, search results, snippets, and framework switching.
Authored Framework Docs
Authored frameworks use docs_mode: authored. The framework owns an MDX tree under
src/content/docs/integrations/<docsFolder>/ with a meta.json sidebar.
To update authored docs:
- Check
getDocsFolder()insrc/lib/registry.ts; the URL slug and folder name may differ. - Edit the MDX page under
src/content/docs/integrations/<docsFolder>/. - Update that folder's
meta.jsonwhen adding, removing, or moving pages. - Reuse shared snippets from
src/content/snippets/when content should stay consistent across frameworks. - Validate the framework route, sidebar, search result, and any shared snippet render.
Reference Docs
Edit API reference pages under src/content/reference/.
The v2 reference does not use meta.json; navigation is generated by walking the tree and
reading each page's title and description frontmatter. Only the legacy reference/v1/
tree uses meta.json.
Snippets
Reusable snippets live under src/content/snippets/. Snippets may be rendered by root docs,
authored framework pages, and showcase-driven framework pages, so keep them general unless
the path is intentionally framework-specific.
Frontend Applicability
Frontend routes use page-level applicability metadata, independent from where the content is authored. A page can be authored MDX, showcase-generated content, mirrored protocol docs, or reference content and still be universal across frontends.
Use the frontend field in page frontmatter or meta.json when a root doc should appear in
non-React frontend docs:
universal— render the same page under/<frontend>/....frontend-variant— render only when a matching page exists undersrc/content/docs/frontends/<frontend>/....hide— omit the page from frontend-scoped docs.
Do not use "showcase-driven" as a proxy for frontend availability. Showcase derivation is an authoring/source detail; frontend applicability controls routing and sidebar inclusion.
AG-UI Mirrored Docs
AG-UI protocol docs are authored upstream in ag-ui-protocol/ag-ui. The
src/content/ag-ui/ tree is a downstream mirror rendered on the CopilotKit docs host.
Change AG-UI docs upstream first, then sync the mirror back into shell-docs.
Top-Level Docs Symlink
The repository's top-level docs/ path is a symlink to showcase/shell-docs/ for
contributor muscle memory. It is not a separate docs app. Do not recreate the old
docs/content/docs/ tree; author CopilotKit docs in showcase/shell-docs/src/content/.