Run Claude Code as an isolated and containerized A2A agent - orchestrate multiple sessions with full visibility on Claude operations and messages. Configure marketplaces, plugins, MCP servers and more.
Quickstart | Sending Messages | Installation | Configuration | Examples | Important
This project lets you deploy and run the Claude Code agent as a self-contained A2A server. This allows you to deploy Claude Code to different environments and interact with it using a standardised protocol. Isolated workspaces, skills, and various other capabilities can easily be extended.
Each Claude Code session runs in its own workspace and sessions can be configured with an .init-session.sh script to install MCP servers, plugins, and customise Claude Code's environment.
I am using this agent extensively in my work on Ark - there are examples on how to build skills, use K8S, playwright, and more, in ./examples/ark.
Run the Claude Code Agent A2A server locally (check important note on managing risk:
# Set your API key. OR use as .env file to set your keys.
export ANTHROPIC_API_KEY="sk-***"
# cp .env.sample .env
# Run in local development / live reload mode.
npm install && npm run dev
# SAFER: Run in local development / live reload mode - but don't inherit the
# user's environment (e.g. sensitive env vars not accessible to claude).
make dev-safe
# Server: http://localhost:2222
# or:
# env -i npm run devOr run in a container (event safer and more isolated):
# Run in a container. Also loads the .env file if present.
make docker-run
# Server: http://localhost:2222The A2A server takes incoming requests and starts a session for each one. Each session runs Claude Code in an isolated workspace - you can run as many sessions in parallel as you need. There are a few ways to send messages to an A2A server.
Script
Use the a2a-msg.sh script to send an A2A message. You'll see rich output in the A2A server in real time:
./scripts/a2a-msg.sh "Tell me what tools you have access to, test one out."Example output:
→ Executing: "clone dwmkerr/claude-code-agent and summarise top three issues"
< system:init session=07898273...
< assistant: "I'll clone the repository and summarize the top three issues."
< assistant: Bash {"command":"git clone https://github.com/dwmkerr/claude-..."}
< assistant: Bash {"command":"gh issue list --limit 3"}
... (hidden for brevity in docs)
← Response: "Here are the top 3 issues: #22 OTEL session ID..."
This script is just a wrapper around the raw curl command that can be used to message an A2A server (see below).
cURL
You can also just hit the server directly with curl:
# Construct an A2A message and send to the A2A server.
curl -N -X POST http://localhost:2222/ \
-H "Content-Type: application/json" \
-d @- << 'EOF'
{
"jsonrpc": "2.0",
"method": "message/stream",
"params": {
"message": {
"messageId": "1",
"contextId": "ctx-1",
"role": "user",
"parts": [{"kind": "text", "text": "Tell me what skills you have loaded."}]
}
},
"id": 1
}
EOFExample output:
{"jsonrpc":"2.0","id":1,"result":{"messageId":"...","contextId":"ctx-1",...}}
{"jsonrpc":"2.0","method":"message/stream","params":{"delta":{"text":"I'll..."}}}
... (hidden for brevity in docs)
{"jsonrpc":"2.0","method":"message/stream","params":{"status":"completed"}}A2A Inspector
You can run the A2A Inspector tool to connect to the server and send messages:
# Clone and run the A2A inspector tool.
git clone https://github.com/a2aproject/a2a-inspector
cd a2a-inspector && ./scripts/run.sh
# Then connect to http://localhost:2222See Installation Guide for all installation options, including:
- Docker - Run in Docker
- DevSpace - Live-reload in Kubernetes
- Helm - Deploy to Kubernetes
- Ark - Deploy on Ark
All options are documented in claude-code-agent.example.yaml. Environment variables from .env are loaded on startup (overriding existing vars). The config file .claude-code-agent.yaml is loaded by default if present.
claude-code-agent [options] [-- <claude-code-args>]
Options:
-p, --port <number> Server port (default: 2222)
-H, --host <string> Server host (default: 0.0.0.0)
-w, --workspace <path> Workspace directory
-c, --config <path> Path to YAML config file
--timeout <seconds> Execution timeout (default: 3600)
--log-path <path> Path to write Claude output logs
--agent-name <name> Agent name for A2A registration
# Pass any Claude Code args after --
claude-code-agent -- --allowedTools Bash,Read| Variable | Description | Default |
|---|---|---|
ANTHROPIC_API_KEY |
API key (required) | - |
CLAUDE_TIMEOUT_SECONDS |
Execution timeout | 3600 |
CLAUDE_CODE_WORKSPACE_DIR |
Working directory | ./workspace (local) or /workspace (docker/helm) |
CLAUDE_AGENT_NAME |
Agent name for A2A registration | claude-code |
CLAUDE_LOG_PATH |
File path for JSONL chunk logs | - (disabled) |
INIT_SESSION |
Session init script path | ./.init-session.sh (auto-detected) |
HOST |
Server host | 0.0.0.0 |
PORT |
Server port | 2222 |
FORCE_COLOR |
Enable colors in logs | 1 |
CLI options override environment variables.
Claude operates in ./workspace locally or /workspace in containers. Override with CLAUDE_CODE_WORKSPACE_DIR.
# Mount a specific folder rather than the local ./workspace folder.
CLAUDE_CODE_WORKSPACE_DIR=/tmp/project1 npm run dev
# Docker - mount a local workspace. This folder is automatically mounted when
# make docker-run is used.
docker run -v ./workspace:/workspace ...
# Helm - enable persistence (creates PVC)
helm install ... --set workspace.persistence.enabled=trueYou can configure each Claude Code session with a .init-session.sh script. This script runs automatically when a new session starts in a workspace, allowing you to set up MCP servers, marketplace plugins, and project-specific configuration.
Default: ./.init-session.sh (auto-detected if present)
Override: --init-session <path> or config file agent.initSession
Example .init-session.sh:
#!/usr/bin/env bash
set -e -o pipefail
echo "Initializing session: $A2A_SESSION_ID"
# Add MCP servers (project scope).
# These may fail locally if already installed at user scope - that's ok.
claude mcp add --scope project shellwright -- npx -y @dwmkerr/shellwright || true
# Add marketplace plugins (project scope).
# These may fail locally if already installed at user scope - that's ok.
claude plugin marketplace add dwmkerr/claude-toolkit || true
claude plugin install --scope project toolkit@claude-toolkit || true
# Set up CLAUDE.md - choose one approach:
# Option 1: Fetch from URL
# curl -s https://example.com/CLAUDE.md > .claude/CLAUDE.md
# Option 2: Heredoc for inline configuration
# mkdir -p .claude
# cat > .claude/CLAUDE.md << 'EOF'
# # Agent Instructions
# Your custom instructions here.
# EOFThe A2A_SESSION_ID environment variable identifies the current session.
Claude code runs in a container, with a number of tools such as curl, wget, etc installed. Check these tools or extend by editing Dockerfile.
If tools require configuration, config files or env vars can be passed to the container. For example, to ensure that the gh CLI can be used, pass a GH_TOKEN by either setting in .env or explicitly pass the environment variable. See the important note on risk.
Enable OTEL tracing by setting CLAUDE_CODE_ENABLE_TELEMETRY=1:
# Docker
docker run -e CLAUDE_CODE_ENABLE_TELEMETRY=1 \
-e OTEL_EXPORTER_OTLP_ENDPOINT=http://phoenix:6006 ...
# Helm
helm install ... --set env.CLAUDE_CODE_ENABLE_TELEMETRY=1
# With envFrom for OTEL secrets (e.g., from Phoenix)
helm install ... \
--set env.CLAUDE_CODE_ENABLE_TELEMETRY=1 \
--set envFrom[0].secretRef.name=otel-environment-variables \
--set envFrom[0].secretRef.optional=trueSee examples/ for usage examples:
- Ark Testing - Test Ark PRs with Kind clusters, MCP servers (Playwright), and skills
Implements A2A protocol:
GET /.well-known/agent-card.json- Agent metadataPOST /- JSON-RPC messagesGET /health- Health check
npm install
npm run dev # Development with hot-reload
npm test # Run tests
npm run build # Build for productionReleases push to GHCR (ghcr.io/dwmkerr/claude-code-agent). For local development, push release candidates to Docker Hub:
# Build and push base image RC
docker build -t dwmkerr/claude-code-agent-base:0.1.2-rc1 -f Dockerfile.base .
docker push dwmkerr/claude-code-agent-base:0.1.2-rc1
# Update Dockerfile and devspace.yaml to use the RC tag, then iterateClone the mckinsey/agents-at-scale-ar repo, build a file called 'issues.md' that has a table of issues/urls/ids/titles and a one line summary for each one. Then suggest a good first issue to work on.
Check out mckinsey/agents-at-scale-ark#531 and test it you need to use ark setup to setup your environment and ark-testing to c heck the dashboard. save screenshots to ./screenshots and let me know when done
Be aware that if you run the agent as a local process with npm, then it will inherit your environment. This presents a significant security risk - for example if you are logged into the GitHub CLI (gh) then the agent will be able to execute GitHub commands with your identity, via the Bash tool.
You can run in local development mode with live-reload using make dev-safe:
# SAFER: Run in local development / live reload mode - but don't inherit the
# user's environment (e.g. sensitive env vars not accessible to claude).
make dev-safe
# Server: http://localhost:2222Behind the scenes dev-safe explicitly excludes the user's environment (this'll ensure your AWS keys or whatever are not passed to the model), i.e:
# env -i npm run devIt is highly recommended that you run the agent in a docker container with make docker-run or by checking the Deploy guide. You can also use make dev-safe. Use make help for all recipes.
