Skip to content
Back to skills

Managed Agents Deployment

ASecurity

Deploying a Managed Agents project to production — wrapping the SDK in FastAPI with SSE, the env vars that have to be set, agent-version pinning, bearer auth, cost tracking via span events, and Docker/Railway/Fly. Read when going from "setup.py worked locally" to "it's running on a server", when designing the request/response contract, when investigating why deployments lose state, or when planning rollouts of agent updates.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 2, 2026
ai-agentspythongofastapidockerapidatabasefrontend

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add Folken2/nuvel --skill managed-agents-deployment --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Managed Agents Deployment?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Managed Agents Deployment
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/folken2-managed-agents-deployment/badge)](https://www.skillsdirectory.com/skills/folken2-managed-agents-deployment)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: managed-agents-deployment
description: Deploying a Managed Agents project to production — wrapping the SDK in FastAPI with SSE, the env vars that have to be set, agent-version pinning, bearer auth, cost tracking via span events, and Docker/Railway/Fly. Read when going from "setup.py worked locally" to "it's running on a server", when designing the request/response contract, when investigating why deployments lose state, or when planning rollouts of agent updates.
---

# Deploying a Managed Agents project

A nuvel-scaffolded Managed Agents project has a clean deploy story: the agent runs on Anthropic's infrastructure, your service is a thin proxy. That changes what you have to think about. This skill covers the parts that aren't obvious.

## What lives where

| Concern | Lives in | Notes |
|---|---|---|
| Agent loop, model inference, sandboxing, cost | Anthropic | Free of you to manage |
| Agent ID, environment ID, agent version | Your env vars | Persisted by `setup.py` to `.env` |
| Custom-tool handlers | Your server process | The only place secrets for non-MCP services can live |
| MCP credentials | Anthropic vaults | OAuth refresh handled by Anthropic |
| Session history | Anthropic | Retrievable via `events.list` for audits |

You ship a thin FastAPI app. The heavy lifting is elsewhere.

## Required env vars

| Variable | Where it comes from |
|---|---|
| `ANTHROPIC_API_KEY` | Your Anthropic account |
| `MANAGED_AGENT_ID` | `setup.py` (returned by `agents.create()`) |
| `MANAGED_AGENT_ENV_ID` | `setup.py` (returned by `environments.create()`) |
| `MANAGED_AGENT_VERSION` | `setup.py` (the current version of the agent) |

The nuvel scaffold's `setup.py` writes the last three to `.env` after applying the YAMLs. For deployment, copy them from your local `.env` to the platform's environment configuration (Railway/Fly/Vercel/etc.) — they're stable across runs unless you re-run `setup.py`.

## Agent-version pinning in production

`MANAGED_AGENT_VERSION` is the current head version after the last `setup.py` run. Two operational patterns:

**Track latest (default).** `sessions.create(agent=AGENT_ID, ...)` uses the current head. New sessions automatically pick up `setup.py` changes. Good for fast iteration; risky for traffic that needs reproducibility.

**Pin explicitly.** `sessions.create(agent={"type": "agent", "id": AGENT_ID, "version": int(VERSION)}, ...)`. New sessions stay on a known version even if someone runs `setup.py` mid-flight. Good for prod; lets you roll forward in CI by re-running `setup.py` and bumping `MANAGED_AGENT_VERSION`.

The nuvel scaffold's `orchestrator.py` defaults to tracking latest. To pin, change the `agent=` argument to the dict form and read `MANAGED_AGENT_VERSION` from env.

## The request/response contract

The default scaffold:

```
POST /run_sse/
Authorization: Bearer <API_KEY>     (if API_KEY env is set)
Content-Type: application/json
{ "prompt": "..." }

Response: text/event-stream
data: {"type": "session.created", "session_id": "sesn_..."}
data: {"type": "agent.message", "content": [...]}
data: {"type": "agent.tool_use", "name": "read", ...}
data: {"type": "session.status_idle", "stop_reason": {"type": "end_turn"}}
data: [DONE]
```

Frontends store the `session_id` from the first event so they can correlate later API calls (events.list for audit, files.list for outputs).

## One session per request

Don't reuse a single session across HTTP requests for different users — each session is a separate conversation thread. Create a fresh session per request:

```python
@app.post("/run_sse/")
async def run_sse(body: dict):
    return StreamingResponse(_sse_stream(body["prompt"]))

async def _sse_stream(prompt: str):
    # Inside the generator: create + stream + tear down per request.
    ...
```

If you want **multi-turn for one user** (e.g. chat), pass the previous `session_id` in subsequent requests and reuse it via `events.send` + `events.stream` against the same session. The session's history is preserved server-side; you don't have to send it back.

## Bearer auth

The scaffold's pattern: if `API_KEY` env is set, require `Authorization: Bearer <API_KEY>` on `/run_sse/`. If unset, no auth (good for local dev). Don't reach for OAuth/JWT until there's a real reason — most internal-tool agents are fine with one shared bearer behind a VPN or Cloudflare Access.

For multi-tenant deploys, put auth in front of the FastAPI app (Cloudflare Access, an API gateway) — not inside it. The agent server should be a dumb relay.

## Cost tracking

Per-turn cost lands on `span.model_request_end` events:

```python
if event.type == "span.model_request_end":
    usage = event.model_usage  # {input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens}
    persist_usage(session.id, usage)
```

Per-session aggregate is on `client.beta.sessions.retrieve(session.id).usage` after the session ends. For multi-tenant cost attribution, persist per-event usage to a database keyed by `session.id` and your tenant ID.

The `MAX_BUDGET_USD` Claude Agent SDK pattern doesn't apply here — Managed Agents don't expose a hard per-session budget. If you need a cap, enforce it at your application layer: subscribe to `span.model_request_end`, sum cost, and `client.beta.sessions.events.send` an `interrupt` if you exceed your threshold.

## Reconnecting under load

A long-lived agent process (cron job, websocket bridge) will eventually drop a stream. Always implement the consolidation pattern from `managed-agents-events` — fetch history on (re)connect, dedupe by event ID, then resume the live stream.

The nuvel scaffold's `server.py` doesn't implement reconnection because the FastAPI request lifecycle is short-lived (one request, one stream). If you're building a long-running consumer, add the pattern.

## Docker + Railway + Fly

The scaffold ships a `Dockerfile` (python:3.12-slim, copies the project, runs `python server.py`) and `railway.json` (Dockerfile builder, `/health` healthcheck). Portable to Fly or Cloud Run with a `fly.toml` or service yaml.

**Env var hygiene at build time.** Don't bake `ANTHROPIC_API_KEY`, `MANAGED_AGENT_ID`, etc. into the Docker image — set them at the platform level. The image stays generic; the env varies per deploy.

**Health check.** `/health` returns 200 with the agent name. Wire it to your platform's healthcheck (`healthcheckPath: /health` in `railway.json` already does this).

**Cold starts.** The Anthropic client doesn't pre-warm. First request after a cold start has ~100-200ms extra latency. Acceptable for most use cases; if it isn't, keep one container warm via a low-frequency cron pinging `/health`.

## Updating the agent without downtime

Edit `agent.yaml`, run `setup.py` — this updates the agent in place (creates a new version) and bumps `MANAGED_AGENT_VERSION` in `.env`. Existing sessions running on older versions continue undisturbed. New sessions pick up the new version (default behavior, since the scaffold tracks latest).

For pinned production, the rollout is two steps:
1. Re-run `setup.py` against your prod environment (creates new version N+1, but pinned sessions still use N).
2. Update `MANAGED_AGENT_VERSION` in your platform's env config and restart. New sessions now use N+1.

If N+1 regresses, set the env var back to N and restart — instant rollback.

## Pre-launch checklist

- [ ] `ANTHROPIC_API_KEY`, `MANAGED_AGENT_ID`, `MANAGED_AGENT_ENV_ID` set in platform env
- [ ] `API_KEY` set if `/run_sse/` is internet-facing
- [ ] `/health` healthcheck wired to the platform
- [ ] Reconnect/consolidation pattern in any long-running consumer (not the FastAPI scaffold by default)
- [ ] Decide: latest-tracking or pinned versions for production traffic
- [ ] If multi-tenant: auth in front of the app, per-request session creation
- [ ] If cost-sensitive: span.model_request_end persistence + per-session budget enforcement

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.