Two legacy docs URLs have been dead ends for six months. Neither has
anything to do with the recent `premium/` → `intelligence/` rename —
they are older, and the rename only moved where they fail.
## `/premium/inspector` — 404
`cc8c945893` ("refactor(docs): optimize structure, content and
navigability", 2026-02-23) renamed `(root)/premium/inspector.mdx` to
`(root)/inspector.mdx` as an `R100` rename — identical content. The page
still exists and `/inspector` serves it. Only the old URL was left
behind, and it has 404'd ever since. It shows up in
`analytics_postgres_contacts.hs_analytics_source_data_1` as a HubSpot
first-touch page, so it had real traffic.
## `/direct-to-llm/guides/premium/*` — wrong page, 200
All four pages under that path (overview, headless-ui, observability,
inspector) were deleted in the same commit. The `R16`
`/direct-to-llm/:path*` wildcard strips the prefix and the remainder
falls through to the docs home, so the reader gets a 200 and the wrong
page. That is why it went unnoticed longer than a 404 would have —
nothing looks broken. `/direct-to-llm/guides/premium/headless-ui` is
also in the HubSpot first-touch data.
`cc8c945893` had no redirect config to update: `seo-redirects.ts` did
not exist yet. The gap is that nobody back-filled these when it was
built.
## What this adds
33 exact entries:
- `INTEL-inspector-root`: `/premium/inspector` → `/inspector`
- `INTEL-inspector×<fw>`: `/<fw>/premium/inspector` →
`/<canonical-fw>/inspector`, expanded over `PREMIUM_URL_FRAMEWORKS`
exactly as the observability entries are
- `INTEL-d2l-guides-*`: the four `/direct-to-llm/guides/premium/*`
pages, each to its current equivalent (the retired observability page
goes to the overview, matching `INTEL-observability-*`)
Both hosts get them, plus the harness copy. `P7` renames `/premium/*` to
a docs-host `/intelligence/*` on the way across, so without the shell
entry the legacy shell URL would 301 into a docs-host 404 — the same
reasoning the `INTEL-observability-root` comment already spells out. The
harness driver is the declared intentional copy of the shell list and
moves with it.
## Why exact entries
Middleware builds `exactMap` from every source without `:path*` and
checks it before the wildcard list. `INTEL-rename-wild` would otherwise
rewrite `/premium/inspector` to a nonexistent `/intelligence/inspector`.
Same mechanism that makes the observability entries work today.
## Verification
- All 24 distinct destinations probed against staging: 22 return 200.
`/langroid/inspector` and `/spring-ai/inspector` 404 — those two
framework surfaces are not served at all, their bare roots and
quickstarts 404 too, and the existing observability entries carry the
same property. No reachable URL changes behavior.
- Catalogue check over all 463 exact sources: no duplicate source, no
self-loop, no wildcard among the new entries.
- `showcase-harness`: 177 test files, 3728 tests pass.
`showcase-scripts`: 78 files, 2543 tests pass. shell-docs lint and
typecheck clean; its redirect suite goes from 10 to 13 tests.
- Decommission fixtures regenerated through the CLI with
`--events-json`, not through the core module, so the byte-for-byte
cross-check between CLI and core keeps its meaning. The diff is 390 →
395 defined, 377 → 382 zero-hit, plus the five new ids.
## Not verifiable in production yet
`docs.copilotkit.ai` has not been promoted since #6818 merged, so
production has no `/intelligence/*` tree and serves `/premium/*`
directly. Everything above was measured on staging, where the rename and
its redirects are live. Reviewing these URLs against production will
show the old behavior until `shell-docs` is promoted.
## Left alone
- `/integrations/direct-to-llm/guides/premium/headless-ui` also 404s,
but there is no `/integrations/direct-to-llm/:path*` rule at all, so
that is a wider gap about the `/integrations/*` prefix rather than this
one.
- `docs/superpowers/plans/2026-08-03-ent-1173-…md` still names the old
content path. It is a record of a finished plan and describes what was
true then.
## Summary
- Add one framework-agnostic WebMCP guide at `/webmcp`.
- Make the page available through every visible frontend and
agent-framework route.
- Add WebMCP to the shared docs navigation.
## Why
Developers need an accurate launch reference that explains WebMCP
without assuming they already understand CopilotKit frontend tools.
WebMCP is page-level rather than agent-specific, so one universal guide
should follow the selected frontend and backend instead of maintaining
duplicated variants.
## How
- Document existing-tool and agentless setup paths, lifecycle behavior,
annotations, security boundaries, experimental browser requirements, and
React Native limitations.
- Mark the guide `frontend: universal`; the existing docs router then
serves the same source at the bare, frontend-scoped, backend-scoped, and
combined URLs.
- Verified lint, typecheck, build, visual rendering, and all 152 route
combinations across 7 frontends and 18 visible agent frameworks.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **Documentation**
- Added documentation for WebMCP support in CopilotKit, including setup
examples for React and core-only usage.
- Documented how frontend tools are exposed to browser agents through
`document.modelContext`.
- Added guidance on deciding when to use an agent, designing reliable
tools, testing, and understanding experimental limitations.
- Added the WebMCP page to the documentation navigation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Adds enableThirdPartyTracking to the Reo.init call in shell-docs so the
docs site matches the marketing site (CopilotKit/website#556). The Reo
dashboard toggle was already enabled on 2026-09-03; this completes the
activation.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## What does this PR do?
Hooks can now expose a frontend tool to browser agents through the
WebMCP browser API, next to the normal agent registration. Set `webmcp:
true`, or pass `{ annotations }` for WebMCP hints:
```ts
useFrontendTool({
name: "searchOrders",
description: "Search the signed-in user's orders by status",
parameters: z.object({ status: z.enum(["open", "shipped", "delivered"]) }),
handler: async ({ status }) => searchOrders(status),
webmcp: { annotations: { readOnlyHint: true } },
});
```
How it works:
1. `FrontendTool` in `@copilotkit/core` gains the `webmcp` option. A new
`WebMCPRegistry` registers the tool on `document.modelContext` with its
name, description, input schema, and annotations. `execute` runs the
tool's own handler. The handler context has no `agent` there.
2. Every tool registry change in `RunHandler` reconciles the WebMCP
registrations. The same availability rules apply as for the agent tool
list. Removing a tool aborts its registration signal, and the browser
then unregisters it.
3. Each adapter picks the option up from core: v2 `useFrontendTool`
(React, Vue, React Native), the v1 `useCopilotAction` and
`useFrontendTool` wrappers (React, Vue), and Angular's
`registerFrontendTool`. Where WebMCP is not available (SSR, React
Native, browsers without the API), registration is a no-op.
The `webmcp` prop is documented on the React, Vue, and Angular reference
pages in shell-docs.
## Related PRs and Issues
- None.
## Checklist
- [x] I have read the [Contribution
Guide](https://github.com/copilotkit/copilotkit/blob/master/CONTRIBUTING.md)
- [x] If the PR changes or adds functionality, I have updated the
relevant documentation
- [ ] "Allow edits by maintainers" is checked (lets us help iterate on
your PR directly — faster turnaround for everyone)
## Testing
**Commands run**
- `pnpm nx run-many -t check-types
--projects=@copilotkit/core,@copilotkit/react-core,@copilotkit/vue,@copilotkit/angular`
— all pass.
- Full test suites: core (829 tests), vue (103), and angular pass.
react-core passes standalone (1589 tests). Under the lefthook pre-commit
hook, react-core flakes on pre-existing e2e tests (A2UI, MCP Apps) that
do not touch this code. Those tests pass when run alone.
**Manual test**
Requires Chrome 149+ with the WebMCP origin trial, or the testing flag.
1. Enable `chrome://flags/#enable-webmcp-testing`, then relaunch Chrome.
2. In an app that uses CopilotKit, register a tool with `webmcp: true`.
3. Run `await document.modelContext.getTools()` in DevTools. The tool is
listed with its schema and annotations.
4. Unmount the hook. Run the command again. The tool is gone.
**How this PR makes testing easy**
The behavior has automated tests on this branch:
- `packages/core/src/core/__tests__/run-handler-webmcp.test.ts` — 15
tests with a `document.modelContext` stub: registration, annotations,
unregistration, availability rules, name collisions, stale-rejection
races, and handler execution.
-
`packages/react-core/src/v2/hooks/__tests__/use-frontend-tool-webmcp.test.tsx`
and the mirrored
`packages/vue/src/v2/hooks/__tests__/use-frontend-tool-webmcp.test.ts` —
pass-through, re-registration, and agent-scoped cases at the hook level.
- `packages/vue/src/hooks/__tests__/use-frontend-tool-webmcp.test.ts` —
reactive `webmcp` getters through the v1 Vue API.
## Risk / rollback
Low. The feature is opt-in per tool. Without `webmcp`, no code path
changes. Where WebMCP is unsupported, registration is a no-op. Revert
this PR to roll back.
## Public API change
New optional `webmcp` prop on frontend tool registrations. Existing call
sites do not change.
**Before**
```ts
useFrontendTool({
name: "searchOrders",
description: "Search orders by status",
parameters: z.object({ status: z.string() }),
handler: async ({ status }) => searchOrders(status),
});
```
**After**
```ts
useFrontendTool({
name: "searchOrders",
description: "Search orders by status",
parameters: z.object({ status: z.string() }),
handler: async ({ status }) => searchOrders(status),
webmcp: { annotations: { readOnlyHint: true } },
});
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Tools can now be exposed to browser agents through WebMCP.
* Added support for custom annotations and automatic parameter schema
generation.
* WebMCP registrations stay synchronized as tools are added, removed,
enabled, or updated.
* Available across Angular, React, and Vue tool APIs.
* WebMCP reuses existing handlers and safely does nothing when
unavailable.
* **Documentation**
* Added usage guidance and examples for configuring WebMCP-enabled
tools.
* Documented that WebMCP invocations do not include an agent context.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Adds a five-minute quickstart for connecting an existing CopilotKit app
to Intelligence. Developers can use a coding-agent prompt or follow
framework-specific manual steps. The guide ends with a saved-thread
check in Inspector.
Linear:
[OSS-1076](https://linear.app/copilotkit/issue/OSS-1076/add-a-quickstart-for-intelligence)
## What changed
- Added the Intelligence quickstart to the docs navigation and overview.
- Added setup examples for React, Vue, Angular, and React Native.
- Added Inspector checks for browser apps and a hosted-project check for
React Native.
- Updated the coding-agent prompt with route, identity, and
authorization requirements.
- Updated Next.js and TanStack Start adapters to forward thread mutation
methods.
## Testing
Commands run:
- `npm exec -- vitest run
src/lib/__tests__/intelligence-quickstart-docs.test.ts
src/lib/__tests__/docs-render.test.ts
src/lib/__tests__/rich-threads-setup-docs.test.ts
src/components/__tests__/rich-threads-setup-prompt.test.tsx`: 39 tests
passed.
- `npm run typecheck`: passed.
- `npm run lint`: passed with existing warnings in unrelated files.
- `npm run build`: passed.
- The pre-commit package, binary, environment-name, lint, and commit
checks passed.
The full shell-docs test run still has unrelated Windows failures in
asset, generated Angular content, and LLM text tests.
Manual test:
1. Start shell-docs and open `/intelligence/quickstart`.
2. Select React, Vue, Angular, and React Native in the frontend
selector.
3. Check that each frontend shows its matching provider example.
4. Check that browser frontends use Inspector to find the new thread.
5. Check that React Native uses the hosted Intelligence project instead.
The new contract test checks the route, navigation, framework examples,
agent prompt, and Inspector completion path.
## Risk / rollback
Risk is low because this PR changes documentation and examples only.
Revert the commit to remove the quickstart and restore the prior adapter
examples.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added an Intelligence quickstart guide covering project setup,
authentication, thread authorization, runtime integration, frontend
configuration, and connection verification.
- Added the quickstart to Intelligence documentation navigation and
linked to it from the overview page.
- Expanded setup guidance with browser and React Native steps for
creating threads and sending messages.
- **Documentation**
- Updated Next.js and TanStack Start examples to forward all Runtime
methods, including `PATCH` and `DELETE`.
- Clarified authentication and thread ownership requirements for Runtime
routes and operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The "Copy agent prompt" button already told the CLI's onboarding graph
which agent framework the reader had selected. The docs carry a second
selector — Frontend — whose choice the prompt dropped, so the graph still
had to ask which frontend to configure.
Add a frontend sentence built exactly like the framework one and placed
between it and the page sentence, which is the order the graph works in:
it settles the agent framework first, then the frontend. Each sentence
leads with its own subject and can be empty independently, so all four
combinations read correctly.
The docs frontend is resolved from the URL, never from a stored
preference — choosing a frontend navigates to another URL, so the URL is
what asserts the selection. This is the rule the selector itself applies
(`urlFrontend ?? "react"`), and the same standard the framework sentence
already holds to. Resolution happens server-side and reaches the button
as a prop, so it cannot drift from the page being rendered.
Why `react` maps to the graph's `nextjs`: every frontend prompt under
`apps/cli/onboarding-prompts/frontend/` names the docs page it belongs
to, and `nextjs.md` is the only one whose documentation link is the
UNPREFIXED https://docs.copilotkit.ai/quickstart.md — the docs' default
`react` frontend, served at the root. Every other prompt points at its
own prefixed page (`/vue.md`, `/angular.md`, `/react-spa.md`,
`/react-native.md`). Same frontend, spelled differently on each side.
Slack and Teams stay deliberately unmapped. They are chat channels, not
application frontends; the graph has no node for either, so naming one
would promise a path the CLI cannot walk. The analytics `frontend`
property follows the same rule as `agent_framework`: the graph slug, and
the key omitted entirely when there is no equivalent.
A guard test over the docs frontend registry reads `FRONTEND_OPTIONS` —
the same list the app itself renders — so adding a frontend forces a
mapping decision instead of silently producing no sentence.
Adds a **Copy agent prompt** button to the docs page-tools row, so a
reader can hand the CopilotKit onboarding flow to their coding agent
from any docs page instead of only from the three hero placements.
Closes OSS-1074.
## What it does
The button copies the canonical onboarding prompt
(`INTELLIGENCE_ONBOARDING_PROMPT`) with a freshly minted run id, plus
two factual sentences:
> … Follow the Markdown instructions it prints until onboarding is
complete. **The developer selected the Mastra agent framework
(`mastra`). The developer copied this prompt from
https://docs.copilotkit.ai/mastra/generative-ui.mdx.**
Both are statements of fact, never instructions — the CLI's prompt graph
stays in charge of the path, exactly as `frameworkPromptSuffix` already
established for the hero button. The framework sentence reuses that
helper verbatim; the page sentence is new and is what distinguishes this
placement from the hero one.
The canonical prompt constant is untouched, and a test asserts the
copied string is exactly `createIntelligenceOnboardingPrompt(runId)`
plus those suffixes, so nobody can quietly rewrite the shared text
through this path.
## Coverage
The button appears on every docs page that has a page-tools row and
resolves to an agent framework:
- all framework-scoped pages (`/<framework>/…`)
- the whole root surface, which is the Built-in Agent lens on those same
pages (`/quickstart`, `/backend/copilot-runtime`, `/faq`, `/concepts/…`,
`/troubleshooting/…`)
- the cookbook
- the frontend surfaces (`/vue/…`, `/angular/…`, `/react-native/…`),
where a missing backend segment *is* how the Built-in Agent is spelled
Deliberately excluded: the API reference (`/reference/…`, no
framework-prefixed variant exists, so the exclusion is consistent) and
the AG-UI docs (a separate protocol with its own brand — offering
CopilotKit setup there is the wrong offer; those pages have no
page-tools row at all).
Earlier revisions of this branch gated the root surface on a
content-resolution signal (`snippet_cell` / a Built-in-Agent override
file). That made identical pages behave differently depending on which
URL the reader arrived through — `/mastra/faq` had the button, `/faq`
did not. The gate is gone; the rule is now simply "does this page
resolve to a framework".
## Fixes a slug rename missed in OSS-1073
`DOCS_SLUG_RENAMES` in `intelligence-onboarding-framework.ts` claimed
`built-in-agent` was a framework the onboarding graph does not know, and
therefore stayed silent for it. The graph does know it — it spells it
`built-in` (`ONBOARDING_AGENT_FRAMEWORKS` in Intelligence
`apps/cli/src/services/onboarding-classification.ts`, and
`onboarding-prompts/framework/built-in.md`). Same shape as the
`crewai-crews` and `strands` renames already in the map.
**This also fixes the existing hero button**, which was dropping the
framework sentence on every Built-in Agent page — `/slack`, `/teams` and
the channel guides with no backend selected. Flagging it here rather
than burying it, since it changes behaviour outside this ticket's scope.
The display name is overridden to "Built-in Agent" at a single shared
call site; the registry name ("CopilotKit's Built-in Agent") would
produce "the CopilotKit's Built-in Agent agent framework".
## Telemetry
Reuses the existing `docs.intelligence_onboarding_prompt_copied` event
rather than adding one, with `surface:
"docs_page_tools_onboarding_prompt"` and `agent_framework` set to the
graph slug (omitted when there is none, matching the hero button). The
run id is minted per click and travels into the CLI, so a copy and the
onboarding run it starts can be joined — the gap OSS-1060 describes. The
button also carries `data-docs-copy-surface`, so the global copy tracker
reports it alongside the other conversion surfaces.
## Known, deliberate
- On the ~21 quickstart pages that embed
`<IntelligenceOnboardingPrompt>`, and on the ten framework roots with a
hero button, two affordances now copy an onboarding prompt. They do not
contradict each other — the page-tools one is a strict superset (it also
names the page). Which one should win is a product call, not made here.
- `/agent-spec/*` and `/a2a/*` get no button: they have no registry
record, so there is no framework to name. Naming nothing would be worse
than staying silent.
## Testing
`npm run typecheck`, `npm run lint` clean. `npm run test`: 568 passing,
with the same 6 pre-existing failures as `main` (`public-assets` ×3,
`angular-docs-content` ×2, `llm-text` ×1) — none related to these files.
Verified in a running dev server, not only in unit tests: the copied
string on framework, Built-in Agent and frontend pages; a fresh run id
per click matching the CLI's `/^[A-Za-z0-9_-]{12}$/`; three rapid clicks
producing exactly one clipboard write and one event; the icon swapping
without the row reflowing; light and dark themes; the mobile wrap; and
the absence of the button on `/reference/…` and `/ag-ui/…`.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a “Copy agent prompt” action to documentation pages.
* Prompts include relevant framework context and a direct link to the
page’s Markdown content.
* Framework-aware onboarding now works across framework docs, cookbook
pages, quickstarts, and other documentation surfaces.
* Added Built-in Agent support for onboarding prompts.
* **Improvements**
* Documentation action controls are presented consistently across
supported pages.
* Copy actions provide clearer loading, success, and error feedback.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
- mark the canonical hook-based React example as a client component
- remove the obsolete LangGraph-specific copy so generated routes have
one source
- add a regression test for the client boundary and single-source
invariant
## Test plan
- `npm exec -- vitest run src/lib/__tests__/llm-text.test.ts -t "keeps
programmatic control|renders a complete programmatic-control"`
- `npm run typecheck`
Linear:
https://linear.app/copilotkit/issue/FAC-170/consolidate-programmatic-control-react-examples-and-document-the
## Summary
- expand the Claude SDK Python shared-state setup with its actual
Messages API tool registration, state update, and route wiring
- document the TypeScript SDK selection and MCP tool registration path
for `set_notes`
- add runtime and rendered-doc regressions for both public framework
routes
Closes FAC-175 and FAC-178.
## Tests
- `npm run typecheck` and focused Vitest coverage in
`showcase/integrations/claude-sdk-typescript`
- `pytest tests/python/` in `showcase/integrations/claude-sdk-python`
- focused setup-content, visual setup, and LLM-text tests in
`showcase/shell-docs`
- `npm run typecheck` in `showcase/shell-docs`
`a2a` and `agent-spec` are documented like agent frameworks — their own
route, their own quickstart, their own page-tools row — but neither is a
registered integration, so there is no display name to substitute into the
framework sentence. Gating the button on that name kept it off the two
quickstart pages where an onboarding offer belongs most.
The framework is now optional. Those pages get the button with the page
sentence alone; the prompt claims no framework rather than naming one the
registry cannot confirm. Nothing is lost by the silence: the CLI's graph
inspects the repository and determines the framework itself, and under A2A
or Agent Spec that is in practice one of the frameworks it already knows.
With the last gate gone, every page reaching DocsPageTools now renders the
button. That is the intended rule: DocsPageView serves only docs surfaces,
and the offer holds on all of them.
The docs spell the framework `deepagents`, the onboarding graph spells it
`deep-agents`, and nothing mapped between them — so every `/deepagents/...`
page copied a prompt with the framework sentence silently missing, the same
way `built-in-agent` did before it was mapped.
The registry-coverage guard did not catch it because it read
`data/registry.json` directly, and docs-only integrations are merged in by
`registry.ts` and never appear in that file. It now reads `getIntegrations()`,
so the slugs most likely to be forgotten are the ones it actually covers;
removing the new rename makes it fail with `[ 'deepagents' ]`.
The Built-in Agent's call-site display name drops to "Built-in": the shared
sentence template already supplies the word "agent", so the previous name
rendered as "the Built-in Agent agent framework".
The root surface is not a frameworkless surface. It is the Built-in
Agent's lens on the same docs the `/<framework>/…` URLs serve, so
`/faq` and `/mastra/faq` are one page read with two different framework
selections. Gating the page-tools "Copy agent prompt" button on
`frameworkOverride` — a CONTENT-resolution signal, true only for pages
carrying a snippet cell or a Built-in-Agent override file — made those
identical pages behave differently depending on the URL the reader
arrived through: `/mastra/backend/copilot-runtime` had the button,
`/backend/copilot-runtime` did not, and likewise for `/faq`,
`/concepts/architecture`, `/troubleshooting/common-issues` and
`/cookbook/arcade`.
`UnscopedDocsPage` now resolves the prompt framework once, for
`ROOT_FRAMEWORK`, and hands it to both branches; the cookbook routes do
the same. `frameworkOverride` is untouched and keeps its narrower
per-branch value — the two props answer different questions and are no
longer expected to agree.
The same reasoning applies to the frontend routes, where a missing
backend segment is how the Built-in Agent is spelled:
`/vue/built-in-agent/<slug>` redirects to `/vue/<slug>`, the framework
selector shows the Built-in Agent as active there, and `resolveAngularDoc`
already resolved `backendFramework ?? ROOT_FRAMEWORK`. The three frontend
branches that still resolved to no framework now do the same, so
`/vue/<slug>` matches `/vue/mastra/<slug>`.
121 of the 141 root-surface docs URLs now carry the button. The 20 that
do not are not root-surface docs pages: 14 legacy tutorial slugs and
`/built-in-agent` redirect to `/`, one lives on the `/reference` surface,
and five are the docs-only `agent-spec` framework, whose slug the
registry has no display name for.
The Built-in Agent's docs are served at the root surface without a framework
prefix, so `unscoped-docs-page.tsx` rendered them and never passed
`onboardingFramework` — 56 root URLs (`/frontend-tools`, `/quickstart`,
`/shared-state`, …) had no "Copy agent prompt" button. The prop is now derived
from the same `frameworkOverride` the component already computes for content
resolution, so the button covers exactly the pages that render BIA-scoped and
nothing else. Genuinely frameworkless pages (`/faq`, `/examples`) still get no
button.
`DOCS_SLUG_RENAMES` now maps `built-in-agent` to the graph's `built-in`. The
old doc comment claimed the CLI's onboarding graph does not know this
framework, which is wrong: `ONBOARDING_AGENT_FRAMEWORKS` lists `built-in` and
the graph ships `onboarding-prompts/framework/built-in.md`. Note that this
rename also changes the EXISTING hero onboarding button: on BIA surfaces its
copied prompt previously named no framework at all and now carries the
framework sentence too. That is the point of the fix, not a side effect.
The registry name is "CopilotKit's Built-in Agent", which the shared sentence
template renders as "the CopilotKit's Built-in Agent agent framework". Rather
than special-case the template, `onboardingFrameworkFor` moves out of the
framework route into `lib/docs-onboarding-framework.ts` and overrides the
display name to "Built-in Agent" there — one place, used by both surfaces that
can render a BIA page.
Reverts the suppression added in edcd9268ee. On the ten framework roots
whose landing page is an authored index.mdx, the hero keeps its own
"Copy onboarding prompt" alongside the page-tools "Copy agent prompt".
The two prompts differ only in that the page-tools one also names the
page it was copied from, so neither contradicts the other.
`<FrameworkOverview>` embedded in an `integrations/<folder>/index.mdx`
renders inside `DocsPageView`, so `/mastra`, `/pydantic-ai`, `/agno`,
`/ag2`, `/llamaindex`, `/crewai-crews`, `/ms-agent-*`, `/deepagents` and
their `/angular/<slug>` equivalents showed the same onboarding prompt
twice: once in the page-tools row, once in the hero below it.
A new `hideOnboardingPrompt` prop takes out the hero's prompt button and
nothing else — the quickstart link and the bespoke-init command chip are
untouched. `DocsPageView`'s components-map override passes it as
`Boolean(onboardingFramework)`, which is the very condition that gates the
page-tools `OnboardingPromptCopyButton` a few lines above it. So the two
buttons cannot both appear, and neither can the hero button disappear from
a page that has no page-tools one: the data-driven framework roots
(`/langgraph-python`, `/claude-sdk-*`, `/google-adk`, `/strands`, …) render
`FrameworkOverview` outside `DocsPageView` and keep their hero button, as
does the docs home hero.
The second components-map override, for `after-features.mdx`, does not get
the flag. It lives in the Tier 1 branch of `FrameworkRootPage`, which
renders `FrameworkOverview` inside `FrameworkRootShell` — a shell with no
page-tools row at all — so an `<FrameworkOverview>` nested there can never
sit on a page carrying the page-tools button. Threading the flag through it
would have to hardcode `false`, which reads as a decision where there is
none.
The "Copy agent prompt" button now appears only on framework-scoped docs
pages. An explicit `onboardingFramework` prop on `DocsPageView` is the gate:
`app/[framework]/[[...slug]]/page.tsx` is the only route that passes it, so
the cookbook, the unscoped pages (`/faq`, `/cli`) and the API reference get
no button by simply leaving it off. A prop rather than a runtime URL check
because `DocsPageView` is shared by all of those.
The copied prompt gains two sentences of context after the canonical text:
which agent framework the reader is reading about (reusing the hero button's
`frameworkPromptSuffix`, which stays silent for frameworks the CLI's
onboarding graph has no node for) and the absolute `.mdx` URL of the page it
was copied from. Both are statements of fact for the receiving agent; the
prompt itself remains the only thing that instructs it. The page URL is
built inside the click handler, since the client base URL reads back an SSR
placeholder during render.
`agent_framework` joins the `promptCopied` payload, carrying the graph slug
the CLI reports for the same run, and is omitted when there is none.
The page-tools row moves into `components/docs-page-tools.tsx` so the
gating rule can be unit-tested without standing up the MDX pipeline.
A second click while the first clipboard write was still pending minted a
second run id, overwrote the first write, and reported a second
`docs.intelligence_onboarding_prompt_copied`. The CLI can close out only one
of them, so the other stayed an open funnel row — the thing the per-click run
id exists to prevent. The handler now ignores re-entrant clicks and the button
is disabled for that window, released on the failure path too.
Four smaller corrections alongside it:
- Drop the `feature: "onboarding"` property. Every other emitter of that event
sends a value of the `IntelligenceOnboardingFeature` union, and a third value
that is not a feature muddies existing breakdowns. The distinction belongs in
`surface`, which now uses one module-level constant,
`docs_page_tools_onboarding_prompt`, for both the event property and the
`data-docs-copy-surface` attribute.
- Keep the label fixed on success and swap the icon instead, matching
`MarkdownCopyButton` next to it. "Copied" is ~45px narrower, so it slid the
neighbouring controls leftward for 1800ms and back under the cursor. Failure
keeps its "Copy blocked" label, and the `aria-live` announcements are
unchanged.
- Honour `props.children` as the idle label, and log a rejected write to the
console so a blocked copy is observable.
- Correct the comment claiming the surface attribute must sit on the button
because the tracker uses `closest()`. It walks the ancestor chain; wrappers
work (`react/docs-conversion.tsx`, `rich-threads-setup-prompt.tsx`). It is on
the button because this button alone should count as that surface.
Tests now cover the in-flight guard, unmount while a write is pending, and the
two `createOnboardingRunId` fallback branches that jsdom's `crypto.randomUUID`
otherwise hides. Three test names that promised more than they asserted are
reworded: the prompt comparison is a local guard, not a cross-repo one; the
rejection test scopes its "reports nothing" claim to this component's own
event, since the global tracker fires before it delegates to `writeText`; and
the attribute test does not exercise the tracker.
Docs readers who want to try CopilotKit had no way to hand the onboarding
instructions to their coding agent from the page they were already reading.
The prompt existed, but only inside the two banner components that appear on a
handful of pages.
This puts it in the page-tools row instead, next to "Copy Markdown" and
"Open", on product docs, the cookbook, unscoped pages and the reference. It is
the accent-coloured primary action of the row; the two existing controls stay
secondary.
The copied text is the canonical prompt verbatim, with no page context
appended, because the same string has to stay byte-identical with the copies
in the Intelligence repo and the Inspector. A fresh run id is minted on every
click, matching the banner, so one clipboard write stays one onboarding
attempt in the funnel. A copy that the browser blocks reports nothing, since a
run id that never reached a clipboard cannot be closed out by the CLI.
AG-UI and the frontends routes are untouched; neither renders a page-tools
row.
Two legacy docs URLs have been dead ends since cc8c945893 ("refactor(docs):
optimize structure, content and navigability", 2026-02-23). That commit had no
redirect config to update — seo-redirects.ts did not exist yet — and nobody
back-filled the entries when it was built.
`/premium/inspector` 404s. The commit renamed `(root)/premium/inspector.mdx` to
`(root)/inspector.mdx` with identical content, so the page still exists; only
the URL moved. Points at /inspector now, expanded over the framework slugs the
way the observability entries are, since /langgraph-python/inspector and its
siblings are served too.
`/direct-to-llm/guides/premium/*` loses the page. All four of them — overview,
headless-ui, observability, inspector — were deleted in the same commit, and
the R16 `/direct-to-llm/:path*` wildcard drops the remainder on the docs home.
That reads as a working link while serving the wrong page, which is why it went
unnoticed longer than a 404 would have. Each gets an exact entry.
Both need entries on the docs host and the shell host: P7 renames `/premium/*`
to a docs-host `/intelligence/*` on the way across, so without the shell entry
the legacy shell URL would 301 into a docs-host 404. The harness driver is the
intentional copy of the shell list and moves with it.
Exact sources beat every wildcard — middleware checks exactMap before the
wildcard list — so these win over INTEL-rename-wild, which would otherwise
rewrite them to a nonexistent /intelligence/inspector.
The decommission report fixtures move with the catalogue: 390 to 395 entries
defined, 377 to 382 zero-hit candidates, plus the five new ids. Regenerated
through the CLI with --events-json so the byte-for-byte cross-check against the
core module keeps its meaning.
Verified all 24 distinct destinations against staging. 22 return 200.
/langroid/inspector and /spring-ai/inspector 404, because those two framework
surfaces are not served at all — their bare roots and quickstarts 404 too. The
existing observability entries carry the same property, so no reachable URL
changes behavior.
Closes OSS-1073. **Stacked on #6815** — review that one first; this PR's
base is its branch, and the diff here is two files.
## Why this is small
#6815 (OSS-1072) reworked `HeroStartActions`, which the home hero and
the framework landing heroes share verbatim. That already gave most
partner landings the onboarding prompt as their first hero action.
Measured against the running app, of the 21 registry integrations:
- `langroid` and `spring-ai` have no landing page (404)
- `built-in-agent` redirects to `/` — its landing *is* the home page
- `crewai-conversational-flows` redirects into a content page
That leaves 17 landing surfaces. #6815 covered 15. This PR covers the
remaining 2.
## What changed
`claude-sdk-python` and `claude-sdk-typescript` pass a framework-scoped
init command (`npx copilotkit@latest init --framework claude-sdk-*`), so
they render the chip branch instead of the shared action row and were
the only landings left without the prompt. They now lead with `Copy
onboarding prompt`, with Quickstart stepped down to the bordered
treatment beside it.
**Their command chip stays**, as a third action after Quickstart.
Everywhere else the prompt replaced a *generic* `npx copilotkit@latest
create`; here the command is framework-specific, is not interchangeable
with the CLI's generic path, and nothing else on the page carries it.
Dropping it would have been a silent content loss on exactly the two
pages where the command matters most.
## Also in scope of the ticket, and already true before this PR
OSS-1073's requirement list asks that "in every quick-start a user is
able to copy a prompt instead of running through the steps". All 16
integration quickstarts already embed `<IntelligenceOnboardingPrompt>`
as their first element on `main` — no change needed there.
## Still open on the ticket, and not code
Two acceptance criteria carry over from OSS-1072 and cannot be closed in
this PR:
- **"The outcome from the coding agent is specific to the user's
selected options in the top left."** Now satisfied for the agent
framework. On a framework landing page the copied prompt appends one
sentence naming the framework the visitor selected, using the slug the
onboarding graph routes on: `` The developer selected the Mastra agent
framework (`mastra`). `` **The graph does not consume it yet.** Verified
end to end against CLI 4.9.24 on a greenfield Next.js project:
`credentials/plan` still instructs the agent to ask, because it defines
"unknown" purely as an absence of repository evidence and has no clause
for a framework named in the incoming prompt. The route the slug points
at is accepted — `onboard read framework/crewai-flows` returns the
CrewAI guide — so the docs-slug-to-graph-slug mapping is proven; the
handover is not. Making the graph honour a pre-selected framework is an
Intelligence-repo change and is not in this PR. Until it lands, this
prompt carries the answer and the graph asks anyway, which costs the
developer one question and nothing else.
Three deliberate boundaries. The sentence **states a fact, it does not
instruct** — the graph already has its own rule for preferring an agent
the repository contains, and a second copy of that rule here would be
one to keep in step. Only the **agent framework** is passed, not the
frontend: the docs offer seven frontends against the graph's five, the
default `react` is ambiguous between the graph's `react-spa` and
`nextjs`, and `slack` / `teams` have no equivalent — a guessed value
would be exactly the unkeepable promise this avoids. And a framework the
graph has no node for **appends nothing at all**, so the prompt never
names a path the CLI cannot walk.
Docs slugs and graph slugs mostly coincide; `crewai-crews` →
`crewai-flows` and `strands` → `strands-python` are the two that do not.
All 17 landing surfaces map. A guard test reads `registry.json` and
fails when a newly added integration falls into neither case.
**The docs home is exempt, and that is a finding rather than a
shortcut.** Measured against the running app, every non-default choice
in the top-left selectors navigates away from `/`: Mastra goes to
`/mastra`, Vue to `/vue`. Even a returning visitor with
`selectedFramework: mastra` in local storage sees "Agent backend:
CopilotKit" on `/`. The home page only ever exists in its default state,
so there is nothing there to pass through — the same requirement on
OSS-1072 is not applicable to that surface. Keeping `/` canonical also
preserves the wording shared with the Intelligence app and the
Inspector, which are framework-agnostic surfaces too.
- **"Running the prompt yields success reliably."** Verified end to end,
with one important caveat. Against a fresh Next.js 16 app, a coding
agent following the copied prompt drove the graph to `CopilotKit
onboarding marked complete` and produced a real assistant reply rendered
in a real browser: typing "Summarise my tasks" returned the
generative-UI component with all four records from `app/tasks.ts`, `POST
/api/copilotkit/agent/default/run` 200, `/info` reporting
`"mode":"intelligence"` and `"licenseStatus":"valid"`, `verify --json`
passing all 7 checks including `intelligence_consumed`, and `verify
--round-trip` passing. The run id round-tripped unchanged throughout.
Two dependencies the prompt does not mention: the developer must sign in
through a browser, and they must supply their own model API key
(`OPENAI_API_KEY` or an Anthropic / Google / MiniMax substitute) — all
19 frameworks in the graph's `credentials/plan` default to a third-party
provider, and the Intelligence key the CLI mints deliberately does not
satisfy it.
**And the run only succeeded because the agent worked around two
documentation defects.** `connect-your-runtime.md` and the quickstart
wire `process.env.INTELLIGENCE_API_KEY` while CLI 4.9.17 writes
`CPK_INTELLIGENCE_API_KEY` (tracked as OSS-1029), and the quickstart's
`model: "openai:gpt-5.4-mini"` names a model that does not exist in the
shipped `BuiltInAgentModel` union — and compiles silently, because the
union ends in `(string & {})`, so it would fail at the first model call.
An agent that follows those pages literally does **not** reach a working
app. Fixing both is a precondition for calling this criterion satisfied
without an asterisk.
## Verification
- `npm run typecheck`, `npm run lint`, `npm run build` clean (the one
lint warning on the touched file is a pre-existing missing `sandbox` on
an unrelated iframe)
- 528 tests pass, including the bespoke-init branch ordering (prompt,
Quickstart, chip) and the slug mapping
- Verified in a browser against the running app: `/mastra` copies 391
chars ending in `` (`mastra`) ``, `/crewai-crews` emits ``
(`crewai-flows`) ``, `/strands` emits `` (`strands-python`) ``,
`/claude-sdk-python` emits `` (`claude-sdk-python`) `` through the chip
branch, and `/` copies exactly 329 chars with no appended sentence
- Checked every one of the 21 integration landing URLs against a dev
server: all 17 real landing surfaces now render
`data-surface="docs_framework_hero"`
- Looked at `/claude-sdk-python` in the browser, light and dark, no
console errors
- The same three test files fail here as on `main` (`public-assets`,
`angular-docs-content`, `llm-text`); `public-assets` is unfetched Git
LFS pointers
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Onboarding prompt buttons now tailor copied prompts to the selected
framework.
- Framework-specific details are included in prompt copy and onboarding
analytics when available.
- Framework overview pages now consistently provide onboarding prompts
alongside quickstart actions.
- Claude Agent SDK setup pages now prioritize the onboarding prompt
before the framework initialization command.
- Framework naming is normalized across supported integrations for more
consistent onboarding guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The Intelligence docs moved from /premium/ to /intelligence/ in #6818, but the
CTA surface identifiers kept the retired tier name. Each value reaches PostHog
twice: as the `location` property on try_for_free_clicked / talk_to_us_clicked,
and as `utm_content` on the outbound signup link, which sticks as a person
property.
Two saved insights ("Which Docs Pages Drive Signups?", on the Kiteline and
North Star 2 dashboards) map that person property to display labels. Both were
extended first, so each retired identifier and its replacement resolve to the
same label and a docs page stays one row across this rename instead of
splitting in two. Person properties are frozen at ingestion time, so historical
rows keep the retired value permanently and no chart can be fixed after the
fact.
Refs OSS-1084
On a framework landing page the URL already asserts which agent framework the
visitor is looking at, so the copied prompt now says so and the CLI's
onboarding graph does not have to ask. The docs home keeps the canonical
prompt: its top-left selection is always the default, because every other
choice navigates away from that page.
The sentence states a fact rather than giving an instruction — the graph has
its own rule for preferring an agent the repository already contains, and
duplicating it here would leave two copies to keep in step.
Docs slugs and the graph's slugs mostly coincide; `crewai-crews` and `strands`
are the two that do not. A framework the graph has no node for appends nothing
at all, so the prompt never names a path the CLI cannot walk. A guard test
reads the registry and fails when a newly added integration falls into neither
case, so the choice has to be made rather than silently skipped.