elevenlabs-agents
This Claude Code skill enables the creation and deployment of production-ready conversational AI voice agents on the ElevenLabs platform. It provides configuration guidance, SDK integration examples for React, React Native, Swift, JavaScript, and server-side environments, system prompt templates, CLI workflows, and troubleshooting for common issues including webhook errors, CSP violations, and deprecated package errors. Use this when building voice agents, AI receptionists, phone systems, or implementing ElevenLabs conversational AI features.
git clone --depth 1 https://github.com/jezweb/claude-skills /tmp/elevenlabs-agents && cp -r /tmp/elevenlabs-agents/plugins/integrations/skills/elevenlabs-agents ~/.claude/skills/elevenlabs-agentsSKILL.md
# ElevenLabs Agent Builder
Build a production-ready conversational AI voice agent. Produces a configured agent with tools, knowledge base, and SDK integration.
## Packages
```bash
npm install @elevenlabs/react # React SDK
npm install @elevenlabs/client # JavaScript SDK (browser + server)
npm install @elevenlabs/react-native # React Native SDK
npm install @elevenlabs/elevenlabs-js # Full API (server only)
npm install -g @elevenlabs/agents-cli # CLI ("Agents as Code")
```
**DEPRECATED:** `@11labs/react`, `@11labs/client` -- uninstall if present.
**Server-only warning:** `@elevenlabs/elevenlabs-js` uses Node.js `child_process` and won't work in browsers. Use `@elevenlabs/client` for browser environments, or create a proxy server.
## Workflow
### Step 1: Create Agent via Dashboard or CLI
**Dashboard:** https://elevenlabs.io/app/conversational-ai -> Create Agent
**CLI (Agents as Code):**
```bash
elevenlabs agents init
elevenlabs agents add "Support Bot" --template customer-service
# Edit agent_configs/support-bot.json
elevenlabs agents push --env dev
```
Templates: `default`, `minimal`, `voice-only`, `text-only`, `customer-service`, `assistant`.
Configure:
- **Voice** -- Choose from 5000+ voices or clone
- **LLM** -- GPT, Claude, Gemini, or custom
- **System prompt** -- Use the 6-component framework below
- **First message** -- What the agent says when conversation starts
### Step 2: Write the System Prompt
Use the 6-component framework for effective agent prompts:
**1. Personality** -- who the agent is:
```
You are [NAME], a [ROLE] at [COMPANY].
You have [EXPERIENCE]. Your traits: [LIST TRAITS].
```
**2. Environment** -- communication context:
```
You're communicating via [phone/chat/video].
Consider [environmental factors]. Adapt to [context].
```
**3. Tone** -- speech patterns and formality:
```
Tone: Professional yet warm. Use contractions for natural speech.
Avoid jargon. Keep responses to 2-3 sentences. Ask one question at a time.
```
**4. Goal** -- objectives and success criteria:
```
Primary Goal: Resolve customer issues on the first call.
Success: Customer verbally confirms issue is resolved.
```
**5. Guardrails** -- boundaries and ethics:
```
Never: provide medical/legal/financial advice, share confidential info.
Always: verify identity before account access, document interactions.
Escalation: customer requests manager, issue beyond knowledge base.
```
**6. Tools** -- available functions and when to use them:
```
1. lookup_order(order_id) -- Use when customer mentions an order.
2. transfer_to_supervisor() -- Use when issue requires manager approval.
Always explain what you're doing before calling a tool.
```
### Step 3: Add Tools
**Client-side tools (run in browser):**
```typescript
const clientTools = {
updateCart: {
description: "Add or remove items from the shopping cart",
parameters: z.object({
action: z.enum(['add', 'remove']),
item: z.string(),
quantity: z.number().min(1)
}),
handler: async ({ action, item, quantity }) => {
const cart = getCart();
action === 'add' ? cart.add(item, quantity) : cart.remove(item, quantity);
return { success: true, total: cart.total, items: cart.items.length };
}
},
navigate: {
description: "Navigate user to a different page",
parameters: z.object({ url: z.string().url() }),
handler: async ({ url }) => { window.location.href = url; return { success: true }; }
}
};
```
**Server-side tools (webhooks):**
```json
{
"name": "get_weather",
"description": "Fetch current weather for a city",
"url": "https://api.weather.com/v1/current",
"method": "GET",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "City name" }
},
"required": ["city"]
},
"headers": {
"Authorization": "Bearer {{secret__weather_api_key}}"
}
}
```
Use `{{secret__key_name}}` for API keys in webhook headers -- never hardcode.
**MCP Tools -- CRITICAL COMPATIBILITY NOTE:**
ElevenLabs labels their MCP integration as "Streamable HTTP" but does NOT support the actual MCP 2025-03-26 Streamable HTTP spec (SSE responses). ElevenLabs expects:
- Plain JSON responses (`application/json`), NOT SSE (`text/event-stream`)
- Protocol version `2024-11-05`, NOT `2025-03-26`
- Simple JSON-RPC over HTTP with direct JSON responses
What does NOT work:
- Official MCP SDK's `createMcpHandler` (returns SSE)
- Cloudflare Agents SDK `McpServer.serve()` (returns SSE)
- Any server returning `Content-Type: text/event-stream`
Working MCP server pattern for ElevenLabs:
```typescript
import { Hono } from 'hono';
import { cors } from 'hono/cors';
const tools = [{
name: "my_tool",
description: "Tool description",
inputSchema: {
type: "object",
properties: { param1: { type: "string", description: "Description" } },
required: ["param1"]
}
}];
async function handleMCPRequest(request, env) {
const { id, method, params } = request;
switch (method) {
case 'initialize':
return {
jsonrpc: '2.0', id,
result: {
protocolVersion: '2024-11-05', // MUST be 2024-11-05
serverInfo: { name: 'my-mcp', version: '1.0.0' },
capabilities: { tools: {} }
}
};
case 'tools/list':
return { jsonrpc: '2.0', id, result: { tools } };
case 'tools/call':
const result = await handleTool(params.name, params.arguments, env);
return { jsonrpc: '2.0', id, result };
default:
return { jsonrpc: '2.0', id, error: { code: -32601, message: `Unknown: ${method}` } };
}
}
const app = new Hono();
app.use('/*', cors({ origin: '*', allowMethods: ['GET', 'POST', 'OPTIONS'] }));
app.post('/mcp', async (c) => {
const body = await c.req.json();
return c.json(await handleMCPRequest(body, c.env)); // Plain JSON, NOT SSE
});
export default app;
```
### Step 4: Add Knowledge Base (RAG)
Upload documents for the agent to referenHit the Cloudflare REST API directly for operations that wrangler and MCP can't handle well. Bulk DNS, custom hostnames, email routing, cache purge, WAF rules, redirect rules, zone settings, Worker routes, D1 cross-database queries, R2 bulk operations, KV bulk read/write, Vectorize queries, Queues, and fleet-wide resource audits. Produces curl commands or scripts. Triggers: 'cloudflare api', 'bulk dns', 'custom hostname', 'email routing', 'cache purge', 'waf rule', 'd1 query', 'r2 bucket', 'kv bulk', 'vectorize query', 'audit resources', 'fleet operation'.
Scaffold and deploy Cloudflare Workers with Hono routing, Vite plugin, and Static Assets. Describe project, scaffold structure, configure bindings, deploy. Use whenever the user wants to create a Worker project, set up Hono on Cloudflare, configure D1 / R2 / KV / Queues bindings, or troubleshoot Worker export syntax, API route conflicts, HMR issues, or deployment failures.
Generate Drizzle ORM schemas for Cloudflare D1 databases with correct D1-specific patterns. Produces schema files, migration commands, type exports, and DATABASE_SCHEMA.md documentation. Handles D1 quirks: foreign keys always enforced, no native BOOLEAN/DATETIME types, 100 bound parameter limit, JSON stored as TEXT. Use when creating a new database, adding tables, or scaffolding a D1 data layer.
Cloudflare D1 migration workflow: generate with Drizzle, inspect SQL for gotchas, apply to local and remote, fix stuck migrations, handle partial failures. Use when running migrations, fixing migration errors, or setting up D1 schemas.
Generate database seed scripts with realistic sample data. Reads Drizzle schemas or SQL migrations, respects foreign key ordering, produces idempotent TypeScript or SQL seed files. Handles D1 batch limits, unique constraints, and domain-appropriate data. Use when populating dev/demo/test databases. Triggers: 'seed database', 'seed data', 'sample data', 'populate database', 'db seed', 'test data', 'demo data', 'generate fixtures'.
Scaffold Hono API routes for Cloudflare Workers. Produces route files, middleware, typed bindings, Zod validation, error handling, and API_ENDPOINTS.md documentation. Use after a project is set up with cloudflare-worker-builder or vite-flare-starter, when you need to add API routes, create endpoints, or generate API documentation.
Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per project.
Scaffold a full-stack Cloudflare app from the vite-flare-starter template — React 19 + Hono + D1+Drizzle + better-auth + Tailwind v4+shadcn/ui + TanStack Query + R2 + Workers AI. Run setup.sh to clone, configure, and deploy. Use whenever the user wants a batteries-included Cloudflare full-stack app, vite-flare-starter scaffold, or a React + Cloudflare app with auth + database + Workers AI ready to go.