Switching frameworks now lands on the same shell as / does, just with
the framework already URL-active. The /<framework> route renders the
docs-landing hero, CLI command, and utility cards (Concepts / API
Reference / Generative UI), then DocsLandingNext's "Continue with X"
branch with Quickstart / Browse {framework} docs / Switch framework
pointers. Replaces the previous bespoke FrameworkLandingPage that
showed a "You're viewing docs scoped to" panel and a hardcoded 4-card
grid (chat-ui / tool-rendering / frontend-tools / human-in-the-loop)
that drifted from the docs landing.
DocsLandingNext now prefers the URL-active framework over the stored
preference so /<framework> can render the "Continue with X" branch
during SSR with no mount-flicker — the previous storedFramework-only
gating caused a brief picker render before the localStorage effect
caught up.
Delete the orphaned per-framework index.mdx files. They were the
backing for the old sidebar Introduction entry (already removed) and
the URL /<framework>/index, which Next.js's optional catch-all
collapses to the bare framework path anyway. Their FrameworkOverview
content (banner video, init command, supportedFeatures grid) was a
legacy marketing-style landing that doesn't fit the new docs-routing
shape.
Each integration's meta.json opened with a "Getting Started" section
containing index (rendered as "Introduction") and quickstart. The
override filter already drops sections and root-equivalent pages, so
quickstart was always filtered (root quickstart.mdx exists), but
index slipped through and rendered as an Introduction link to
/<framework>/index — duplicating /<framework> with the marketing-style
FrameworkOverview content. Drop the entire opening section from every
framework's meta.json so the framework block in the sidebar starts at
the first framework-unique topic.
Also flatten empty-title wrapper groups in buildFrameworkOverridesNav.
buildNavTree clears the title on a spread-derived group when the
preceding section has the same name (so the renderer doesn't double-
print "Generative UI"). The override filter then drops those section
headers, leaving titleless containers that only added an extra indent
step around their children. Inline the children at the wrapper's
level instead, raising "Your Components" up where "Generative UI"
used to sit.
The root /quickstart page is a routing shim — it has no real content,
just a pointer to the per-framework quickstarts. Showing it in the
sidebar on / leads users into a dead-end click ("This page is a
routing shim..."). Hide the entry until a framework is active in the
URL or stored in localStorage; once either is set, SidebarLink prepends
it and the click lands on real per-framework content.
The framework-scoped route resolves root MDX before per-framework
overrides, which is correct for most pages — root content rendered
with framework-specific snippets is the primary path. But the new
root quickstart.mdx is a routing shim that exists only so the sidebar
entry has a backing page; real quickstart content lives per-framework
at integrations/<framework>/quickstart.mdx. Special-case the
quickstart slug so the override always wins for framework-scoped URLs.
While here, add the missing crewai-crews → crewai-flows docs-folder
mapping. The registry slug was renamed but the docs folder kept the
older name, so /crewai-crews/quickstart couldn't find the override.
The merged landing's "no framework selected" branch previously showed a
flat IntegrationGrid. Swap it back to the categorized picker (Popular /
Agent Frameworks / Provider SDKs / …) so the docs root mirrors the same
shape users saw before the merge — the affordance to pick a backend is
unchanged from their perspective.
Also re-add the "Quickstart" sidebar entry so every framework has it.
The page itself is a routing shim; SidebarLink prepends the stored
framework, and direct hits to /quickstart 308 to /.
Extract FRAMEWORK_CATEGORY_ORDER into lib/framework-categories so the
client component can pull the constant without dragging fs-using
helpers from lib/docs-render through the bundle. docs-render
re-exports the constant so existing server-side imports keep working.
The docs landing at `/` and the standalone `/quickstart` picker did
overlapping jobs and confused first-time users. "Quickstart" as a
top-level URL was misleading: clicking it from the shell landing or
the docs overview's top-card list led to a 23-line picker rather than
the actual quickstart guide (which lives at `/<framework>/quickstart`,
117–527 lines per framework).
Merge them. `/` becomes the single docs-side landing:
- Always shown: hero + product positioning, the `npx copilotkit@latest
create` CLI command (moved up from /quickstart), and three utility
cards (Concepts, API Reference, Generative UI).
- Conditional below: a new `DocsLandingNext` client component that
branches on `storedFramework`. Null → "Pick your agent framework"
+ the integrations grid (the picker). Set → "Continue with
{name}" + three pointer cards (quickstart for that framework,
framework landing, switch frameworks).
The standalone `/quickstart` page is deleted; `/quickstart` 301-redirects
to `/`. `/<framework>/quickstart` is unchanged — that's the canonical
per-framework quickstart guide.
Side effects of the merge:
- The unscoped catch-all's `DocsOverview` was rewritten to drop the
former two-step "Pick a backend / Or jump into a topic" panels.
The framework picker is now in `DocsLandingNext` (only when there's
no stored choice); the topic cards (DOCS_SECTIONS) were a flatter
duplicate of the new JTBD sidebar and got deleted entirely.
- `content/docs/index.mdx` was the file that rendered at `/index`
(reachable from a sidebar entry under Get Started). With the
merged `/` landing serving as the canonical overview, the
`/index` URL stops being meaningful — `index.mdx` is deleted and
the entry is removed from the top-level `meta.json`.
- `DocsLandingNext` is registered in the MDX components map so
future pages can drop it inline if useful, but its primary use is
inside `DocsOverview` itself.
Pairs with PDX-46 (BIA-as-default). Once BIA defaults are in, the
"no framework" branch of `DocsLandingNext` becomes rare and the page
reads as the "what's next" experience for nearly every visitor.
Closes PDX-58.
The concepts/three-types-of-gen-ui page and the canonical
learn/generative-ui/index page both use "Open-Ended" (with the
suffix) as the third gen-UI category alongside Controlled and
Declarative. The sidebar subsection had been shipped as just "Open"
in the JTBD reorg, leaving readers with three different namings
across the site ("Open" in nav, "Open-Ended" in concept page,
"Open-Ended" / "Fully Generated" in the learn page).
Align the sidebar to the canonical name. The other two subsections
("Controlled" and "Declarative") were already consistent.
Two changes to index.mdx that align it with the new JTBD sidebar
instead of competing with it:
- Drop the lower "Explore by feature" 6-card section. Every entry
there (Chat UI, Headless UI, Generative UI, Backend & Runtime,
Programmatic Control, API Reference) was a flatter version of a
sidebar section the JTBD reorg introduced. The overview pitching
the same content twice made the page heavier without adding routing
value.
- Swap one of the 4 top cards (was: Chat UI → /prebuilt-components)
for Concepts → /concepts/architecture so the conceptual entry
point is reachable from the docs front door, not just the sidebar
subgroup.
The overview is now: 4 top cards (Quickstart, API Reference, Concepts,
Generative UI), the LandingCodeShowcase, and the IntegrationGrid.
Tighter and clearly a doc-router rather than a product-pitch redux.
The merge anchor was hardcoded to "app control" with fallbacks to
"threads" and "backend". After the JTBD reorg renamed "App Control"
→ "Give Your App Agent Powers" and "Backend" → "Agents & Backends",
none of the candidates matched and every framework-scoped sidebar fell
back to append-at-end, relegating the framework section ("Built-in
Agent", "LangGraph (Python)", etc.) to the bottom of the nav.
Restore the original placement by adding the new section names to the
anchor candidate list: "give your app agent powers" (the renamed App
Control) and "agents & backends" (the renamed Backend) take priority,
with the old names kept as fallbacks for resilience. The match is
case-insensitive and stops at the first hit. Verified the framework
section now lands between Give Your App Agent Powers and Agents &
Backends for /built-in-agent/* and /langgraph-python/*.
"Cloud" implied a single deployment shape (managed-only). "Enterprise"
is the accurate name for the layer — same Intelligence Platform runs
hosted at Copilot Cloud or self-hosted via the copilot-intelligence
Helm chart. The page already used "Enterprise" terminology in the
body; this aligns the slug, page title, and meta entry to match.
File renamed via git mv (history preserved). search-index.json paths
update on the next build (gitignored, regenerated).
Replaces the TODO placeholders left by the JTBD restructure with
written explanation-layer content sourced from existing repo material
(learn/architecture, learn/generative-ui, learn/intelligence-platform,
ag-ui/concepts/architecture, premium/overview) and from two CopilotKit
blog posts ("AG-UI Is Redefining the Agent–User Interaction Layer"
and "The Three Types of Generative UI: Static, Declarative and Fully
Generated").
- concepts/architecture.mdx: the three-layer stack (frontend, runtime,
agent), AG-UI as the protocol bridge between runtime and agent, the
request flow at a glance. Reuses the existing architecture-diagram
PNG via ImageZoom and links out to the deeper learn/* coverage.
- concepts/three-types-of-gen-ui.mdx: a freedom-vs-control framing of
Controlled / Declarative / Open-Ended generative UI with one concrete
example per type and explicit "when to pick" guidance. Notes the
alias terminology (Static, Fully Generated) so readers can match the
blog and the learn/ pages. Cross-links to the implementation pages
for each type.
- concepts/oss-vs-cloud.mdx: clear OSS-vs-Enterprise feature split with
a capability-by-capability table, hosted-vs-self-hosted explanation,
and a decision rubric ("if you want CopilotKit to *be* your
conversation persistence layer, that's where Enterprise begins").
All three keep the explanation-layer scope (Diátaxis): they orient
and explain, then point the reader at the canonical detailed pages
for implementation specifics. None of them duplicate how-to content.
The concepts/what-is-copilotkit.mdx placeholder duplicated the
overview rendered at /index.mdx — same intent ("orient the reader"),
same target audience. Keep the index page as the single what-is
entry point and remove the concept-page slot.
The current meta convention pairs a `---X---` section header with a
`...x` spread that resolves to a sub-meta whose `title` is also "X".
buildNavTree emitted both a section node and a group node with the
same title, and the renderers showed each one — so users saw "BUILD
GENERATIVE UI" (section, uppercase tracking-widest) followed by
"Build Generative UI" (group, regular case) for the same content.
The doubling was already on the live site for one section
("Generative UI") and didn't get pushback there, but the JTBD reorg
makes it more visible: every spread-backed section ends up doubled
(Migrate, Other, etc.).
Fix in two halves, kept narrow:
- buildNavTree: when the previously-pushed node is a section header
with the same title that the spread's group would carry, set the
group's title to empty string. The group still wraps its children
for indentation/nesting; only the redundant inner label is dropped.
- All three nav renderers (renderNavItem in docs-page-view.tsx,
OverviewNavItem in app/[[...slug]]/page.tsx, RenderNav in
app/[framework]/[[...slug]]/page.tsx) gain a `{node.title && ...}`
guard so an empty string doesn't render an empty <div>.
Sections without a matching spread (Get Started → index/quickstart/
coding-agents listed inline) and spreads without a preceding section
header (legacy framework-tree work, override merges) are unaffected.
A spread whose sub-meta title differs from the section header (e.g.
section "Observe & Operate" + ...troubleshooting whose title is
"Troubleshooting") still renders both labels, which is correct —
they're meaningfully different and the inner one acts as a
sub-grouping label.
Restructures the top-level sidebar from feature-primitive sections
(Basics / App Control / Backend / Generative UI / Platform / Premium
Features / Troubleshooting) into 9 jobs-to-be-done sections that match
how readers describe what they want to build. Decisions captured in
the IA Restructure plan.
Section structure:
1. Get Started — index, quickstart, coding-agents, + concepts subtree
(placeholders for what-is-copilotkit, architecture,
three-types-of-gen-ui, oss-vs-cloud)
2. Build Chat UIs — prebuilt-components, custom-look-and-feel,
multimodal-attachments
3. Build Generative UI — nested Controlled / Declarative / Open
subgroups (tool-based, tool-rendering, state-rendering, reasoning,
your-components / a2ui + dynamic-schema + fixed-schema / mcp-apps)
4. Give Your App Agent Powers — frontend-tools, shared-state,
multi-agent/subagents, programmatic-control
5. Agents & Backends — built-in-agent (new), copilot-runtime,
custom-agent, ag-ui, runtime-server-adapter
6. Observe & Operate — inspector, vs-code-extension, +
troubleshooting subgroup (event-inspector, hook-explorer,
debug-mode, observability-connectors, common-issues,
error-debugging)
7. Enterprise — premium/overview, premium/observability,
premium/self-hosting, threads (merged from former Threads section
per product call: threads + persistence are part of Enterprise)
8. Migrate — v2, 1.10.X, 1.8.2 (moved out of Troubleshooting and
renamed to drop the redundant 'migrate-to-' prefix)
9. Other — contributing, telemetry (unchanged)
Reference stays as a separate root-true tree, not surfaced through the
top-level meta. Its v1/v2 treatment is a follow-up decision.
Page moves and new files:
- Migration guides moved from troubleshooting/migrate-to-{v2,1.10.X,
1.8.2}.mdx to migrate/{v2,1.10.X,1.8.2}.mdx with 301 redirects from
the old URLs in next.config.ts. Migrate gets its own first-class
section with a lucide/RefreshCw icon — separate from
Troubleshooting per IA-analysis pillar ("I'm upgrading deliberately"
≠ "something broke").
- 4 concept placeholders + index under content/docs/concepts/. Each
has frontmatter (title, description, icon, doc_type: explanation)
and a TODO body referencing where the content will come from
(existing repo material + blog posts). Slot exists; content
backfills later.
- New built-in-agent.mdx at root — 1-page summary that places BIA in
Agents & Backends as a peer to copilot-runtime / custom-agent / etc,
with a link out to the full BIA-scoped docs at /built-in-agent.
Other meta moves:
- programmatic-control: Basics → Give Your App Agent Powers
- inspector: Basics → Observe & Operate
- vs-code-extension: Platform → Observe & Operate
- multimodal-attachments: Platform → Build Chat UIs
- runtime-server-adapter: Platform → Agents & Backends
- The 3 migration pages: Troubleshooting → Migrate (with file moves)
Removed dead code: the `...unselected` line in top-level meta.json
was a no-op (unselected/meta.json has `root: true` so the spread
produced nothing). Stripped during the rewrite.
Multiple new visible labels are intentional. The renderer renders
sections (uppercase tracking-widest) and groups (medium-weight regular
case) at the same level when a section spreads a sub-meta with a
matching title — same pattern that's been live for 'Generative UI'
through every prior PR. The Build Generative UI nesting (Controlled /
Declarative / Open) is a deliberate three-types-of-gen-UI subgrouping
inside the section, surfaced via subsection headers in
generative-ui/meta.json's pages array.
## Summary
Six small, independently-verifiable shell-docs cleanup commits. All
scoped to polish — no structural reorganization.
- **Sidebar title now shows the integration name** on framework-scoped
routes. Previously every `/<framework>/*` URL hardcoded `\"CopilotKit
Docs\"` at the top of the sidebar; now `/langgraph-python/*` reads
\"LangGraph (Python)\", `/built-in-agent/*` reads \"Built-in Agent\",
`/ms-agent-dotnet/*` reads \"MS Agent Framework (.NET)\", etc. Unscoped
routes (`/`, `/quickstart`) keep the \"CopilotKit Docs\" default.
- **Event Inspector + Hook Explorer added to the Troubleshooting
sidebar.** Both pages exist on disk but weren't in
`troubleshooting/meta.json`, making them unreachable from the sidebar —
only direct-URL navigation surfaced them. Inserted between Debug Mode
and Observability Connectors so the four debugging tools cluster
together.
- **Framework selector now reflects the stored choice on unscoped
pages.** The dropdown's display label was derived from the URL-derived
`framework` only. On unscoped pages where `framework` is null, it
reverted to the \"Pick an agentic backend\" placeholder even when
localStorage held the user's prior selection — so the choice appeared to
be forgotten on every return to the root. Falls back to
`storedFramework`, matching the precedence the Clear-Selection button
below already uses.
- **Wire the orphan `multi-agent/subagents` page into the App Control
nav.** `content/docs/multi-agent/subagents.mdx` is a real page with
`snippet_cell: subagents` and a lucide icon, but had no entry in any
`meta.json` — only direct-URL navigation reached it. Slotted into App
Control next to `frontend-tools` and `shared-state`.
- **Collapse legacy `/frontend-actions` into `/frontend-tools`.**
`content/docs/frontend-actions.mdx` was a 33-line stub from when the
feature was called \"Frontend Actions\" (the API is now exclusively
`useFrontendTool`). Deleted the orphan + added a 301 redirect in
`next.config.ts` so external links still land cleanly. The HTML anchor
IDs `id=\"frontend-actions-example\"` referenced from 12 framework
`frontend-tools.mdx` files are unaffected (anchors, not URLs).
- **Drop dormant per-framework threads + self-hosting stubs.** 24
byte-identical stub files across 12 framework trees: 12 ×
`integrations/<fw>/threads.mdx` (7L each, body `<Threads />`, all md5
`0371508d…`) and 12 × `integrations/<fw>/premium/self-hosting.mdx` (8L
each, body `<SelfHosting />`, all md5 `06d17f98…`). The
`buildFrameworkOverridesNav` filter already dropped them from the merged
sidebar (root wins), and the framework-scoped router falls back to root
MDX when no per-framework override exists — so deletion is invisible to
users. Net 187 lines gone. Path-exclusion patterns added to
`sync-docs-from-main.ts` so future upstream syncs don't resurrect them.
## Test plan
- [ ] `/langgraph-python/quickstart`,
`/langgraph-typescript/quickstart`, `/langgraph-fastapi/quickstart` show
\"LangGraph (Python)\", \"LangGraph (TypeScript)\", \"LangGraph
(FastAPI)\" respectively at the top of the sidebar.
- [ ] `/built-in-agent/quickstart` shows \"Built-in Agent\".
- [ ] `/mastra/quickstart` shows \"Mastra\".
- [ ] `/ms-agent-dotnet/auth` and `/ms-agent-python/auth` show \"MS
Agent Framework (.NET)\" and \"MS Agent Framework (Python)\".
- [ ] `/quickstart` (unscoped) keeps \"CopilotKit Docs\" — default
unchanged.
- [ ] Pick a framework, navigate back to `/` — the sidebar dropdown
shows the stored choice with violet active styling, not the \"Pick an
agentic backend\" placeholder.
- [ ] Use Clear Selection — dropdown reverts to placeholder; `framework`
is null and `storedFramework` is null.
- [ ] After a dev server restart (meta.json cache is module-scoped): the
Troubleshooting section in any docs page sidebar lists Common Issues →
Error Debugging → Debug Mode → **Event Inspector** → **Hook Explorer** →
Observability Connectors → migrate-* in that order.
- [ ] After a dev server restart: `/multi-agent/subagents` appears in
the App Control sidebar section (after Shared State) and renders with
the \"Sub-Agents\" title.
- [ ] After a dev server restart (next.config.ts redirects load on
startup): `curl -I http://localhost:3003/frontend-actions` returns `301`
with `Location: /frontend-tools`.
- [ ] `/frontend-tools` renders unchanged.
- [ ] All of these continue to render with multi-hundred-KB bodies after
stub deletion (routing fallback to root MDX): `/built-in-agent/threads`,
`/langgraph-python/threads`, `/mastra/threads`,
`/built-in-agent/premium/self-hosting`,
`/langgraph-python/premium/self-hosting`. Sidebar appearance unchanged —
these stubs were already filtered from the override nav.
24 files in two byte-identical families across 12 integration trees:
- 12 `integrations/<fw>/threads.mdx` — 7 lines each, all md5 0371508d…,
body is just `<Threads />`.
- 12 `integrations/<fw>/premium/self-hosting.mdx` — 8 lines each, all
md5 06d17f98…, body is just `<SelfHosting />`.
Both render shared snippets the root-level pages already render. The
`buildFrameworkOverridesNav` filter dropped them from the merged
sidebar (root wins), and the framework-scoped router falls back to
root MDX when no per-framework override exists, so deletion is
invisible to users — `/built-in-agent/threads`,
`/langgraph-python/premium/self-hosting`, etc. continue to render
identically. Verified: each URL still returns 200 with full body
(340–465 KB) by curling the dev server before commit.
Add path-exclusion patterns to sync-docs-from-main.ts so future
upstream syncs don't resurrect them. Same shape as the BIA branch's
`(other)/` exclusion. Sample-tested the regexes against expected-
exclude and expected-keep paths — all classify correctly.
Audit covered every `integrations/<fw>/*.mdx` with body ≤ 2 non-blank
lines; no false-negative stubs of other shapes.
content/docs/frontend-actions.mdx was a 33-line stub from when the
feature was called "Frontend Actions." The product API is now
exclusively useFrontendTool, the canonical page is /frontend-tools
(1967 bytes, snippet_cell-driven, in the App Control sidebar
section), and the orphan stub had no entry in any meta.json — it
only rendered if you typed /frontend-actions directly.
Per the IA analysis: "redirect or delete; pick one." Picked both:
delete the orphan file + add a 301 redirect /frontend-actions →
/frontend-tools so any external link (search results, blog posts,
customer docs) lands cleanly on the canonical page.
Other 'frontend-actions' references in the repo are stable HTML
anchor IDs (`id="frontend-actions-example"` in 12 integration
`frontend-tools.mdx` files) and external links to the legacy
docs.copilotkit.ai site — neither breaks.
content/docs/multi-agent/subagents.mdx is a real, well-written page
(snippet_cell: subagents, lucide/Users icon) covering the supervisor →
specialized-sub-agents pattern. It rendered at /multi-agent/subagents
but had no entry in any meta.json, so it was unreachable from the
sidebar — a true orphan.
Slot it into the existing App Control section (next to frontend-tools
and shared-state, where it fits conceptually as another agent-behavior
control). The structural IA restructure (sam-shell-docs-ia, PR 2) can
promote it to a dedicated '---Multi-Agent---' section later if the
JTBD reorganization warrants it; this commit just stops it from being
hidden.
The 'multi-agent-flows' references in three integration metas
(crewai-flows, llamaindex, pydantic-ai) point at framework-specific
files (e.g. integrations/crewai-flows/multi-agent-flows.mdx), not at
this top-level page — different topic, no overlap.
The sidebar framework dropdown derived its display label and
"current" highlight from the URL-derived `framework` only. On
unscoped pages (/, /quickstart, /threads, etc.) where `framework` is
null, that resolved to `undefined` and the dropdown reverted to its
"Pick an agentic backend" placeholder — even when localStorage held
the user's prior selection. Visually this looked like the user's
choice had been forgotten on every return to a root-scoped URL.
Fall back to `storedFramework` when `framework` is null. Same
precedence as the Clear-Selection button further down the file
(`framework || storedFramework`). Framework-scoped routes are
unaffected because `framework` is set there.
Both files exist on disk (event-inspector.mdx, hook-explorer.mdx) but
weren't in troubleshooting/meta.json's pages array, so they were
unreachable from the sidebar — only direct-URL navigation surfaced
them. buildNavTree iterates meta.pages exclusively when present
(filesystem auto-discovery only fires when meta.json is missing or
its pages field is missing), so the slugs were effectively orphans.
Inserted between debug-mode and observability-connectors so the four
in-IDE debugging tools (error-debugging → debug-mode → event-inspector
→ hook-explorer) cluster naturally before observability and the
migration-guide tail.
Note: dev server picks up the new entries on restart — readMeta in
lib/docs-render.tsx caches at module scope by design (comment notes
this is intentional).
The sidebar title on /<framework>/* routes was hardcoded to
"CopilotKit Docs" — a regression noted in the IA analysis where
upstream's `integrations/langgraph/meta.json` correctly rebrands the
sidebar via `title: "LangChain"` + `root: true`.
Pass the integration's display name from the registry (already in
scope at this call site for mergeFrameworkNav and other uses) instead
of the hardcoded string. Verified across slugs: /langgraph-python/*
shows "LangGraph (Python)", /built-in-agent/* shows "Built-in
Agent", /ms-agent-dotnet/* shows "MS Agent Framework (.NET)",
unscoped routes (e.g. /quickstart) keep "CopilotKit Docs" via the
DocsPageView default prop.
18 per-framework MDX pages had the closing half of a multi-line
import statement left at the top of the file (the orphaned
"Symbol1, Symbol2, } from '...'" tail with the opening "import {"
line missing). The current sync-docs-from-main import stripper
handles multi-line imports correctly, so this was a historical
artifact from an earlier stripper version that misparsed them —
every affected file predates that fix.
MDX treats the orphan as plain text, so pages rendered the
identifier list and "} from ..." string as visible garbage at the
top before the real content started. Strip the orphan blocks; future
syncs won't re-introduce them.
The MDX registry had TailoredContent and TailoredContentOption
stubbed as passthrough <div>{children}</div> wrappers. MDX pages
author these as a variant-switcher (e.g. on Readables:
"Custom graph" vs "Prebuilt agent" paths for LangGraph setup), so
the stub rendered both option paths stacked — the same useAgentContext
example, the same steps, effectively duplicating multi-hundred-line
sections on every page that uses the component.
Swap the stubs for the real implementation at
components/react/tailored-content.tsx, which has been in the repo
since the shell-docs move but was never wired in. The real component
renders only the selected option and persists the choice in a URL
search param (?impl=graph / ?impl=prebuilt).
Registry slugs don't always match the integrations/<folder>/ name on
disk. Three LangChain/LangGraph variants (langgraph-python, langgraph-
typescript, langgraph-fastapi) read from the single langgraph/ tree,
ms-agent-dotnet and ms-agent-python share microsoft-agent-framework/,
and google-adk/strands are legacy renames that point at adk/ and
aws-strands/ respectively.
Before: the framework-scoped router, the sidebar-override nav
builder, and the "not available for this framework" fallback all
used the URL slug directly as a folder name, so any of the seven
mismatched slugs showed empty sidebars, 404s on framework-unique
pages (/langgraph-python/auth, /ms-agent-dotnet/auth), and missing
'available in other integrations' matches.
After: lib/registry exposes getDocsFolder(slug) backed by a small
DOCS_FOLDER_OVERRIDES table. Callers resolve the URL slug to its
actual folder before touching disk; findFrameworksWithPage takes the
resolver as a parameter so docs-render stays registry-free.
Per-page variant selectors authored as <Tabs groupId="..." default="Python">
now open with the URL-matching tab preselected instead of the author's
hardcoded default. getTabDefault(slug, groupId) reads
TAB_DEFAULTS_BY_SLUG; a wrapper in DocsPageView's MDX components map
injects the resolved value into <Tabs> via a 'default' prop alias.
/langgraph-typescript/configurable opens TypeScript, /ms-agent-dotnet/
auth opens .NET, /langgraph-fastapi/deep-agents opens FastAPI. Slugs
and groupIds without a mapping fall through to the existing behavior
(author default, then first items label).
Every framework under integrations/<fw>/ shipped its own copy of
contributing/ + telemetry/ content that was byte-identical (or
trivially divergent — a stray "cd" path, a legacy CLI name) to the
canonical copy at root (other)/. The duplicates were stale sync
artifacts with no framework-specific content: "how to contribute to
CopilotKit" and "how to configure telemetry" don't vary by agent
framework.
Beyond disk clutter (~2.5k lines across 8 frameworks), the duplicates
surfaced as a "Other" group nested under the framework-scoped
sidebar section whenever the merged nav built from meta.json — a
second copy of root's own "Other" section at the bottom of the
sidebar. Deleting the trees makes that UI bug disappear without any
filter patching.
Scope:
- Remove integrations/<fw>/(other)/ trees for ag2, agno, aws-strands,
crewai-flows, langgraph, llamaindex, mastra, microsoft-agent-framework.
- Drop ---Other--- + ...(other) entries from each framework's meta.json.
- Add a path-exclusion filter in sync-docs-from-main.ts so the next
sync run doesn't resurrect the subtrees when upstream edits touch
them. Upstream keeps its copies (removing them there means touching
all 13 parallel framework trees, out of scope for this branch).
The docs landing page and sidebar framework-selector both gated a
grayed-out card state and a "soon" label on integration.deployed.
That flag tracks whether a live showcase demo with tagged cells
exists — a showcase concern, not a docs concern. Built-in Agent has
ready docs even though no showcase package is published yet, so the
card was incorrectly rendered as "coming soon" and stayed visually
inert after clearing the stored framework.
Every integration that ships docs should be pickable from these
surfaces with the same visual weight. The deployed flag continues to
drive the showcase app, router-pivot filtering, and snippet cell
assertions — this change only touches the two docs-picker call sites.
Before this change, visiting /<framework>/<slug> for a topic that only
exists under integrations/<other-framework>/ returned a bare 404 — for
example, /mastra/advanced-configuration (the page only lives under
integrations/built-in-agent/).
Now the router checks whether the slug exists in any other integration
and renders a framework-scoped fallback page inside the docs shell:
sidebar and framework switcher stay intact, and the body lists the
integrations where the topic does exist with direct links. Genuine
unknown slugs still 404.
New helper findFrameworksWithPage walks integrations/<slug>/ for each
registered framework. NotAvailableForFrameworkPage renders the shell
around the fallback body. Nav tree build is hoisted so both the happy
path and the fallback share one source.
Per-framework meta.json files (mastra, langgraph, llamaindex, etc.)
mirror the root tree's section names ("Getting Started", "Basics").
Passing them through buildFrameworkOverridesNav into the merged
sidebar caused duplicate React keys when the merge ran — every root
section collided with the override's copy of the same title.
The override block is already wrapped in a single "{frameworkName}"
section by mergeFrameworkNav, so nested section headers added no
information anyway. Drop them at the filter step.
Registers Built-in Agent as a framework in the registry and wires up
a router + sidebar-nav pattern so its content can live at /built-in-agent/*
without needing a dedicated per-framework content tree for every topic.
Content model:
- Root MDX pages (/quickstart, /frontend-tools, /shared-state, etc.) are
the canonical home for framework-agnostic topics. Rendered at
/built-in-agent/<slug> via the existing framework-override mechanism.
- integrations/built-in-agent/*.mdx is the escape hatch for topics that
are genuinely BIA-specific (copilot-runtime, server-tools, mcp-servers,
model-selection, advanced-configuration, custom-agent). The router
falls back to these when no root equivalent exists.
- Root wins when both exist.
Changes:
- shared/manifest.schema.json: add 'built-in' to the category enum.
- shared/packages.json: register built-in-agent slug.
- packages/built-in-agent/manifest.yaml: new. deployed:false (showcase
package TBD in a follow-up), sort_order:0, category:popular so it
appears at the top of the framework dropdown.
- public/logos/built-in-agent.svg: new logo asset (extracted from the
inline CopilotKit mark in brand-nav.tsx).
- shell-docs/src/app/[framework]/[[...slug]]/page.tsx: router gains a
fallback to integrations/<framework>/<slug>.mdx when the root file
doesn't exist. Sidebar nav merges in per-framework overrides as a
labeled section positioned after 'App Control' (mirrors upstream's
integrations/built-in-agent/meta.json ordering).
- shell-docs/src/components/docs-page-view.tsx: new optional
contentSlugPath prop lets the router thread through the override
content path without changing the URL-slug used for breadcrumbs and
active-link detection.
- shell-docs/src/lib/docs-render.tsx: new buildFrameworkOverridesNav
helper that walks integrations/<framework>/* and filters out pages
that already exist at root.
## Summary
The top-nav "Integrations" link on shell-docs (and the inline link
inside `IntegrationGrid`) both pointed at `/integrations` on shell-docs
itself — a redundant framework-picker + matrix page that duplicated the
sidebar's framework selector. The real integration explorer (live demos,
filtering, feature browsing) lives on the shell app at `/integrations`.
This PR routes both links to the shell host instead.
## Changes
- `showcase/shell-docs/src/components/brand-nav.tsx` — top-nav
"Integrations" href is now `${NEXT_PUBLIC_SHELL_URL}/integrations`.
- `showcase/shell-docs/src/components/integration-grid.tsx` — inline
"See Integrations" href updated the same way.
- `showcase/shell-docs/next.config.ts` — adds `NEXT_PUBLIC_SHELL_URL`
build-time validation mirroring the existing `NEXT_PUBLIC_BASE_URL`
pattern: throws during `next build` if missing, warns in dev.
- `showcase/shell-docs/src/content/docs/integrations/index.mdx` —
deleted. The redundant page those links targeted. Legacy per-framework
subtrees under `integrations/*` are unchanged.
Components use a localhost:3000 dev fallback via
`process.env.NEXT_PUBLIC_SHELL_URL ?? "http://localhost:3000"` — matches
the existing dev-fallback pattern documented in `next.config.ts` for
`NEXT_PUBLIC_BASE_URL`. No hardcoded prod URLs in the code.
## Prod safety
`next build` fails loudly if `NEXT_PUBLIC_SHELL_URL` is unset. Since
`NEXT_PUBLIC_*` values are inlined at build time, a successful prod
build ships with the correct host baked in; the localhost fallback is
only reachable in dev.
## Test plan
With shell running at `http://localhost:3000` and shell-docs running at
`http://localhost:3003`:
- [ ] Hover the "Integrations" link in shell-docs' top nav — status bar
shows `http://localhost:3000/integrations`
- [ ] Click it — lands on the live `IntegrationExplorer` at
`localhost:3000/integrations`
- [ ] The inline "See Integrations" link rendered by `<IntegrationGrid
/>` (e.g. on `/prebuilt-components`) behaves the same way
- [ ] Visiting `/integrations` on shell-docs directly (e.g.
`http://localhost:3003/integrations`) 404s — the page was deleted
- [ ] Sidebar and other nav elements unchanged
Add */src/data/*.json patterns to showcase/.gitignore for all 4 shell
apps. Remove 11 tracked JSON blobs (~28K lines of generated content)
that were causing constant git noise from embedded timestamps and
leaking into PRs on every build/dev run.
Every build path (Docker, CI, npm run build, npm run dev) regenerates
these files — they never needed to be committed.
Every generator embedded `generated_at: new Date().toISOString()` in its
output, causing constant git noise on every build/dev run even when
actual content was unchanged. Remove the field from all 4 generator
scripts, all consumer interfaces (Registry, BundledContent,
BundledStarters, DocsStatusBundle), inline type casts, and test
assertions.
Also: add shell-dashboard as a generate-registry output directory (it
was cross-importing from shell); move probe-docs output to
shell-dashboard/src/data/ (sole consumer); update test beforeAll to
generate files instead of restoring from git HEAD (prep for gitignore).
Shell owns /integrations (live explorer) and /matrix (feature matrix),
mirroring shell's existing redirect table that sends /docs/*, /ag-ui/*,
/reference/*, and /<framework>/* to the docs host. Adds the reverse
redirects in shell-docs' next.config so /integrations and /matrix jump
out to showcase.copilotkit.ai at the edge.
Removes the redundant shell-docs framework-picker page at
showcase/shell-docs/src/content/docs/integrations/index.mdx. All internal
links can now use bare /integrations hrefs — the redirect handles the
cross-host jump in production, and in dev it 404s cleanly (no local
page to render). Legacy per-framework subtrees under integrations/* are
unchanged.
## Summary
First round of the snippet-linking sweep: every code fence in shell-docs
should be a `<Snippet>` pointing to real showcase source, not
hand-written inline ```tsx.
Scope on this PR is **prebuilt-components + the unselected twin** — 4
commits, easy per-commit review.
### Commits
- `7efe08ae8` — **Strip hand-written fences from Styling sections** on
all 6 prebuilt-components pages (base + unselected ×
chat/sidebar/popup). Keeps the `## Styling` header, intro copy, and
bullet links to `/custom-look-and-feel/*`; drops only the duplicative
slot-override code.
- `157cdae57` — **Wording pass**: replace "showcase cell" references
with neutral phrasing ("the example below", etc.) across 21 files.
- `f6086011a` — **Snippet-ify the Code example section on both chat.mdx
pages.** Adds a new `@region[chat-component]` to
`showcase/packages/langgraph-python/src/app/demos/agentic-chat/page.tsx`
wrapping the existing `Chat` helper (hook + render). Hand-written tsx
fences on `docs/prebuilt-components/chat.mdx` and
`docs/unselected/prebuilt-components/chat.mdx` replaced with `<Snippet
region="chat-component">`. The three `demo-content.json` bundles are
regenerated to include the new region.
- `ef0823372` — **Snippet-ify variant code blocks on
`unselected/prebuilt-components/index.mdx`.** Three hand-written tsx
fences (CopilotChat, CopilotSidebar, CopilotPopup variants) become
Snippets pointing at `chat-component` (agentic-chat),
`sidebar-basic-setup` (prebuilt-sidebar), and `popup-basic-setup`
(prebuilt-popup). Drops the redundant Deep customization inline example
in favor of a link to the Slots guide.
### Showcase-source change
Only one: `@region[chat-component]` / `@endregion[chat-component]`
markers added around the existing `Chat` helper in
`showcase/packages/langgraph-python/src/app/demos/agentic-chat/page.tsx`
(2 lines, no runtime behavior change).
## Test plan
Run shell-docs at `localhost:3003`.
Prebuilt-components pages (clear framework selection to reach
`/unselected/*`):
- [ ] `/langgraph-python/prebuilt-components/chat` — Basic setup =
`provider-setup` Snippet; Code example = new `chat-component` Snippet
showing the full `Chat` function; Styling = header + intro + 3 bullet
links, no code
- [ ] `/langgraph-python/prebuilt-components/sidebar` — Basic setup =
`sidebar-basic-setup` Snippet; Configuring = `sidebar-configuration`
Snippet; Styling = header + intro + link, no code
- [ ] `/langgraph-python/prebuilt-components/popup` — Basic setup =
`popup-basic-setup` Snippet; Styling = header + intro + link, no code
- [ ] `/unselected/prebuilt-components/chat`, `/sidebar`, `/popup` —
same expected rendering as the langgraph-python variants
Index page (URL-only, not in sidebar):
- [ ] `/unselected/prebuilt-components` — 3 variant subsections
(CopilotChat, CopilotSidebar, CopilotPopup), each showing a real-source
Snippet block; Deep customization is a one-paragraph pointer to Slots,
no code
Replaces the three hand-written tsx fences (CopilotChat, CopilotSidebar,
CopilotPopup variants) with Snippet references pointing at real showcase
regions: chat-component in agentic-chat, sidebar-basic-setup in
prebuilt-sidebar, and popup-basic-setup in prebuilt-popup.
Also drops the redundant Deep customization inline example — the section
already links out to the dedicated Slots guide; a hand-written slot-pattern
example duplicates what that guide covers with real code. Shortened the
lead-in to point readers at Slots for runnable examples.
One fence remains on this page: the 'Setup' section's CSS stylesheet import,
a one-line CLI-style instruction with no corresponding showcase region.
Left inline as a legitimate snippet-linking exception (same pattern used
for npx commands).
Replaces the hand-written tsx fence in the 'Code example' section of both
docs/prebuilt-components/chat.mdx and docs/unselected/prebuilt-components/chat.mdx
with a <Snippet> reference to a new chat-component region in the
langgraph-python agentic-chat demo source.
The new @region[chat-component] wraps the whole Chat helper function in
showcase/packages/langgraph-python/src/app/demos/agentic-chat/page.tsx,
so readers see a self-contained real-code component (hook + render) with
the view-source link that a Snippet provides.
Also regenerates the three demo-content.json bundles to include the new
region.
Declare open-gen-ui and open-gen-ui-advanced in langgraph-python
manifest (code existed, was never registered). Add both to
constrained-explicit allowlist, fill shell_docs_path for 5 demos,
add hitl-in-app override, drop stale chat-customization-css fallback.
Regenerate registry.json, demo-content.json, constraints.json,
and docs-status.json across shell / shell-dojo / shell-docs.
Bump feature/demo count assertion 30→32 in generate-registry test.
Extend check-binaries.sh whitelist for sister-shell demo-content.
Resolves former priority item 5. The Styling sections on the chat, sidebar,
and popup prebuilt-component pages (base + unselected/) each had an inline
tsx code fence that duplicated styling patterns already covered on the
dedicated /custom-look-and-feel/{css,slots,headless-ui} pages. Per Atai's
directive that every code fence in shell-docs should be a showcase-linked
Snippet, not hand-written, removing these fences is the right move here.
Section headers, intro copy, and bullet links to the dedicated styling
pages are preserved — those are legitimate pointers.
The Styling section referenced "import the stylesheet once at your app
boundary" but the fenced block was empty, leaving users with nowhere
to copy from.
Previously <main> was both the scroll container AND width-capped
(`flex-1 max-w-4xl px-8 py-10 overflow-y-auto`). The scrollbar
rendered at the capped column's right edge, parking it mid-viewport
with a blank gutter beside it.
Separate the concerns: <main> is now full-width with the scroll, and
an inner <div> caps the content width and owns the padding. Scrollbar
now lands at the viewport edge (or TOC's left edge on pages that
render the right-rail TOC).
Applies to the four docs entry points that shared this pattern:
the root overview, the /<framework> landing + scoped pages, the
/ag-ui route, and the shared DocsPageView used by scoped docs.
The four docs flex containers used `calc(100vh - 52px)` to subtract the
top nav, but BrandNav is 52px flex content + 1px bottom border = 53px.
The 1px undercount made body overflow by exactly 1px and produced a
document-level scrollbar on top of the inner <main>'s own scroll.
The reference route already uses `calc(100vh - 53px)`; this aligns the
other four layouts with that convention.
Adds multimodal-attachments, runtime-server-adapter, and vs-code-extension
pages under a new ---Platform--- section in meta.json. threads.mdx was
already in place and left untouched. fumadocs-ui import lines are stripped
since shell-docs pulls components from its MDX registry instead.
When the runtime registers an agent as default, CopilotKit hooks auto-select
it; passing agentId: "default" (or a stale "assistant" ID that isn't
actually registered) is noise. Applies to built-in-agent/shared-state.mdx
and unselected/shared-state.mdx across shell-docs and upstream.