From cloudflare
Build stateful AI agents using the Cloudflare Agents SDK. Load when creating agents with persistent state, scheduling, RPC, MCP servers, email handling, or streaming chat. Covers Agent class, AIChatAgent, state management, and Code Mode for reduced token usage.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cloudflare:agents-sdkThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build persistent, stateful AI agents on Cloudflare Workers using the `agents` npm package.
Build persistent, stateful AI agents on Cloudflare Workers using the agents npm package.
npm install agents
Agents require a binding in wrangler.jsonc:
{
"durable_objects": {
// "class_name" must match your Agent class name exactly
"bindings": [{ "name": "Counter", "class_name": "Counter" }]
},
"migrations": [
// Required: list all Agent classes for SQLite storage
{ "tag": "v1", "new_sqlite_classes": ["Counter"] }
]
}
| Use Case | Base Class | Package |
|---|---|---|
| Custom state + RPC, no chat | Agent | agents |
| Chat with message persistence | AIChatAgent | @cloudflare/ai-chat |
| Building an MCP server | McpAgent | agents/mcp |
| Task | API |
|---|---|
| Persist state | this.setState({ count: 1 }) |
| Read state | this.state.count |
| Schedule task | this.schedule(60, "taskMethod", payload) |
| Schedule cron | this.schedule("0 * * * *", "hourlyTask") |
| Cancel schedule | this.cancelSchedule(id) |
| Queue task | this.queue("processItem", payload) |
| SQL query | this.sql`SELECT * FROM users WHERE id = ${id}` |
| RPC method | @callable() async myMethod() { ... } |
| Streaming RPC | @callable({ streaming: true }) async stream(res) { ... } |
import { Agent, routeAgentRequest, callable } from "agents";
type State = { count: number };
export class Counter extends Agent<Env, State> {
initialState = { count: 0 };
@callable()
increment() {
this.setState({ count: this.state.count + 1 });
return this.state.count;
}
}
export default {
fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 })
};
Use AIChatAgent for chat with automatic message persistence and resumable streaming.
Install additional dependencies first:
npm install @cloudflare/ai-chat ai @ai-sdk/openai
Add wrangler.jsonc config (same pattern as base Agent):
{
"durable_objects": {
"bindings": [{ "name": "Chat", "class_name": "Chat" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["Chat"] }]
}
import { AIChatAgent } from "@cloudflare/ai-chat";
import { routeAgentRequest } from "agents";
import { streamText, convertToModelMessages } from "ai";
import { openai } from "@ai-sdk/openai";
export class Chat extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
const result = streamText({
model: openai("gpt-4o"),
messages: await convertToModelMessages(this.messages),
onFinish
});
return result.toUIMessageStreamResponse();
}
}
export default {
fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 })
};
Client (React):
import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";
const agent = useAgent({ agent: "Chat", name: "my-chat" });
const { messages, input, handleSubmit } = useAgentChat({ agent });
Code Mode generates executable JavaScript instead of making individual tool calls. Use it when:
See references/codemode.md for setup and examples.
streamText and toUIMessageStreamResponse() for chatAgent<Env, State> ensures type safety for this.stateschedule() for time-based, queue() for sequential processingnpx claudepluginhub quad1661/skillsGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.