
Copilotkit
- 2 installs
- 1 repo stars
- Updated February 18, 2026
- hexiaochun/agent-skills
Builds AI copilot and agentic features into React apps with CopilotKit chat UI, generative UI, and agent backends.
About
Builds AI copilot features into React apps with CopilotKit, covering chat UI, generative UI, frontend/backend tools, shared state, human-in-the-loop, and agent-framework integration. A developer uses it to add agentic copilot capabilities to a React application.
- React copilot UI, generative UI, and shared-state hooks
- Integrates LangGraph/Mastra/Agent Spec agent backends and MCP Apps
Copilotkit by the numbers
- 2 all-time installs (skills.sh)
- Ranked #13,958 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/hexiaochun/agent-skills --skill copilotkitAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 1 |
| Last updated | February 18, 2026 |
| Repository | hexiaochun/agent-skills ↗ |
What it does
Builds AI copilot and agentic features into React apps with CopilotKit chat UI, generative UI, and agent backends.
Files
CopilotKit — Agentic Application Framework
Build AI copilot features into React apps: chat UI, generative UI, frontend/backend tools, shared state, human-in-the-loop, and agent framework integration.
Quick Start
1. Install
npm install @copilotkit/react-ui @copilotkit/react-coreFor self-hosted runtime:
npm install @copilotkit/runtime2. Provider Setup (layout.tsx)
import "@copilotkit/react-ui/styles.css";
import { CopilotKit } from "@copilotkit/react-core";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{/* Option A: Copilot Cloud */}
<CopilotKit publicApiKey="<your-key>">
{children}
</CopilotKit>
{/* Option B: Self-hosted */}
{/* <CopilotKit runtimeUrl="/api/copilotkit">{children}</CopilotKit> */}
</body>
</html>
);
}3. Add Chat UI
Pick one of three built-in components:
import { CopilotPopup } from "@copilotkit/react-ui";
export function App() {
return (
<>
<YourMainContent />
<CopilotPopup
instructions="You are a helpful assistant."
labels={{ title: "AI Assistant", initial: "How can I help?" }}
/>
</>
);
}Alternatives: CopilotSidebar (wraps children), CopilotChat (inline, any size).
---
Core Hooks
useCopilotReadable — Provide context to LLM
import { useCopilotReadable } from "@copilotkit/react-core";
const [items, setItems] = useState([...]);
useCopilotReadable({ description: "User's todo items", value: items });Supports hierarchical context via parentId (return value of parent call).
useFrontendTool — Frontend executable tool + optional UI
import { useFrontendTool } from "@copilotkit/react-core";
useFrontendTool({
name: "addTodo",
description: "Add a new todo item",
parameters: [
{ name: "text", type: "string", description: "Todo content", required: true },
],
handler: async ({ text }) => {
setTodos(prev => [...prev, text]);
},
render: ({ status, args, result }) => {
if (status === "inProgress") return <Spinner />;
return <TodoCard text={args.text} />;
},
});render is optional. When provided, UI appears inline in chat during tool execution.
useRenderToolCall — Render-only (no handler)
import { useRenderToolCall } from "@copilotkit/react-core";
useRenderToolCall({
name: "get_weather",
render: ({ status, args }) => {
if (status !== "complete") return <p>Loading weather...</p>;
return <WeatherCard location={args.location} />;
},
});useDefaultTool — Fallback renderer for all tools
import { useDefaultTool } from "@copilotkit/react-core";
useDefaultTool({
render: ({ name, args, status, result }) => (
<div>
<span>{status === "complete" ? "✓" : "⏳"} {name}</span>
{status === "complete" && result && <pre>{JSON.stringify(result, null, 2)}</pre>}
</div>
),
});useCopilotChat — Headless chat API
import { useCopilotChat } from "@copilotkit/react-core";
import { Role, TextMessage } from "@copilotkit/runtime-client-gql";
const { visibleMessages, appendMessage, stopGeneration, isLoading } = useCopilotChat();
appendMessage(new TextMessage({ content: "Hello", role: Role.User }));useCopilotChatSuggestions — Auto-generate suggestions
import { useCopilotChatSuggestions } from "@copilotkit/react-ui";
useCopilotChatSuggestions({
instructions: "Suggest next actions based on current state.",
minSuggestions: 1,
maxSuggestions: 3,
}, [relevantState]);---
Generative UI — Three Patterns
Static (AG-UI) — Pre-built components, agent selects + fills data
Use useFrontendTool with render. Agent chooses which tool/component to show.
Declarative (A2UI / Open-JSON-UI) — Agent returns structured JSON UI spec
Agent emits JSON describing cards/lists/forms. Frontend renders with its own styling.
Open-ended (MCP Apps) — Agent returns full HTML/JS in sandboxed iframe
npm install @ag-ui/mcp-apps-middlewareimport { BuiltInAgent } from "@copilotkit/runtime/v2";
import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
const agent = new BuiltInAgent({
model: "openai/gpt-4o",
prompt: "You are a helpful assistant.",
}).use(
new MCPAppsMiddleware({
mcpServers: [{ type: "http", url: "http://localhost:3108/mcp", serverId: "my-server" }],
}),
);---
Shared State (with LangGraph)
Backend state definition (Python)
from copilotkit import CopilotKitState
class AgentState(CopilotKitState):
language: str = "english"Frontend read/write — useCoAgent
import { useCoAgent } from "@copilotkit/react-core";
const { state, setState } = useCoAgent<{ language: string }>({
name: "sample_agent",
initialState: { language: "english" },
});Render state in chat — useCoAgentStateRender
import { useCoAgentStateRender } from "@copilotkit/react-core";
useCoAgentStateRender({
name: "sample_agent",
render: ({ state }) => state.language ? <div>Lang: {state.language}</div> : null,
});---
Human-in-the-Loop (with LangGraph)
Backend — interrupt()
from langgraph.types import interrupt
def chat_node(state, config):
name = state.get("agent_name") or interrupt("What should I call you?")
# ... continue with nameFrontend — useLangGraphInterrupt
import { useLangGraphInterrupt } from "@copilotkit/react-core";
useLangGraphInterrupt({
render: ({ event, resolve }) => (
<div>
<p>{event.value}</p>
<input type="text" name="response" />
<button onClick={() => resolve(document.querySelector('input').value)}>Submit</button>
</div>
),
});Supports enabled for conditional routing and handler for programmatic pre-processing.
---
Backend Actions (Self-hosted Runtime)
API Route (Next.js App Router)
import { CopilotRuntime, ExperimentalEmptyAdapter, copilotRuntimeNextJSAppRouterEndpoint } from "@copilotkit/runtime";
const runtime = new CopilotRuntime({
actions: ({ properties, url }) => [
{
name: "fetchUser",
description: "Fetch user by ID from database",
parameters: [{ name: "userId", type: "string", description: "User ID", required: true }],
handler: async ({ userId }) => {
return await db.users.findById(userId);
},
},
],
});
const serviceAdapter = new ExperimentalEmptyAdapter();
export const POST = async (req: NextRequest) => {
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
runtime, serviceAdapter, endpoint: "/api/copilotkit",
});
return handleRequest(req);
};actions is a factory function receiving { properties, url } — dynamically expose different actions per page.
---
Styling & Customization
CSS Variables (simplest)
<div style={{
"--copilot-kit-primary-color": "#6366f1",
"--copilot-kit-background-color": "#0f172a",
"--copilot-kit-secondary-color": "#1e293b",
"--copilot-kit-secondary-contrast-color": "#f8fafc",
} as CopilotKitCSSProperties}>
<CopilotSidebar />
</div>CSS Classes
Key classes: .copilotKitMessages, .copilotKitInput, .copilotKitUserMessage, .copilotKitAssistantMessage, .copilotKitHeader, .copilotKitButton, .copilotKitWindow.
Custom Labels & Icons
<CopilotChat
labels={{ title: "My AI", initial: "Ask anything", placeholder: "Type here..." }}
icons={{ openIcon: <MyIcon />, sendIcon: <SendIcon /> }}
/>Available icons: openIcon, closeIcon, headerCloseIcon, sendIcon, activityIcon, spinnerIcon, stopIcon, regenerateIcon, pushToTalkIcon.
---
CopilotKit Provider — Key Props
| Prop | Type | Description |
|---|---|---|
publicApiKey | string | Copilot Cloud API key |
runtimeUrl | string | Self-hosted runtime endpoint |
agent | string | Agent name to use |
threadId | string | Conversation thread ID |
headers | Record<string, string> | Custom request headers |
properties | Record<string, any> | Custom props (auth, metadata) |
credentials | RequestCredentials | CORS cookie policy, e.g. "include" |
showDevConsole | boolean | Show dev console |
---
Decision Guide
| Need | Solution |
|---|---|
| Add chat to existing app | CopilotPopup or CopilotSidebar |
| Fully custom chat UI | useCopilotChat (headless) |
| LLM reads app state | useCopilotReadable |
| LLM modifies app state | useFrontendTool with handler |
| Custom UI in chat messages | useFrontendTool or useRenderToolCall with render |
| Agent framework (LangGraph/Mastra) | useCoAgent + useCoAgentStateRender |
| User approval flows | useLangGraphInterrupt |
| Server-side data/API calls | Backend actions via CopilotRuntime |
| External MCP tool UIs | MCPAppsMiddleware |
Additional Resources
- For complete API reference and advanced patterns, see reference.md
- Official docs: https://docs.copilotkit.ai
- GitHub: https://github.com/CopilotKit/CopilotKit
- Generative UI playground: https://github.com/CopilotKit/generative-ui-playground
CopilotKit — Complete API Reference
Packages
| Package | Purpose |
|---|---|
@copilotkit/react-core | Provider, hooks (useFrontendTool, useCopilotReadable, useCopilotChat, useCoAgent, etc.) |
@copilotkit/react-ui | Chat components (CopilotChat, CopilotSidebar, CopilotPopup), styles, suggestions |
@copilotkit/runtime | Self-hosted backend runtime (CopilotRuntime, adapters, endpoints) |
@copilotkit/runtime/v2 | v2 BuiltInAgent class |
@copilotkit/runtime-client-gql | Client types (TextMessage, Role, MessageRole) |
@ag-ui/mcp-apps-middleware | MCP Apps middleware for BuiltInAgent |
copilotkit (Python) | CopilotKitState, LangGraph integration |
---
Hooks — Full Parameter Reference
useFrontendTool
useFrontendTool({
name: string; // Tool name (unique identifier)
description: string; // Natural language description for LLM
parameters: Parameter[]; // Input parameter definitions
handler: (args: T) => any; // Execution function (runs in browser)
render?: (props: RenderProps) => ReactElement; // Optional inline UI
disabled?: boolean; // Disable tool availability
});Parameter type:
type Parameter = {
name: string;
type: "string" | "number" | "boolean" | "object" | "string[]" | "number[]" | "boolean[]" | "object[]";
description: string;
required?: boolean; // default: true
enum?: string[]; // for string type only
attributes?: Parameter[]; // for object/object[] nested fields
};RenderProps:
type RenderProps = {
status: "inProgress" | "executing" | "complete";
args: T; // Streamed args (may be partial during inProgress)
result?: any; // Only available when status === "complete"
};useCopilotReadable
const contextId: string = useCopilotReadable({
description: string; // What this data represents
value: any; // Data (objects auto-serialized to JSON)
parentId?: string; // Parent context ID for hierarchy
categories?: string[]; // Visibility categories
available?: "enabled" | "disabled";
convert?: (description: string, value: any) => string; // Custom serializer
});Returns a unique context ID (use as parentId for child contexts).
useCopilotAction (v1, still supported)
useCopilotAction({
name: string;
handler: (args: T) => Promise<any>;
description?: string;
available?: "enabled" | "disabled" | "remote"; // "remote" = only for remote agents
followUp?: boolean; // default: true — feed result back to LLM
parameters?: Parameter[];
render?: string | ((props: ActionRenderProps) => ReactElement);
renderAndWaitForResponse?: (props: ActionRenderPropsWait) => ReactElement;
dependencies?: any[];
});ActionRenderPropsWait adds:
{ respond: (result: any) => void } // Must call to unblock; only available during "executing"useRenderToolCall
useRenderToolCall({
name: string; // Must match a backend tool name
description?: string;
parameters?: Parameter[];
render: (props: { status: string; args: T }) => ReactElement;
});useDefaultTool
useDefaultTool({
render: (props: { name: string; args: any; status: string; result?: any }) => ReactElement;
});useCopilotChat
const {
visibleMessages, // Message[]
appendMessage, // (msg: TextMessage, opts?) => Promise
setMessages, // (msgs: Message[]) => void
deleteMessage, // (id: string) => void
reloadMessages, // (messageId: string) => Promise
stopGeneration, // () => void
reset, // () => void — clear all messages
isLoading, // boolean
runChatCompletion, // () => Promise
mcpServers, // MCPServerConfig[]
setMcpServers, // (servers: MCPServerConfig[]) => void
} = useCopilotChat({
id?: string; // Shared state across components with same ID
headers?: Record<string, string>;
initialMessages?: Message[];
makeSystemMessage?: SystemMessageFunction;
disableSystemMessage?: boolean;
suggestions?: "auto" | "manual" | SuggestionItem[];
onInProgress?: (isLoading: boolean) => void;
onSubmitMessage?: (content: string) => Promise | void;
onStopGeneration?: OnStopGeneration;
onReloadMessages?: OnReloadMessages;
});useCoAgent (LangGraph shared state)
const { state, setState } = useCoAgent<StateType>({
name: string; // Agent name (must match backend)
initialState?: StateType;
});state is reactive — auto-updates when agent state changes.
useCoAgentStateRender
useCoAgentStateRender({
name: string; // Agent name
render: (props: { state: StateType }) => ReactElement | null;
});useLangGraphInterrupt
useLangGraphInterrupt({
enabled?: (context: { eventValue: any }) => boolean; // Conditional routing
handler?: async (context: { result: any; event: any; resolve: Function }) => any; // Pre-processing
render: (props: { event: any; resolve: (value: any) => void; result?: any }) => ReactElement;
});useCopilotChatSuggestions
useCopilotChatSuggestions({
instructions: string; // Prompt for suggestion generation
minSuggestions?: number;
maxSuggestions?: number;
}, dependencies?: any[]); // Re-generate when deps change---
Components — Full Props
CopilotKit Provider
<CopilotKit
publicApiKey?: string
runtimeUrl?: string
publicLicenseKey?: string
agent?: string
threadId?: string
headers?: Record<string, string>
properties?: Record<string, any>
credentials?: RequestCredentials
showDevConsole?: boolean
enableInspector?: boolean
guardrails_c?: { validTopics?: string[]; invalidTopics?: string[] }
authConfig_c?: { SignInComponent: React.ComponentType }
transcribeAudioUrl?: string
textToSpeechUrl?: string
onError?: CopilotErrorHandler
>
{children}
</CopilotKit>CopilotPopup / CopilotSidebar / CopilotChat
Shared props:
instructions?: string // System prompt for the AI
labels?: {
initial?: string // First message shown
title?: string // Header title
placeholder?: string // Input placeholder
stopGenerating?: string // Stop button text
regenerateResponse?: string
}
icons?: {
openIcon?: ReactNode
closeIcon?: ReactNode
headerCloseIcon?: ReactNode
sendIcon?: ReactNode
activityIcon?: ReactNode
spinnerIcon?: ReactNode
stopIcon?: ReactNode
regenerateIcon?: ReactNode
pushToTalkIcon?: ReactNode
}CopilotSidebar additional:
defaultOpen?: boolean // Start expanded
children: ReactNode // Main app content (wrapped)CopilotPopup additional:
defaultOpen?: boolean
// Rendered at same level as main content (not wrapping)---
Self-Hosted Runtime Setup
Next.js App Router
// app/api/copilotkit/route.ts
import {
CopilotRuntime,
ExperimentalEmptyAdapter,
copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
import { NextRequest } from "next/server";
const runtime = new CopilotRuntime({
actions: ({ properties, url }) => [
{
name: "myAction",
description: "Does something useful",
parameters: [
{ name: "input", type: "string", description: "The input", required: true },
],
handler: async ({ input }) => {
return { result: `Processed: ${input}` };
},
},
],
});
const serviceAdapter = new ExperimentalEmptyAdapter();
export const POST = async (req: NextRequest) => {
const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
runtime,
serviceAdapter,
endpoint: "/api/copilotkit",
});
return handleRequest(req);
};With BuiltInAgent (v2)
import { BuiltInAgent } from "@copilotkit/runtime/v2";
const agent = new BuiltInAgent({
model: "openai/gpt-4o",
prompt: "You are a helpful assistant.",
});
const runtime = new CopilotRuntime({
agents: { default: agent },
});With MCP Apps
import { MCPAppsMiddleware } from "@ag-ui/mcp-apps-middleware";
const agent = new BuiltInAgent({
model: "openai/gpt-4o",
prompt: "You are a helpful assistant.",
}).use(
new MCPAppsMiddleware({
mcpServers: [
{ type: "http", url: "http://localhost:3108/mcp", serverId: "my-server" },
// SSE transport:
// { type: "sse", url: "https://mcp.example.com/sse", headers: { "Authorization": "Bearer token" }, serverId: "my-sse-server" },
],
}),
);Always provide serverId in production. Without it, CopilotKit hashes the URL — if URL changes, history breaks.---
Agent Framework Integration
LangGraph (Python)
# agent.py
from copilotkit import CopilotKitState
from langgraph.graph import StateGraph
from langchain_openai import ChatOpenAI
class AgentState(CopilotKitState):
custom_field: str = ""
def chat_node(state: AgentState, config):
# Access frontend tools via state
tools = state.get("copilotkit", {}).get("actions", [])
model = ChatOpenAI(model="gpt-4o").bind_tools(tools)
response = model.invoke(state["messages"], config)
return { **state, "messages": response }
graph = StateGraph(AgentState)
graph.add_node("chat", chat_node)
# ... add edges, compileLangGraph (TypeScript)
async function chatNode(state: AgentState, config: RunnableConfig) {
const tools = state.copilotkit?.actions;
const model = new ChatOpenAI({ model: "gpt-4o" }).bindTools(tools);
const response = await model.invoke(state.messages, config);
return { ...state, messages: response };
}Agent Spec (Python backend + CopilotKit frontend)
from pyagentspec.agent import Agent
from pyagentspec.llms import OpenAiCompatibleConfig
from pyagentspec.tools import ClientTool
from pyagentspec.property import StringProperty
from pyagentspec.serialization import AgentSpecSerializer
llm = OpenAiCompatibleConfig(name="llm", model_id="gpt-4o-mini", url="https://api.openai.com/v1")
# ClientTool name/description/inputs MUST match frontend useFrontendTool
tool = ClientTool(
name="sayHello",
description="Say hello to the user.",
inputs=[StringProperty(title="name", description="User name")],
)
agent = Agent(
name="my_agent", llm_config=llm,
system_prompt="A helpful assistant.",
tools=[tool], human_in_the_loop=True,
)
# FastAPI server
from fastapi import APIRouter, FastAPI
from ag_ui_agentspec.agent import AgentSpecAgent
from ag_ui_agentspec.endpoint import add_agentspec_fastapi_endpoint
router = APIRouter()
add_agentspec_fastapi_endpoint(
app=router,
agentspec_agent=AgentSpecAgent(AgentSpecSerializer().to_json(agent), runtime="langgraph"),
path="/langgraph/my_agent",
)
app = FastAPI()
app.include_router(router)---
CSS Variables Reference
| Variable | Purpose |
|---|---|
--copilot-kit-primary-color | Buttons, interactive elements |
--copilot-kit-contrast-color | Text on primary color |
--copilot-kit-background-color | Main background |
--copilot-kit-secondary-color | Cards, panels, hover surfaces |
--copilot-kit-secondary-contrast-color | Primary text color |
--copilot-kit-separator-color | Borders, dividers |
--copilot-kit-muted-color | Disabled/inactive elements |
CSS Classes Reference
| Class | Target |
|---|---|
.copilotKitMessages | Message scroll container |
.copilotKitInput | Input area container |
.copilotKitUserMessage | User message bubble |
.copilotKitAssistantMessage | AI response bubble |
.copilotKitHeader | Top header bar |
.copilotKitButton | Toggle button (popup/sidebar) |
.copilotKitWindow | Root chat window |
.copilotKitChat | Base chat layout |
.copilotKitSidebar | Sidebar mode wrapper |
.copilotKitPopup | Popup mode wrapper |
.copilotKitMarkdown | Markdown rendered content |
.copilotKitCodeBlock | Code block styling |
---
CLI Commands
# Initialize CopilotKit in existing Next.js project
npx copilotkit@latest init
# Create new project from template
npx copilotkit@latest create -f <framework>
# Frameworks: langgraph-py, langgraph-js, mastra, mcp-apps---
v1 → v2 Migration
| v1 (still supported) | v2 (recommended) |
|---|---|
useCopilotAction | useFrontendTool |
useCopilotReadable | useAgentContext |
useCopilotChat | useAgent |
---
Architecture Overview
Frontend (React) Backend
┌──────────────────────┐ ┌────────────────────────┐
│ <CopilotKit> │ │ CopilotRuntime │
│ ├─ CopilotChat/ │ │ ├─ BuiltInAgent │
│ │ Sidebar/Popup │ │ │ └─ MCPApps MW │
│ ├─ useFrontendTool │◄───►│ ├─ Backend Actions │
│ ├─ useCopilotRead. │AG-UI│ └─ Service Adapter │
│ ├─ useCoAgent │ │ │
│ └─ useLangGraphInt. │ │ Agent (LangGraph/ │
│ │ │ Mastra/AgentSpec/...) │
└──────────────────────┘ └────────────────────────┘