---
title: How to Run Claude Managed Agents with Chat SDK
description: Pair the Chat SDK with Claude Managed Agents to run a streaming research analyst in a browser chat, using Anthropic's Chat SDK quickstart.
url: /kb/guide/claude-managed-agents-chat-sdk
canonical_url: "https://vercel.com/kb/guide/claude-managed-agents-chat-sdk"
published: 2026-07-24
last_updated: 2026-08-21
authors: CJ Avilla, Ben Sabic, Anshuman Bhardwaj
related:
  - /docs/services
  - /kb/guide/vercel-services
  - /docs/services/config-reference
  - /docs/project-configuration/vercel-json
  - /docs/frameworks/backend/hono
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---
<!-- docsgraph:related -->
## Related pages

> **For AI agents:** Follow these links to understand how this page connects to the rest of the Vercel ecosystem. For the full cross-link map (inbound, outbound, prerequisites, and semantic neighbors), see the .graph.md link below.

- [Anthropic Messages API](https://vercel.com/docs/ai-gateway/sdks-and-apis/anthropic-messages-api?from=related) — Use the Anthropic Messages API with AI Gateway for seamless integration with Anthropic SDK tools.
- [Vercel Deployment Guide](https://ai-sdk.dev/docs/advanced/vercel-deployment-guide?from=related)
- [Build AI agents with AI Gateway and AI SDK](https://vercel.com/kb/guide/ai-gateway-and-ai-sdk?from=related) — Build AI agents on Vercel with AI Gateway and AI SDK, then make them reliable, capable, and durable with Sandbox, Chat S
- [Build a Claude Managed Agent with Vercel Sandbox](https://vercel.com/kb/guide/run-claude-managed-agent-tools-with-vercel-sandbox?from=related) — Build a Claude Managed Agent with Vercel Sandbox: each session runs in a fresh microVM with credential brokering and a w
- [Build your own Slackbot with Vercel Connect](https://vercel.com/kb/guide/build-a-slack-bot-with-vercel-connect?from=related) — Learn how to build your very own Slackbot with Chat SDK and AI SDK. Vercel Connect supplies runtime Slack tokens and for
- [Production architecture for a RAG chatbot on Vercel](https://vercel.com/kb/guide/rag-chatbot-production-architecture-on-vercel?from=related) — Architect a production RAG chatbot on Vercel Functions with Fluid compute, AI Gateway, and a region-pinned vector store.
- [Build Notion-style real-time presence with WebSockets on Vercel](https://vercel.com/kb/guide/real-time-presence-hono-react?from=related) — Build the avatar faces that appear when a teammate opens a page and vanish when they leave. Powered by a Hono WebSocket

Full cross-link map for this page: [/kb/guide/claude-managed-agents-chat-sdk.graph.md](/kb/guide/claude-managed-agents-chat-sdk.graph.md)
<!-- /docsgraph:related -->


[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) are agents that Anthropic runs for you, with server-side sessions, sandboxed tools, and an event stream your app consumes.

Vercel's [Chat SDK](https://chat-sdk.dev/) gives that agent a chat surface through a single type-safe handler, with adapters for the web, Slack, Teams, Discord, Telegram, and WhatsApp.

The new [Anthropic quickstart](https://github.com/anthropics/claude-quickstarts/tree/main/managed-agents/chat-sdk) pairs Claude Managed Agents with Chat SDK into a research analyst in a browser chat. Each conversation maps to a single persistent session; replies stream token by token, and a live feed shows the agent's activity.

## Overview

In this guide, you'll learn how to:

- Provision a Managed Agents research analyst and its sandbox environment
  
- Run the Chat SDK web chat locally and watch the agent research in real time
  
- Update the agent's model and system prompt without creating duplicates
  
- Deploy the chat to Vercel using [Vercel Services](https://vercel.com/docs/services)
  

## Prerequisites

Before you begin, make sure you have:

- Node.js 22.9 or later
  
- An Anthropic API key from [platform.claude.com](https://platform.claude.com), or run `ant auth login`
  
- An Anthropic organization with Managed Agents access
  

## How it works

### Sessions are the conversation store

The quickstart holds no state of its own. Every conversation in the browser maps to exactly one Managed Agents session, and the sessions API backs each part:

| In the browser         | What powers it                                                                                      |
| ---------------------- | --------------------------------------------------------------------------------------------------- |
| Starting a new chat    | `POST /api/sessions` creates a session, and `useChat` uses the returned session ID as its thread ID |
| Conversation sidebar   | `sessions.list()`                                                                                   |
| Replaying a transcript | `sessions.events.list()`                                                                            |
| Follow-up questions    | The session holds the research context server-side                                                  |

### The web adapter needs no platform registration

The demo uses the [Chat SDK's web adapter](https://chat-sdk.dev/adapters/official/web), so there is no chat platform to register with. You don't need a Slack app, a webhook to verify, or a tunnel. The only credential is your Anthropic auth.

### Replies and activity stream on separate channels

When a message arrives, the adapter holds the HTTP response open while the bridge holds an Anthropic event stream open for the same turn, forwarding each `agent.message` event to the response. The acknowledgment appears within seconds, and the finished brief arrives with the same response minutes later.

Tool calls, model requests, and thinking indicators stream separately. The page receives them as a live feed over `GET /api/activity` while the turn runs.

### The agent runs entirely on Anthropic's side

The tool loop, sandboxed web research, session state, compaction, and prompt caching all occur within the session.

The agent's shell tool is disabled by design. The analyst reads arbitrary web pages, and prompt-injected content combined with an auto-approved shell and open egress would create an exfiltration path. The brief relies on web search, web fetch, and the file tools instead.

## Steps

### 1\. Clone the quickstart

Clone the repository and move into the project:

```bash
git clone https://github.com/anthropics/claude-quickstarts.git
cd claude-quickstarts/managed-agents/chat-sdk
```

### 2\. Install dependencies

```bash
npm install
```

This installs:

- Chat SDK packages:
  
  - `chat`: the core SDK with the type-safe handler and message primitives
    
  - `@chat-adapter/web`: the web adapter that serves the browser chat surface
    
  - `@chat-adapter/state-memory`: in-memory adapter state
    
- Anthropic SDK: `@anthropic-ai/sdk` 0.109.0 or later
  
- Server and UI: Hono and the React chat page's dependencies
  

### 3\. Configure authentication

Copy the environment template:

```bash
cp .env.example .env
```

Then add Anthropic auth in one of two ways:

- Uncomment `ANTHROPIC_API_KEY` in `.env` and paste a key from [platform.claude.com](https://platform.claude.com).
  
- Run `ant auth login` once and leave the variable out, since the SDK discovers CLI credentials on its own.
  

### 4\. Provision the agent and environment

```bash
npm run setup
```

This one-time step creates two persistent resources:

- A cloud sandbox environment where the agent's tools run
  
- The analyst agent, configured with a model (Claude Opus by default, overridable with `QUICKSTART_MODEL`), a system prompt tuned for chat-length research briefs, and a toolset with bash disabled
  

The script prints both IDs:

```plaintext
environment: env_...
analyst:     agent_... (version 1, claude-opus-4-8)

Add to .env:
CLAUDE_AGENT_ID=agent_...
CLAUDE_ENVIRONMENT_ID=env_...
```

Paste the two IDs into `.env`. Don't re-run `npm run setup` later, because it would create a duplicate agent. To change the agent, use `npm run update-agent`.

### 5\. Run the chat locally

Start the development server:

```bash
npm run dev
```

Open `http://localhost:3000`, select New chat, and ask for a brief on any topic. Here's what you should see:

1. An acknowledgment message within seconds
   
2. The activity feed filling with searches for one to three minutes
   
3. The brief streaming in token by token
   
4. A collapsed tool-call trace and a "Brief ready" card linking to the session's trace in the Anthropic Console
   

To confirm that sessions hold all the state, restart the development server and reload the page. The sidebar and every transcript come back intact from the sessions API, and follow-up questions in a replayed chat still work because the session keeps the research context server-side.

### 6\. Customize the agent

The agent's entire identity (name, model, and system prompt) lives in `setup/agent-config.ts`. After editing it, push the change as a new agent version:

```bash
npm run update-agent
```

Running sessions keep their pinned version and new chats use the latest, so an edit never disrupts a conversation in flight.

## Deploying to Vercel

Deploying to Vercel comes down to a Vite build for the page, a Node entry for the API, environment variables, and a longer function duration.

### 1\. Serve the page from the CDN and the API from a function

The local Node server serves both the chat page and the API. On Vercel, use [Vercel Services](https://vercel.com/kb/guide/vercel-services) to deploy them as two services in the same project:

- A Vite service builds the existing `web/` directory and serves the generated frontend assets from Vercel’s CDN.
  
- A Node service runs the Hono application and handles the four `/api` routes through `deployedApi()`.
  

First, create the API entry point for the Hono server by adding a new `server.ts` file at the project root:

```typescript
import { createAdaptorServer } from "@hono/node-server";

import { deployedApi } from "./src/app";

const app = deployedApi();

export const server = createAdaptorServer({
  fetch: app.fetch,
  serverOptions: { requestTimeout: 0 },
});

export function listen() {
  const port = Number(process.env.PORT) || 3000;
  const hostname = process.env.HOST || "127.0.0.1";
  server.listen(port, hostname, () => {
    console.log(`Research analyst API running at http://${hostname}:${port}`);
  });
}

if (!process.env.VERCEL || process.env.VERCEL_ENV === "development") listen();

export default server;
```

This adapts the Fetch-native Hono application to a Node HTTP server. Vercel imports the exported server in production, while the local development command starts it normally.

Now, install Vite and its React plugin as development dependencies:

```bash
npm install --save-dev vite@^7 @vitejs/plugin-react@^5
```

Add these scripts alongside the existing ones in `package.json`:

```json
{
  "scripts": {
    "dev:api": "tsx watch --env-file-if-exists=.env server.ts",
    "dev:web": "vite --config vite.config.ts",
    "build": "vite build --config vite.config.ts"
  }
}
```

Then, configure Vite to read the frontend from `web/` and write the production bundle to `dist/`. For this, create a new file called `vite.config.ts` at the project root:

```typescript
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
  root: "web",
  plugins: [react()],
  server: {
    host: "127.0.0.1",
    port: Number(process.env.PORT) || 5173,
    strictPort: true,
  },
  build: {
    emptyOutDir: true,
    outDir: "../dist",
  },
});
```

Finally, create a `vercel.json` file at the project root to configure Vercel Services and the rewrites:

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "services": {
    "web": {
      "root": ".",
      "framework": "vite",
      "buildCommand": "npm run build",
      "outputDirectory": "dist",
      "devCommand": "npm run dev:web"
    },
    "api": {
      "root": ".",
      "framework": "node",
      "entrypoint": "server.ts",
      "devCommand": "npm run dev:api"
    }
  },
  "rewrites": [
    {
      "source": "/api/(.*)",
      "destination": { "service": "api" }
    },
    {
      "source": "/(.*)",
      "destination": { "service": "web" }
    }
  ]
}
```

With these changes in place, test the setup by running:

```bash
vercel dev -L
```

This will start both services locally and give you a single URL to test the project. Once you are ready, you can deploy the project to Vercel by running:

```bash
vercel deploy
```

Vercel builds the frontend into `dist/` and serves it through the web service. Requests for the page and its generated assets are handled by the CDN-backed Vite deployment, while `/api/*` requests are routed to the Node service running the Hono application on Vercel Functions.

### 2\. Add production credentials

CLI credentials from `ant auth login` only exist on your machine, and the Anthropic client reads `process.env` at module scope, so the deployment needs its configuration set as environment variables before imports run. In your project settings, open **Environment Variables** and add:

| Variable                | Value                                                                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `ANTHROPIC_API_KEY`     | The key from [platform.claude.com](https://platform.claude.com). The SDK also accepts `ANTHROPIC_AUTH_TOKEN` as the bearer-token form |
| `CLAUDE_AGENT_ID`       | The `agent_...` ID printed by `npm run setup`                                                                                         |
| `CLAUDE_ENVIRONMENT_ID` | The `env_...` ID printed by `npm run setup`                                                                                           |

`deployedApi()` checks these on every request and names the missing variable in its 500 response. Don't run `npm run setup` as part of the build: the agent and environment are persistent resources, and re-running setup creates duplicates. Provision once from your machine and reuse the IDs.

### 3\. Learn what stays per instance

The Managed Agents session holds every conversation, so `createMemoryState()` in `src/bot.ts` carries only Chat SDK internals, and the quickstart keeps memory state in production on a single instance.

Fluid compute runs many requests on one instance but scales to more instances under load, and three behaviors in the quickstart are process-local:

| Behavior              | Where it lives                           | On multiple instances                                                                                                                                                                                                                                              |
| --------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Message dedup         | `createMemoryState()` in `src/bot.ts`    | Duplicate deliveries of the same message ID could each start a turn. `useChat` sends each message once, so this matters when you add retries or a second surface. The fix is `createRedisState()` from `@chat-adapter/state-redis`, which auto-detects `REDIS_URL` |
| Turn ordering         | `enqueueTurn` in `src/managed-agents.ts` | Two instances streaming the same session would each post every reply. The browser serializes sends per conversation, so this appears when something else writes into the same session concurrently                                                                 |
| Activity feed fan-out | `src/activity.ts`                        | When `GET /api/activity` lands on a different instance than the turn's `/api/chat`, the feed shows empty for that turn. This is cosmetic: the chat lane is unaffected                                                                                              |

For a demo or low-traffic deployment, ship as-is.

Before scaling past one instance, make the Redis swap and treat the other two rows as known behavior rather than bugs to chase.

### 4\. Raise the max duration for the chat route

The research turns hold the `/api/chat` response open for one to three minutes while the brief streams. Vercel Functions on fluid compute default to a 300-second maximum duration, which covers a typical turn, and Pro and Enterprise teams can raise the limit to 800 seconds for longer research runs.

To raise the project default, open the [Functions page](https://vercel.com/d?to=%2F%5Bteam%5D%2F%5Bproject%5D%2Fsettings%2Ffunctions) in your project settings. Under **Advanced Settings**, set a new value for **Function Max Duration**.

You can also set `maxDuration` per [function](https://vercel.com/docs/services/config-reference#functions) in `vercel.json` if only the chat route needs the longer window. For runs beyond 800 seconds, [extended max duration](https://vercel.com/docs/project-configuration/vercel-json#functions) supports per-function limits up to 30 minutes on supported Node.js and Python runtimes. Project defaults stay capped at 800 seconds.

Fluid compute fits this workload well. Active CPU billing only applies while your code executes and pauses while the function waits on I/O, and this function spends nearly the entire turn waiting on Anthropic's event stream.

### 5\. Lock down authentication first

Deploying makes every route public, so complete the `getUser` replacement described in [best practices](https://vercel.com/kb/guide/claude-managed-agents-chat-sdk#replace-the-demo-authentication-before-exposing-the-server) before your first production deploy. The demo authentication treats every caller as the same user, which is safe on `127.0.0.1` and nowhere else: anyone who reaches the URL can run research turns on your bill, list your sessions, and replay every transcript.

Vercel's Deployment Protection can gate the URL while `getUser` is still the demo version, but treat it as a stopgap rather than a fix.

## Best practices

### Replace the demo authentication before exposing the server

The `getUser` function in `src/bot.ts` is the security boundary for every route: `/api/chat`, `/api/sessions`, `/api/history`, and `/api/activity`. The demo version accepts every caller as the same local user, which is why the server binds to `127.0.0.1` by default.

Before setting `HOST=0.0.0.0` or deploying:

- Replace `getUser` with your real session lookup (e.g., with Better Auth)
  
- Scope sessions per user by writing the resolved user ID into session metadata
  

### Never trust a browser-supplied conversation ID

The browser sends session IDs, and the server's Anthropic credentials can see every session in the workspace. The quickstart's `ownedSession()` check in `src/managed-agents.ts` verifies that an incoming ID resolves, belongs to this agent, and isn't archived before any route touches it. If you fork the project, keep that function in the path of anything that accepts a conversation ID from a client.

### Raise idle timeouts for long-lived responses

The `/api/chat` response stays open for the whole research turn, often minutes at a time. A reverse proxy or load balancer with a default idle timeout (often 60s) will close the response right when the brief is due.

On Vercel, this limit is the function's max duration. If you host the app elsewhere or put your own proxy in front of it, raise the proxy's idle timeout for the `/api/chat` route and verify that your platform allows long streaming responses.

## Troubleshooting

| Symptom                                                         | Likely cause                                                                                                                                                               | Fix                                                                                                                   |
| --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Replies arrive whole but never stream                           | The organization doesn't have session streaming enabled, or the installed `@anthropic-ai/sdk` is older than 0.109.0                                                        | Upgrade the SDK to 0.109.0 or later and confirm streaming is enabled for your organization                            |
| Every request fails with a 404                                  | The organization has no Managed Agents access. The SDK sends the `managed-agents-2026-04-01` beta header on every call, so an org without access rejects the first request | Use an organization that has Managed Agents access                                                                    |
| 400 Invalid agent ID                                            | `.env` still contains the `agent_...` placeholder                                                                                                                          | Re-paste the IDs printed by `npm run setup`                                                                           |
| Acknowledgment arrives, then a network error replaces the brief | Something between the browser and the server closed the long-lived response. The turn still finished server-side                                                           | Reopen the chat from the sidebar to see the reply, then raise the function's max duration or the proxy's idle timeout |

## Resources and next steps

- Move the same handler to Slack, Teams, Discord, Telegram, or WhatsApp by adding an adapter in `src/bot.ts`. See the [Chat SDK adapters directory](https://chat-sdk.dev/adapters) and the porting notes in the quickstart's [`skill.md`](https://github.com/anthropics/claude-quickstarts/blob/main/managed-agents/chat-sdk/skill.md)
  
- Learn how Vercel builds and runs Hono apps in the [Hono documentation](https://vercel.com/docs/frameworks/backend/hono)
  
- Learn more about the Chat SDK's core patterns in the [documentation](https://chat-sdk.dev/docs/getting-started)
  
- Explore sessions, environments, memory stores, and multi-agent rosters in the [Claude Managed Agents documentation](https://platform.claude.com/docs/en/managed-agents/overview)
  
- Learn more about [Vercel Services](https://vercel.com/docs/services)