Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt

Use this file to discover all available pages before exploring further.

A counter agent with persistent state, callable methods, and real-time sync to a React frontend. This is the simplest example showing the core patterns of Cloudflare Agents.

What it demonstrates

  • Persistent State - Counter value survives restarts and hibernation
  • Callable Methods - Type-safe RPC via the @callable() decorator
  • Real-time Sync - State changes automatically sync to all connected clients
  • React Integration - useAgent hook for frontend integration

Server Implementation

server.ts
import { Agent, routeAgentRequest, callable } from "agents";

export type CounterState = { count: number };

export class CounterAgent extends Agent<Env, CounterState> {
  initialState = { count: 0 };

  @callable()
  increment() {
    this.setState({ count: this.state.count + 1 });
    return this.state.count;
  }

  @callable()
  decrement() {
    this.setState({ count: this.state.count - 1 });
    return this.state.count;
  }
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    return (
      (await routeAgentRequest(request, env)) ??
      new Response("Not found", { status: 404 })
    );
  }
};

React Client

client.tsx
import { useAgent } from "agents/react";
import { useState } from "react";
import type { CounterAgent, CounterState } from "./server";

function Counter() {
  const [count, setCount] = useState(0);

  const agent = useAgent<CounterAgent, CounterState>({
    agent: "CounterAgent",
    onStateUpdate: (state) => setCount(state.count)
  });

  return (
    <div>
      <span>{count}</span>
      <button onClick={() => agent.stub.increment()}>+</button>
      <button onClick={() => agent.stub.decrement()}>-</button>
    </div>
  );
}

How it works

1

Define Agent State

The CounterState type defines the shape of the agent’s persistent state. This state is stored in Durable Objects and syncs to all connected clients.
2

Mark Methods as Callable

The @callable() decorator exposes methods as RPC endpoints. Clients can call them like local functions via agent.stub.methodName().
3

Update State

this.setState() updates the agent’s state and automatically broadcasts the change to all connected WebSocket clients.
4

Connect from React

The useAgent hook establishes a WebSocket connection, receives state updates via onStateUpdate, and provides a type-safe stub for calling methods.

Key Concepts

State Persistence

Agent state is stored in Durable Objects and survives:
  • Worker restarts
  • Hibernation (when no clients are connected)
  • Redeployments

Real-time Broadcasting

When setState() is called:
  1. State is persisted to Durable Objects storage
  2. Update is broadcast to all connected WebSocket clients
  3. Each client’s onStateUpdate callback fires with the new state

Type Safety

The useAgent hook is fully typed:
const agent = useAgent<CounterAgent, CounterState>({
  agent: "CounterAgent",
  onStateUpdate: (state) => {
    // `state` is typed as CounterState
    setCount(state.count);
  }
});

// `stub` has the same methods as CounterAgent
await agent.stub.increment();

Running the Example

npm create cloudflare@latest -- --template cloudflare/agents-starter
cd my-agent
npm run dev

Next Steps

AI Chat Example

Add AI chat with streaming and tool execution

Workflows Example

Build multi-step workflows with human approval

MCP Server

Expose your agent as an MCP server

API Reference

Full Agent class documentation

Build docs developers (and LLMs) love