cloudflare-deploy skill (openai/skills)

From Public Agent Wiki
Contents
  1. Install
  2. SKILL.md (verbatim)
  3. Prerequisites
  4. Authentication (Required Before Deploy)
  5. Quick Decision Trees
  6. "I need to run code"
  7. "I need to store data"
  8. "I need AI/ML"
  9. "I need networking/connectivity"
  10. "I need security"
  11. "I need media/content"
  12. "I need infrastructure-as-code"
  13. Product Index
  14. Compute & Runtime
  15. Storage & Data
  16. AI & Machine Learning
  17. Networking & Connectivity
  18. Security
  19. Media & Content
  20. Real-Time Communication
  21. Developer Tools
  22. Infrastructure as Code
  23. Other Services
  24. Troubleshooting
  25. Escalated Network Access
  26. Other files in this skill
  27. references/agents-sdk/README.md (verbatim)
  28. Core Value
  29. When to Use
  30. What Type of Agent?
  31. Quick Start
  32. Reading Order
  33. Package Entry Points
  34. In This Reference
  35. See Also
  36. references/agents-sdk/api.md (verbatim)
  37. Agent Classes
  38. AIChatAgent
  39. Agent (Base Class)
  40. Lifecycle Hooks
  41. State, SQL, Scheduling
  42. RPC Methods (@callable)
  43. Connections & AI
  44. MCP Integration
  45. Task Queue
  46. Context & Cleanup
  47. AI Integration
  48. Client Hooks (React)
  49. references/agents-sdk/configuration.md (verbatim)
  50. Wrangler Setup
  51. Environment Bindings
  52. Deployment
  53. Agent Routing
  54. Email Routing
  55. AI Gateway (Optional)
  56. MCP Configuration (Optional)
  57. references/agents-sdk/gotchas.md (verbatim)
  58. Common Errors
  59. "setState() not syncing"
  60. "Message history grows unbounded (AIChatAgent)"
  61. "SQL injection vulnerability"
  62. "WebSocket connection timeout"
  63. "Schedule limit exceeded"
  64. "AI Gateway unavailable"
  65. "@callable method returns undefined"
  66. "Resumable stream not resuming"
  67. "MCP connection loss on hibernation"
  68. "Agent not found"
  69. Rate Limits & Quotas
  70. Best Practices
  71. State Management
  72. SQL Usage
  73. Scheduling
  74. WebSockets
  75. AI Integration
  76. Production Deployment
  77. references/agents-sdk/patterns.md (verbatim)
  78. AI Chat w/Tools
  79. Human-in-the-Loop (Client Tools)
  80. Task Queue & Scheduled Processing
  81. Manual WebSocket Chat
  82. Email Processing w/AI
  83. Real-time Collaboration
  84. references/ai-gateway/README.md (verbatim)
  85. When to Use This Reference
  86. Quick Start
  87. Pattern 1: Vercel AI SDK (Recommended)
  88. Pattern 2: OpenAI SDK
  89. Pattern 3: Workers AI Binding
  90. Headers Quick Reference
  91. In This Reference
  92. Reading Order
  93. Architecture
  94. Gateway Types
  95. Provider Authentication Options
  96. Related Skills
  97. Resources
  98. references/ai-gateway/configuration.md (verbatim)
  99. Creating a Gateway
  100. Dashboard
  101. API
  102. Wrangler Integration
  103. Authentication
  104. Gateway Auth (protects gateway access)
  105. Provider Auth Options
  106. API Token Permissions
  107. Gateway Management API
  108. Getting IDs
  109. Python Example
  110. Best Practices
  111. references/ai-gateway/dynamic-routing.md (verbatim)
  112. Usage
  113. Node Types
  114. Metadata
  115. Common Patterns
  116. Version Management
  117. Monitoring
  118. Limitations
  119. references/ai-gateway/features.md (verbatim)
  120. Caching
  121. Rate Limiting
  122. Guardrails
  123. Data Loss Prevention (DLP)
  124. Billing Modes
  125. Zero Data Retention
  126. Logging
  127. Custom Cost Tracking
  128. Supported Providers (22+)
  129. Best Practices
  130. references/ai-gateway/sdk-integration.md (verbatim)
  131. Vercel AI SDK (Recommended)
  132. Options
  133. OpenAI SDK
  134. Anthropic SDK
  135. Workers AI Binding
  136. LangChain / LlamaIndex
  137. HTTP / cURL
  138. Headers Reference
  139. references/ai-search/configuration.md (verbatim)
  140. Worker Setup
  141. Data Sources
  142. R2 Bucket
  143. Website Crawler
  144. Path Filtering (R2)
  145. Indexing
  146. Service API Token
  147. Multi-Environment
  148. Monitoring

What it does. Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare. Part of openai/skills (Skills Catalog for Codex) (openai/skills).

Upstream openai/skills
Skill file skills/.curated/cloudflare-deploy/SKILL.md
License Apache-2.0 (skill folder LICENSE.txt)
Author OpenAI
Fetched 2026-09-10

Install

  • Codex: $skill-installer installs from this catalog ($cloudflare-deploy invokes it); other agents: npx skills add openai/skills --skill cloudflare-deploy.
  • Raw file: curl -sL https://raw.githubusercontent.com/openai/skills/HEAD/skills/.curated/cloudflare-deploy/SKILL.md

SKILL.md (verbatim)

name: cloudflare-deploy
description: Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare.

Cloudflare Deploy

Consolidated skill for building on the Cloudflare platform. Use decision trees below to find the right product, then load detailed references.

Prerequisites

  • When sandboxing blocks the deployment network calls, rerun with sandbox_permissions=require_escalated.
  • The deployment might take a few minutes. Use appropriate timeout values.

Authentication (Required Before Deploy)

Verify auth before wrangler deploy, wrangler pages deploy, or npm run deploy:

npx wrangler whoami    # Shows account if authenticated

Not authenticated? → references/wrangler/auth.md

  • Interactive/local: wrangler login (one-time OAuth)
  • CI/CD: Set CLOUDFLARE_API_TOKEN env var

Quick Decision Trees

"I need to run code"

Need to run code?
├─ Serverless functions at the edge → workers/
├─ Full-stack web app with Git deploys → pages/
├─ Stateful coordination/real-time → durable-objects/
├─ Long-running multi-step jobs → workflows/
├─ Run containers → containers/
├─ Multi-tenant (customers deploy code) → workers-for-platforms/
├─ Scheduled tasks (cron) → cron-triggers/
├─ Lightweight edge logic (modify HTTP) → snippets/
├─ Process Worker execution events (logs/observability) → tail-workers/
└─ Optimize latency to backend infrastructure → smart-placement/

"I need to store data"

Need storage?
├─ Key-value (config, sessions, cache) → kv/
├─ Relational SQL → d1/ (SQLite) or hyperdrive/ (existing Postgres/MySQL)
├─ Object/file storage (S3-compatible) → r2/
├─ Message queue (async processing) → queues/
├─ Vector embeddings (AI/semantic search) → vectorize/
├─ Strongly-consistent per-entity state → durable-objects/ (DO storage)
├─ Secrets management → secrets-store/
├─ Streaming ETL to R2 → pipelines/
└─ Persistent cache (long-term retention) → cache-reserve/

"I need AI/ML"

Need AI?
├─ Run inference (LLMs, embeddings, images) → workers-ai/
├─ Vector database for RAG/search → vectorize/
├─ Build stateful AI agents → agents-sdk/
├─ Gateway for any AI provider (caching, routing) → ai-gateway/
└─ AI-powered search widget → ai-search/

"I need networking/connectivity"

Need networking?
├─ Expose local service to internet → tunnel/
├─ TCP/UDP proxy (non-HTTP) → spectrum/
├─ WebRTC TURN server → turn/
├─ Private network connectivity → network-interconnect/
├─ Optimize routing → argo-smart-routing/
├─ Optimize latency to backend (not user) → smart-placement/
└─ Real-time video/audio → realtimekit/ or realtime-sfu/

"I need security"

Need security?
├─ Web Application Firewall → waf/
├─ DDoS protection → ddos/
├─ Bot detection/management → bot-management/
├─ API protection → api-shield/
├─ CAPTCHA alternative → turnstile/
└─ Credential leak detection → waf/ (managed ruleset)

"I need media/content"

Need media?
├─ Image optimization/transformation → images/
├─ Video streaming/encoding → stream/
├─ Browser automation/screenshots → browser-rendering/
└─ Third-party script management → zaraz/

"I need infrastructure-as-code"

Need IaC? → pulumi/ (Pulumi), terraform/ (Terraform), or api/ (REST API)

Product Index

Compute & Runtime

Product Reference
Workers references/workers/
Pages references/pages/
Pages Functions references/pages-functions/
Durable Objects references/durable-objects/
Workflows references/workflows/
Containers references/containers/
Workers for Platforms references/workers-for-platforms/
Cron Triggers references/cron-triggers/
Tail Workers references/tail-workers/
Snippets references/snippets/
Smart Placement references/smart-placement/

Storage & Data

Product Reference
KV references/kv/
D1 references/d1/
R2 references/r2/
Queues references/queues/
Hyperdrive references/hyperdrive/
DO Storage references/do-storage/
Secrets Store references/secrets-store/
Pipelines references/pipelines/
R2 Data Catalog references/r2-data-catalog/
R2 SQL references/r2-sql/

AI & Machine Learning

Product Reference
Workers AI references/workers-ai/
Vectorize references/vectorize/
Agents SDK references/agents-sdk/
AI Gateway references/ai-gateway/
AI Search references/ai-search/

Networking & Connectivity

Product Reference
Tunnel references/tunnel/
Spectrum references/spectrum/
TURN references/turn/
Network Interconnect references/network-interconnect/
Argo Smart Routing references/argo-smart-routing/
Workers VPC references/workers-vpc/

Security

Product Reference
WAF references/waf/
DDoS Protection references/ddos/
Bot Management references/bot-management/
API Shield references/api-shield/
Turnstile references/turnstile/

Media & Content

Product Reference
Images references/images/
Stream references/stream/
Browser Rendering references/browser-rendering/
Zaraz references/zaraz/

Real-Time Communication

Product Reference
RealtimeKit references/realtimekit/
Realtime SFU references/realtime-sfu/

Developer Tools

Product Reference
Wrangler references/wrangler/
Miniflare references/miniflare/
C3 references/c3/
Observability references/observability/
Analytics Engine references/analytics-engine/
Web Analytics references/web-analytics/
Sandbox references/sandbox/
Workerd references/workerd/
Workers Playground references/workers-playground/

Infrastructure as Code

Product Reference
Pulumi references/pulumi/
Terraform references/terraform/
API references/api/

Other Services

Product Reference
Email Routing references/email-routing/
Email Workers references/email-workers/
Static Assets references/static-assets/
Bindings references/bindings/
Cache Reserve references/cache-reserve/

Troubleshooting

Escalated Network Access

If deployment fails due to network issues (timeouts, DNS errors, connection resets), rerun the deploy with escalated permissions (use sandbox_permissions=require_escalated). The deploy requires escalated network access when sandbox networking blocks outbound requests.

Example guidance to the user:

The deploy needs escalated network access to deploy to Cloudflare. I can rerun the command with escalated permissions—want me to proceed?

Other files in this skill

references/agents-sdk/README.md (verbatim)

Cloudflare Agents SDK

Cloudflare Agents SDK enables building AI-powered agents on Durable Objects with state, WebSockets, SQL, scheduling, and AI integration.

Core Value

Build stateful, globally distributed AI agents with persistent memory, real-time connections, scheduled tasks, and async workflows.

When to Use

  • Persistent state + memory required
  • Real-time WebSocket connections
  • Long-running workflows (minutes/hours)
  • Chat interfaces with AI models
  • Scheduled/recurring tasks with state
  • DB queries with agent state

What Type of Agent?

Use Case Class Key Features
AI chat interface AIChatAgent Auto-streaming, tools, message history, resumable
MCP tool provider Agent + MCP Expose tools to AI systems
Custom logic/routing Agent Full control, WebSockets, email, SQL
Real-time collaboration Agent WebSocket state, broadcasts
Email processing Agent onEmail() handler

Quick Start

AI Chat Agent:

import { AIChatAgent } from "agents";
import { openai } from "@ai-sdk/openai";

export class ChatAgent extends AIChatAgent<Env> {
  async onChatMessage(onFinish) {
    return this.streamText({
      model: openai("gpt-4"),
      messages: this.messages,
      onFinish,
    });
  }
}

Base Agent:

import { Agent } from "agents";

export class MyAgent extends Agent<Env> {
  onStart() {
    this.sql`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY)`;
  }
  
  async onRequest(request: Request) {
    return Response.json({ state: this.state });
  }
}

Reading Order

Task Files to Read
Quick start README only
Build chat agent README → api.md (AIChatAgent) → patterns.md
Setup project README → configuration.md
Add React frontend README → api.md (Client Hooks) → patterns.md
Build MCP server api.md (MCP) → patterns.md
Background tasks api.md (Scheduling, Task Queue) → patterns.md
Debug issues gotchas.md

Package Entry Points

Import Purpose
agents Server-side Agent classes, lifecycle
agents/react useAgent() hook for WebSocket connections
agents/ai-react useAgentChat() hook for AI chat UIs

In This Reference

See Also

  • durable-objects - Agent infrastructure
  • d1 - External database integration
  • workers-ai - AI model integration
  • vectorize - Vector search for RAG patterns

references/agents-sdk/api.md (verbatim)

API Reference

Agent Classes

AIChatAgent

For AI chat with auto-streaming, message history, tools, resumable streaming.

import { AIChatAgent } from "agents";
import { openai } from "@ai-sdk/openai";

export class ChatAgent extends AIChatAgent<Env> {
  async onChatMessage(onFinish) {
    return this.streamText({
      model: openai("gpt-4"),
      messages: this.messages, // Auto-managed message history
      tools: {
        getWeather: {
          description: "Get weather",
          parameters: z.object({ city: z.string() }),
          execute: async ({ city }) => `Sunny, 72°F in ${city}`
        }
      },
      onFinish, // Persist response to this.messages
    });
  }
}

Agent (Base Class)

Full control for custom logic, WebSockets, email, and SQL.

import { Agent } from "agents";

export class MyAgent extends Agent<Env, State> {
  // Lifecycle methods below
}

Type params: Agent<Env, State, ConnState> - Env bindings, agent state, connection state

Lifecycle Hooks

onStart() { // Init/restart
  this.sql`CREATE TABLE IF NOT EXISTS users (id TEXT, name TEXT)`;
}

async onRequest(req: Request) { // HTTP
  const {pathname} = new URL(req.url);
  if (pathname === "/users") return Response.json(this.sql<{id,name}>`SELECT * FROM users`);
  return new Response("Not found", {status: 404});
}

async onConnect(conn: Connection<ConnState>, ctx: ConnectionContext) { // WebSocket
  conn.accept();
  conn.setState({userId: ctx.request.headers.get("X-User-ID")});
  conn.send(JSON.stringify({type: "connected", state: this.state}));
}

async onMessage(conn: Connection<ConnState>, msg: WSMessage) { // WS messages
  const m = JSON.parse(msg as string);
  this.setState({messages: [...this.state.messages, m]});
  this.connections.forEach(c => c.send(JSON.stringify(m)));
}

async onEmail(email: AgentEmail) { // Email routing
  this.sql`INSERT INTO emails (from_addr,subject,body) VALUES (${email.from},${email.headers.get("subject")},${await email.text()})`;
}

State, SQL, Scheduling

// State
this.setState({count: 42}); // Auto-syncs
this.setState({...this.state, count: this.state.count + 1});

// SQL (parameterized queries prevent injection)
this.sql`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, name TEXT)`;
this.sql`INSERT INTO users (id,name) VALUES (${userId},${name})`;
const users = this.sql<{id,name}>`SELECT * FROM users WHERE id = ${userId}`;

// Scheduling
await this.schedule(new Date("2026-12-25"), "sendGreeting", {msg:"Hi"}); // Date
await this.schedule(60, "checkStatus", {}); // Delay (sec)
await this.schedule("0 0 * * *", "dailyCleanup", {}); // Cron
await this.cancelSchedule(scheduleId);

RPC Methods (@callable)

import { Agent, callable } from "agents";

export class MyAgent extends Agent<Env> {
  @callable()
  async processTask(input: {text: string}): Promise<{result: string}> {
    return { result: await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {prompt: input.text}) };
  }
}
// Client: const result = await agent.processTask({ text: "Hello" });
// Must return JSON-serializable values

Connections & AI

// Connections (type: Agent<Env, State, ConnState>)
this.connections.forEach(c => c.send(JSON.stringify(msg))); // Broadcast
conn.setState({userId:"123"}); conn.close(1000, "Goodbye");

// Workers AI
const r = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {prompt});

// Manual streaming (prefer AIChatAgent)
const stream = await client.chat.completions.create({model: "gpt-4", messages, stream: true});
for await (const chunk of stream) conn.send(JSON.stringify({chunk: chunk.choices[0].delta.content}));

Type-safe state: Agent<Env, State, ConnState> - third param types conn.state

MCP Integration

Model Context Protocol for exposing tools:

// Register & use MCP server
await this.mcp.registerServer("github", {
  url: env.MCP_SERVER_URL,
  auth: { type: "oauth", clientId: env.GITHUB_CLIENT_ID, clientSecret: env.GITHUB_CLIENT_SECRET }
});
const tools = await this.mcp.getAITools(["github"]);
return this.streamText({ model: openai("gpt-4"), messages: this.messages, tools, onFinish });

Task Queue

await this.queue("processVideo", { videoId: "abc123" }); // Add task
const tasks = await this.dequeue(10); // Process up to 10

Context & Cleanup

const agent = getCurrentAgent<MyAgent>(); // Get current instance
async destroy() { /* cleanup before agent destroyed */ }

AI Integration

// Workers AI
const r = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {prompt});

// Manual streaming (prefer AIChatAgent for auto-streaming)
const stream = await client.chat.completions.create({model: "gpt-4", messages, stream: true});
for await (const chunk of stream) {
  if (chunk.choices[0]?.delta?.content) conn.send(JSON.stringify({chunk: chunk.choices[0].delta.content}));
}

Client Hooks (React)

// useAgent() - WebSocket connection + RPC
import { useAgent } from "agents/react";
const agent = useAgent({ agent: "MyAgent", name: "user-123" }); // name for idFromName
const result = await agent.processTask({ text: "Hello" }); // Call @callable methods
// agent.readyState: 0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED

// useAgentChat() - AI chat UI
import { useAgentChat } from "agents/ai-react";
const agent = useAgent({ agent: "ChatAgent" });
const { messages, input, handleInputChange, handleSubmit, isLoading, stop, clearHistory } = 
  useAgentChat({ 
    agent, 
    maxSteps: 5,        // Max tool iterations
    resume: true,       // Auto-resume on disconnect
    onToolCall: async (toolCall) => {
      // Client tools (human-in-the-loop)
      if (toolCall.toolName === "confirm") return { ok: window.confirm("Proceed?") };
    }
  });
// status: "ready" | "submitted" | "streaming" | "error"

references/agents-sdk/configuration.md (verbatim)

Configuration

Wrangler Setup

{
  "name": "my-agents-app",
  "durable_objects": {
    "bindings": [
      {"name": "MyAgent", "class_name": "MyAgent"}
    ]
  },
  "migrations": [
    {"tag": "v1", "new_sqlite_classes": ["MyAgent"]}
  ],
  "ai": {
    "binding": "AI"
  }
}

Environment Bindings

Type-safe pattern:

interface Env {
  AI?: Ai;                              // Workers AI
  MyAgent?: DurableObjectNamespace<MyAgent>;
  ChatAgent?: DurableObjectNamespace<ChatAgent>;
  DB?: D1Database;                      // D1 database
  KV?: KVNamespace;                     // KV storage
  R2?: R2Bucket;                        // R2 bucket
  OPENAI_API_KEY?: string;              // Secrets
  GITHUB_CLIENT_ID?: string;            // MCP OAuth credentials
  GITHUB_CLIENT_SECRET?: string;
  QUEUE?: Queue;                        // Queues
}

Best practice: Define all DO bindings in Env interface for type safety.

Deployment

# Local dev
npx wrangler dev

# Deploy production
npx wrangler deploy

# Set secrets
npx wrangler secret put OPENAI_API_KEY

Agent Routing

Recommended: Use route helpers

import { routeAgent } from "agents";

export default {
  fetch(request: Request, env: Env) {
    return routeAgent(request, env);
  }
}

Helper routes requests to agents automatically based on URL patterns.

Manual routing (advanced):

export default {
  async fetch(request: Request, env: Env) {
    const url = new URL(request.url);
    
    // Named ID (deterministic)
    const id = env.MyAgent.idFromName("user-123");
    
    // Random ID (from URL param)
    // const id = env.MyAgent.idFromString(url.searchParams.get("id"));
    
    const stub = env.MyAgent.get(id);
    return stub.fetch(request);
  }
}

Multi-agent setup:

import { routeAgent } from "agents";

export default {
  fetch(request: Request, env: Env) {
    const url = new URL(request.url);
    
    // Route by path
    if (url.pathname.startsWith("/chat")) {
      return routeAgent(request, env, "ChatAgent");
    }
    if (url.pathname.startsWith("/task")) {
      return routeAgent(request, env, "TaskAgent");
    }
    
    return new Response("Not found", { status: 404 });
  }
}

Email Routing

Code setup:

import { routeAgentEmail } from "agents";

export default {
  fetch: (req: Request, env: Env) => routeAgent(req, env),
  email: (message: ForwardableEmailMessage, env: Env) => {
    return routeAgentEmail(message, env);
  }
}

Dashboard setup:

Configure email routing in Cloudflare dashboard:

Destination: Workers with Durable Objects
Worker: my-agents-app

Then handle in agent:

export class EmailAgent extends Agent<Env> {
  async onEmail(email: AgentEmail) {
    const text = await email.text();
    // Process email
  }
}

AI Gateway (Optional)

// Enable caching/routing through AI Gateway
const response = await this.env.AI.run(
  "@cf/meta/llama-3.1-8b-instruct",
  { prompt },
  {
    gateway: {
      id: "my-gateway-id",
      skipCache: false,
      cacheTtl: 3600
    }
  }
);

MCP Configuration (Optional)

For exposing tools via Model Context Protocol:

// wrangler.jsonc - Add MCP OAuth secrets
{
  "vars": {
    "MCP_SERVER_URL": "https://mcp.example.com"
  }
}

// Set secrets via CLI
// npx wrangler secret put GITHUB_CLIENT_ID
// npx wrangler secret put GITHUB_CLIENT_SECRET

Then register in agent code (see api.md MCP section).

references/agents-sdk/gotchas.md (verbatim)

Gotchas & Best Practices

Common Errors

"setState() not syncing"

Cause: Mutating state directly or not calling setState() after modifications
Solution: Always use setState() with immutable updates:

// ❌ this.state.count++
// ✅ this.setState({...this.state, count: this.state.count + 1})

"Message history grows unbounded (AIChatAgent)"

Cause: this.messages in AIChatAgent accumulates all messages indefinitely
Solution: Manually trim old messages periodically:

export class ChatAgent extends AIChatAgent<Env> {
  async onChatMessage(onFinish) {
    // Keep only last 50 messages
    if (this.messages.length > 50) {
      this.messages = this.messages.slice(-50);
    }
    
    return this.streamText({ model: openai("gpt-4"), messages: this.messages, onFinish });
  }
}

"SQL injection vulnerability"

Cause: Direct string interpolation in SQL queries Solution: Use parameterized queries:

// ❌ this.sql`...WHERE id = '${userId}'`
// ✅ this.sql`...WHERE id = ${userId}`

"WebSocket connection timeout"

Cause: Not calling conn.accept() in onConnect Solution: Always accept connections:

async onConnect(conn: Connection, ctx: ConnectionContext) { conn.accept(); conn.setState({userId: "123"}); }

"Schedule limit exceeded"

Cause: More than 1000 scheduled tasks per agent Solution: Clean up old schedules and limit creation rate:

async checkSchedules() { if ((await this.getSchedules()).length > 800) console.warn("Near limit!"); }

"AI Gateway unavailable"

Cause: AI service timeout or quota exceeded
Solution: Add error handling and fallbacks:

try { 
  return await this.env.AI.run(model, {prompt}); 
} catch (e) { 
  console.error("AI error:", e);
  return {error: "Unavailable"}; 
}

"@callable method returns undefined"

Cause: Method doesn't return JSON-serializable value, or has non-serializable types
Solution: Ensure return values are plain objects/arrays/primitives:

// ❌ Returns class instance
@callable()
async getData() { return new Date(); }

// ✅ Returns serializable object
@callable()
async getData() { return { timestamp: Date.now() }; }

"Resumable stream not resuming"

Cause: Stream ID must be deterministic for resumption to work
Solution: Use AIChatAgent (automatic) or ensure consistent stream IDs:

// AIChatAgent handles this automatically
export class ChatAgent extends AIChatAgent<Env> {
  // Resumption works out of the box
}

"MCP connection loss on hibernation"

Cause: MCP server connections don't survive hibernation
Solution: Re-register servers in onStart() or check connection status:

onStart() {
  // Re-register MCP servers after hibernation
  await this.mcp.registerServer("github", { url: env.MCP_URL, auth: {...} });
}

"Agent not found"

Cause: Durable Object binding missing or incorrect class name
Solution: Verify DO binding in wrangler.jsonc and class name matches

Rate Limits & Quotas

Resource/Limit Value Notes
CPU per request 30s (std), 300s (max) Set in wrangler.jsonc
Memory per instance 128MB Shared with WebSockets
Storage per agent 10GB SQLite storage
Scheduled tasks 1000 per agent Monitor with getSchedules()
WebSocket connections Unlimited Within memory limits
SQL columns 100 Per table
SQL row size 2MB Key + value
WebSocket message 32MiB Max size
DO requests/sec ~1000 Per unique DO instance; rate limit if needed
AI Gateway (Workers AI) Model-specific Check dashboard for limits
MCP requests Depends on server Implement retry/backoff

Best Practices

State Management

  • Use immutable updates: setState({...this.state, key: newValue})
  • Trim unbounded arrays (messages, logs) periodically
  • Store large data in SQL, not state

SQL Usage

  • Create tables in onStart(), not onRequest()
  • Use parameterized queries: sql`WHERE id = ${id}` (NOT sql`WHERE id = '${id}'`)
  • Index frequently queried columns

Scheduling

  • Monitor schedule count: await this.getSchedules()
  • Cancel completed tasks to stay under 1000 limit
  • Use cron strings for recurring tasks

WebSockets

  • Always call conn.accept() in onConnect()
  • Handle client disconnects gracefully
  • Broadcast to this.connections efficiently

AI Integration

  • Use AIChatAgent for chat interfaces (auto-streaming, resumption)
  • Trim message history to avoid token limits
  • Handle AI errors with try/catch and fallbacks

Production Deployment

  • Rate limiting: Implement request throttling for high-traffic agents (>1000 req/s)
  • Monitoring: Log critical errors, track schedule count, monitor storage usage
  • Graceful degradation: Handle AI service outages with fallbacks
  • Message trimming: Enforce max history length (e.g., 100 messages) in AIChatAgent
  • MCP reliability: Re-register servers on hibernation, implement retry logic

references/agents-sdk/patterns.md (verbatim)

Patterns & Use Cases

AI Chat w/Tools

Server (AIChatAgent):

import { AIChatAgent } from "agents";
import { openai } from "@ai-sdk/openai";
import { tool } from "ai";
import { z } from "zod";

export class ChatAgent extends AIChatAgent<Env> {
  async onChatMessage(onFinish) {
    return this.streamText({
      model: openai("gpt-4"),
      messages: this.messages, // Auto-managed
      tools: {
        getWeather: tool({
          description: "Get current weather",
          parameters: z.object({ city: z.string() }),
          execute: async ({ city }) => `Weather in ${city}: Sunny, 72°F`
        }),
        searchDocs: tool({
          description: "Search documentation",
          parameters: z.object({ query: z.string() }),
          execute: async ({ query }) => JSON.stringify(
            this.sql<{title, content}>`SELECT title, content FROM docs WHERE content LIKE ${'%' + query + '%'}`
          )
        })
      },
      onFinish,
    });
  }
}

Client (React):

import { useAgent } from "agents/react";
import { useAgentChat } from "agents/ai-react";

function ChatUI() {
  const agent = useAgent({ agent: "ChatAgent" });
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgentChat({ agent });
  
  return (
    <div>
      {messages.map(m => <div key={m.id}>{m.role}: {m.content}</div>)}
      <form onSubmit={handleSubmit}>
        <input value={input} onChange={handleInputChange} disabled={isLoading} />
        <button disabled={isLoading}>Send</button>
      </form>
    </div>
  );
}

Human-in-the-Loop (Client Tools)

Server defines tool, client executes:

// Server
export class ChatAgent extends AIChatAgent<Env> {
  async onChatMessage(onFinish) {
    return this.streamText({
      model: openai("gpt-4"),
      messages: this.messages,
      tools: {
        confirmAction: tool({
          description: "Ask user to confirm",
          parameters: z.object({ action: z.string() }),
          execute: "client", // Client-side execution
        })
      },
      onFinish,
    });
  }
}

// Client
const { messages } = useAgentChat({
  agent,
  onToolCall: async (toolCall) => {
    if (toolCall.toolName === "confirmAction") {
      return { confirmed: window.confirm(`Confirm: ${toolCall.args.action}?`) };
    }
  }
});

Task Queue & Scheduled Processing

export class TaskAgent extends Agent<Env> {
  onStart() { 
    this.schedule("*/5 * * * *", "processQueue", {}); // Every 5 min
    this.schedule("0 0 * * *", "dailyCleanup", {}); // Daily
  }
  
  async onRequest(req: Request) {
    await this.queue("processVideo", { videoId: (await req.json()).videoId });
    return Response.json({ queued: true });
  }
  
  async processQueue() {
    const tasks = await this.dequeue(10);
    for (const task of tasks) {
      if (task.name === "processVideo") await this.processVideo(task.data.videoId);
    }
  }
  
  async dailyCleanup() {
    this.sql`DELETE FROM logs WHERE created_at < ${Date.now() - 86400000}`;
  }
}

Manual WebSocket Chat

Custom protocols (non-AI):

export class ChatAgent extends Agent<Env> {
  async onConnect(conn: Connection, ctx: ConnectionContext) {
    conn.accept();
    conn.setState({userId: ctx.request.headers.get("X-User-ID") || "anon"});
    conn.send(JSON.stringify({type: "history", messages: this.state.messages}));
  }
  
  async onMessage(conn: Connection, msg: WSMessage) {
    const newMsg = {userId: conn.state.userId, text: JSON.parse(msg as string).text, timestamp: Date.now()};
    this.setState({messages: [...this.state.messages, newMsg]});
    this.connections.forEach(c => c.send(JSON.stringify(newMsg)));
  }
}

Email Processing w/AI

export class EmailAgent extends Agent<Env> {
  async onEmail(email: AgentEmail) {
    const [text, from, subject] = [await email.text(), email.from, email.headers.get("subject") || ""];
    this.sql`INSERT INTO emails (from_addr, subject, body) VALUES (${from}, ${subject}, ${text})`;
    
    const { text: summary } = await generateText({
      model: openai("gpt-4o-mini"), prompt: `Summarize: ${subject}\n\n${text}`
    });
    
    this.connections.forEach(c => c.send(JSON.stringify({type: "new_email", from, summary})));
    if (summary.includes("urgent")) await this.schedule(0, "sendAutoReply", { to: from });
  }
}

Real-time Collaboration

export class GameAgent extends Agent<Env> {
  initialState = { players: [], gameStarted: false };
  
  async onConnect(conn: Connection, ctx: ConnectionContext) {
    conn.accept();
    const playerId = ctx.request.headers.get("X-Player-ID") || crypto.randomUUID();
    conn.setState({ playerId });
    
    const newPlayer = { id: playerId, score: 0 };
    this.setState({...this.state, players: [...this.state.players, newPlayer]});
    this.connections.forEach(c => c.send(JSON.stringify({type: "player_joined", player: newPlayer})));
  }
  
  async onMessage(conn: Connection, msg: WSMessage) {
    const m = JSON.parse(msg as string);
    
    if (m.type === "move") {
      this.setState({
        ...this.state,
        players: this.state.players.map(p => p.id === conn.state.playerId ? {...p, score: p.score + m.points} : p)
      });
      this.connections.forEach(c => c.send(JSON.stringify({type: "player_moved", playerId: conn.state.playerId})));
    }
    
    if (m.type === "start" && this.state.players.length >= 2) {
      this.setState({...this.state, gameStarted: true});
      this.connections.forEach(c => c.send(JSON.stringify({type: "game_started"})));
    }
  }
}

references/ai-gateway/README.md (verbatim)

2 placeholder credentials shortened to pass the site's secret filter.

Cloudflare AI Gateway

Expert guidance for implementing Cloudflare AI Gateway - a universal gateway for AI model providers with analytics, caching, rate limiting, and routing capabilities.

When to Use This Reference

  • Setting up AI Gateway for any AI provider (OpenAI, Anthropic, Workers AI, etc.)
  • Implementing caching, rate limiting, or request retry/fallback
  • Configuring dynamic routing with A/B testing or model fallbacks
  • Managing provider API keys securely with BYOK
  • Adding security features (guardrails, DLP)
  • Setting up observability with logging and custom metadata
  • Debugging AI Gateway requests or optimizing configurations

Quick Start

What's your setup?

Most modern pattern using official ai-gateway-provider package with automatic fallbacks.

import { createAiGateway } from 'ai-gateway-provider';
import { createOpenAI } from '@ai-sdk/openai';
import { generateText } from 'ai';

const gateway = createAiGateway({
  accountId: process.env.CF_ACCOUNT_ID,
  gateway: process.env.CF_GATEWAY_ID,
});

const openai = createOpenAI({ 
  apiKey: YOUR_KEY 
});

// Single model
const { text } = await generateText({
  model: gateway(openai('gpt-4o')),
  prompt: 'Hello'
});

// Automatic fallback array
const { text } = await generateText({
  model: gateway([
    openai('gpt-4o'),              // Try first
    anthropic('claude-sonnet-4-5'), // Fallback
  ]),
  prompt: 'Hello'
});

Install: npm install ai-gateway-provider ai @ai-sdk/openai @ai-sdk/anthropic

Pattern 2: OpenAI SDK

Drop-in replacement for OpenAI API with multi-provider support.

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: YOUR_KEY
  baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/compat`,
  defaultHeaders: {
    'cf-aig-authorization': `Bearer ${cfToken}` // For authenticated gateways
  }
});

// Switch providers by changing model format: {provider}/{model}
const response = await client.chat.completions.create({
  model: 'openai/gpt-4o', // or 'anthropic/claude-sonnet-4-5'
  messages: [{ role: 'user', content: 'Hello!' }]
});

Pattern 3: Workers AI Binding

For Cloudflare Workers using Workers AI.

export default {
  async fetch(request, env, ctx) {
    const response = await env.AI.run(
      '@cf/meta/llama-3-8b-instruct',
      { messages: [{ role: 'user', content: 'Hello!' }] },
      { 
        gateway: { 
          id: 'my-gateway',
          metadata: { userId: '123', team: 'engineering' }
        } 
      }
    );
    
    return Response.json(response);
  }
};

Headers Quick Reference

Header Purpose Example Notes
cf-aig-authorization Gateway auth Bearer {token} Required for authenticated gateways
cf-aig-metadata Tracking {"userId":"x"} Max 5 entries, flat structure
cf-aig-cache-ttl Cache duration 3600 Seconds, min 60, max 2592000 (30 days)
cf-aig-skip-cache Bypass cache true -
cf-aig-cache-key Custom cache key my-key Must be unique per response
cf-aig-collect-log Skip logging false Default: true
cf-aig-cache-status Cache hit/miss Response only HIT or MISS

In This Reference

File Purpose
sdk-integration.md Vercel AI SDK, OpenAI SDK, Workers binding patterns
configuration.md Dashboard setup, wrangler, API tokens
features.md Caching, rate limits, guardrails, DLP, BYOK, unified billing
dynamic-routing.md Fallbacks, A/B testing, conditional routing
troubleshooting.md Debugging, errors, observability, gotchas

Reading Order

Task Files
First-time setup README + configuration.md
SDK integration README + sdk-integration.md
Enable caching README + features.md
Setup fallbacks README + dynamic-routing.md
Debug errors README + troubleshooting.md

Architecture

AI Gateway acts as a proxy between your application and AI providers:

Your App → AI Gateway → AI Provider (OpenAI, Anthropic, etc.)
         ↓
    Analytics, Caching, Rate Limiting, Logging

Key URL patterns:

  • Unified API (OpenAI-compatible): https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/compat/chat/completions
  • Provider-specific: https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/{provider}/{endpoint}
  • Dynamic routes: Use route name instead of model: dynamic/{route-name}

Gateway Types

  1. Unauthenticated Gateway: Open access (not recommended for production)
  2. Authenticated Gateway: Requires cf-aig-authorization header with Cloudflare API token (recommended)

Provider Authentication Options

  1. Unified Billing: Use AI Gateway billing to pay for inference (keyless mode - no provider API key needed)
  2. BYOK (Store Keys): Store provider API keys in Cloudflare dashboard
  3. Request Headers: Include provider API key in each request
  • Workers AI - For env.AI.run() details
  • Agents SDK - For stateful AI patterns
  • Vectorize - For RAG patterns with embeddings

Resources

references/ai-gateway/configuration.md (verbatim)

2 placeholder credentials shortened to pass the site's secret filter.

Configuration & Setup

Creating a Gateway

Dashboard

AI > AI Gateway > Create Gateway > Configure (auth, caching, rate limiting, logging)

API

curl -X POST https://api.cloudflare.com/client/v4/accounts/{account_id}/ai-gateway/gateways \
  -H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" \
  -d '{"id":"my-gateway","cache_ttl":3600,"rate_limiting_interval":60,"rate_limiting_limit":100,"collect_logs":true}'

Naming: lowercase alphanumeric + hyphens (e.g., prod-api, dev-chat)

Wrangler Integration

[ai]
binding = "AI"

[[ai.gateway]]
id = "my-gateway"
wrangler secret put CF_API_TOKEN
wrangler secret put OPENAI_API_KEY  # If not using BYOK

Authentication

Gateway Auth (protects gateway access)

const client = new OpenAI({
  baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
  defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});

Provider Auth Options

1. Unified Billing (keyless) - pay through Cloudflare, no provider key:

const client = new OpenAI({
  baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
  defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});

Supports: OpenAI, Anthropic, Google AI Studio

2. BYOK - store keys in dashboard (Provider Keys > Add), no key in code

3. Request Headers - pass provider key per request:

const client = new OpenAI({
  apiKey: YOUR_KEY
  baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
  defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});

API Token Permissions

  • Gateway management: AI Gateway - Read + Edit
  • Gateway access: AI Gateway - Read (minimum)

Gateway Management API

# List
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/ai-gateway/gateways \
  -H "Authorization: Bearer $CF_API_TOKEN"

# Get
curl .../gateways/{gateway_id}

# Update
curl -X PUT .../gateways/{gateway_id} \
  -d '{"cache_ttl":7200,"rate_limiting_limit":200}'

# Delete
curl -X DELETE .../gateways/{gateway_id}

Getting IDs

  • Account ID: Dashboard > Overview > Copy
  • Gateway ID: AI Gateway > Gateway name column

Python Example

from openai import OpenAI
import os

client = OpenAI(
    api_key=YOUR_KEY
    base_url=f"https://gateway.ai.cloudflare.com/v1/{os.environ['CF_ACCOUNT_ID']}/{os.environ['GATEWAY_ID']}/openai",
    default_headers={"cf-aig-authorization": f"Bearer {os.environ['CF_API_TOKEN']}"}
)

Best Practices

  1. Always authenticate gateways in production
  2. Use BYOK or unified billing - secrets out of code
  3. Environment-specific gateways - separate dev/staging/prod
  4. Set rate limits - prevent runaway costs
  5. Enable logging - track usage, debug issues

references/ai-gateway/dynamic-routing.md (verbatim)

Dynamic Routing

Configure complex routing in dashboard without code changes. Use route names instead of model names.

Usage

const response = await client.chat.completions.create({
  model: 'dynamic/smart-chat', // Route name from dashboard
  messages: [{ role: 'user', content: 'Hello!' }]
});

Node Types

Node Purpose Use Case
Conditional Branch on metadata Paid vs free users, geo routing
Percentage A/B split traffic Model testing, gradual rollouts
Rate Limit Enforce quotas Per-user/team limits
Budget Limit Cost quotas Per-user spending caps
Model Call provider Final destination

Metadata

Pass via header (max 5 entries, flat only):

headers: {
  'cf-aig-metadata': JSON.stringify({
    userId: 'user-123',
    tier: 'pro',
    region: 'us-east'
  })
}

Common Patterns

Multi-model fallback:

Start → GPT-4 → On error: Claude → On error: Llama

Tiered access:

Conditional: tier == 'enterprise' → GPT-4 (no limit)
Conditional: tier == 'pro' → Rate Limit 1000/hr → GPT-4o
Conditional: tier == 'free' → Rate Limit 10/hr → GPT-4o-mini

Gradual rollout:

Percentage: 10% → New model, 90% → Old model

Cost-based fallback:

Budget Limit: $100/day per teamId
  < 80%: GPT-4
  >= 80%: GPT-4o-mini
  >= 100%: Error

Version Management

  • Save changes as new version
  • Test with model: 'dynamic/route@v2'
  • Roll back by deploying previous version

Monitoring

Dashboard → Gateway → Dynamic Routes:

  • Request count per path
  • Success/error rates
  • Latency/cost by path

Limitations

  • Max 5 metadata entries
  • Values: string/number/boolean/null only
  • No nested objects
  • Route names: alphanumeric + hyphens

references/ai-gateway/features.md (verbatim)

Features & Capabilities

Caching

Dashboard: Settings → Cache Responses → Enable

// Custom TTL (1 hour)
headers: { 'cf-aig-cache-ttl': '3600' }

// Skip cache
headers: { 'cf-aig-skip-cache': 'true' }

// Custom cache key
headers: { 'cf-aig-cache-key': 'greeting-en' }

Limits: TTL 60s - 30 days. Does NOT work with streaming.

Rate Limiting

Dashboard: Settings → Rate-limiting → Enable

  • Fixed window: Resets at intervals
  • Sliding window: Rolling window (more accurate)
  • Returns 429 when exceeded

Guardrails

Dashboard: Settings → Guardrails → Enable

Filter prompts/responses for inappropriate content. Actions: Flag (log) or Block (reject).

Data Loss Prevention (DLP)

Dashboard: Settings → DLP → Enable

Detect PII (emails, SSNs, credit cards). Actions: Flag, Block, or Redact.

Billing Modes

Mode Description Setup
Unified Billing Pay through Cloudflare, no provider keys Use cf-aig-authorization header only
BYOK Store provider keys in dashboard Add keys in Provider Keys section
Pass-through Send provider key with each request Include provider's auth header

Zero Data Retention

Dashboard: Settings → Privacy → Zero Data Retention

No prompts/responses stored. Request counts and costs still tracked.

Logging

Dashboard: Settings → Logs → Enable (up to 10M logs)

Each entry: prompt, response, provider, model, tokens, cost, duration, cache status, metadata.

// Skip logging for request
headers: { 'cf-aig-collect-log': 'false' }

Export: Use Logpush to S3, GCS, Datadog, Splunk, etc.

Custom Cost Tracking

For models not in Cloudflare's pricing database:

Dashboard: Gateway → Settings → Custom Costs

Or via API: set model, input_cost, output_cost.

Supported Providers (22+)

Provider Unified API Notes
OpenAI openai/gpt-4o Full support
Anthropic anthropic/claude-sonnet-4-5 Full support
Google AI google-ai-studio/gemini-2.0-flash Full support
Workers AI workersai/@cf/meta/llama-3 Native
Azure OpenAI azure-openai/* Deployment names
AWS Bedrock Provider endpoint only /bedrock/*
Groq groq/* Fast inference
Mistral, Cohere, Perplexity, xAI, DeepSeek, Cerebras Full support -

Best Practices

  1. Enable caching for deterministic prompts
  2. Set rate limits to prevent abuse
  3. Use guardrails for user-facing AI
  4. Enable DLP for sensitive data
  5. Use unified billing or BYOK for simpler key management
  6. Enable logging for debugging
  7. Use zero data retention when privacy required

references/ai-gateway/sdk-integration.md (verbatim)

4 placeholder credentials shortened to pass the site's secret filter.

AI Gateway SDK Integration

import { createAiGateway } from 'ai-gateway-provider';
import { createOpenAI } from '@ai-sdk/openai';
import { generateText } from 'ai';

const gateway = createAiGateway({
  accountId: process.env.CF_ACCOUNT_ID,
  gateway: process.env.CF_GATEWAY_ID,
  apiKey: YOUR_KEY // Optional for auth gateways
});

const openai = createOpenAI({ apiKey: YOUR_KEY });

// Single model
const { text } = await generateText({
  model: gateway(openai('gpt-4o')),
  prompt: 'Hello'
});

// Automatic fallback array
const { text } = await generateText({
  model: gateway([
    openai('gpt-4o'),
    anthropic('claude-sonnet-4-5'),
    openai('gpt-4o-mini')
  ]),
  prompt: 'Complex task'
});

Options

model: gateway(openai('gpt-4o'), {
  cacheKey: 'my-key',
  cacheTtl: 3600,
  metadata: { userId: 'u123', team: 'eng' }, // Max 5 entries
  retries: { maxAttempts: 3, backoff: 'exponential' }
})

OpenAI SDK

const client = new OpenAI({
  apiKey: YOUR_KEY
  baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
  defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});

// Unified API - switch providers via model name
model: 'openai/gpt-4o'  // or 'anthropic/claude-sonnet-4-5'

Anthropic SDK

const client = new Anthropic({
  apiKey: YOUR_KEY
  baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/anthropic`,
  defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});

Workers AI Binding

# wrangler.toml
[ai]
binding = "AI"
[[ai.gateway]]
id = "my-gateway"
await env.AI.run('@cf/meta/llama-3-8b-instruct', 
  { messages: [...] },
  { gateway: { id: 'my-gateway', metadata: { userId: '123' } } }
);

LangChain / LlamaIndex

// Use OpenAI SDK pattern with custom baseURL
new ChatOpenAI({
  configuration: {
    baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`
  }
});

HTTP / cURL

curl https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/openai/chat/completions \
  -H "Authorization: Bearer $OPENAI_KEY" \
  -H "cf-aig-authorization: Bearer $CF_TOKEN" \
  -H "cf-aig-metadata: {\"userId\":\"123\"}" \
  -d '{"model":"gpt-4o","messages":[...]}'

Headers Reference

Header Purpose
cf-aig-authorization Gateway auth token
cf-aig-metadata JSON object (max 5 keys)
cf-aig-cache-ttl Cache TTL in seconds
cf-aig-skip-cache true to bypass cache

references/ai-search/configuration.md (verbatim)

AI Search Configuration

Worker Setup

// wrangler.jsonc
{
  "ai": { "binding": "AI" }
}
interface Env {
  AI: Ai;
}

const answer = await env.AI.autorag("my-instance").aiSearch({
  query: "How do I configure caching?",
  model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast"
});

Data Sources

R2 Bucket

Dashboard: AI Search → Create Instance → Select R2 bucket

Supported formats: .md, .txt, .html, .pdf, .doc, .docx, .csv, .json

Auto-indexed metadata: filename, folder, timestamp

Website Crawler

Requirements:

  • Domain on Cloudflare
  • sitemap.xml at root
  • Bot protection must allow CloudflareAISearch user agent

Path Filtering (R2)

docs/**/*.md          # All .md in docs/ recursively
**/*.draft.md         # Exclude (use in exclude patterns)

Indexing

  • Automatic: Every 6 hours
  • Force Sync: Dashboard button (30s rate limit between syncs)
  • Pause: Settings → Pause Indexing (existing index remains searchable)

Service API Token

Dashboard: AI Search → Instance → Use AI Search → API → Create Token

Permissions:

  • Read - search operations
  • Edit - instance management

Store securely:

wrangler secret put AI_SEARCH_TOKEN

Multi-Environment

# wrangler.toml
[env.production.vars]
AI_SEARCH_INSTANCE = "prod-docs"

[env.staging.vars]
AI_SEARCH_INSTANCE = "staging-docs"
const answer = await env.AI.autorag(env.AI_SEARCH_INSTANCE).aiSearch({ query });

Monitoring

const instances = await env.AI.autorag("_").listInstances();
console.log(instances.find(i => i.name === "docs"));

Dashboard shows: files indexed, status, last index time, storage usage.

Back to openai/skills (Skills Catalog for Codex) or Agent skills.