showcase/shell-docs/src/content/docs/cookbook/claude-managed-agents.mdx
Claude Managed Agents run Claude agents in Anthropic-hosted environments. Anthropic manages the model runtime and workspace; your app starts sessions, streams their events, and supplies any application-specific tools. This recipe connects one of those hosted agents to a compact CopilotKit chat over AG-UI.
The example is a focused finance assistant. Ask what a recurring investment could grow to and the managed agent calculates in its hosted workspace, calls one backend tool, and CopilotKit renders an interactive growth projection inline. It is adapted from Anthropic's Claude Managed Agents × CopilotKit quickstart, reduced to one interaction that fits a Cookbook pane.
ManagedAgentsAgent maps each CopilotKit thread to one Claude Managed Agents session.show_growth_projection with structured numbers.useRenderTool matches that streamed tool call by name and mounts the React chart in the transcript.Use the suggested prompt, then adjust the contribution and return sliders in the resulting chart.
<iframe src="https://showcase-claude-managed-agents-production.up.railway.app" title="Claude Managed Agents × CopilotKit live demo" className="w-full h-[480px] sm:h-[600px] block rounded-xl border border-[var(--border)]" />claude-fable-5 model is unavailable
under zero data retention.Clone CopilotKit and enter the standalone showcase:
git clone https://github.com/CopilotKit/CopilotKit.git
cd CopilotKit/examples/showcases/claude-managed-agents
npm install
cp .env.example .env
Add your key to .env:
ANTHROPIC_API_KEY=sk-ant-your_key
# Optional; defaults to claude-fable-5
ANTHROPIC_MODEL=claude-haiku-4-5
Provision the persistent environment and managed agent once, then start the server and frontend:
npm run setup
npm run dev
Open http://localhost:5173. npm run setup writes the generated resource IDs to the
gitignored agent-ids.json; rerunning it reuses those IDs instead of creating more billable resources. Use
npm run setup -- --force only when you intentionally want a replacement environment and agent.
Select the suggested prompt or ask:
If I invest $500/month at a 7% annual return, what will I have in 20 years?
Claude passes the assumptions to show_growth_projection and keeps its prose short while the chart
carries the result. Move either slider to explore the assumptions without starting another agent run. A
follow-up in the same CopilotKit thread resumes the same managed session and workspace.
The setup script creates long-lived managed resources. The environment blocks outbound hosts, package managers, and MCP servers, while the agent disables its complete built-in toolset. The runtime adds only the focused financial visualization tool when it creates a session:
const environment = await client.beta.environments.create({
name: `financial-assistant-demo-${Date.now().toString(36)}`,
config: {
type: "cloud",
networking: {
type: "limited",
allowed_hosts: [],
allow_package_managers: false,
allow_mcp_servers: false,
},
},
});
const model = process.env.ANTHROPIC_MODEL ?? "claude-fable-5";
const agent = await client.beta.agents.create({
name: "financial-assistant",
model,
system: ASSISTANT_SYSTEM,
tools: [{
type: "agent_toolset_20260401",
default_config: { enabled: false },
}],
});
The model is fixed when the managed agent is provisioned. Changing ANTHROPIC_MODEL later does not update that
agent. Run npm run setup -- --force with the new model, then replace the generated environment and agent IDs
wherever the demo is deployed.
At runtime, the AG-UI adapter owns managed-session creation and maps it to the CopilotKit thread. The visual tool
is supplied as a session override, so changing its schema does not require a new managed-agent version.
CopilotSseRuntime is imported under that exact name; it is CopilotKit's V2 runtime for direct SSE connections.
The adapter requires only the managed agent and environment IDs, while this recipe adds backendTools for the
interactive projection:
import { CopilotSseRuntime } from "@copilotkit/runtime/v2";
import { ManagedAgentsAgent } from "@ag-ui/claude-managed-agents";
import {
createCopilotRequestBodyParser,
createFinancialAssistantAgentConfig,
} from "./runtimeLimits";
import { configureDemoRunLimits } from "./requestLimits";
const runtime = new CopilotSseRuntime({
agents: {
"financial-assistant": new ManagedAgentsAgent(
createFinancialAssistantAgentConfig(ids),
),
},
});
configureDemoRunLimits(app, createCopilotRequestBodyParser());
The runtime helper keeps the public demo bounded: it leaves turnTimeoutMs at 90 seconds and rejects request bodies
over 256 KB. The adapter already serializes runs per thread.
Only the canonical POST /api/copilotkit/agent/financial-assistant/run path, with one optional trailing slash, can
start the provider-backed agent. Run aliases, unknown agents, and suggestion routes are rejected before the runtime.
Provider-like attempts are limited to 20 per client IP per minute before body parsing, and the process accepts
2,000 successful run requests per 24-hour window. Other CopilotKit routes do not use these allowances.
The single backend tool declares the exact data the UI needs. Its handler only acknowledges the render because the streamed tool call itself is the user-visible result:
export const financialAssistantTools: BackendCustomTool[] = [{
name: "show_growth_projection",
description: "Render an interactive compound-growth chart in the chat.",
parameters: {
type: "object",
properties: {
title: { type: "string" },
initialAmount: { type: "number", minimum: 0 },
monthlyContribution: { type: "number", minimum: 0 },
annualReturnPercent: { type: "number", minimum: 0, maximum: 30 },
years: { type: "integer", minimum: 1, maximum: 50 },
},
required: ["title", "initialAmount", "monthlyContribution", "annualReturnPercent", "years"],
},
handler: () => "Rendered the projection to the user.",
}];
CopilotKit matches the AG-UI tool-call events by name with
useRenderTool. The runnable example validates and coerces the streamed
arguments with Zod before mounting the chart:
useRenderTool(
{
name: "show_growth_projection",
parameters: growthSchema,
render: vizRender(
growthSchema,
"Building growth projection…",
GrowthProjection,
),
},
[],
);
The example supports a single-process deployment: build the Vite frontend, then let the Express server serve
both web/dist and /api/copilotkit.
npm install && npm run build && npm start
Set ANTHROPIC_API_KEY and the two IDs printed by npm run setup:
ANTHROPIC_ENVIRONMENT_ID=env_...
ANTHROPIC_AGENT_ID=agent_...
ALLOWED_ORIGINS=https://your-app.example.com
ANTHROPIC_MODEL is used by setup, not by the running server. To change models on Railway, reprovision first and
then update ANTHROPIC_ENVIRONMENT_ID and ANTHROPIC_AGENT_ID with the replacement IDs.
On Railway, the per-IP limiter uses Railway's X-Real-IP header and normalizes IPv6 client addresses with
express-rate-limit. It does not enable Express proxy trust or use X-Forwarded-For. Missing or malformed
X-Real-IP values share one conservative bucket; local and direct deployments use the socket-derived
request.ip instead.
The adapter's default session store is in memory. A server restart starts fresh managed sessions, while the
provisioned environment and agent remain reusable. Replace it with a durable SessionStore if thread continuity
must survive deploys or multiple server replicas.
useRenderTool component; the AG-UI transport does not change.Full source: examples/showcases/claude-managed-agents. The example includes the runtime and frontend.