> ## 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.

# Quick Start

> Build your first AI agent in 10 minutes

<Note>
  **What you'll build:** A counter agent with persistent state that syncs to a React frontend in real-time.

  **Time:** \~10 minutes
</Note>

## Create a New Project

Use the Cloudflare agents starter template to scaffold a new project:

```bash theme={null}
npm create cloudflare@latest -- --template cloudflare/agents-starter
cd my-agent
npm install
```

This creates a project with:

* `src/server.ts` - Your agent code
* `src/client.tsx` - React frontend
* `wrangler.jsonc` - Cloudflare configuration

<Steps>
  <Step title="Start the dev server">
    ```bash theme={null}
    npm run dev
    ```

    Open [http://localhost:5173](http://localhost:5173) to see your agent in action.
  </Step>
</Steps>

## Your First Agent

Let's build a simple counter agent from scratch. Replace `src/server.ts`:

```typescript src/server.ts theme={null}
import { Agent, routeAgentRequest, callable } from "agents";

// Define the state shape
type CounterState = {
  count: number;
};

// Create the agent
export class Counter extends Agent<Env, CounterState> {
  // Initial state for new instances
  initialState: CounterState = { count: 0 };

  // Methods marked with @callable can be called from the client
  @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;
  }

  @callable()
  reset() {
    this.setState({ count: 0 });
  }
}

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

<Warning>
  Methods must be decorated with `@callable()` to be invoked from clients.
</Warning>

### Configure the Agent

Update `wrangler.jsonc` to register the agent:

```jsonc wrangler.jsonc theme={null}
{
  "name": "my-agent",
  "main": "src/server.ts",
  "compatibility_date": "2025-01-01",
  "compatibility_flags": ["nodejs_compat"],
  "durable_objects": {
    "bindings": [
      {
        "name": "Counter",
        "class_name": "Counter"
      }
    ]
  },
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": ["Counter"]
    }
  ]
}
```

<Note>
  * `name` in bindings becomes the property on `env` (e.g., `env.Counter`)
  * `class_name` must match your exported class name exactly
  * `new_sqlite_classes` enables SQLite storage for state persistence
</Note>

## Connect from React

Replace `src/client.tsx` to connect to your agent:

```tsx src/client.tsx theme={null}
import { useState } from "react";
import { useAgent } from "agents/react";

// Match your agent's state type
type CounterState = {
  count: number;
};

export default function App() {
  const [count, setCount] = useState(0);

  // Connect to the Counter agent
  const agent = useAgent<CounterState>({
    agent: "Counter",
    onStateUpdate: (state) => setCount(state.count)
  });

  return (
    <div style={{ padding: "2rem", fontFamily: "system-ui" }}>
      <h1>Counter Agent</h1>
      <p style={{ fontSize: "3rem" }}>{count}</p>
      <div style={{ display: "flex", gap: "1rem" }}>
        <button onClick={() => agent.stub.decrement()}>-</button>
        <button onClick={() => agent.stub.reset()}>Reset</button>
        <button onClick={() => agent.stub.increment()}>+</button>
      </div>
    </div>
  );
}
```

### Key Concepts

<CardGroup cols={3}>
  <Card title="useAgent" icon="hook">
    Connects to your agent via WebSocket
  </Card>

  <Card title="onStateUpdate" icon="arrows-rotate">
    Fires whenever the agent's state changes
  </Card>

  <Card title="agent.stub" icon="function">
    Calls methods marked with `@callable()` on your agent
  </Card>
</CardGroup>

## What Just Happened?

When you clicked the button:

<Steps>
  <Step title="Client called agent.stub.increment()">
    The call is sent over WebSocket to the agent
  </Step>

  <Step title="Agent ran increment()">
    Updated state with `setState()`
  </Step>

  <Step title="State persisted to SQLite">
    Happens automatically on every `setState()` call
  </Step>

  <Step title="Broadcast sent to all clients">
    All connected clients receive the state update
  </Step>

  <Step title="React updated via onStateUpdate">
    Your UI re-renders with the new state
  </Step>
</Steps>

```mermaid theme={null}
graph LR
    A[Browser React] <-->|WebSocket| B[Agent Counter]
    B --> C[SQLite State]
```

## Understanding Agent Instances

<AccordionGroup>
  <Accordion title="Agent instance" icon="cube">
    Each unique name gets its own agent. `Counter:user-123` is separate from `Counter:user-456`
  </Accordion>

  <Accordion title="Persistent state" icon="database">
    State survives restarts, deploys, and hibernation. It's stored in SQLite
  </Accordion>

  <Accordion title="Real-time sync" icon="bolt">
    All clients connected to the same agent receive state updates instantly
  </Accordion>

  <Accordion title="Hibernation" icon="moon">
    When no clients are connected, the agent hibernates (no cost). It wakes on the next request
  </Accordion>
</AccordionGroup>

## Connect from Vanilla JS

If you're not using React:

```typescript theme={null}
import { AgentClient } from "agents/client";

const agent = new AgentClient({
  agent: "Counter",
  name: "my-counter", // optional, defaults to "default"
  onStateUpdate: (state) => {
    console.log("New count:", state.count);
  }
});

// Call methods
await agent.call("increment");
await agent.call("reset");
```

## Deploy to Cloudflare

When you're ready to deploy:

```bash theme={null}
npm run deploy
```

Your agent is now live on Cloudflare's global network, running close to your users.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Agent not found / 404 errors" icon="triangle-exclamation">
    Make sure:

    1. Agent class is exported from your server file
    2. `wrangler.jsonc` has the binding and migration
    3. Agent name in client matches the class name (case-insensitive)
  </Accordion>

  <Accordion title="State not syncing" icon="triangle-exclamation">
    Check that:

    1. You're calling `this.setState()`, not mutating `this.state` directly
    2. The `onStateUpdate` callback is wired up in your client
    3. WebSocket connection is established (check browser dev tools)
  </Accordion>

  <Accordion title="Method X is not callable errors" icon="triangle-exclamation">
    Make sure your methods are decorated with `@callable()`:

    ```typescript theme={null}
    import { callable } from "agents";

    @callable()
    increment() {
      // ...
    }
    ```
  </Accordion>

  <Accordion title="Type errors with agent.stub" icon="triangle-exclamation">
    Add the agent type parameter:

    ```typescript theme={null}
    const agent = useAgent<Counter, CounterState>({
      agent: "Counter",
      onStateUpdate: (state) => setCount(state.count)
    });

    // Now agent.stub is fully typed
    agent.stub.increment(); // ✓ TypeScript knows this method exists
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

Now that you have a working agent, explore these topics:

<CardGroup cols={2}>
  <Card title="State Management" icon="database" href="/core/state-management">
    Deep dive into `setState()`, `initialState`, and `onStateChanged()`
  </Card>

  <Card title="Client SDK" icon="code" href="/client/client-sdk">
    Full `useAgent` and `AgentClient` API reference
  </Card>

  <Card title="Scheduling" icon="clock" href="/background/scheduling">
    Run tasks on a delay, schedule, or cron
  </Card>

  <Card title="Agent Class" icon="cube" href="/core/agent-class">
    Lifecycle methods, HTTP handlers, and WebSocket events
  </Card>
</CardGroup>

### Common Use Cases

| I want to...             | Read...                                       |
| ------------------------ | --------------------------------------------- |
| Add AI/LLM capabilities  | [Chat Agents](/ai/chat-agents)                |
| Expose tools via MCP     | [Creating MCP Servers](/mcp/creating-servers) |
| Run background tasks     | [Scheduling](/background/scheduling)          |
| Handle emails            | [Email Routing](/channels/email)              |
| Use Cloudflare Workflows | [Workflows](/background/workflows)            |
