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/).
Adds app/og/[...slug]/route.tsx for per-page social-share image
generation, and a vercel.json with maxDuration: 60 on app/og/** so
the Edge function has enough headroom to render OG cards.
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.
The aggregated multi-turn probe from #4672 hit a CopilotKit v2 quirk on
/demos/beautiful-chat: only the FIRST useComponent tool call in a
conversation paints its component. Subsequent tool calls emit (the
agent's followup content arrives) but the component never mounts.
Reproduced cleanly without any frontend tool involvement —
pie-chart turn 1 paints 5 svg circles in seconds, bar-chart turn 2
emits "Bar chart rendered above..." but paints zero recharts elements.
The runner can't sidestep this from inside one conversation without a
page.reload() between turns, which the structural Page type doesn't
expose. Splitting into per-pill scripts means each probe gets its own
browser launch — fresh page state, fresh conversation, no useComponent
ordering pollution. CATALOG_TO_D5_KEY maps `beautiful-chat` to all
listed literals; isD5Green requires every key green for the cell to
advance to D5, and per-pill failure isolation surfaces in PB row names.
Coverage in this PR (5 pills):
- beautiful-chat-toggle-theme (frontend tool, html.dark flip)
- beautiful-chat-pie-chart (controlled gen-UI useComponent)
- beautiful-chat-bar-chart (controlled gen-UI useComponent)
- beautiful-chat-search-flights (A2UI fixed-schema FlightCards)
- beautiful-chat-schedule-meeting (HITL with slot-click resolution)
All 5 verified locally end-to-end (5/5 pass against the local stack).
Out of scope, intentionally (track in follow-up):
- Excalidraw — depends on mcp.excalidraw.com reachability
- Calculator — sandboxed iframe; dup of d5-gen-ui-open
- Sales Dashboard — generate_a2ui → render_a2ui chain renders
Metric labels but Row-bound charts don't paint
recharts containers under aimock fixtures (live
pill against same fixture chain shows the
inverse symptom). Suggests aimock's
non-progressive arg streaming differs from a
live LLM in a way the A2UI binder is sensitive
to. Needs separate aimock/binder investigation.
- Task Manager — manage_todos dispatches and agent emits closing
content, but StateStreamingMiddleware's
state.todos propagation doesn't populate the
App pane TodoList through aimock — same suspected
root cause as Sales Dashboard.
Architecture details:
- _beautiful-chat-shared.ts factors DOM helpers + per-pill
assertions, mirroring _hitl-shared.ts's pattern for an extended
Page type with click() + a runtime guard
- Each fixture uses unique D5-prefixed userMessage substrings; the
multi-stage Schedule Meeting flow uses hasToolResult false→true
for round disambiguation (no toolCallId leakage since each probe
runs in its own fresh page session)
## Summary
- **Dashboard mapping fix.** `CATALOG_TO_D5_KEY` in
`showcase/shell-dashboard/src/lib/live-status.ts` was missing `voice →
["voice"]`, so `computeMaxPossible` capped the langgraph-python voice
cell at D4 even when the d5-voice probe row was green. The harness
`REGISTRY_TO_D5` already had the entry; only the dashboard mirror was
out of sync.
- **Sample-button decoupled from `/transcribe`.** The "Play sample"
button used to fetch `sample.wav` and POST it to the runtime's
transcription endpoint, which made the sample button and the mic
indistinguishable under aimock (both returned the canned transcription).
Reworked it into a synchronous static-text injector — sample button is
now a deterministic test/demo affordance, and the mic is the only path
that exercises real Whisper transcription. Synced across all 18
voice-enabled integrations. Phrase stays `"What is the weather in
Tokyo?"` so aimock's `weather in Tokyo` substring fixture still matches.
- **Probe-test parity.** Added the missing `d5-voice.test.ts` companion
(every other `d5-*.ts` script has one) — 9 tests covering registration,
`buildTurns`, `preFill` (sample-button click + textarea-poll path), and
the weather/Tokyo assertion.
- **QA + e2e cleanup** for langgraph-python: dropped the
no-longer-applicable "Transcribing…" mid-flight assertion and the `block
/demo-audio/sample.wav` error-state subsection. Other 16 integrations'
qa/e2e files follow in a parity sync PR.
## Test plan
- [x] `nx test @copilotkit/showcase-harness -- --run d5-voice` → 9/9
pass
- [x] `npm test` in `showcase/shell-dashboard` → 509/510 pass (1
skipped, 0 failed)
- [x] `nx build @copilotkit/showcase-harness` → clean
- [x] Local boot: `langgraph-cli dev` (port 8123) + `next dev` (port
3000) + dashboard (port 3002) — voice page at `/demos/voice` renders,
"Play sample" injects the canned phrase instantly, send → agent returns
weather, mic → real Whisper transcription with `OPENAI_API_KEY` set
- [ ] Reviewer: confirm the langgraph-python voice cell on the live
dashboard advances to D5 once the next d5-voice probe tick lands a green
row
The langgraph-python voice cell sat at D4 even when its d5-voice probe
row was green. Root cause: the dashboard's CATALOG_TO_D5_KEY mirror in
showcase/shell-dashboard/src/lib/live-status.ts was missing voice ->
["voice"], so computeMaxPossible capped voice at D4 regardless of probe
state. The harness REGISTRY_TO_D5 already had the entry; only the
dashboard mirror was out of sync.
Separately, the "Play sample" button used to fetch sample.wav and POST
it to /transcribe. With aimock that meant both the sample button AND
the mic returned the same canned response, which made it impossible to
demo the mic path locally without conflating the two affordances.
Reworked the button into a synchronous static-text injector
(onTranscribed(sampleText)) so:
- Sample button = deterministic test/demo affordance, no runtime calls.
- Mic = real Whisper transcription via /transcribe.
Synced across all 18 voice-enabled integrations. Phrase stays "What is
the weather in Tokyo?" so aimock's "weather in Tokyo" substring fixture
still matches.
Also adds the missing d5-voice.test.ts companion (every other d5-* probe
script has one) and trims the langgraph-python qa/voice.md + e2e steps
that depended on the now-removed async behavior.
## Summary
Brings the docs→dashboard sign-up funnel to shell-docs and pulls the
threads documentation stack into parity with upstream. Mirrors PRs
[#4592](https://github.com/CopilotKit/CopilotKit/pull/4592) (Wave 1, 30+
placements), [#4642](https://github.com/CopilotKit/CopilotKit/pull/4642)
(rebrand + threads restoration), and follow-up commit `0ada76b9a` (CTAs
on threads pages). Lands in four commits:
1. **Port the `OpsPlatformCTA` component** to
`showcase/shell-docs/src/components/react/ops-platform-cta.tsx` and wire
it into the shared MDX registry.
2. **Place 22 `<OpsPlatformCTA>` instances** across shell-docs MDX pages
with stable surface identifiers that match upstream's, so PostHog click
attribution stays continuous across the docs.copilotkit.ai cutover.
3. **Rebrand "CopilotKit platform" → "Enterprise Intelligence
Platform"** in shell-docs prose, mirroring the docs/ rebrand.
4. **Add useThreads at the canonical reference path** + threads-stack
content parity (see "Threads parity" below).
## Adaptations from upstream
- **Visual tokens** — swapped indigo/purple Tailwind utilities for
`--accent` / `--violet-light` / `--border` / `--text*` CSS variables
already used by the rest of shell-docs.
- **No dark mode** — dropped `dark:` modifiers; shell-docs has no dark
theme yet.
- **No lucide-react** — inlined `ArrowRight`, `Info`, and `Sparkles` as
SVG components.
- **No client-side PostHog** — shell-docs ships server-side PostHog
(middleware) only and has no `posthog-js`. UTM params on the dashboard
URL (`utm_source=docs`, `utm_medium=cta`, `utm_campaign=intelligence`,
`utm_content={surface}`) are the source of truth for click attribution.
- **Inline-style overrides** — `text-decoration: none` on the card/tile
wrappers and explicit `color` on the inline-button text and info-link to
defeat shell-docs's `.reference-content a` rule.
## Placement coverage
22 placements: 18 direct ports of upstream surfaces, 3 path-adjusted,
and 1 structural.
**Direct (18):** `inspector`, `shared-state`, `threads`,
`troubleshooting/event-inspector`; integration quickstarts for `a2a`,
`ag2`, `agent-spec`, `built-in-agent` (overview + quickstart),
`crewai-flows`, `deepagents`; `langgraph/prebuilt-components`; the four
shared snippets (`basics/prebuilt-components`, `premium/headless-ui`,
`premium/observability`, `premium/overview`); the shared
`threads/threads` snippet; the canonical `reference/hooks/useThreads`.
**Path-adjusted (3):** `learn/intelligence-platform` →
`premium/intelligence-platform`; `learn/threads` →
`premium/threads-explained`; `learn/tutorials/multi-conversation-chat` →
`tutorials/multi-conversation-chat`.
**Structural (1):** root `prebuilt-components.mdx` →
`prebuilt-components/index.mdx`.
**Skipped:** `quickstart.mdx` (root, routing shim), `(root)/index.mdx`
(no MDX docs landing), per-framework integration `index.mdx` files (no
FrameworkOverview equivalent),
`reference/v2/components/{CopilotChat,CopilotKit}.mdx` and
`reference/v2/index.mdx` (different layout).
## Routing note
A few placement targets are MDX files that shell-docs doesn't currently
expose at a public URL — they're orphans pending a registered framework
slug. Specifically: `agent-spec/quickstart.mdx`,
`deepagents/quickstart.mdx`, `a2a/quickstart.mdx`. Mirroring the
upstream placement here is defensive; tracked as part of the broader IA
gap work in PDX-84.
## Rebrand sweep
11 files updated, 50 occurrences collapsed into the canonical name.
Patterns: `CopilotKit platform` → `Enterprise Intelligence Platform`;
`CopilotKit Intelligence Platform` → `Enterprise Intelligence Platform`;
`Intelligence Platform` (standalone) → `Enterprise Intelligence
Platform`. Also fixes two `a Enterprise` → `an Enterprise` article
typos. URL slugs (`/learn/intelligence-platform`,
`/premium/intelligence-platform`) intentionally untouched.
## Threads parity
The previous version of shell-docs had `useThreads.mdx` at
`src/content/docs/reference/v2/hooks/useThreads.mdx`, but the canonical
reference renderer reads from `src/content/reference/`, not
`src/content/docs/reference/`. Result: `/reference/hooks/useThreads`
404'd while upstream's docs had a working useThreads page for weeks.
This PR moves useThreads to the canonical path so it resolves, and pulls
the rest of the threads stack into content parity with upstream:
- `OpsPlatformCTA` added to the reference page's component map so hook
reference pages can host sign-up CTAs (used here on useThreads itself).
- useThreads recreated at `src/content/reference/hooks/useThreads.mdx`.
Drops the `<ThreadsEarlyAccess>` wrapper (canonical reference dir
doesn't use it — threads is GA) and the `doc_type` frontmatter field
(canonical hooks use plain `title` + `description` only). Keeps the
local `lastRunAt` PropertyReference (deliberately preserved per commit
`9f18b50f0`) and the new CTA placement.
- Cross-links to useThreads in `threads.mdx` and the shared snippet
repointed at `/reference/hooks/useThreads` (canonical) instead of
`/reference/v2/hooks/useThreads` (404).
- Prerequisite version bumped from `@copilotkit/react-core v1.50+` to
`v1.56+` in `threads.mdx` and the shared snippet, matching upstream.
Page-structure differences from upstream are preserved per shell-docs
IA: `learn/threads` stays `premium/threads-explained`,
`learn/intelligence-platform` stays `premium/intelligence-platform`,
`learn/tutorials/...` stays `tutorials/...`.
## Test plan
- [ ] `/inspector`, `/threads`, `/shared-state`,
`/troubleshooting/event-inspector` render the inline CTA above the page
content
- [ ] `/built-in-agent`, `/built-in-agent/quickstart`,
`/ag2/quickstart`, `/crewai-crews/quickstart` render the card CTA above
the prerequisites/video, with no underlines on the title/body and white
button text on the violet button
- [ ] `/langgraph-python/prebuilt-components` renders the inline CTA
above the IframeSwitcher
- [ ] `/premium/intelligence-platform` and `/premium/threads-explained`
render their CTAs between the intro paragraph and the first concept
section
- [ ] `/tutorials/multi-conversation-chat` renders its CTA inside the
early-access wrapper
- [ ] `/prebuilt-components` renders the inline CTA above "Pre-built
components for agentic chat"
- [ ] `/reference/hooks/useThreads` resolves (no 404) and renders the
card CTA above "## Overview", with the `lastRunAt` PropertyReference
still present in the Return Value section
- [ ] CTA buttons all link to
`dashboard.operations.copilotkit.ai/?utm_source=docs&utm_medium=cta&utm_campaign=intelligence&utm_content={surface}`
with the correct surface ID
- [ ] Pages that mention the platform brand consistently say "Enterprise
Intelligence Platform" — no remaining "CopilotKit platform" /
"CopilotKit Intelligence Platform" / bare "Intelligence Platform"
- [ ] `/threads` "Next steps" → "API reference" link goes to the working
`/reference/hooks/useThreads` (not the 404
`/reference/v2/hooks/useThreads`)
The dashboard image was being built with only `OPS_BASE_URL` set; the
two other compile-time env vars used by the matrix view stayed unset:
- NEXT_PUBLIC_POCKETBASE_URL — left at the dev fallback in production
builds, which surfaces a "FATAL-CONFIG: NEXT_PUBLIC_POCKETBASE_URL
was unset at build time" banner in the browser console and causes
the matrix's PB SSE subscription to fail (no live updates).
- NEXT_PUBLIC_SHELL_URL — left unset, so every Demo / Code link in
the matrix renders as `about:blank#shell-url-missing`.
Pin both at build time:
- POCKETBASE_URL → http://localhost:8090 (host port the user's browser
reaches; container-internal `pocketbase:8090` is unresolvable from
outside the compose network).
- SHELL_URL → http://localhost:3100 (langgraph-python integration
host port; no shared "shell" service in the local stack).
PocketBase 0.22's email validator rejects `admin@localhost` (single-
label TLD) with `validation_is_email: Must be a valid email address`,
breaking PB auth from the harness CLI on a fresh local stack —
`pb-write-failed` / `pb-auth failed: 400` on every --live run.
Switch the hardcoded local creds to `admin@localhost.dev`. The
matching superuser must be created with the running server's data
directory pinned: `pocketbase admin create admin@localhost.dev
showcase-local-dev --dir=/pb_data` (the create command's default
`./pb_data` differs from the server's `--dir=/pb_data`, so the record
otherwise lands in a different SQLite file and the running server
can't see it).
`buildSmokeInputs` was passing `name: manifest.name` (the display name,
e.g. "LangGraph (Python)") which the liveness driver's `deriveSlug`
stripped of a leading `showcase-` prefix and used as the slug —
producing rows like `health:LangGraph (Python)` and
`agent:LangGraph (Python)` that didn't join with anything else on the
dashboard's depth ladder.
Production discovery sets `name` to the Railway service name
(`showcase-<slug>`), which strips cleanly to the slug. Mirror that
shape from the local CLI so all rows for a service share the same
keyspace and the dashboard cell can advance past D0.
The CLI's runner.ts created a `pbWriter` when --live was passed but
never plumbed it into `ctx.writer`, so every per-feature side row from
every driver (e2e-deep's `d5:<slug>/<featureType>`, liveness's
`health:<slug>` / `agent:<slug>`, etc.) was silently dropped. Only
the aggregate primary results made it to PocketBase, which is why the
dashboard matrix showed every cell as D0 even after a successful
--live probe run.
Now `ctx.writer = pbWriter` when --live is on; without --live the
field is omitted, matching the legacy "no side emission" behavior.
Promotes /demos/headless-complete to its own D5 feature type so the
dashboard cell can reach D5 instead of riding on the headless-simple
probe (which was navigating to /demos/headless-simple regardless of
which catalog feature triggered it).
- New gen-ui-headless-complete D5 feature type + script that clicks
each suggestion chip via preFill and asserts the right surface
renders: WeatherCard (get_weather), StockCard (get_stock_price),
HighlightNote (frontend useComponent), Excalidraw best-effort, and
the canonical "Asia is the largest continent" text reply.
- Existing gen-ui-headless script now drives both turns by chip
click (Profile card + Largest continent) instead of typing.
- Fixtures pin narration legs with both userMessage AND toolCallId
and order them before the bare userMessage toolCall fixture —
aimock's toolCallId matcher reads the LAST tool message in the
request, but in a multi-turn probe that "last tool" stays on a
previous turn's id until a new tool runs, which would otherwise
hijack a later turn's prompt with a stale narration.
- headless-complete UserBubble + AssistantBubble now carry
data-message-role so the harness conversation runner can detect
message arrivals (mirrors the headless-simple convention).
- Mappings updated in lockstep:
- REGISTRY_TO_D5: headless-complete -> ["gen-ui-headless-complete"]
- CATALOG_TO_D5_KEY (dashboard): same.
Builds on the initial Search Flights-only probe by extending to a
multi-turn ConversationTurn[] that asserts surface-specific render
fingerprints for 7 of the 9 pills in /demos/beautiful-chat.
Pills covered (turn order is load-bearing — see script jsdoc):
1. Toggle Theme — html.dark class flip (toggleTheme frontend tool)
2. Pie Chart — >= 3 svg circles (pieChart useComponent)
3. Bar Chart — recharts container + >= 2 bar rectangles
4. Search Flights — A2UI FlightCard literal fingerprints (#4668 path)
5. Schedule Meeting — MeetingTimePicker mounts; assertion CLICKS a slot
to resolve the HITL pause before subsequent turns
6. Sales Dashboard — A2UI dynamic generate_a2ui → secondary render_a2ui;
"Total Revenue" + recharts container (90s budget)
7. Task Manager — enableAppMode + manage_todos; "To Do" column +
canonical todo title visible. MUST be last
(flips layout, breaks chat input on narrow widths)
Pills intentionally skipped (track in follow-up):
- Excalidraw Diagram — depends on mcp.excalidraw.com reachability,
turning D5 reliability into a 3rd-party uptime bet
- Calculator App — sandboxed iframe makes assertions cross-frame-fragile;
generateSandboxedUi already covered by d5-gen-ui-open
on a different demo route (would duplicate coverage)
Probe uses the runner's structural ConversationPage type for most assertions
(via page.evaluate helpers in the d5-chat-css globalThis-cast pattern, which
keeps the harness's Node-only tsconfig clean of DOM lib types). Schedule
Meeting narrows to an extended Page type with click() — same runtime-guarded
cast used in d5-hitl-text-input — so it can dispatch the HITL slot click.
Fixture file expanded from 2 to 15 entries covering all 7 turns plus their
multi-stage chains (Sales Dashboard primary + secondary LLM + post-tool;
Task Manager enableAppMode → manage_todos → narration). Re-bundled into
showcase/aimock/d5-all.json (additions only — no other fixtures changed).
Conversation runner reports failure_turn so per-pill failure isolation is
preserved on the dashboard's drilldown without needing 7 separate D5 literals.
Beautiful Chat was capped at D4 in the dashboard because it had no
dedicated D5 probe and was deliberately excluded from CATALOG_TO_D5_KEY
(commit 974494ecb stripped the freeloading "agentic-chat" alias). PR
#4668 fixed the A2UI surface rendering and added e2e tests, but those
land at the D3 tier — D5 is a separate probe with its own driver.
Changes:
- New d5-beautiful-chat probe asserts the A2UI fixed-schema FlightCard
surface renders with literal United/Delta/$349/$289 fingerprints from
the search_flights tool. 60s budget on first card, 5s on siblings.
- New harness/fixtures/d5/beautiful-chat.json with two-stage fixture
(hasToolResult false→true) mirroring the gen-ui-headless pattern.
Fixture spliced into the bundled aimock/d5-all.json.
- New "beautiful-chat" D5FeatureType literal in the registry's union +
runtime mirror.
- d5-feature-mapping.ts: replace "beautiful-chat": ["agentic-chat"]
alias with ["beautiful-chat"] so the probe targets its own dedicated
PB key instead of freeloading agentic-chat's green status.
- live-status.ts CATALOG_TO_D5_KEY: re-add "beautiful-chat":
["beautiful-chat"] so computeMaxPossible lifts the D4 cap to D5.
Three CTA `body` strings rendered "publicLicenseKey" as plain prose,
which reads as code (camelCase identifier) where the surrounding
sentence is conversational. Switches to "public license key" — the
phrase, not the prop name. Code samples and reference docs that
reference the actual `publicLicenseKey` prop are unchanged.
The useThreads page existed in shell-docs at
\`src/content/docs/reference/v2/hooks/useThreads.mdx\` but that tree
isn't routed — the canonical reference renderer reads from
\`src/content/reference/\`, not \`src/content/docs/reference/\`. As a
result \`/reference/hooks/useThreads\` 404'd while the upstream docs
have had a working useThreads page for weeks.
Moves the page to the canonical location so it resolves at
\`/reference/hooks/useThreads\`, and pulls the rest of the threads
content stack into parity with upstream:
- Add \`OpsPlatformCTA\` to the reference renderer's component map so
hook reference pages can host sign-up CTAs (used here on useThreads
itself).
- Recreate useThreads at the canonical path. Drops the
\`<ThreadsEarlyAccess>\` wrapper (canonical reference dir doesn't use
it — threads is GA, no banner) and the \`doc_type: reference\`
frontmatter field (canonical hooks use plain title + description).
Keeps the local additions: \`<OpsPlatformCTA>\` placement and the
\`lastRunAt\` PropertyReference (deliberately kept per commit
9f18b50f0).
- Fix cross-links to useThreads in threads.mdx and the shared snippet
to point at the canonical \`/reference/hooks/useThreads\` instead of
the broken \`/reference/v2/hooks/useThreads\`.
- Bump the prerequisite from \`@copilotkit/react-core v1.50+\` to
\`v1.56+\` in threads.mdx and the shared snippet to match upstream.
Out of scope: the broader \`/reference/v2/hooks/\<Name\>\` broken-link
problem across other shell-docs pages (useFrontendTool, useAgent,
etc. — same dirname mismatch but for hooks unrelated to this PR).
That's tracked under PDX-103 / PDX-84.
Page-structure differences from upstream are preserved per the
shell-docs IA decision to drop the \`learn/\` concept: \`learn/threads\`
stays \`premium/threads-explained\`, \`learn/intelligence-platform\`
stays \`premium/intelligence-platform\`, \`learn/tutorials/...\` stays
\`tutorials/...\`.
Mirrors the placements upstream docs/ shipped in PR #4592 (Wave 1) and
PR #4642 (Wave 2 — restored threads pages). 22 placements total: 18
direct ports of upstream surfaces, 3 path-adjusted (learn/* → premium/*
or tutorials/*), and 1 structural (root prebuilt-components → its
shell-docs directory index). Surface identifiers match upstream so
PostHog `try_for_free_clicked` events can be reasoned about across
the cutover.
Skipped:
- `quickstart.mdx` (root) — routing shim, no real content
- `(root)/index.mdx` — shell-docs has no MDX docs landing
- Per-framework integration `index.mdx` files — shell-docs has no
per-framework overview pages, the upstream FrameworkOverview
afterFeatures slot has no equivalent
- `reference/v2/components/{CopilotChat,CopilotKit}.mdx` and
`reference/v2/index.mdx` — shell-docs reference layout differs
PDX-110.
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.
## Summary
Adds hand-rolled persistent suggestion chips to the `headless-simple`
and `headless-complete` demos in the langgraph-python north-star,
propagates the same surface to the other 17 showcase integrations, and
adds a deterministic aimock fixture so a new chip-click e2e test
("Largest continent") rounds-trips against a stable `Asia is the largest
continent…` response across all 18 demos.
## What changed
**Phase 0 — north-star (commit `7cbc5ea8`)**
- `showcase/aimock/feature-parity.json` — new fixture: `What is the
largest continent?` → `Asia is the largest continent — about 30% of
Earth's land area, home to over 4.6 billion people.`
- `langgraph-python/src/app/demos/headless-{simple,complete}/page.tsx` —
refactor `send` / `handleSubmit` to accept `(override?: string)` so chip
clicks dispatch synchronously without a `setInput` round-trip; render a
persistent `<div data-testid="headless-suggestions">` chip row above the
composer with 5 canonical entries; remove the dead
`useConfigureSuggestions` call from headless-complete (it was
registering suggestions nothing rendered).
- `langgraph-python/tests/e2e/headless-{simple,complete}.spec.ts` —
append one new test in each spec asserting chip click → user message →
`Asia` reply.
**Phase 1 — parity propagation across 17 integrations (commit
`4882c61f`)**
- Spec files `headless-simple.spec.ts` and `headless-complete.spec.ts`
are now byte-identical to the north-star in every integration (10 tests
each = 5 simple + 5 complete; verified via `cmp` for all 34 spec files).
- The 5-entry `suggestions` const is byte-identical between every
integration's simple and complete demos.
- All 17 integrations now expose the same selector surface (canonical
headings, empty-state text, `data-testid="headless-complete-messages"`,
dynamic placeholder, `rounded-br-sm` user bubble, no CopilotChat-default
testids).
**Glue preserved per integration** (verified by post-blitz code review):
- `built-in-agent`: `<CopilotKitProvider runtimeUrl="/api/copilotkit"
useSingleEndpoint>` + `agentId: "default"`
- `google-adk` / `llamaindex`: `agentId: "headless_simple"` /
`"headless_complete"` (Python-style underscores)
- `claude-sdk-typescript`: headless-complete
`runtimeUrl="/api/copilotkit-headless-complete"`
- `spring-ai`: 70-line `deduplicateMessages` adapter workaround +
`useMemo` import preserved verbatim
- All `@region[...]` markers preserved in place
**Adapter-specific decisions worth flagging in review:**
- `google-adk` headless-complete: rewrote `message-list.tsx` from
`msg-user`/`msg-assistant`/`agent-thinking` testid scheme to the
canonical `headless-complete-messages` wrapper; rewrote `input-bar.tsx`
placeholder to canonical dynamic; added the missing subtitle and
empty-state hint
- `ms-agent-dotnet`: extracted inline composer to a new `input-bar.tsx`
to match north-star structure
- `llamaindex`, `ms-agent-python`: added the canonical empty-state hint
(was missing entirely)
- `agno`, `built-in-agent`, `crewai-crews`, `mastra`, `ms-agent-dotnet`,
`pydantic-ai`: replaced per-integration empty-state hint with the
canonical Excalidraw line — chosen for parity over per-integration
accuracy (some demos don't actually wire an Excalidraw tool; alignment
was the explicit goal)
## Verification
- `validate-parity.ts`: 18/18 packages pass, 0 MUST failures
- `aimock-fixtures` test suite: 18/18 pass
- aimock fixture probed directly: `What is the largest continent?`
returns the canonical Asia response
- Each propagation slot reported `tsc --noEmit` clean (0 new errors) +
`playwright --list` shows all 10 expected tests
- Code review (`pr-review-toolkit:code-reviewer`) on the full diff: 0
Critical / Important / Minor findings, 1 stylistic nit (north-star
`input-bar.tsx` `onSubmit` type contravariant-loose, harmless)
## What was NOT done
Live per-integration Playwright runs against rebuilt Docker images. The
17 containers would each need a no-cache rebuild (~5-15 min each = hours
total) and the canonical local-test path is `showcase test <slug>` per
the existing CLI / CI pipeline. Static + structural verification covers
the propagation pattern.
## Test plan
- [ ] Run `showcase test <slug>` (or equivalent CI job) for at least one
drift-heavy integration: `google-adk` (testid scheme rewrite),
`built-in-agent` (provider glue), `spring-ai` (dedup workaround),
`llamaindex` (added testid + empty-state)
- [ ] Run the existing per-integration Playwright suites for at least
the north-star (`langgraph-python`) to confirm the new chip test passes
against a real backend + aimock
- [ ] Confirm aimock fixture validation still passes after deploy
The validate-fixture-tool-surface check on PR #4669 flagged 18 drift
violations: every headless-simple demo carried 'Weather in Tokyo' /
'AAPL stock price' / 'Highlight a note' / 'Sketch a diagram' chips
that substring-match aimock fixtures returning tool calls
(get_weather / get_stock_price / highlight_note / etc.) — but
headless-simple demos only register 'show_card' via useComponent.
Tool-call dispatch had no matching renderer.
Trim the headless-simple chip list to two in-surface entries:
- 'Profile card' → 'Show me a profile card for Ada Lovelace' (existing
show_card fixture; show_card is already registered by useComponent).
- 'Largest continent' → 'What is the largest continent?' (text-only
fixture from Phase 0; no tool dependency).
The chip-click e2e test only asserts on the 'Largest continent' chip,
so the trim is test-compatible.
Headless-complete keeps the canonical 5-chip list (its tool surface
covers weather/stock/highlight/excalidraw via tool-renderers.tsx and
backend agents).
For google-adk/headless-complete: add a useDefaultRenderTool() wildcard
catch-all. The validator looks at page.tsx + hooks/* and a backend
agent file; google-adk's tool registrations live in tool-renderers.tsx
(unparsed) and there's no matching agents/headless_complete.py file,
so the validator saw an empty tool surface. The wildcard registers '*'
which matches every fixture tool — same pattern north-star already
uses in its own tool-renderers.tsx.
Follow-up to #4664 — same root cause, two more callsites and one
inflation.
## Two issues
### 1. Live cell + Ref Depth column still rendered red
`composed-cell.tsx`, `feature-grid.tsx` (via `ref-depth-column.tsx`) had
the same regression-vs-ceiling collision the matrix views did: they
passed `regression={depth.isRegression}` to `DepthChip`, and
`regression` short-circuits the chip to red regardless of `maxDepth`.
Switched them to pass `maxDepth={depth.maxPossible}` only.
`RefDepthCellProps.regression?` flips to `maxDepth?` to stop propagating
the dead prop.
### 2. `maxPossible` was inflated to 6
`computeMaxPossible` returned **6** whenever a D5 mapping existed, on
the assumption D6 was structurally reachable. There is no per-feature D6
registry, so D6 is a stretch goal in practice — every D5 cell rendered
amber as "1 below ceiling," even when it was the realistic ceiling. Cap
at 5; D6-green cells still render green because `depthColorClass` treats
`depth >= maxDepth` as at-ceiling.
This restores the cap from commit `eda75a512` (*"D5 mapping means max=5
not 6 (D6 probes are rare)"*) which was lost in the subsequent depth
thrash.
`page.tsx` `healthStats` also dropped its `isRegression` short-circuit
so the stats bar mirrors the chip's graduated logic instead of
double-counting non-ceiling cells as red.
## Verified locally
Pointed dev dashboard at production PocketBase + harness:
- Before: 539 D5 cells **amber**, 162 D4 green
- After: **701 green**, 0 amber, 0 red
## Test plan
- [x] `depth-utils`, `depth-chip`, `parity-matrix`, `cell-matrix`,
`composed-cell`, `feature-grid` test files — 115/115 passing
- [x] Visual check on local dashboard against prod data — all wired
cells now render green
- [ ] On deploy, confirm matrix view at
`dashboard.showcase.copilotkit.ai/#matrix:depth,health` matches local
## Summary
Search Flights and Sales Dashboard pills on the langgraph-python
beautiful-chat demo now produce visible A2UI surfaces. Three independent
bugs were masking each other:
- **Tool args were silently rejected.** `Flight` TypedDict required `id`
+ `statusIcon`, which the aimock fixture doesn't supply. langchain
bounced the call with `flights.0.id: Field required` and the agent
surfaced the validation error string as the "tool result" — so the LLM
summarized "Two flights shown above" without any cards ever rendering.
Made `Flight` permissive (`total=False` then `list[dict]`); only the
fields `_build_flight_components` reads need to be there.
- **`search_flights` now expands flights into literal-children
FlightCards server-side.** The structural-children template form
(`Row.children = { componentId, path }`) doesn't reliably expand for our
custom catalog — the working sibling demo (`a2ui-fixed-schema`) avoids
the form for the same reason.
- **Sales Dashboard pill went into a tool-call loop** because the
`userMessage + toolName` fixtures matched both the initial call and the
post-tool turn. Hoisted the `toolCallId` fixture above them so the
follow-up turn returns content and breaks the loop. Three new fixtures
at the top of `feature-parity.json`: a follow-up content match, the
secondary-LLM `render_a2ui` call, and the primary `generate_a2ui` call.
Reintroduced custom `Row`/`Column` renderers with `gap` support — the
basic catalog versions ignore it and the dashboard cards were squished.
Children are array-of-strings only (matches what the agent and fixture
emit).
## Test plan
- [x] All 7 tests in
`showcase/integrations/langgraph-python/tests/e2e/beautiful-chat.spec.ts`
pass (45s). Two new ones cover both pills end-to-end: `Search Flights
pill renders FlightCard surface from A2UI fixed schema` and `Sales
Dashboard pill renders A2UI dashboard surface`.
- [x] `pnpm test aimock-fixtures` passes (18/18) — fixture schema
validator is happy with the 3 new entries.
- [x] Manual visual confirmation: both pills render full surfaces with
proper card spacing.
- [x] No regression on existing `Toggle Theme` / `Pie Chart` / `Bar
Chart` pills.
## Notes
- Added a 3-second `waitForTimeout` to the spec's `beforeEach` so the v2
chat provider hydrates before suggestion clicks dispatch. Without it,
the click can race past hydration and silently no-op (the existing
pre-existing tests happened to be tolerant of this; the A2UI ones
aren't).
- System prompt cleaned up: dropped references to tools that don't exist
(`log_a2ui_event`, "enable app mode") and named `pieChart`/`barChart`
explicitly.
Search Flights and Sales Dashboard pills both produce visible surfaces
on the langgraph-python beautiful-chat demo. Three independent bugs were
masking each other:
- Flight TypedDict required `id` + `statusIcon`, which the aimock fixture
doesn't supply. langchain rejected the call with `flights.0.id: Field
required` and the agent surfaced the error string as the tool result.
Made the type permissive (only the fields `_build_flight_components`
reads need to be there).
- search_flights now expands flights into literal-children FlightCard
components server-side instead of relying on the structural-children
template form (the binder doesn't reliably expand it for our custom
catalog — sibling demos avoid the form for the same reason).
- Sales Dashboard pill went into a tool-call loop because the
userMessage+toolName fixtures matched both the initial call and the
post-tool turn. Hoisted the toolCallId fixture above them so the
follow-up turn returns content and breaks the loop.
Custom Row/Column reintroduced with `gap` support — the basic catalog's
versions ignore it, leaving cards squished. Children are array-of-strings
only (matches what the agent and fixture emit).
Two new e2e tests cover both pills end-to-end. 3s wait in beforeEach so
the v2 chat provider hydrates before the click dispatches. Full spec:
7/7 green.
Two follow-ups to the parity/cell-matrix fix:
1. The live cell view (`composed-cell.tsx`, `feature-grid.tsx` →
`ref-depth-column.tsx`) had the same regression-vs-ceiling collision —
they passed `regression={isRegression}` to DepthChip and `regression`
short-circuits the chip to red regardless of `maxDepth`. Switched
them to pass `maxDepth={maxPossible}` only, mirroring the matrix fix.
`RefDepthCellProps` also flips `regression?` → `maxDepth?` to stop
propagating the dead prop.
2. `computeMaxPossible` returned 6 whenever a D5 mapping existed, on the
assumption D6 was structurally reachable. There is no per-feature D6
registry, so D6 is a stretch goal in practice and every D5 cell was
rendered amber as "below ceiling". Cap at 5; D6-green cells still
render green because `depthColorClass` treats `depth >= maxDepth`
as at-ceiling. Tests updated accordingly.
`page.tsx` healthStats lost its `isRegression` short-circuit so it now
mirrors the same graduated logic the chips use.
Apply the same @langchain/core 1.1.44 and @langchain/langgraph 1.3.0 bumps
to the showcase copy that the Dojo received in the prior commits, so
validate-pins no longer flags drift between the two. Also pin
langgraph-cli@1.2.1 in the dev scripts here for the same reason as the Dojo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
Three logically-distinct commits landing on the legacy `docs/` site:
1. **Restore the Threads + Intelligence Platform docs** — reverts the
removal in commit `b08da7970`. Brings back the Threads management
surface (`useThreads` hook, multi-conversation tutorial, per-integration
Threads how-tos, the shared snippet) and the Intelligence Platform /
self-hosting pages, with sidebar entries.
2. **Drop the early-access password gate on threads pages** — removes
the `<ThreadsEarlyAccess>` wrapper from the five MDX entry points,
deletes the now-unused component, and unwires the MDX-registry entries
in the home and integrations route handlers. Threads is GA, no
client-side gate needed.
3. **Rebrand to "Enterprise Intelligence Platform"** — collapses the
three legacy phrasings (`CopilotKit platform`, `CopilotKit Intelligence
Platform`, `Intelligence Platform`) into one canonical name across
prose, CTA copy, frontmatter descriptions, and the Learn landing card.
## Scope notes
- URL slugs (`/learn/intelligence-platform`,
`/premium/intelligence-platform`) are intentionally unchanged —
text-only rename.
- The CTA component button label (`Get Intelligence free`) is unchanged.
- Existing typo "an CopilotKit platform" naturally resolves to
grammatically-correct "an Enterprise Intelligence Platform".
- `docs/public/llms-full.txt` is a generated artifact and is left alone
— it'll regenerate on the next build.
- This PR touches `docs/` only. The new `showcase/shell-docs/` site has
its own copy of these phrases that we'll handle separately.
## Test plan
- [ ] `/threads` renders without the password splash
- [ ] `/learn/threads`, `/reference/v2/hooks/useThreads`,
`/learn/tutorials/multi-conversation-chat`, and the per-integration
`/<framework>/threads` pages all render without the gate
- [ ] `/learn/intelligence-platform` and `/premium/self-hosting` pages
render with the new brand name
- [ ] Sidebars on root, learn, reference/v2/hooks, and the 12
integration sections show their restored entries
- [ ] CTA cards on the home page, quickstart, prebuilt-components,
shared-state, and integration overview pages show "Enterprise
Intelligence Platform" copy
- [ ] CTA button still says "Get Intelligence free" and routes to
dashboard with `try_for_free_clicked` PostHog event
The matrix chips were hard-coded red at D5 because parity-matrix and
cell-matrix passed `regression={depth.isRegression}` to DepthChip but
never `maxDepth`. DepthChip short-circuits to red when `regression` is
true, regardless of depth. Since `isRegression` was redefined as
`achieved < maxPossible` and `computeMaxPossible` returns 6 whenever a
D5 mapping exists, every D5 cell without a green D6 probe (the common
case — D6 probes are rare) ended up red.
Pass `maxDepth={depth.maxPossible}` and drop the `regression` prop. This
re-engages the chip's intended graduated coloring: green at ceiling,
amber 1-2 below, red 3+ below. The `isRegression` field is still used
by the cell-matrix `filter="regressions"` row filter — that's unchanged.
## Summary
- Two object literals in
`showcase/shell-dashboard/src/components/parity-matrix.tsx`
(`ParityCategorySection`) were missing the required `maxPossible` field
on `DepthResult`, causing `next build` to fail with TS2322 on every
shell-dashboard production build.
- This blocked rebuilding the deployed showcase shell-dashboard, which
currently ships with `NEXT_PUBLIC_SHELL_URL` unset — every Demo button
on the dashboard renders as
`about:blank#shell-url-missing/integrations/<slug>/<feature>/preview`
instead of the actual preview URL.
- Setting `maxPossible: 0` alongside `achieved: 0` for unwired cells is
the natural fallback (no probe → no ceiling) and matches how `DepthChip`
already renders an unshipped cell.
## Background
The fix is cherry-picked from commit `1db2fbc7b` on the
`fix/dashboard-polish` branch (Jordan Ritter) — that branch also has 8
other commits (D5 depth model rework, ops→harness rename) which together
form a larger polish pass that hasn't been opened as a PR yet. Landing
this 2-line slice standalone unblocks the showcase deploy without
waiting on review of the larger branch.
Once this lands, re-running `gh workflow run showcase_build.yml --ref
main -f service=shell-dashboard` will produce a working production image
with `NEXT_PUBLIC_SHELL_URL=https://showcase.copilotkit.ai` baked in.
## Test plan
- [ ] CI typecheck passes (was previously failing here)
- [ ] CI build of showcase-shell-dashboard image succeeds
- [ ] After merge: trigger \`showcase_build.yml\` for
\`shell-dashboard\` and verify deployed dashboard's Demo links resolve
to \`https://showcase.copilotkit.ai/integrations/...\` instead of the
\`about:blank#shell-url-missing\` sentinel
## Summary
Cleans up shell-docs after PR #4521 reintroduced content earlier PRs
intentionally retired, adds a Deploy section with an inlined AWS
AgentCore guide using a custom command-tabs component, and hardens the
sync script against future regressions of the same shape.
## Changes
### Deploy section + AgentCore page (custom UX)
- New `<AgentCoreCommandTabs />` component — framework-aware command
tabs with hljs highlighting and copy buttons, built on shell-docs's own
`<Tabs>`/`<Tab>` primitives. Upstream's version depends on fumadocs-ui,
which shell-docs doesn't install.
- Replaces main's `<Content />` stub at `/deploy/agentcore` with the
full inlined guide.
- Wires the Deploy section into the root sidebar via `deploy/meta.json`
+ a `---Deploy---` group in `meta.json`.
- Registers the component in `mdx-registry.tsx`.
### Remove duplicates reintroduced by the upstream sync
- Delete
`learn/{index,intelligence-platform,threads,tutorials/multi-conversation-chat}.mdx`.
Canonical homes are at `/premium/intelligence-platform`,
`/premium/threads-explained`, and `/tutorials/multi-conversation-chat`.
`next.config.ts` already redirects `/learn/*` to those destinations.
- Delete root `ag-ui-middleware.mdx`. Canonical home is
`/agentic-protocols/ag-ui-middleware`. `next.config.ts` already
redirects `/ag-ui-middleware`.
### Harden sync script
Add `PATH_EXCLUSIONS` regexes so next sync runs don't bring these paths
back:
- `docs/content/docs/learn/`
- `docs/content/docs/(root)/ag-ui-middleware.mdx`
- Orphan shared-state files:
`langgraph/shared-state/workflow-execution`,
`adk/shared-state/{workflow-execution,state-inputs-outputs}`,
`llamaindex/shared-state/state-inputs-outputs`
- AgentCore upstream sources (root shell, per-framework
`deploy-agentcore.mdx`, shared snippet) — shell-docs owns the canonical
inlined version
### Optional schema migrations Step
Adds an opt-in `(Optional) Enable schema migrations` Step to
`premium/self-hosting.mdx` covering `migrations.enabled: true` in the
Helm values + the verification behavior.
## Test plan
- [ ] `/deploy/agentcore` renders the inlined guide; both
`<AgentCoreCommandTabs />` blocks show framework tabs with highlighted
bash and a working copy button
- [ ] Deploy appears as a sidebar group between Premium and What's New
- [ ] `/learn/threads`, `/learn/intelligence-platform`,
`/learn/tutorials/multi-conversation-chat`, and `/learn` all redirect to
their canonical destinations (no longer 200 with duplicate content)
- [ ] `/ag-ui-middleware` redirects to
`/agentic-protocols/ag-ui-middleware`
- [ ] The optional schema migrations Step renders in
`/premium/self-hosting` between the secrets Step and the
install-the-chart Step
- [ ] Next dry-run of `sync-docs-from-main.ts` does not flag the
newly-excluded paths
Two object literals in parity-matrix.tsx ParityCategorySection were missing
the required maxPossible field on DepthResult, causing 'next build' to fail
with TS2322 and blocking the shell-dashboard production rebuild. Setting
maxPossible: 0 matches achieved: 0 for unwired cells (no probe → no ceiling),
which is consistent with how DepthChip renders an unshipped cell.
Cherry-picked from 1db2fbc7b on fix/dashboard-polish (Jordan Ritter); landing
standalone so the showcase deploy can rebuild from main without waiting on
the larger dashboard-polish branch.
PATH_EXCLUSIONS is the durable mechanism for keeping retired upstream
paths out of shell-docs, but it requires the person retiring a page to
also add the regex — and that step has been missed (#4521 brought back
/learn/* and root /ag-ui-middleware.mdx after earlier PRs intentionally
removed them).
Add a safety net: before writing each upstream file, check if its target
shell-docs path exists in git's deletion history and isn't currently on
disk. If so, surface it in the auto-PR's review-items.txt under a new
'Files re-introduced from shell-docs deletion history' section and
include reintroduced.length in hasReviewItems so the PR is flagged
needs-review (exit 3) instead of auto-merged.
Doesn't block the write — content is still synced, the detector is
informational. The fix loop is: human reviews, decides intent. If
unwanted, add a PATH_EXCLUSIONS regex and delete the file; next sync
the detector picks it up again until the regex is in place.
Verified locally — current dry-run flags 3 real findings (root/index,
langgraph/index, microsoft-agent-framework/index) that were deleted in
favor of meta.json folder pages.
What we learned getting 18 integrations to D5 green — and what was
still wrong even when green. Cross-framework patterns (V1/V2, testids,
runtime hoisting, agent naming, multimodal shims, Pydantic models),
per-framework edge cases for all 15 frameworks, aimock fixture gotchas,
and the 6 things that were "green but wrong."
The Helm chart supports running schema migrations as a pre-install Job
(disabled by default). Document the opt-in path and the verification
behavior so operators can decide whether to enable it.
The previous sync brought back /learn/*, root /ag-ui-middleware.mdx, the
upstream AgentCore 3-shell + shared snippet, and several orphan
shared-state files that shell-docs deliberately doesn't carry. Add
matching PATH_EXCLUSIONS so future syncs don't reintroduce them.
Not bumping .docs-sync-sha — the previous sync's sha is still accurate
and the new exclusions take effect on the next run.
These were re-introduced by an upstream docs sync. Canonical homes are
already in shell-docs at /premium/intelligence-platform,
/premium/threads-explained, /tutorials/multi-conversation-chat, and
/agentic-protocols/ag-ui-middleware. next.config.ts already redirects
the retired paths to the canonical destinations.
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
The auto-sync removed the lastRunAt entry from the useThreads API reference,
but the field is still present on the Thread type and drives sort behavior in
packages/core/src/threads.ts. Restoring the doc keeps the API reference
complete.
The --isolate flag was rewritten in PR #4570 to use temp overlay
files instead of mutating originals in place. Add sections to
DEBUGGING.md (how it works, troubleshooting) and RUNBOOK.md
(operational notes for parallel runs and cleanup).