# How to Run Claude Managed Agents with Chat SDK

**Author:** CJ Avilla, Ben Sabic

---

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

A 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 one persistent session, replies stream token by token, and a live feed shows the agent's tool calls as it works.

## 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
  
- Prepare the quickstart for deployment and other chat surfaces
  

## Prerequisites

Before you begin, make sure you have:

- Node.js 22.9 or later
  
- Anthropic API key from [platform.claude.com](http://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 of the UI:

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

Because the sessions API is the entire conversation store, restarting the server loses nothing.

### 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 onto the response. The acknowledgment renders within seconds, and the finished brief lands on 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, the sandboxed web research, session state, compaction, and prompt caching all happen inside 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:

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

### 2\. Install dependencies

`npm install`

This installs:

- **Chat SDK packages**:
  
  - `chat`: the core SDK with the type-safe handler and thread/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:

`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

`npm run setup`

This one-time step creates two persistent resources through the Managed Agents API:

- **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:

`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

Start the development server:

`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 server and reload the page. The sidebar and every transcript come back from the sessions API, and follow-up questions in a replayed chat 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:

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

## 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, such as NextAuth, Clerk, or a session cookie
  
- Scope sessions per user by writing the resolved user ID into session metadata at create time
  

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

Before deploying:

- Raise the proxy's idle timeout for the `/api/chat` route
  
- Verify that your serverless platform allows long streaming responses
  

The four API routes are one platform-neutral Hono app (`src/app.ts`) that mounts on any host that can run a fetch handler.

## 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 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`](http://skill.md)
  
- Learn the Chat SDK's core patterns for threads, messages, and handlers in the [Chat SDK documentation](https://chat-sdk.dev/docs/getting-started)
  
- Explore sessions, environments, memory stores, and multiagent rosters in the [Claude Managed Agents documentation](https://platform.claude.com/docs/en/managed-agents/overview)
  
- Build the browser side of streaming chat with [`useChat`](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot) [in the AI SDK](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot)

---

[View full KB sitemap](/kb/sitemap.md)
