Agents SDK
OpenAIOfficialCreated by CloudflareDistributed by OpenAI
- Skill
- Tool integration
- Cloud and DevOps
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Agents SDK provides a framework for building stateful, durable AI agents directly on Cloudflare Workers. It simplifies the development of complex agentic applications by offering built-in state management, RPC capabilities via WebSockets, durable workflows, and seamless integration with MCP servers. The SDK is designed to handle real-time interactions, scheduled tasks, and email routing, while providing React hooks for easy client-side integration.
What it does
- Enables creation of stateful agents with SQLite-backed persistence.
- Exposes agent methods as callable RPC endpoints via WebSockets.
- Supports durable, multi-step background workflows.
- Integrates with MCP servers for expanded tool capabilities.
- Provides React hooks for real-time agent communication.
- Handles scheduled tasks and cron jobs within the agent lifecycle.
When to use it
- When building stateful AI agents on the Cloudflare Workers platform.
- When you need durable, multi-step workflows for background processing.
- When implementing real-time WebSocket-based communication between clients and agents.
- When connecting to or building MCP servers for agent tool use.
- When you require persistent state that auto-syncs to client applications.
Advantages
- Native integration with Cloudflare Workers and Durable Objects.
- Simplifies complex state management and persistence.
- Reduces round-trips with callable RPC methods.
- Provides robust support for resumable streaming and durable workflows.
- Streamlines client-side development with dedicated React hooks.
Usage examples
- “How do I define a callable method in my Cloudflare Agent?”
- You use the @callable() decorator on your class method, which allows it to be invoked remotely via WebSocket RPC from a client.
- “How can I persist state in my agent?”
- You use the this.setState() method within your Agent class, which updates the SQLite-backed state and triggers any defined validation or update hooks.
- “How do I connect a React frontend to my agent?”
- You use the useAgent hook from the agents/react package, providing the agent name and instance identifier to manage state and communication.
- “Can I run background tasks in my agent?”
- Yes, you can use the this.schedule() or this.scheduleEvery() methods to trigger one-time or recurring tasks, or use AgentWorkflow for durable multi-step processes.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/openai/agents-sdk/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip agents-sdk.zip -d .agents/skills
Documentation by Cloudflare
Cloudflare Agents SDK
Your knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any Agents SDK task.
Retrieval Sources
Fetch current docs from https://github.com/cloudflare/agents/tree/main/docs before implementing.
| Topic | Doc | Use for |
|---|---|---|
| Getting started | docs/getting-started.md | First agent, project setup |
| State | docs/state.md | setState, validateStateChange, persistence |
| Routing | docs/routing.md | URL patterns, routeAgentRequest, basePath |
| Callable methods | docs/callable-methods.md | @callable, RPC, streaming, timeouts |
| Scheduling | docs/scheduling.md | schedule(), scheduleEvery(), cron |
| Workflows | docs/workflows.md | AgentWorkflow, durable multi-step tasks |
| HTTP/WebSockets | docs/http-websockets.md | Lifecycle hooks, hibernation |
docs/email.md | Email routing, secure reply resolver | |
| MCP client | docs/mcp-client.md | Connecting to MCP servers |
| MCP server | docs/mcp-servers.md | Building MCP servers with McpAgent |
| Client SDK | docs/client-sdk.md | useAgent, useAgentChat, React hooks |
| Human-in-the-loop | docs/human-in-the-loop.md | Approval flows, pausing workflows |
| Resumable streaming | docs/resumable-streaming.md | Stream recovery on disconnect |
Cloudflare docs: https://developers.cloudflare.com/agents/
Capabilities
The Agents SDK provides:
Persistent state - SQLite-backed, auto-synced to clients
Callable RPC -
@callable()methods invoked over WebSocketScheduling - One-time, recurring (
scheduleEvery), and cron tasksWorkflows - Durable multi-step background processing via
AgentWorkflowMCP integration - Connect to MCP servers or build your own with
McpAgentEmail handling - Receive and reply to emails with secure routing
Streaming chat -
AIChatAgentwith resumable streamsReact hooks -
useAgent,useAgentChatfor client apps
FIRST: Verify Installation
npm ls agents # Should show agents packageIf not installed:
npm install agentsWrangler Configuration
{
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}Agent Class
import { Agent, routeAgentRequest, callable } from "agents";
type State = { count: number };
export class Counter extends Agent<Env, State> {
initialState = { count: 0 };
// Validation hook - runs before state persists (sync, throwing rejects the update)
validateStateChange(nextState: State, source: Connection | "server") {
if (nextState.count < 0) throw new Error("Count cannot be negative");
}
// Notification hook - runs after state persists (async, non-blocking)
onStateUpdate(state: State, source: Connection | "server") {
console.log("State updated:", state);
}
@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 })
};Routing
Requests route to /agents/{agent-name}/{instance-name}:
| Class | URL |
|---|---|
Counter | /agents/counter/user-123 |
ChatRoom | /agents/chat-room/lobby |
Client: useAgent({ agent: "Counter", name: "user-123" })
Core APIs
| Task | API |
|---|---|
| Read state | this.state.count |
| Write state | this.setState({ count: 1 }) |
| SQL query | this.sql`SELECT * FROM users WHERE id = ${id}` |
| Schedule (delay) | await this.schedule(60, "task", payload) |
| Schedule (cron) | await this.schedule("0 * * * *", "task", payload) |
| Schedule (interval) | await this.scheduleEvery(30, "poll") |
| RPC method | @callable() myMethod() { ... } |
| Streaming RPC | @callable({ streaming: true }) stream(res) { ... } |
| Start workflow | await this.runWorkflow("ProcessingWorkflow", params) |
React Client
import { useAgent } from "agents/react";
function App() {
const [state, setLocalState] = useState({ count: 0 });
const agent = useAgent({
agent: "Counter",
name: "my-instance",
onStateUpdate: (newState) => setLocalState(newState),
onIdentity: (name, agentType) => console.log(`Connected to ${name}`)
});
return (
<button onClick={() => agent.setState({ count: state.count + 1 })}>
Count: {state.count}
</button>
);
}References
references/workflows.md - Durable Workflows integration
references/callable.md - RPC methods, streaming, timeouts
references/state-scheduling.md - State persistence, scheduling
references/streaming-chat.md - AIChatAgent, resumable streams
references/mcp.md - MCP server integration
references/email.md - Email routing and handling
references/codemode.md - Code Mode (experimental)
Files
- ATTRIBUTION.mdAdded by AutoGineer906 B
- LICENSE.txt10.5 KiB
- SKILL.md5.5 KiB
- agents/openai.yaml342 B
- assets/cloudflare-small.svg1.2 KiB
- assets/cloudflare.png1.2 KiB
- references/callable.md2.1 KiB
- references/codemode.md5.3 KiB
- references/email.md3.5 KiB
- references/mcp.md3.5 KiB
- references/state-scheduling.md3.7 KiB
- references/streaming-chat.md4.1 KiB
- references/workflows.md3.8 KiB
references/email.md
Email Handling
Fetch docs/email.md from https://github.com/cloudflare/agents/tree/main/docs for complete documentation.
Overview
Agents receive and reply to emails via Cloudflare Email Routing.
Wrangler Configuration
{
"durable_objects": {
"bindings": [{ "name": "EmailAgent", "class_name": "EmailAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["EmailAgent"] }],
"send_email": [
{ "name": "SEB", "destination_address": "[email protected]" }
]
}Basic Email Handler
import { Agent } from "agents";
import { type AgentEmail } from "agents/email";
import PostalMime from "postal-mime";
export class EmailAgent extends Agent<Env, State> {
async onEmail(email: AgentEmail) {
const raw = await email.getRaw();
const parsed = await PostalMime.parse(raw);
console.log("From:", email.from);
console.log("Subject:", parsed.subject);
await this.replyToEmail(email, {
fromName: "My Agent",
subject: `Re: ${parsed.subject}`,
body: "Thanks for your email!"
});
}
}Routing Emails
import { routeAgentRequest, routeAgentEmail } from "agents";
import { createAddressBasedEmailResolver } from "agents/email";
export default {
async email(message, env) {
await routeAgentEmail(message, env, {
resolver: createAddressBasedEmailResolver("EmailAgent")
});
},
async fetch(request, env) {
return routeAgentRequest(request, env) ?? new Response("Not found", { status: 404 });
}
};Resolvers
Address-Based (Inbound Mail)
Routes based on recipient address:
import { createAddressBasedEmailResolver } from "agents/email";
const resolver = createAddressBasedEmailResolver("EmailAgent");
// [email protected] → EmailAgent, instance "support"
// [email protected] → NotificationAgent, instance "user123"Secure Reply (Reply Flows)
Verifies replies are authentic using HMAC-SHA256 signatures:
import { createSecureReplyEmailResolver } from "agents/email";
const resolver = createSecureReplyEmailResolver(env.EMAIL_SECRET, {
maxAge: 7 * 24 * 60 * 60, // 7 days (default: 30 days)
onInvalidSignature: (email, reason) => {
console.warn(`Invalid signature from ${email.from}: ${reason}`);
}
});Sign outbound emails to enable secure reply routing:
await this.replyToEmail(email, {
fromName: "My Agent",
body: "Thanks!",
secret: this.env.EMAIL_SECRET // Signs headers for secure reply routing
});Catch-All (Single Instance)
Routes all emails to one agent instance:
import { createCatchAllEmailResolver } from "agents/email";
const resolver = createCatchAllEmailResolver("EmailAgent", "default");Combining Resolvers
async email(message, env) {
const secureReply = createSecureReplyEmailResolver(env.EMAIL_SECRET);
const addressBased = createAddressBasedEmailResolver("EmailAgent");
await routeAgentEmail(message, env, {
resolver: async (email, env) => {
// Try secure reply first
const result = await secureReply(email, env);
if (result) return result;
// Fall back to address-based
return addressBased(email, env);
}
});
}Utilities
import { isAutoReplyEmail } from "agents/email";
async onEmail(email: AgentEmail) {
if (isAutoReplyEmail(email.headers)) {
// Skip auto-replies (vacation, out-of-office, etc.)
return;
}
// Process email...
}Requirements and compatibility
Written for: OpenAI Codex
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server, Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Cloudflare
- Publisher
- OpenAI (Official)
- Distributed by
- OpenAI
- Source
- openai/plugins · plugins/cloudflare/skills/agents-sdk · commit d420d13
- Licence
- Apache License 2.0 (redistribution allowed)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Cloudflare or OpenAI.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download agents-sdk.zip