## 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.
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.
## Summary
- sync the AG-UI applications quickstart with the corrected root route
- add coverage that rejects the stale `/copilotkit` URL
## Testing
- `npm test -- src/lib/__tests__/ag-ui-content-links.test.ts`
- `npm run typecheck`
- `git diff --check origin/main...HEAD`
Linear: FAC-123
Eight suites assert on the old paths — sitemap URLs, file existence,
loadDoc slugs and the Angular canonical-slug mapping. In the redirect
suite only the destinations move; the /premium/observability sources
stay, since a redirect source describes a URL that must keep resolving.
Refs OSS-1078
/premium/* is an indexed URL surface, so the folder rename needs a
redirect for every old path — at the root and under each of the 22
canonical and 14 legacy framework slugs. A wildcard covers the tree
(including future pages and the .md/.mdx LLM variants); exact entries
cover the bare folder URLs, which no wildcard prefix can match.
Existing entries that pointed INTO the tree are repointed: the retired
observability pages, the premium folder index, and four next.config
destinations. Sources are left untouched — they describe URLs that must
keep resolving.
Two entries in next.config keep the built-in-agent surface at one hop:
its generic prefix-stripping catch-all runs before the middleware and
would otherwise hand the middleware a /premium/ path to rename in a
second hop.
The shell host and the harness probe carry their own copies of the
table, and the harness header requires them to stay in sync or the
decommission report surfaces phantom zero-hit entries. Both updated.
Refs OSS-1078
Three maps key off the content path or the URL slug: the shared-snippet
registries in docs-render and mdx-registry, the slug-to-component maps,
and the Angular canonical-slug map. All of them still named premium, so
after the folder rename the shared Overview, SelfHosting, Inspector and
HeadlessUI snippets would resolve to a path that no longer exists.
Refs OSS-1078
The product is called Intelligence, but the docs served it under
/premium/ — including a per-integration premium/ folder in twelve
integrations. Readers and coding agents both hit a URL naming a tier
that no longer exists.
Renames the folder to intelligence/ at the root, in the twelve
integration trees, and in the shared snippets, and rewrites every
inbound link. Page slugs are deliberately unchanged so the redirect
surface stays a pure prefix rename.
Also drops the premium: true frontmatter key from fourteen pages: no
code reads it, so it was dead. The one remaining piece of tier prose,
a "Premium UI capabilities" table cell, becomes "Platform-gated UI
capabilities".
Analytics surface identifiers (docs_premium_*) are left verbatim —
renaming them would silently break the PostHog dashboards that read
them. They are internal event names, not docs content, and belong in
their own change.
Refs OSS-1078
The Claude Agent SDK overviews pass a framework-scoped init command, so they
render the chip branch rather than the shared hero action row and were the
only two partner landings left without the onboarding prompt. They now lead
with it, with Quickstart stepped down beside it.
Their command chip stays as a third action. `npx copilotkit@latest init
--framework claude-sdk-*` is not interchangeable with the generic CLI command
the prompt replaces elsewhere, and nothing else on the page carries it.
The label is now "Copy onboarding prompt", the wording OSS-1072 asks for, and
the hint line under the action row is gone — the label already names what gets
copied, so the second line only repeated it. With nothing below the row,
HeroStartActions collapses to the row itself instead of wrapping it.
The docs hero offered three competing entry points: a Quickstart picker, a
CLI command menu, and — buried below the fold — the onboarding prompt a
developer hands to their coding agent. The prompt is the path we want people
on, so it moves into the hero and takes the accent, Quickstart steps down to
the bordered treatment beside it, and the CLI command menu goes away with the
`create` command and the "Build with agents" link it carried. A muted hint
line names where the copied prompt is meant to go, which the removed menu
used to make obvious by showing its command inline.
The prompt is identical on every surface: the CLI's onboarding graph inspects
the repository and picks its own path, so a framework-scoped variant would be
a promise the CLI does not keep. HeroStartActions stays shared verbatim, so
the eleven framework landing pages using it get the same row. The four
frameworks with bespoke init commands render a different branch and are
untouched.
QuickstartLinkButton gains a `variant` prop defaulting to primary, so those
bespoke landing pages keep their only hero button looking unchanged.
Three defects, all in the credential this branch renames.
Twelve integration quickstarts read `CPK_INTELLIGENCE_API_KEY=your_license_key`,
eleven of them under "The runtime reads the license key from step 1". The project
API key and the self-hosted license token are different credentials with
different lifetimes, and ENT-1151 exists to take the license token out of managed
setup -- so a reader who goes looking for a license key to paste finds a dead end
on the very page meant to connect them. Now `cpk-...`, and "reads the project API
key from step 1".
The placeholder prefix was wrong in the other direction on five pages, and newly
pinned that way by a test: `cpk_...`, with `cpk-...` asserted absent. A
provisioned key is `cpk-<projectId>_<short>_<long>` -- see the `cpk-` keyPrefix
in Intelligence's `apps/app-api/src/api-keys.ts` and the `parseApiKeyToken`
fixtures. No key the platform issues starts with `cpk_`, so the placeholder
taught a reader to distrust their own key. Both assertions are flipped.
The new copy guard scans every MDX page rather than listing the twelve, so a page
added next month is covered the day it lands. It reports the offending file and
value, which is how the twelve above were enumerated.
Finally, the retired-name boundary check is extracted to an exported
`retiredNameReference` and unit-tested. It is the load-bearing half of that rule
and it fails in one direction only: the canonical name ends with the retired one,
so a plain substring match reports all ~250 correct sites and the guard gets
switched off. The repo-wide scan cannot cover this -- it can say "clean", not
that the boundary is what made it clean, and it goes green either way once the
last old name is gone.
Verified: guard script exit 0; guard tests 20 passed; managed-starter-docs 10
passed (was 9); oxfmt and oxlint clean on the three changed TypeScript files.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>