Deploying your agent
Deploy your agent on any sandbox and connect with any env
Package it
The framework deploys container images, so the first step is a Dockerfile next to agent.py:
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir "agentenv-framework-protocol[agent]" "mcp>=1.25,<2" anthropic
COPY agent.py .
CMD ["python", "agent.py"]Register it
Registering builds the image and stores it as an artifact, a stored object that the framework
versions. It then stores the agent, a document that points at that artifact, under an id you
choose. These pages use the id claudius:
agent-env a2a-agent put --id claudius --dockerfile claudius/Dockerfile --skip-validationBuilding Docker image...
Creating DockerImageArtifact...
Created artifact: id=a2a-agent-claudius version=1
Registering A2A agent...
Created A2A agent: id=claudius version=1 image=a2a-agent-claudius:1Each put of the same id stores a new version, and older versions never change. Without
--skip-validation, the put also deploys the agent to run conformance checks, which need an object
store that signs URLs, such as S3; on the local defaults they stop with RuntimeError: A2A validation requires a signable object store for the presigned-URI probe.
Point it at a model
A deploy passes the agent a model endpoint and key, as LITELLM_BASE_URL and LITELLM_API_KEY.
Neither has a default, so set them under [model] in .agentenv/config.toml, with the key as a
secret: reference:
[model]
base_url = "https://llm.example.com/v1"
api_key = "secret:litellm_api_key"secret:litellm_api_key names a key in your secret store, so the file never holds the key itself.
The default store reads it from a litellm_api_key environment variable or a YAML file, and
Secret store covers the others.
The LITELLM_BASE_URL and LITELLM_API_KEY environment variables win over the file. When the
secret store has no value for the key, a deploy stops before it starts a container, with Error: Unresolved secret:litellm_api_key reference (no value and no default).
ClaudiusRLMAgent sends Anthropic Messages API requests to that endpoint, for claude-opus-5-5 by
default. A LiteLLM proxy with that model serves them at /v1/messages, next to its
OpenAI-compatible routes.
Deploy your agent
With the agent registered and pointed at a model, one command deploys it:
agent-env a2a-agent deploy --id claudiusSandbox backend: config default
Fetching A2A agent: id=claudius version=latest...
Found: id=claudius version=1 image=a2a-agent-claudius
Deploying (ttl=7200s)...
Deployed!
Instance ID: claudius-4msj7n4d
A2A URL: http://localhost:42031
Sandbox ID: local-531d8cae
Agent Card: claudius
Expires At (UTC): 2026-09-29 21:44 UTCA2A URL is how the framework, or you, reach your agent: it serves its card there and takes tasks
at /a2a. The instance id uniquely identifies this deployment of the agent.
Where the instance runs depends on the sandbox. The default is local, where the agent is a
container on your machine's Docker. --sandbox picks another built-in, such as modal, or a
provider you register under [sandbox.providers.<name>] in config.toml.
The framework records every instance. agent-env a2a-agent get-instance --id claudius-4msj7n4d
reads the record back: the agent id and the exact version it deployed, the instance's A2A URL, the
sandbox it runs in and when it expires. The record also stores the card the instance served.
Use it
The framework uses your agent through what the instance's card declares. The card's url, /a2a,
takes tasks as A2A messages, and its extensions list what else the agent supports: mcp-config takes
environments, agent-config takes settings such as the model, and trajectory hands back what the
agent did. In a task, a deploy_agent step deploys the agent and posts it each
env's MCP URL, and a prompt_agent step sets its config, sends the prompt and reads the trajectory.
Other extensions are declared the same way, and the framework uses one only when the card lists it:
an agent that implements peer-agents/v1 can message the other agents in a task. Useful A2A
extensions covers every one.
Tear it down
Deploying again starts another instance with another id, and the agent itself never changes. An
instance runs until its TTL runs out, which you set with --ttl-seconds, or until you close it
from Python by its id:
import asyncio
from agent_env.a2a_agent.store import get_a2a_agent_instance_store
from agent_env.providers.sandbox_providers.sandbox_provider import build_sandbox_provider
async def main() -> None:
deployed = get_a2a_agent_instance_store().get("claudius-4msj7n4d")
sandbox = await build_sandbox_provider(deployed.sandbox_type).get_sandbox(deployed.sandbox_id)
await sandbox.terminate()
asyncio.run(main())In a task, a teardown_sandboxes step closes the instances of the agents it names.
Last updated on