Help us improve
Share bugs, ideas, or general feedback.
From copilotkit
Pre-deploy checklist for CopilotKit v2 apps: switches InMemoryAgentRunner to persistent runner, validates CORS, env secrets, debug/dev flags, and cloud Intelligence URLs. Load before first production deploy.
npx claudepluginhub copilotkit/copilotkit --plugin copilotkitHow this skill is triggered — by the user, by Claude, or both
Slash command
/copilotkit:go-to-productionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Run through each section before deploying. This is a pointer skill — each
Guides CopilotKit setup in React projects with Next.js (App/Pages), Vite+React, or Angular: detects framework, installs packages, wires runtime (Hono/Express), configures AI providers, adds chat UI.
Guides deployment of Google ADK agents to Cloud Run, GKE, or Agent Runtime, covering CI/CD, secrets, and rollback.
Provides Clerk production readiness checklist with env validation, security checks, and TypeScript script for live keys, API connectivity, webhooks, and middleware.
Share bugs, ideas, or general feedback.
Run through each section before deploying. This is a pointer skill — each check delegates to the skill that owns the detail.
Expected:
import { CopilotRuntime } from "@copilotkit/runtime/v2";
import { SqliteAgentRunner } from "@copilotkit/sqlite-runner";
new CopilotRuntime({
agents,
runner: new SqliteAgentRunner({ dbPath: "/var/data/threads.db" }),
});
Fail condition: runtime uses the default InMemoryAgentRunner (or passes
one explicitly) while the deployment has more than one replica or any
restart-surviving requirement.
Fix: switch to SqliteAgentRunner (single-host durable) or
CopilotKitIntelligence (multi-host durable). See copilotkit/runtime → references/agent-runners.md.
Expected:
// Node / server runtime — `env` here is Node's `process.env`:
new CopilotRuntime({
agents,
intelligence: {
apiUrl: "https://api.cloud.copilotkit.ai",
wsUrl: "wss://api.cloud.copilotkit.ai",
licenseToken: process.env.COPILOTKIT_LICENSE_TOKEN,
},
});
Fail condition: apiUrl points to a self-hosted URL — Intelligence is not
self-hostable.
Fix: use Cloud URLs or downgrade to SqliteAgentRunner for on-prem
durability. See copilotkit/runtime → references/intelligence-mode.md.
Expected:
const handler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit",
cors: true,
});
Fail condition: frontend and runtime are on different origins, and cors
is not enabled (or is not equivalently handled by a reverse proxy / CDN).
Fix: set cors: true on createCopilotRuntimeHandler, or handle CORS at
the proxy layer. See copilotkit/runtime → references/setup-endpoint.md.
Expected:
<CopilotKitProvider runtimeUrl="/api/copilotkit" showDevConsole="auto" />
Fail condition: showDevConsole={true} hardcoded — internal error details
render to end users.
Fix: use "auto" (the default), or gate on NODE_ENV.
Expected:
<CopilotKitProvider
runtimeUrl="/api/copilotkit"
debug={process.env.NODE_ENV !== "production"}
/>
Fail condition: debug={{ events: true, lifecycle: true, verbose: true }}
shipped to prod — large log volume and verbose logs can include PII
payloads.
Fix: gate debug on environment, or omit it entirely.
Expected:
new CopilotRuntime({
agents,
debug: process.env.NODE_ENV !== "production",
});
Fail condition: debug: true or { verbose: true } shipped — Pino logs
expand in volume and may include tool-call payloads.
Fix: gate on environment. See copilotkit/debug-and-troubleshoot.
Expected:
<CopilotKitProvider
runtimeUrl="https://api.myapp.com/copilotkit"
credentials="include"
/>
Fail condition: cross-origin runtime with cookie-session auth, no
credentials="include" — browsers strip cookies and /info plus the SSE
stream go unauthenticated.
Fix: add credentials="include", and set CORS on the runtime to allow
credentials. See copilotkit/react-core → references/provider-setup.md.
Expected:
new CopilotRuntime({
agents,
hooks: {
onBeforeHandler: async ({ request }) => {
const session = await getSession(request);
if (!session) return new Response("Unauthorized", { status: 401 });
},
},
});
Fail condition: ad-hoc auth checks inside tool handlers instead of hook /
middleware.
Fix: centralize auth in hooks.onBeforeHandler or
beforeRequestMiddleware. CopilotKit does NOT ship auth, rate-limit, or
observability — use your server framework's tooling. See
copilotkit/runtime → references/middleware.md.
Expected:
<CopilotKitProvider publicApiKey={import.meta.env.VITE_CPK_PUBLIC_API_KEY} />
Fail condition: key inlined as a string literal in committed source.
Fix: read from build-time env (VITE_*, NEXT_PUBLIC_*, etc.) and inject
via CI. publicLicenseKey is also accepted as an alias
(publicApiKey ?? publicLicenseKey); prefer publicApiKey for
consistency with the HTTP header (X-CopilotCloud-Public-Api-Key) and
Cloud dashboard label.
Expected (Node / server runtime):
new CopilotRuntime({
agents,
licenseToken: process.env.COPILOTKIT_LICENSE_TOKEN,
});
On Cloudflare Workers, env here refers to the Worker binding argument
passed to fetch(request, env) — not a module-global.
Fail condition: license token hardcoded in source or absent in prod.
Fix: inject via environment variable. See copilotkit/runtime → references/setup-endpoint.md.
Expected (Cloudflare Workers — runtime hoisted to module scope, lazy init):
import {
CopilotRuntime,
createCopilotRuntimeHandler,
BuiltInAgent,
} from "@copilotkit/runtime/v2";
interface Env {
OPENAI_API_KEY: string;
}
let cachedHandler: ((r: Request) => Response | Promise<Response>) | null = null;
function getHandler(env: Env) {
if (cachedHandler) return cachedHandler;
const runtime = new CopilotRuntime({
agents: {
// Thread env.OPENAI_API_KEY explicitly — `process.env` is undefined on
// Workers, so BuiltInAgent's env-var fallback never fires.
default: new BuiltInAgent({
model: "openai/gpt-4o",
apiKey: env.OPENAI_API_KEY,
}),
},
});
cachedHandler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit",
cors: true,
});
return cachedHandler;
}
export default {
fetch(request: Request, env: Env) {
return getHandler(env)(request);
},
};
Fail condition: Workers / Vercel Edge code reads process.env.* — those
runtimes don't expose it. Also: constructing new CopilotRuntime(...)
inside fetch(request, env) on every request wastes CPU and drops
in-memory runner state.
Fix: use the platform's env argument (Workers env, Vercel Edge
request.env), and hoist the runtime + handler to module scope. Workers
isolates reuse module globals across requests (in-isolate only — for
cross-isolate durability pair with SqliteAgentRunner or Intelligence).
See copilotkit/0-to-working-chat.
Expected:
<CopilotKitProvider runtimeUrl="/api/copilotkit" />
// or
<CopilotKitProvider publicApiKey="ck_pub_..." />
Fail condition: any agents__unsafe_dev_only={{ ... }} prop in shipped
client code — registers agents in the browser and leaks credentials.
Fix: move agent construction to the server (runtime) or use
publicApiKey (Cloud). See copilotkit/spa-without-runtime.
Fail condition: any selfManagedAgents={{ ... }} prop. It's an alias of
agents__unsafe_dev_only — same leak.
Fix: same as above.
Both props are supported — publicApiKey is canonical and wins when both
are set (resolvedPublicKey = publicApiKey ?? publicLicenseKey). Prefer
publicApiKey in new code. The only fail condition here is a hardcoded
string literal — see "Check: publicApiKey is env-sourced, not hardcoded"
above. See copilotkit/v1-to-v2-migration for v1 → v2 rename details.
Wrong:
// Kubernetes 3 replicas, default runner
new CopilotRuntime({ agents });
Correct:
new CopilotRuntime({
agents,
runner: new SqliteAgentRunner({ dbPath: "/var/data/threads.db" }),
});
Thread state is per-instance in InMemory; the load balancer may send a
follow-up request to a different replica → agent_thread_locked on one
replica and empty state on another.
Source: packages/runtime/src/v2/runtime/runner/in-memory.ts; packages/core/src/core/core.ts:96
Wrong:
<CopilotKitProvider showDevConsole={true} />
Correct:
<CopilotKitProvider showDevConsole="auto" />
Exposes internal error details (stack traces, troubleshooting links) to end users.
Source: docs/snippets/shared/troubleshooting/error-debugging.mdx:22-24
Wrong:
<CopilotKitProvider debug={{ events: true, lifecycle: true, verbose: true }} />
Correct:
<CopilotKitProvider debug={process.env.NODE_ENV !== "production"} />
verbose expands event payloads into logs — can include PII. Large log
volume as a secondary concern.
Source: docs/snippets/shared/troubleshooting/debug-mode.mdx:145-149
Wrong:
<CopilotKitProvider runtimeUrl="https://api.myapp.com/copilotkit" />
Correct:
<CopilotKitProvider
runtimeUrl="https://api.myapp.com/copilotkit"
credentials="include"
/>
Cross-origin browsers strip cookies by default; /info and SSE stream go
unauthenticated.
Source: packages/react-core/src/v2/providers/CopilotKitProvider.tsx:118-120
Wrong:
const agent = new BuiltInAgent({ apiKey: process.env.OPENAI_API_KEY });
Correct: see copilotkit/0-to-working-chat (Cloudflare branch) — use
the env binding argument.
Source: examples/v2/runtime/cf-workers/src/index.ts:7-17
showDevConsole is "auto" (or omitted)debug on provider and runtime is off or dev-gatedcredentials="include" set if runtime is cross-origin and uses cookieshooks or middlewarepublicApiKey / licenseToken sourced from env vars (not hardcoded)process.envagents__unsafe_dev_only and selfManagedAgents absent from bundleagent_thread_locked, runtime_info_fetch_failed,
agent_run_failed (see copilotkit/debug-and-troubleshoot)