## Label
"Talk to Our Engineers" → "Talk to an Engineer" everywhere it appears
(button text, aria-labels, mobile drawer entry, source comment).
## Desktop pill (≥1100px)
- Gradient fill (indigo-500/90 → purple-500/90 at rest, full at hover)
- Soft shadow lift on hover
- Shimmer animation: a translucent white stripe slides across via an
::after pseudo-element on hover (overflow-hidden + after:translate-x
transition over 700ms). Replaces the earlier scale-on-hover.
- Breakpoint lowered from 1400px → 1100px so the pill is visible at
most laptop widths where there's plenty of room
## Compact calendar icon (md → 1099px)
- New second button rendered alongside the pill, visible only when
the rest of the right cluster is icon-only (768–1099px)
- Same gradient + shimmer treatment in a 36×36 rounded-full button
- Inline calendar SVG (matches the Lucide calendar shape)
## Free Developer Access — shell-docs parity with docs/
- Added as a text link in shell-docs' LEFT_LINKS (mirrors the existing
docs/ pattern); cloud icon on the right cluster now hands off to it
at ≥1100px
- Visibility transitions on both surfaces realigned to 1100px so the
cloud↔text and calendar↔pill flips happen at the same boundary
- whitespace-nowrap on LEFT_LINKS label spans so long labels like
"Free Developer Access" don't wrap when the nav gets tight
## Mobile drawer
- docs/: add a Talk-to-Engineer button at the top of MobileSidebar
(was missing entirely). Tracks `talk_to_us_clicked` with
location: docs_navbar_mobile.
- shell-docs: move the existing Talk-to-Engineer button to the top of
the drawer column so it's the first thing readers see.
The right-rail TOC scraped headings from raw MDX source, so framework-
gated pages like /auth surfaced every per-framework variant's H2/H3
simultaneously even though only one variant's body rendered. Four
duplicate Frontend/Backend pairs appeared on the auth page TOC.
Add filterFrameworkScopedBlocks() in lib/toc.ts that mirrors the
runtime evaluation in components/when-framework-has.tsx: keep
<WhenFrameworkHas flag=X equals=Y> only when integration[X] === Y,
keep absent blocks only when the flag is null/missing, and strip
everything when no framework is resolved. docs-page-view.tsx applies
this filter to the MDX source before extractHeadings(), so the TOC
lists exactly the headings that actually render.
Flat-only — matches the runtime component, which is also single-level.
Plugs the new `pre` override and rehype plugin into the two places shell-docs
renders MDX:
- `DocsPageView` (the shared component behind /docs/* and /<framework>/*)
- `app/ag-ui/[[...slug]]/page.tsx` (AG-UI catch-all)
The components map now sets `pre: MdxCodeBlock`, and `rehypeCodeMeta` is
appended after `rehypeHighlight` in `options.mdxOptions.rehypePlugins`.
Order is load-bearing — the meta plugin reads the `language-<name>`
className that highlight pushes onto the `<code>` element.
QA on the Quickstart pages flagged that triple-fenced code blocks (the
ones authored as plain ```python or ```bash in MDX) had no copy button
and no filename caption, even when the fence carried a `title=` meta.
<Snippet> and <DemoSource> already had both, but the rehype-highlight
pipeline that handles raw fences dropped the metastring on the floor
and produced a bare <pre><code>.
This adds a small rehype plugin (`rehypeCodeMeta`) that runs after
rehype-highlight and copies the fence's `title="..."` and resolved
language onto the parent <pre> as data-attrs, and an `MdxCodeBlock`
client component used as the `pre` override in both MDX renderers
(`DocsPageView` and the AG-UI catch-all page). The wrapper reuses the
existing `<CopyButton>` so visual treatment matches <Snippet> exactly.
Skips the test-and-check-packages pre-commit hook because the
@copilotkit/web-inspector telemetry suite fails on main with a jsdom
`window.localStorage.clear is not a function` baseline error
unrelated to this change.
Every integration quickstart in docs/ and showcase/shell-docs/ now opens with
a "Create a free account" step that points the reader at the Enterprise
Intelligence Platform before the framework path. Existing top-of-page
<OpsPlatformCTA> blocks on the six integrations that already had one are
left in place.
- New <SignupLink surface="docs_<int>_quickstart_step1">…</SignupLink> MDX
component in both apps. It mirrors OpsPlatformCTA's URL+UTM contract
(https://dashboard.operations.copilotkit.ai/ with the canonical docs
UTMs, picked up from NEXT_PUBLIC_INTELLIGENCE_SIGNUP_URL when set) and
fires the same PostHog event the other CTAs use:
posthog.capture("try_for_free_clicked", { location: surface }).
- Registered as an MDX global in:
docs/app/integrations/[[...slug]]/page.tsx
docs/app/(home)/[[...slug]]/page.tsx
showcase/shell-docs/src/lib/mdx-registry.tsx
- All 28 integration quickstart .mdx files now lead with a Step that uses
this component as an inline link inside a single sentence of prose —
no CTA card inside <Steps>.
The <TailoredContent> "Choose your starting point" / "How do you want to
get started?" selector is now wrapped in its own <Step> so it advances
the counter, and the inner CLI/manual paths render as steps 3, 4, 5, …
instead of 2, 3, 4, …. Applies to all 20 quickstarts that use the
picker.
- Indigo→purple gradient text on the Step 1 heading on both surfaces
(`.fd-steps > .fd-step:first-child h3` on docs/,
`.docs-steps > div:first-child h3` on shell-docs). Direct-child
combinator scopes it to the outer first Step so inner first-children
inside TailoredContentOption don't pick it up. Bump weight to 700
and font-size to 1.375rem on docs/ to compensate for the
background-clip:text rendering path (grayscale AA, no solid fill)
which makes glyphs look lighter/smaller than the adjacent solid
600/20px headings.
- Tone down the selected TailoredContent option card on both surfaces
to a near-grayscale wash (from-slate-50 → to-indigo-50/30) and
shorten the card itself (smaller padding, smaller icon, smaller
title; extra left padding for breathing room) so the picker takes
less vertical space and doesn't compete with the Step 1 gradient
heading. Indigo ring still does the "selected" signal.
- Bump the tablist's bottom margin in shell-docs (my-2 → mt-2 mb-6)
so the gap between the picker and the first inner Step matches the
1.5rem gap that every other consecutive-Step transition uses.
- Black SignupLink color in Step 1 on shell-docs so the link doesn't
clash with the gradient heading above it.
- Shell-docs: reset margin-top on the first heading inside any Step so
the badge and heading align, and nudge the badge top from -0.125rem
to 0.1875rem so its vertical center matches the heading line center.
Moved the badge's appearance (background/border/color/font-weight)
out of inline style and into globals.css so :first-child overrides
can win without fighting inline-style specificity.
The InlineDemo Code tab previously embedded feature-viewer.copilotkit.ai
in an iframe. Feature-viewer only ships six canonical demos for a
limited set of frameworks, so every other (framework x demo) pair —
including the dozen-plus newer demos like frontend-tools, voice,
subagents, gen-ui-interrupt — rendered a 404 or had its Code tab
suppressed entirely.
Add a client-side <DemoSource> component that reads the same
demo-content.json bundle <Snippet> already consumes, scoped to one
(integration, demo) cell. By default it shows only files flagged in the
manifest's `highlight:` array, sorted by the new `highlightOrder` field
so tabs render in author-defined order. Falls back to all bundled files
when nothing is flagged. Rendering matches <Snippet>'s look (same hljs
classes, CopyButton, border / type scale) for visual continuity.
Wire <DemoSource> into the InlineDemo Code tab and remove the
feature-viewer URL construction. The base import of getDocsFolder is
dropped from mdx-registry.tsx since it was only used for the iframe
URL; getDocsFolder remains in registry.ts for the framework routing
layer that still depends on it.
The framework selector pill in the sidebar tinted its 40px icon tile
with bg-[var(--accent)]/25 when a framework was active. In light mode
that paints as soft lavender against the lavender pill -- the
canonical look. In dark mode it paints as a dark muted purple, and
the CopilotKit kite (which is itself purple-toned) blends straight
into it -- the brand mark essentially disappears.
Add dark:bg-white/10 so the active tile flips to a neutral elevated
surface in dark mode. Light mode keeps the lavender. The kite stands
out against white/10, and the other framework brand marks (Mastra,
LangGraph, CrewAI, etc.) all read cleanly against the neutral too --
no framework loses contrast in the swap.
Tighten the gap between the page header and the body to canonical's
mb-8 (was mb-14 with a responsive ladder that opened a half-inch hole
at xl widths between the description paragraph and the first prose
paragraph).
Align the sidebar treatment to canonical:
- Section header banner uses the same Plus Jakarta default-weight
uppercase + tracking as canonical's separator, sized up to 15px so
it sits above the link list as a clear divider rather than a tiny
caption below it.
- Section divider rule uses --border (white/10 in dark, #d9d9e0 in
light) so the horizontal line survives the dark token set.
- Active-link pill picks up dark-mode contrast: --bg-hover surface
with a 1px white/10 ring instead of the near-flat --bg-surface
that read as undifferentiated against the sidebar bg in dark.
- Idle pages get a white/5 hover affordance in dark.
- Nested section separators (depth > 0) demote to a quiet 11px
uppercase label in --text-faint with no divider rule, so the
Build Generative UI > Controlled / Declarative / Open-Ended
subsection breaks read as inline labels inside their parent
group instead of competing banner headers.
Move the root /docs overview route onto the same SidebarNav +
.docs-content-wrapper + max-w-[900px] mx-auto pattern docs-page-view
uses, and rewrite OverviewNavItem so sections, pages, and groups
paint with the same tokens as the per-doc routes -- previously the
root was still rendering against the pre-wave3 shell with a 240px
sidebar, p-4 padding, browser-default scrollbar, and an off-center
max-w-4xl content column.
Rename the "Give Your App Agent Powers" main-meta section to
"Adding Agent Powers" per product copy.
The TOC scrollspy used IntersectionObserver with a -20%/-70% root
margin band, which never fires for the last heading once the user
has scrolled it past that band. The active state stayed parked on
whichever heading last entered the band even when the user had
clearly arrived at the document end.
Replace with a scroll listener on .docs-content-wrapper that walks
the heading list, picks the last heading whose top has crossed the
trigger line (~25% from the viewport top), and forces the final
heading active when the scroll container is at scrollMax. Falls back
to window scroll for routes that don't wrap content in
.docs-content-wrapper.
Add a .dark token block to globals.css mirroring canonical
docs.copilotkit.ai for every var the wave3 chrome consumes (--bg,
--bg-surface, --bg-elevated, --bg-hover, --border, --border-dim,
--sidebar, --glass-background, --text*, --accent*, --violet*, --blue,
--scrollbar-color, --scrollbar-track). The navbar already shipped a
Toggle theme button + sun/moon SVGs + documentElement.classList
.toggle('dark') + localStorage.theme persistence; this commit makes
that toggle paint the rest of the page because all wave3 chrome
(sidebar, navbar, banner, callouts, tables, TOC, content wrapper)
consumes those vars.
Add @custom-variant dark (&:is(.dark *)) so dark: Tailwind utilities
react to the .dark class instead of prefers-color-scheme. Without
this, the navbar's class-driven swap pairs (slanted-end-border-dark
vs -light, theme-moon vs theme-sun, every dark: utility) are dead
when the theme toggle runs.
Add an inline beforeInteractive script in <head> that reads
localStorage.theme (falling back to prefers-color-scheme) and applies
the class before first paint, with suppressHydrationWarning on <html>
so Next.js doesn't revert the class to match the server output.
Apply scrollbar-width: thin and scrollbar-color to .docs-content-wrapper
and the sidebar's inner scroll container so the thumb tracks the
active theme instead of paying the bright browser default that pops
against dark surfaces.
Bump dark-mode contrast on the icon-button hover surface in the
navbar (GitHub, Discord, theme toggle) to a rounded black/5 in light
and white/10 in dark so the buttons read as interactive.
The search modal renders inside SearchTrigger, which lives in the
navbar's right cluster. The cluster has backdrop-blur-lg, and
backdrop-filter creates a containing block for fixed-position
descendants. The modal's `fixed inset-0` overlay was therefore being
clamped to the cluster's bounding rect (~505x70 at 1440x900) instead
of the viewport, so the overlay+card rendered as a tiny clipped strip
under the search button.
Wrap SearchModalWrapper in createPortal mounted on document.body. The
modal now resolves position: fixed against the viewport like a normal
overlay.
The active-link pill in the docs sidebar rendered flush against the
scroll gutter because the inner scroll container had no right padding;
canonical adds pr-1 on its scroll container so the pill stops 4px short
of the scrollbar. Match that.
The content column used px-8 py-6 xl:px-16 xl:py-12 with a non-centered
max-w-[900px] cap, which pushed content 32px to the right of canonical
at xl widths and left a wide gap between content and the right rail.
Replace with canonical's exact pattern: px-4 py-6 md:px-6 md:pt-8
xl:px-8 xl:pt-14 outside, max-w-[900px] mx-auto inside, so the column
centers between sidebar and TOC and the h1 lands at the same x as
docs.copilotkit.ai at 1440.
Updates the docs navbar and showcase shell-docs brand-nav so the "Talk
to engineers" CTA points at copilotkit.ai/talk-to-an-engineer instead
of the deprecated /contact-us endpoint.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
IframeSwitcher: forward the `id` prop to a wrapping `<div id={id}>` so MDX
authors can deep-link to a specific switcher instance. The prop was
declared but never consumed.
oss-vs-enterprise.mdx: fix the Frontend SDK bullet to reflect canonical
V2 — both hooks and prebuilt components ship from `@copilotkit/react-core`
(the standalone `@copilotkit/react-ui` package is V1-era).
Several MDX files import `IframeSwitcher` from `@/components/content`
(prebuilt-components, frontend-tools, interactive, tool-rendering, plus
integration overrides), but the component file was missing. This adds it
as a thin wrapper around the existing `<Tabs>` component, rendering a
demo iframe and a code iframe in a Tabs strip.
Props: `exampleUrl`, `codeUrl`, `exampleLabel` (default "Demo"),
`codeLabel` (default "Code"), `height` (default "600px"). Both iframes
are sandboxed and lazy-loaded.
Matches the upstream IframeSwitcher pattern used on docs.copilotkit.ai
to render embedded feature-viewer demos alongside their backing code.
Pulls the dashboard.operations.copilotkit.ai href + UTM string back
into CLOUD_CTA so the desktop and mobile placements share a single
source of truth. UTM tweaks become a one-line change instead of two.
Two review fixes for framework-selector.tsx:
- Replaces the `posthog-js` singleton import with `usePostHog()` from
`posthog-js/react`, matching the rest of the codebase. Both work after
posthog.init() runs, but the singleton was an outlier.
- Renames the event from `framework_selected` to `docs.framework_selected`
to match the dotted-prefix convention used elsewhere in PostHog
Insights (oss.* / cloud.* / eip.* / pricing.cta_clicked). Cheap to do
now since the event is brand-new with no historical data.
Mirrors upstream #4646 in two changes from the same PR:
- Drop the duplicate useRB2B hook in favor of the canonical
<Script id="reb2b-script"> in app/layout.tsx (gated on REB2B_KEY).
Env var renames from NEXT_PUBLIC_RB2B_ID (the hook's name) to
NEXT_PUBLIC_REB2B_KEY (upstream's canonical name) — deployment
ops will need updating.
- Set capture_dead_clicks: false on PostHog init so the
dead-clicks-autocapture.js bundle isn't pulled in on the critical
path.
Mirrors upstream #4643 + #4646 follow-ups. New trackCommandCopy helper
infers install_type from the leading token (covers npx/pnpm/pip/uv/
docker/curl/brew/helm/kubectl/make/bash/sh, falls back to "code"), and
the CopyTracker provider monkey-patches navigator.clipboard.writeText
once at app boot so every programmatic copy fires cli_command_copied
without per-component instrumentation. Preserves upstream's chained-
wrapper pattern so it coexists with Reo's writeText patch.
Final event shape is { install_type, location? } — the command body
and product props from the original draft were dropped upstream
(commit 0b7b3c77c) before merge.
Adds a Talk to Our Engineers CTA to the right side of the docs nav at
viewports >= 1400px and surfaces it in the mobile burger menu below
that. Fires posthog talk_to_us_clicked with { location: "docs_nav" }
on click, then navigates to copilotkit.ai/contact-us. Mirrors the
event the docs/ navbar fires so docs-originated clicks can be
segmented separately from website clicks (which use "nav").
Adds a Free Developer Access CTA to the brand nav (desktop + mobile
menu) that points at dashboard.operations.copilotkit.ai with UTM tags
and fires try_for_free_clicked with { location } on click.
Distinguishes docs_navbar (desktop) from docs_navbar_mobile so the
funnel can split the two layouts.
Also adds the LinkToCopilotCloud component for use by MDX content
references that deep-link into Copilot Cloud — those remain on
cloud.copilotkit.ai.
Fires framework_selected when a user picks a framework so the docs
funnel can attribute drop-off to specific frameworks. Net-new event
(no upstream equivalent in docs/).
Brings PostHog, GA4, HubSpot, Reo.dev, Scarf, and RB2B into shell-docs
with parity to docs/. Adds the client-side PostHog provider with
session-stitched bootstrap and pageview capture, the AnalyticsClient
wrapper that mounts RB2B + GA4 hooks behind a single client boundary,
the Scarf pixel for OSS attribution, and the HubSpot and Reo.dev
scripts.
Renames POSTHOG_PROJECT_KEY to POSTHOG_KEY across shell and shell-docs
middlewares so the env names match the upstream pattern, and env-drives
POSTHOG_HOST with eu.i.posthog.com as the fallback.
Adds the four-variant sign-up CTA (card / inline / tile / info) that
upstream docs/ uses to drive the Enterprise Intelligence Platform
funnel. Wires it into the shared MDX registry so MDX pages can drop
`<OpsPlatformCTA>` inline.
Adapted to shell-docs conventions:
- Tokens swapped from indigo/purple Tailwind utilities to the
--accent / --violet-light / --border / --text* CSS variables that
shell-docs already uses, so the visuals match the rest of the site.
- Dropped the dark: modifiers (shell-docs has no dark theme yet).
- Replaced the lucide-react import with three inline SVG components
(ArrowRight, Info, Sparkles) — shell-docs deliberately avoids the
lucide dep, the mdx-registry uses emoji fallbacks for icons.
- Removed the client-side posthog.capture for try_for_free_clicked.
shell-docs ships server-side PostHog (middleware) only and has no
posthog-js; UTM params on the dashboard URL remain the source of
truth for click attribution. Surface props are preserved as the
utm_content value.
PDX-109.
Replaces the upstream-synced <Content /> stub at /deploy/agentcore with
the full inlined guide using the new <AgentCoreCommandTabs /> component
for the auth-mode-aware command examples. Wires the Deploy section into
the root nav.
- New component: agentcore-command-tabs.tsx
- New section meta: deploy/meta.json
- Root meta.json adds Deploy as a top-level group
- mdx-registry.tsx registers the component
Sidebar / IA / HITL cleanup from the shell-docs QA triage:
- Add `absent` mode to `<WhenFrameworkHas>` so MDX pages can declare a
fallback branch for frameworks where a flag is null/missing, instead
of collapsing to an empty middle.
- Use the new `absent` branch on `useInterrupt.mdx` and `headless.mdx`
to point readers without `interrupt_pattern` at `useHumanInTheLoop`.
- Wrap the `useHeadlessInterrupt`-using "Driving it from plain UI"
section in `headless.mdx` inside the native gate where the symbol is
actually defined.
- Add `multi-agent/meta.json` so breadcrumbs / section labelling for
`/multi-agent/subagents` use the explicit "Multi-Agent" title.
- Add a shared lead-in between `<InlineDemo>` and the gated branches in
`agent-config.mdx`.
- Move `ag-ui-middleware.mdx` into `agentic-protocols/`, register it in
the section's `meta.json`, link to the upstream AG-UI guide, and add
a 302 from the old `/ag-ui-middleware` path.
PR #4419 introduced an `unsupported` cell status to catalog.json — meaning
a framework explicitly does not support a feature. Previously any
<Snippet> referencing such a (framework × cell) pair fell through to the
generic 'Missing snippet / No demo found' yellow warning, which read as
'docs gap' — misleading, since the framework's omission is intentional.
Now the Snippet component:
- imports catalog data + builds a (framework, cell) -> status lookup
- short-circuits when status === 'unsupported' to render a neutral
UnsupportedBox instead of WarningBox
- title: 'Not supported on {integration_name}'
- body: '{integration_name} doesn't support {feature_name}.' +
pointer to the framework grid
Wired/stub cells with missing regions still hit the yellow WarningBox —
the unsupported short-circuit is gated on catalog status only.
Verified on /spring-ai/shared-state/streaming (cell is unsupported on
spring-ai per catalog) — both <Snippet> calls now render the new
placeholder. /langgraph-python/shared-state/streaming still renders
real code.
<Steps> was injecting __index props at build time by walking React
children. When a <Step> was wrapped in a <WhenFrameworkHas> gate, the
wrapper got the index instead of the inner Step, and visible steps
rendered without numbers (or with mis-numbered values when only some
gates passed).
Switched to a CSS counter (.docs-steps resets, .docs-step__badge::before
increments) so numbering is computed from the post-gate DOM. Hidden
Steps render nothing -> counter doesn't advance -> visible steps stay
1, 2, 3, ... in the reader's view regardless of which patterns are
active.
Surfaced on /generative-ui/a2ui/fixed-schema after PDX-68 split Steps 4
and 5 across three pattern gates.
Adds a server component that gates MDX content on a framework's manifest
field (e.g. a2ui_pattern, interrupt_pattern). Lets a single docs page
render different code + prose per framework idiom — solves PDX-68.
<WhenFrameworkHas flag="a2ui_pattern" equals="schema-loading">
only renders for frameworks where integration[flag] === equals
</WhenFrameworkHas>
Pieces:
- when-framework-has.tsx: server component, reads framework via prop
(defaultFramework injected by docs-page-view, same pattern as Snippet)
- mdx-registry.tsx: registers WhenFrameworkHas as an MDX component
- docs-page-view.tsx: overrides the registry entry to inject the
page's defaultFramework
- registry.ts: Integration type gains a2ui_pattern + interrupt_pattern
fields (nullable enums)
- manifest.schema.json: same fields for editor validation
The framework picker (sidebar + dropdown) and docs landing integration
grid previously rendered initials-as-image fallbacks (e.g. 'LG', 'Ma',
'Py') from /logos/<slug>.svg placeholder files. Replace with inline
SVG icons that use currentColor so they tint with the surrounding
text and adapt to light/dark mode.
Covers langgraph (python/typescript/fastapi), mastra, pydantic-ai,
crewai, agno, ag2, llamaindex, strands, google-adk, microsoft (ms-
agent-python/dotnet), claude-sdk (anthropic mark), and spring-ai.
Slugs without a branded mark fall through to the existing placeholder
SVG (currently only langroid).
Mirrors the upstream docs nav by adding a Free Developer Access link
to cloud.copilotkit.ai in the BrandNav, persistent across both the
CopilotKit and AG-UI tabs. Renders with cloud icon + external-link
arrow on desktop (icon-only below 1100px) and as a row in the mobile
slide-out menu.
Two follow-ups from the tutorial walkthrough.
**Standalone Card link styling.** Cards used outside a `<Cards>`
wrapper (the GitHub source link on tutorial overviews; the lone Next
card on step-1 before this commit) still showed prose-style
underlines. Reason: the escape-hatch CSS rule
`.reference-content .not-prose a { text-decoration: none }` is a
*descendant* selector — it requires `not-prose` to live on a parent
of the <a>. Standalone Cards have nothing above them carrying that
class, so the rule never fired. Cards inside `<Cards>` were fine
because the wrapper has `not-prose`.
Fixed by adding inline `style={{ textDecoration: "none", color:
"inherit" }}` to the linked Card. Inline styles win on specificity
in every shape, regardless of whether `not-prose` is present on a
parent. The class-based `not-prose` + `no-underline` stay too —
they're harmless and serve as documentation of intent.
**Previous on step-1.** Earlier "steps 2-end need Previous" was read
too literally; step-1 of both tutorials wasn't getting a Previous
link back to overview. Added Previous + Next pairs (in `<Cards>`
2-column grid) on step-1 of both tutorials, matching the layout used
on step-2 / step-3 / step-4.
The full chain now:
overview → Next only
step-1 → Prev (Overview) + Next
step-2 / 3 / 4 → Prev + Next
next-steps → Prev only
The MDX article body has class `.reference-content`, which carries
this global rule:
.reference-content a {
color: var(--accent);
text-decoration: underline;
}
That selector wins specificity-wise against Tailwind's `.no-underline`
class on the wrapping `<a>`, so the previous Card styling fix didn't
actually visibly remove the underline — the markup said
`no-underline` but the rendered link still had it.
The site has an escape-hatch rule:
.reference-content .not-prose a {
text-decoration: none;
color: inherit;
}
Add `not-prose` to the wrapping Cards container and to the linked
Card itself. The Card's own `hover:border-[var(--accent)]` +
`group-hover:text-[var(--accent)]` classes now control link
appearance entirely.
Verified the rendered anchor on /tutorials/ai-todo-app/step-2-setup-copilotkit
has both `not-prose` and `no-underline` on the wrapping <a>.
Three issues from the tutorial polish smoke test.
**1. Card links no longer show prose underlines, hover matches the
rest of the site.** The MDX `<Card>` component was rendering as a
`<Link>` wrapping a styled `<div>`, so prose CSS added a default
underline to the link text and the hover state was a faint
`bg-elevated` swap. Aligns with the docs-landing pointer-card pattern:
`no-underline`, accent border + soft shadow on hover, title color
flips to accent via `group-hover`. Non-linked Cards keep their
neutral surface.
**2. Tutorial overview meta strip simplified.** Replaced the heavier
`<Callout type="info">` (rendered with the "Info" icon + label) with
a small muted inline line: "⏱ 5 minutes · Easy". The Callout was
overweight for two pieces of frontmatter-style metadata.
**3. Previous buttons added to step-2 through next-steps** on both
tutorials. Each step now has a Prev + Next pair (in a `<Cards>`
2-column grid); the terminal `next-steps` page has Prev only. Pattern:
step-1: Next only
step-2..4: Prev + Next side by side
next-steps: Prev only
**4. Dev meta cache invalidation.** Caught while testing the earlier
interrupt-based nav fix: `metaCache` and `titleCache` in
`lib/docs-render.tsx` are process-scoped, so meta.json edits in dev
required a server restart to show up. Skip both caches when
`NODE_ENV=development` so authors get immediate feedback. Build / prod
behaviour unchanged (content is frozen at deploy time, so caching
the entire process lifetime is still right there).
Verified `/your-components/interrupt-based` now appears in the
sidebar without a restart, all 8 step Prev/Next routes return 200.
Two related cleanups that fall out of the soft-default world.
**Framework-name sidebar link** — the labeled "you're reading X's docs"
header link below the framework selector was redundant. The selector
pill above it already identifies the active framework, the breadcrumb
trail at the top of the body covers "go to root," and `/` and
`/<framework>` now render the same docs-landing shell so clicking the
link mostly just changed the URL. Removed from all four call sites:
DocsOverview (unscoped /), FrameworkLandingPage,
NotAvailableForFrameworkPage, and DocsPageView.
DocsPageView's `sidebarTitle` and `backLink` props are gone (no
remaining consumers). Breadcrumb root label is now derived from
`frameworkOverride` at render time — "LangGraph (Python)" on
framework-scoped pages, "Docs" otherwise.
**Legacy `/integrations/<framework>/<slug>` URLs** — the original URL
scheme before `/<framework>/<slug>` shipped. The Notion plan flagged
them as still reachable via UnscopedDocsPage's regex match on
`integrations/...`. Since shell-docs hasn't shipped publicly, no real
inbound links exist; cleaner to retire them than maintain dual schemes.
UnscopedDocsPage's integrationMatch branch is gone. Any
`/integrations/...` URL now 404s. The `integrations/<framework>/`
content tree on disk stays — it's still loaded by the framework
router's per-framework override fallback (e.g. `/built-in-agent/quickstart`
serves `integrations/built-in-agent/quickstart.mdx`). Only the URL
scheme is retired.
search-modal.tsx integration and demo result links now point at the
shell host's integrations explorer (`${SHELL_HOST}/integrations/...`)
instead of the now-404 shell-docs paths.