Two things this PR was missing, both now closed.
## The Claude SDK quickstarts are unblocked
#6618 put `showcase/integrations/claude-sdk-{python,typescript}` on
`createCopilotRuntimeHandler` with `mode: "single-route"`, at the **plain**
`route.ts` path. That dissolves the coupling that forced these two pages to be
reverted earlier: `verify-shell-docs.ts` asserts each page claims a starter file
at `src/app/api/copilotkit/route.ts` AND that the file exists in the extracted
starter. Single-route keeps that path, so the prose claims and
`requiredStarterFiles` are unchanged — only the fence bodies move to v2.
The two content assertions that pinned those pages to v1
(`ExperimentalEmptyAdapter`, `copilotRuntimeNextJSAppRouterEndpoint`) now
require `createCopilotRuntimeHandler`, the `/v2` entrypoint,
`mode: "single-route"` and a `POST` export. Mutation-checked: flipping the
fixture to `mode: "multi-route"` fails with
`app/api/copilotkit/route.ts missing single-route mode`.
## Snippet gating: 1 -> 20 route fences
I previously claimed the integration pages could not be doctested because of
path aliases and per-integration deps. **That was an assumption I never
checked, and it was wrong.** Of the 52 migrated route fences, 47 import nothing
project-relative; 36 are complete, self-standing routes. 27 pages were
eligible, 20 now hold a gated fence — each extracted and typechecked by
`tsc --noEmit` against real npm-installed packages in CI.
One fence per (page, title): `extract.ts` concatenates tagged blocks sharing a
title, so a second complete route on the same page would collide.
Mutation-checked on `snippets/integrations/langsmith/index.mdx`: restoring the
v1 import in the gated fence turns the run red (20 passed, 1 failed). My first
attempt at this check was a no-op — the pattern missed because the fence is
JSX-indented — and it "passed" misleadingly. The real check asserts the mutation
reached the extracted snippet before trusting the result.
### Harness changes this needed
- `extract.ts` now finds the nearest `doctest.json` by walking up to the docs
root, instead of looking only in the page's own directory. Otherwise gating
20 pages means ~20 duplicated dependency lists that then drift. A shared list
lives at `content/doctest.json`; `docs/integrations/langgraph/` keeps its own
(Python deps) and now also carries the TS deps its page needs.
- `run.ts` installs each dependency set **once**, into
`.doctest-output/.deps/<hash>`, and links it into every snippet sharing that
set. Per-snippet installs took **7:58** for 21 snippets, uncomfortably close
to the job's 15-minute timeout; shared installs take **0:45** cold. Different
dep sets still get separate stores, so this is a dedupe, not a merge.
### `@ag-ui/*` versions have to be pinned to what the runtime expects
Unpinned, the gated fences failed with `HttpAgent is not assignable to
AbstractAgent — separate declarations of a private property '_debug'`: npm
installs a newer `@ag-ui/client` than `@copilotkit/runtime` depends on, so two
`AbstractAgent` declarations collide. The sidecar pins `@ag-ui/client@0.0.57` and
`@ag-ui/core@0.0.57` to match `@copilotkit/runtime@1.68.3`.
## Seven fences are deliberately NOT gated
Un-tagged with the reason, rather than left failing or quietly dropped:
- `docs/auth.mdx`, `docs/premium/connect-your-runtime.mdx` — illustrative
fences referencing placeholders (`myAgent`, `verifyJwt`) that cannot compile
standalone by design.
- the four langgraph-family pages and
`snippets/self-hosting-copilot-runtime-langgraph-endpoint.mdx` — these hit
`LangGraphAgent is not assignable to AbstractAgent — separate declarations of
a private property '_debug'`, which pinning does not fix.
**That last one is a real pre-existing defect, not a migration regression.** I
reconstructed the v1 form of the langgraph quickstart snippet verbatim from
`origin/main` and typechecked it against the identical installed dependencies:
it fails with the same error. So these snippets have never typechecked against
published packages — worth filing separately. It is also what the ~220
`@ts-ignore` comments across `showcase/integrations` were papering over.
## Verified
doc-tests (cold, no cache) -> 21 passed, 0 failed in 0:45
mutation check (real, verified) -> 20 passed, 1 failed
vitest extract + verify-shell-docs -> 34 passed
showcase/shell-docs typecheck -> exit 0
showcase/shell-docs build -> exit 0
structural audit -> 21/21 pages, fence + JSX identical to HEAD
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add verify-shell-docs (+ unit tests), probe-shell-docs, probe-claude-quickstarts
(Playwright), and check-claude-quickstarts-runtime (extracts and runs the
documented commands/snippets) to gate the shell-docs build and quickstart
runtime. Includes CR hardening: drained server pipes, temp-dir cleanup,
SIGKILL escalation, a stack-trace-leak guard that matches SSE-escaped newlines,
and a fixed false-negative in the missing-import check.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Derive snippet component names from SNIPPET_MAP in docs-render.tsx at
runtime instead of maintaining a hardcoded 35-entry set that was already
13 entries behind. Replace name-level handledByInline gate with per-match
inline pattern check to fix a false-negative path. Align function
signature with sibling check functions. Add 3 unit tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Six fixes from CR Round 1 partition, all bucket (a):
- frontend_tools.py: docstring claimed the file was "Chat Customization
(CSS) demo" but langgraph.json wires it as the Frontend Tools demo
graph, and the new MDX setup snippets cite this exact file via the
freshly-added `# region: middleware` markers. Users following the
langgraph-python copilot-middleware setup would see CSS-demo wording
on a Frontend Tools page. Rewrote the docstring to match what the
cell actually demonstrates (mirroring the sibling
frontend_tools_async.py phrasing).
- page.tsx mergeFrameworkNav: when introNode was non-null AND the root
nav had no "Get Started" section, introNode was prepended to rootNav
shifting every existing index +1. The adjustment block only added +1
when getStartedIdx !== -1, so the splice-back position for the
framework section was off-by-one in the no-Get-Started branch — the
framework header rendered one slot too early in the sidebar.
- docs-page-view.tsx h2/h3 overrides: `{...rest}` was spread AFTER
`id={id}`, so an MDX-supplied `<h2 id="custom">` would override the
slugified id and silently break the TOC anchor + any inbound deep-
links keyed on the slug. Reordered the spread so rest comes first
and the slug-id always wins.
- probe-shell-docs.ts: terminated with bare `main();` while every
sibling script (audit-docs-porting, verify-shell-docs) wraps in
`.catch(e => { console.error(e); process.exit(1); })`. A rejected
main() would surface as an unhandled rejection on older Node
runtimes and exit 0 in CI, masking failure. Aligned with the
established pattern.
- verify-shell-docs.ts: all four regex checks (InlineDemo refs,
Snippet regions, internal links, alias imports) scanned page.body
raw without first stripping fenced code blocks. Any docs page that
showed example code containing `<InlineDemo demo="x" />`,
`[link](/path)`, or `import x from "@/..."` triggered a false-
positive validator failure. Mirrors audit-docs-porting.ts's
FENCED_CODE_RE approach. Adds a regression test that fails without
the strip.
- 3 new MDX content fixes:
* mcp-apps.mdx + open-generative-ui.mdx: removed duplicate `<Callout>`
"Free course" blocks (the same Callout appeared twice on each
page, separated only by the Key Benefits list).
* subagents.mdx: changed `[OnStateChanged, OnRunStatusChanged]` to
`[UseAgentUpdate.OnStateChanged, UseAgentUpdate.OnRunStatusChanged]`
— the bare identifiers aren't exported (the reference doc
`useAgent.mdx` confirms the qualified form), so a user copying
the snippet would hit an import error.
Call-site enumeration:
- frontend_tools.py: only langgraph.json + the new setup MDX files
reference this file by name; both consume the region markers, not
the docstring. Docstring rewrite has zero call-site impact.
- mergeFrameworkNav: single caller (FrameworkScopedDocsPage at this
file's bottom). The new branch covers a strictly broader case;
the original splice/replace paths are unchanged.
- h2/h3: only used by the MDXRemote `components` map below. Spread
order is a local prop-precedence change; no upstream callers.
- probe-shell-docs main(): no external callers.
- verify-shell-docs check functions: 4 exported functions called
from runChecks() below + the test file. Strip is internal to each
function so signature is unchanged.
- UseAgentUpdate: confirmed exported from `@copilotkit/react-core/v2`
per reference doc useAgent.mdx; no implementation change needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>