Builds AI agents on Cloudflare using the Agents SDK with state management, real-time WebSockets, scheduled tasks, tool integration, and chat capabilities. Generates production-ready agent code deployed to Workers. Use when: user wants to "build an agent", "AI agent", "chat agent", "stateful agent", mentions "Agents SDK", needs "real-time AI", "WebSocket AI", or asks about agent "state management", "scheduled tasks", or "tool calling". Biases towards retrieval from Cloudflare docs over pre-trained knowledge.
Generates Cloudflare Workers code for AI agents with state management, WebSockets, scheduled tasks, and tool integration.
npx claudepluginhub cloudflare/skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/agent-patterns.mdreferences/examples.mdreferences/state-patterns.mdreferences/troubleshooting.mdYour knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any agent-building task.
| Source | How to retrieve | Use for |
|---|---|---|
| Agents SDK docs | https://github.com/cloudflare/agents/tree/main/docs | SDK API, state, routing, scheduling |
| Cloudflare Agents docs | https://developers.cloudflare.com/agents/ | Platform integration, deployment |
| Workers docs | Search tool or https://developers.cloudflare.com/workers/ | Runtime APIs, bindings, config |
npm install -g wrangler)npm create cloudflare@latest -- my-agent --template=cloudflare/agents-starter
cd my-agent
npm start
Agent runs at http://localhost:8787
An Agent is a stateful, persistent AI service that:
Client connects → Agent.onConnect() → Agent processes messages
→ Agent.onMessage()
→ Agent.setState() (persists + syncs)
Client disconnects → State persists → Client reconnects → State restored
import { Agent, Connection } from "agents";
interface Env {
AI: Ai; // Workers AI binding
}
interface State {
messages: Array<{ role: string; content: string }>;
preferences: Record<string, string>;
}
export class MyAgent extends Agent<Env, State> {
// Initial state for new instances
initialState: State = {
messages: [],
preferences: {},
};
// Called when agent starts or resumes
async onStart() {
console.log("Agent started with state:", this.state);
}
// Handle WebSocket connections
async onConnect(connection: Connection) {
connection.send(JSON.stringify({
type: "welcome",
history: this.state.messages,
}));
}
// Handle incoming messages
async onMessage(connection: Connection, message: string) {
const data = JSON.parse(message);
if (data.type === "chat") {
await this.handleChat(connection, data.content);
}
}
// Handle disconnections
async onClose(connection: Connection) {
console.log("Client disconnected");
}
// React to state changes
onStateUpdate(state: State, source: string) {
console.log("State updated by:", source);
}
private async handleChat(connection: Connection, userMessage: string) {
// Add user message to history
const messages = [
...this.state.messages,
{ role: "user", content: userMessage },
];
// Call AI
const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
messages,
});
// Update state (persists and syncs to all clients)
this.setState({
...this.state,
messages: [
...messages,
{ role: "assistant", content: response.response },
],
});
// Send response
connection.send(JSON.stringify({
type: "response",
content: response.response,
}));
}
}
// src/index.ts
import { routeAgentRequest } from "agents";
import { MyAgent } from "./agent";
export default {
async fetch(request: Request, env: Env) {
// routeAgentRequest handles routing to /agents/:class/:name
return (
(await routeAgentRequest(request, env)) ||
new Response("Not found", { status: 404 })
);
},
};
export { MyAgent };
Clients connect via: wss://my-agent.workers.dev/agents/MyAgent/session-id
name = "my-agent"
main = "src/index.ts"
compatibility_date = "2024-12-01"
[ai]
binding = "AI"
[durable_objects]
bindings = [{ name = "AGENT", class_name = "MyAgent" }]
[[migrations]]
tag = "v1"
new_classes = ["MyAgent"]
// Current state is always available
const currentMessages = this.state.messages;
const userPrefs = this.state.preferences;
// setState persists AND syncs to all connected clients
this.setState({
...this.state,
messages: [...this.state.messages, newMessage],
});
// Partial updates work too
this.setState({
preferences: { ...this.state.preferences, theme: "dark" },
});
For complex queries, use the embedded SQLite database:
// Create tables
await this.sql`
CREATE TABLE IF NOT EXISTS documents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`;
// Insert
await this.sql`
INSERT INTO documents (title, content)
VALUES (${title}, ${content})
`;
// Query
const docs = await this.sql`
SELECT * FROM documents WHERE title LIKE ${`%${search}%`}
`;
Agents can schedule future work:
async onMessage(connection: Connection, message: string) {
const data = JSON.parse(message);
if (data.type === "schedule_reminder") {
// Schedule task for 1 hour from now
const { id } = await this.schedule(3600, "sendReminder", {
message: data.reminderText,
userId: data.userId,
});
connection.send(JSON.stringify({ type: "scheduled", taskId: id }));
}
}
// Called when scheduled task fires
async sendReminder(data: { message: string; userId: string }) {
// Send notification, email, etc.
console.log(`Reminder for ${data.userId}: ${data.message}`);
// Can also update state
this.setState({
...this.state,
lastReminder: new Date().toISOString(),
});
}
// Delay in seconds
await this.schedule(60, "taskMethod", { data });
// Specific date
await this.schedule(new Date("2025-01-01T00:00:00Z"), "taskMethod", { data });
// Cron expression (recurring)
await this.schedule("0 9 * * *", "dailyTask", {}); // 9 AM daily
await this.schedule("*/5 * * * *", "everyFiveMinutes", {}); // Every 5 min
// Manage schedules
const schedules = await this.getSchedules();
await this.cancelSchedule(taskId);
For chat-focused agents, extend AIChatAgent:
import { AIChatAgent } from "agents/ai-chat-agent";
export class ChatBot extends AIChatAgent<Env> {
// Called for each user message
async onChatMessage(message: string) {
const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", {
messages: [
{ role: "system", content: "You are a helpful assistant." },
...this.messages, // Automatic history management
{ role: "user", content: message },
],
stream: true,
});
// Stream response back to client
return response;
}
}
Features included:
saveMessages() for persistenceimport { useAgent } from "agents/react";
function Chat() {
const { state, send, connected } = useAgent({
agent: "my-agent",
name: userId, // Agent instance ID
});
const sendMessage = (text: string) => {
send(JSON.stringify({ type: "chat", content: text }));
};
return (
<div>
{state.messages.map((msg, i) => (
<div key={i}>{msg.role}: {msg.content}</div>
))}
<input onKeyDown={(e) => e.key === "Enter" && sendMessage(e.target.value)} />
</div>
);
}
const ws = new WebSocket("wss://my-agent.workers.dev/agents/MyAgent/user123");
ws.onopen = () => {
console.log("Connected to agent");
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Received:", data);
};
ws.send(JSON.stringify({ type: "chat", content: "Hello!" }));
See references/agent-patterns.md for:
# Deploy
npx wrangler deploy
# View logs
wrangler tail
# Test endpoint
curl https://my-agent.workers.dev/agents/MyAgent/test-user
See references/troubleshooting.md for common issues.
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Search, retrieve, and install Agent Skills from the prompts.chat registry using MCP tools. Use when the user asks to find skills, browse skill catalogs, install a skill for Claude, or extend Claude's capabilities with reusable AI agent components.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.