New users were still discovering cloud.copilotkit.ai through docs pages,
the README, example READMEs, and in-app banners/console messages. Replace
all user-facing web links with dashboard.operations.copilotkit.ai (the
destination the marketing-site CTAs already use). Functional API endpoints
(api.cloud.copilotkit.ai) are deliberately untouched since existing cloud
customers depend on them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Northstar AI CRM — a full-featured agentic sales CRM for an enterprise
hardware seller, built with CopilotKit, the AG-UI protocol, and a
TypeScript Strands agent (@strands-agents/sdk + @ag-ui/aws-strands).
The first TypeScript Strands example under examples/.
Highlights:
- Agentic canvas: tool calls render on the workspace — quote approval
opens a quote page; analyze_team and generate_weekly_report open
dedicated report pages; frontend tools navigate the workspace.
- Generative UI cards, human-in-the-loop follow-up approval, and a live
STATE_SNAPSHOT that syncs a SQLite CRM store with the board,
dashboard, and report pages.
- Dashboard, pipeline (Kanban), products, team, and reports surfaces.
Self-contained under examples/showcases/strands-crm with an agent/ +
frontend/ split and a concurrently dev script; listed in
examples/README.md.
## Summary
Makes the `examples/showcases/banking/` SaaS demo customer-ready by
migrating it to **CopilotKit v2** and polishing it into a credible,
reliable reference. Closes the non-memory gaps from FOR-133's assessment
(FOR-138).
- **v2 migration**: v2 Hono runtime route (`BuiltInAgent` +
`createCopilotHonoHandler` + `InMemoryAgentRunner`), `CopilotKit`
provider + `CopilotPopup`, hooks moved to `@copilotkit/react-core/v2`
(`useAgentContext`, `useHumanInTheLoop`, `useComponent`, Zod params), on
`workspace:*` packages.
- **File-backed data store**: domain data in `src/data/seed.json` behind
a typed `src/lib/store.ts` (in-memory, resets to seed on restart). Clean
seam left for the memory track (FOR-137).
- **Credible identity + data**: Northwind Finance / Alex Morgan /
`@northwind.example`, refreshed transaction dates + future card
expiries, `Intl` currency formatting.
- **Dropped** the SQL page + fake-MSA RAG feature (and committed
ServiceNow secret) — focused fintech story.
- **Framework/build**: Next 16 async route `params`, Tailwind v4 (so the
v2 stylesheet imports normally), correct `next`/`react` versions, single
lockfile, accurate v2 README.
- **Tests**: LLM-free Playwright smoke test (also fails on
hydration/uncaught errors).
## Verified live (real OpenAI key)
Full golden path works end-to-end: chat renders → "show transactions for
card 4242" renders the generative-UI list → "add a card" → HITL approval
card → Approve → new card appears in the grid. 0 console errors. Build +
typecheck + smoke test green; no committed secrets.
Three v2 chat-rendering bugs were found and fixed by running it live:
use the full `CopilotKit` provider (not the low-level
`CopilotKitProvider`, which omits `ThreadsProvider`); set
`useSingleEndpoint={false}` to match the multi-endpoint route; and use
`useComponent` with a `deps` array for display-only generative UI
(avoids a stale-closure empty render).
## Non-goals (deliberately out of scope)
- Real auth.
- Conversation threads + long-term/self-learning memory → FOR-137.
- Deleting the duplicate `enterprise-brex` demo + repointing its deploy.
## Test plan
- [ ] `pnpm --filter demo-saas-copilot build` succeeds
- [ ] `pnpm --filter demo-saas-copilot exec tsc --noEmit` clean
- [ ] `pnpm --filter demo-saas-copilot test:e2e` passes
- [ ] With `OPENAI_API_KEY` set: run the golden path (transactions
gen-UI, add-card HITL → approve → grid update)
## Known minor follow-ups
- Removing deprecated `showDevConsole` surfaces the v2 Web Inspector /
announcement banner.
- Newly-added cards get a near-term generated expiry.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The static/quality format job runs in check mode on push and was failing
on main: `ruff format --check .` flagged 5 unformatted Python files under
examples/showcases/a2ui-pdf-analyst/agent (main.py, src/dynamic_agent.py,
src/fixed_agent.py, src/multimodal_middleware.py, src/pdf_tools.py). The
oxfmt JS/TS check already passes, so this is ruff-only drift. Applied
`ruff format` (pinned 0.15.13, matching CI); diff is formatting-only.
Display-only generative UI must use useComponent (not useFrontendTool): its
render is unconditional so the card persists after the tool call completes.
Also pass [transactions, cards] as deps so the renderer re-registers when the
data loads -- otherwise the closure captures the initial empty transactions
and the list renders empty.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The migration mounted the low-level CopilotKitProvider, which omits the
ThreadsProvider that holds the rendered message thread, so the agent ran but
the transcript stayed empty. Use the full CopilotKit provider, and set
useSingleEndpoint={false} to match the multi-endpoint Hono route (the default
single-endpoint transport 404s against it).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- cards PUT handler: stop console.info'ing the request body, which
included the plaintext PIN on every PIN-change request.
- wrapper.tsx: drop the duplicate ./globals.css import (already
imported in app/layout.tsx, which is the canonical place).
- copilot-context.tsx: replace window.location.pathname read during
render with usePathname() from next/navigation, matching how
components/layout.tsx already derives the current route.
- next.config.mjs: remove the eslint.ignoreDuringBuilds block — Next 16
no longer runs ESLint at build, and the key now produces an
"Unrecognized key(s): 'eslint'" warning. Confirmed warning is gone.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
package.json was pinning next@14 / react@18, but the root pnpm.overrides
were already forcing next@16 / react@19 at install time and the code uses
Next 16 async params. Bump the declared ranges to ^16.0.10 / ^19 (and
@types/react{,-dom} to ^19) so the manifest matches reality and matches
the v2 reference demos (mcp-apps, generative-ui-playground).
Also drop examples/showcases/banking/pnpm-lock.yaml: the demo is a
workspace package (listed in root pnpm-workspace.yaml and resolved in the
root pnpm-lock.yaml), so the per-demo lockfile was vestigial v1 cruft
that contradicted the v2 migration.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace v1-era hooks/data references with the actual v2 surface:
useAgentContext / useFrontendTool / useHumanInTheLoop from
@copilotkit/react-core/v2, the Hono runtime route, the seed.json + store
data layer, and the Northwind identity. Drop mentions of removed
SQL/MSA/ServiceNow/RAG features.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove the /Hydration/i pattern from the ignored-console-errors filter so
Next.js hydration mismatches surface as real failures, and add a
page.on("pageerror", ...) listener that records uncaught exceptions and
asserts none occurred. pageerrors are not filtered — any uncaught
exception fails the smoke test.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a CI-safe Playwright smoke test that verifies the banking showcase
boots and the CopilotKit v2 popup opens with its configured suggestion
pills, without invoking the agent (so it runs in CI without secrets).
Covers:
- Document title shows the Northwind Finance brand
- Credit-cards dashboard renders ("Credit Cards" heading)
- CopilotPopup launcher opens the dialog (Northwind Copilot)
- Three suggestion pills render: View transactions, Add a card,
Assign a policy
The dev server gets a dummy OPENAI_API_KEY so the runtime route boots,
but the test never sends a chat message or clicks a suggestion.
.gitignore: ignore test-results/, playwright-report/, and
tsconfig.tsbuildinfo so they don't become clutter.
Banking was on Tailwind v3, which made the pre-compiled v2 stylesheet
(`@copilotkit/react-core/v2/styles.css`, built as Tailwind v4 output)
incompatible with the PostCSS pipeline. A temporary inline-CSS hack in
`layout.tsx` worked around this. Migrate to Tailwind v4 to match the
canonical v2 demos and remove the hack.
- package.json: tailwindcss ^4, add @tailwindcss/postcss ^4, replace
tailwindcss-animate with tw-animate-css (v4 drop-in)
- postcss.config.mjs: switch plugin to @tailwindcss/postcss
- globals.css: use @import "tailwindcss" + @import "tw-animate-css";
add @custom-variant dark for the existing .dark/.light class toggle;
move shadcn color/radius mapping into @theme inline (preserves
bg-background/text-foreground/rounded-{lg,md,sm} semantics)
- tailwind.config.ts: deleted; theme now lives in CSS
- components.json: clear stale tailwind.config reference
- layout.tsx: drop the readFileSync/dangerouslySetInnerHTML inline-CSS
workaround; import "@copilotkit/react-core/v2/styles.css" the normal
way alongside ./globals.css
Verified: tsc clean, next build clean, Playwright-rendered all four
pages (/, /dashboard, /cards, /team) with computed-style checks
(sidebar bg-gray-900 dark, rounded-lg=8px, .border=1px) and opened
the copilot popup which renders fully styled with the v2 stylesheet.
The banking showcase was migrated to CopilotKit v2 but `src/app/layout.tsx`
still imported the removed `@copilotkit/react-ui/styles.css`, causing every
route to 500 with "Module not found". Drop the dead import.
Banking is still on Tailwind v3, while the v2 stylesheet
(`@copilotkit/react-core/v2/styles.css`) is pre-compiled Tailwind v4 output
containing bare `@layer base { ... }` rules. Tailwind v3's PostCSS plugin
rejects `@layer base` without a matching `@tailwind base` directive, so any
CSS import routed through the JS/TSX pipeline fails the build. Move the v2
stylesheet load to a server-side `fs.readFileSync` + inline `<style>` tag in
the root layout so the CSS reaches the browser without passing through
PostCSS / Tailwind v3. This avoids a full Tailwind v4 migration of the app.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace toy team names and @example.com emails with credible
professional names and @northwind.example addresses (preserve ids,
roles, team assignments). Default Admin is Alex Morgan.
- Set <title> metadata to IDENTITY.brand (Northwind Finance).
- Add formatCurrency helper in lib/utils.ts and route all money
rendering (transactions list, credit-card details, dashboard +
cards summary tiles) through it so amounts always render as
$10,000.00 / -$1,000.00.
- Instruct the Northwind Copilot prompt to treat the rendered
showTransactions list as the single source of truth so prose no
longer restates counts/totals and contradicts the rendered list.
- Remove stray console.log and tighten == to === in components/layout.tsx.
Replace the in-memory `data` literal in `api/v1/data.ts` with a
file-seeded, module-singleton store:
- `src/data/seed.json` holds the seed (cards, team, policies,
transactions) with refreshed dates (within ~60 days of 2026-06-02)
and valid future card expiries.
- `src/lib/store.ts` deep-clones the seed at module init and exposes
typed read accessors (cards/team/policies/transactions, findCard,
findPolicy, findTransaction) plus the exact mutator set the routes
use (addCard, updateCardPin, assignPolicyToCard, addPolicy,
updateTransaction, addMember, updateMember, removeMember).
- All `src/app/api/v1/**/route.ts` files now read/write through the
store. `data.ts` retains the shared interfaces/enums/CARD_COLORS/
generateUniqueId and drops the literal `data` constant.
- Mutations persist for the running server process and reset to seed
on restart (intentional demo behavior; no disk write-back).
- Domain-data only — conversation threads/memory live in a separate
ticket (FOR-137).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Switch imports from @copilotkit/react-core to /v2 in layout.tsx and actions.ts
- Replace useCopilotReadable with useAgentContext
- Stringify the credit cards/policies/transactions context value to satisfy
the JsonSerializable type
- Switch imports from @copilotkit/react-core to /v2
- Replace useCopilotReadable with useAgentContext (stringify object value)
- Convert navigateToPageAndPerform parameters array to a Zod object schema
The cookbook's 'Try it live' iframe is 600px tall, but the demo page
included its own h1/subtitle + ~32px main padding + the chat section had
minHeight:520, which pushed total content past 600px and forced a
scrollbar inside the iframe.
The shell-docs cookbook page already provides a header and surrounding
chrome; the demo's own h1 ('CopilotKit x Daytona') and subtitle are
redundant in the embedded context. Drop them and let the chat fill the
iframe viewport exactly:
- Remove the <header> (h1 + subtitle).
- Set <main> to height:100vh, padding:0, margin:0.
- Chat <section> uses flex:1 + minHeight:0 (no fixed minHeight) so it
grows/shrinks to fill the available iframe height.
Side effect: the standalone Railway URL now also shows just the chat
(no h1/subtitle). Fine — the URL is a demo embedding target rather
than a polished standalone landing.
OSS-222
CI's check-config-allowlist failed on the new daytona-runcode showcase.
Rather than just adding an .mjs row, convert to .ts to match the
dominant pattern across examples/showcases/* (the .mjs predates the
Next 14 TS-config support and is only kept in a handful of older
showcases — banking, enterprise-brex, orca, presentation). New
showcases should follow the .ts convention.
- Replace examples/showcases/daytona-runcode/next.config.mjs with an
equivalent next.config.ts (empty config, same behavior).
- Add the new path to .github/config-allowlist.txt in alphabetical
position (between chatkit-studio/.../world and deep-agents-finance-erp).
- Verified locally: bash .github/scripts/check-config-allowlist.sh passes.
OSS-222
Addresses PR #5087 review comment from @tylerslaton:
> Remove the blue padding around the chat, change the header to
> 'CopilotKit x Daytona'
- Drop the linear-gradient(160deg,#f8fafc,#eef2ff) background from
<main>. The chat's own white card now stands on the default page
background — no surrounding tint.
- Change the h1 from 'CopilotKit × Daytona' (× = U+00D7
multiplication sign) to literal 'CopilotKit x Daytona' (ASCII x), per
Tyler's literal request.
Mirrored byte-for-byte from the Railway demo source.
OSS-222
Reviewer asked to emphasize the runCode tool more, so:
- Replace CopilotSidebar with a centered CopilotChat (the chat is now the
focal point of the page rather than a docked side panel).
- Increase the renderer's code pane to ~12 lines (was ~6) so multi-line
generated code is visible without scrolling.
- Add 'Generated code:' label above the code pane to match the 'Result:'
label below.
- Configure starter suggestion pills via useConfigureSuggestions with
descriptive titles ('Python — Zoo animals', 'TypeScript — Fibonacci
numbers', 'JavaScript — Current timestamp') and available: 'always' so
they persist across iterations rather than disappearing after the first
message.
- Wrap the chat in CopilotChatConfigurationProvider to replace the default
'How can I help you today?' welcome text with something on-topic
('Ready to run code in a Daytona sandbox. Try a starter below, or
describe what you'd like to execute.').
- Tighten the BuiltInAgent system prompt so the agent does not restate
stdout in chat text — the renderer card already shows it.
OSS-222
The deployable Next.js demo behind the new Daytona cookbook recipe. A minimal
CopilotKit Built-in Agent whose only added capability is the recipe's runCode
server tool — executes Python / TypeScript / JavaScript in an isolated Daytona
sandbox and streams the result back to the chat via a custom useRenderTool
card (fixed-height streaming code pane with react-syntax-highlighter +
vscDarkPlus, mirroring @copilotkit/react-ui's own CodeBlock, and a fixed-
height result pane with a 'Generated code:' / 'Result:' label pair). The
agent's system prompt instructs it not to restate stdout in chat text since
the renderer already shows it.
Standalone npm project — intentionally not in the monorepo's pnpm workspace
(matches the existing examples/showcases/* convention; only generative-ui-
playground is in the workspace globs). Validated end to end against published
@copilotkit/runtime@1.58.0 with both Python and JavaScript snippets round-
tripping through real Daytona sandboxes.
OSS-222
## Summary
Replace the abrupt "cut in" with a 300ms fade + slide-from-bottom
entrance on each chat card so they feel connected to the streaming
response instead of popping in.
Follow-up polish on
[#4587](https://github.com/CopilotKit/CopilotKit/pull/4587).
## What changed
Added `animate-in fade-in slide-in-from-bottom-2 duration-300 ease-out`
to the root element of every tool render surface in the chat:
- `ToolCard` — `SpecializedToolCard` and `DefaultToolCard` (covers
`do_research`, `do_projections`, `navigate_and_filter`, dashboard ops,
`render_chat_visual`, etc.)
- `InlineChart` (both placeholder and rendered chart)
- `CashPositionCard` (both placeholder and full card)
- `InventoryReorderCard` (both placeholder and full card)
- `InvoiceApprovalCard` (both placeholder and full card)
## Why this approach
- **`tw-animate-css` is already imported** in
`examples/showcases/deep-agents-finance-erp/src/app/globals.css` — no
new dependencies.
- **Mount-time CSS animation, not Framer Motion** — the cards are
short-lived per turn and don't need orchestration; CSS keyframes resolve
to `animation-name: enter` exactly once on first paint and don't re-fire
on prop transitions, so swapping between `InProgress` and the populated
state stays smooth.
- 300ms `ease-out` matches the rest of the demo's transition timing.
## Test plan
- [x] Chat → "Cash Position" → cards slide+fade in (verified via
`getComputedStyle().animationName === "enter"`, `animationDuration ===
"0.3s"`).
- [x] Same animation fires for `do_research` / `do_projections` tool
cards, inline charts, approval cards, and inventory reorder cards.
- [x] No layout shift or jank in successive turns.
- [ ] Reviewer: visual verification on a non-mac browser if possible
(animation runs on standard CSS, but worth confirming).
## Notes
- No JS/runtime changes. Pure CSS class additions via Tailwind
utilities.
- Decoupled from the HITL fix in
[#4630](https://github.com/CopilotKit/CopilotKit/pull/4630) — landing
this independently is fine.
Replace the abrupt "cut in" with a 300ms fade + slide-from-bottom
entrance on each chat card so they feel connected to the streaming
response instead of popping in.
Applied to all five tool render surfaces:
- ToolCard (Specialized + Default variants — do_research, do_projections,
navigate_and_filter, dashboard ops, render_chat_visual, etc.)
- InlineChart
- CashPositionCard
- InventoryReorderCard
- InvoiceApprovalCard
Uses tw-animate-css utilities (`animate-in fade-in slide-in-from-bottom-2
duration-300 ease-out`), already imported in globals.css — no new deps.
The agent's request_approval tool calls copilotkit_interrupt() which
raises GraphInterrupt and the runtime emits a CUSTOM { name:
"on_interrupt" } event. The previous useHumanInTheLoop hook only handles
frontend-executed tools and was ignoring those events, so the approval
card flashed in then vanished without ever exposing Approve/Reject.
- Switch to useInterrupt for the interrupt-driven flow
- Add a no-op useRenderTool for request_approval to suppress the
wildcard tool renderer (which would otherwise show a half-finished
generic card during streaming)
- JSON-parse event.value (the runtime delivers the interrupt payload as
a string, not an object — accessing properties directly silently
returns undefined and filters the interrupt out)
- Persistent follow-up suggestion chips above the input; the third chip
rotates based on the currently loaded dashboard so we never suggest
switching to the dashboard the user is already viewing.
- Hide the assistant message toolbar except on hover and only on the
latest turn — drops the floating copy icon that previously appeared
mid-conversation between tool cards.
- Replace the raw markdown preview under do_research/do_projections
tool cards with a clean "Completed data gathering" status caption.
- Expand the orchestrator prompt with natural-language intent mapping
so spending / cash-flow / revenue / executive-overview questions
route to load_dashboard against the matching template (no save +
reset + update churn), and approval-context invoice queries route
to request_approval instead of just charting.
24 examples bumped from various 15.0-15.4 versions to 15.5.15.
chat-with-your-data bumped from 15.6.0-canary to 16.1.7.
next-openai: moved OpenAI client init into handlers (15.5 evaluates
edge routes at build time).
Remaining on 14.x: next-pages-router(v1), state-machine, travel,
banking, enterprise-brex, presentation, todo — require major rewrite.
Replace `RUN curl -LsSf https://astral.sh/uv/install.sh | sh` across all
starter Dockerfiles with `COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx
/usr/local/bin/`. The curl|sh form has a pipe-swallow latent bug: when
astral.sh returns a 5xx, curl fails but `sh` gets no stdin and exits 0,
so the layer "succeeds" with no uv binary. A later `RUN uv sync` then
crashes with `uv: not found` (exit 127). This already bit the agno
starter today (run 24809910399) when astral.sh had a transient outage;
upstream recovered on its own so this is latent-bug cleanup, not a
hotfix.
Using the official uv image is uv's own recommended pattern: it's
cache-friendly, network-free at build time, and sidesteps the pipe
failure mode entirely.
Scope: all 20 Dockerfiles under examples/integrations/*/Dockerfile,
examples/integrations/*/docker/Dockerfile.agent, and
examples/showcases/scene-creator/agent/Dockerfile.
Verified locally: `docker build -f docker/Dockerfile.agent ./agent`
for agno succeeds against the new pattern.