Skip to main content

Claude Code

Run Claude Code inside an AgentVisor sandbox with policy-enforced outbound HTTP and host-side credential brokering.

Difficulty: Expert

info

This example uses agentvisor exec mode. Unlike serve and run, exec mode bridges your terminal directly into the sandbox without Temporal workflows or an HTTP API. All HTTP proxy, MCP, A2A, and store features remain available.

What You'll Learn

  • Using agentvisor exec to run Claude Code (or any AI coding tool) inside an isolated sandbox
  • Providing a custom Dockerfile to install Node.js and the claude CLI into the minimal guest image
  • Configuring proxy credential brokering so the host-side ANTHROPIC_API_KEY never enters the guest verbatim
  • Writing an MPE policy that restricts outbound HTTP to only api.anthropic.com
  • Why Claude Code's telemetry requests are denied — and why that's the correct behavior

Security Model

The sandbox enforces the same defense-in-depth as serve mode:

  • HTTP proxy: All outbound HTTP/HTTPS is intercepted by the policy engine. Claude Code can only reach explicitly allowed endpoints (api.anthropic.com)
  • Credential substitution: A symbolic token is injected into the guest; the real ANTHROPIC_API_KEY stays on the host and is substituted by the proxy only for allowed destinations
  • Network isolation: No direct outbound connections — all traffic goes through the proxy
  • Syscall filtering: gVisor's application kernel (when --sandbox=gvisor)

Telemetry and auto-update requests from Claude Code (statsig.anthropic.com, api.github.com, etc.) are denied by policy. This is intentional — those domains are not in the allowlist.

Project Structure

claude-code/
├── mav-agent-config.yaml # Interactive provider + claude command
├── agentvisor.yaml # Proxy credential-broker (must be in cwd or config dir)
├── Dockerfile # Installs Node.js 18 + git + claude CLI
├── .dockerignore # Excludes policies/, *.md, agentvisor.yaml
└── policies/
├── domain.yml # MPE PolicyDomain — Anthropic API only
└── test.yml # Policy test cases

mav-agent-config.yaml

framework:
provider: interactive
command: ["claude", "--dangerously-skip-permissions"]
env:
TERM: xterm-256color

--dangerously-skip-permissions bypasses Claude Code's built-in per-command consent prompts. The MPE policy — not Claude Code's internal model — is the enforcement boundary inside the sandbox.

agentvisor.yaml

proxy:
credentials:
- name: anthropic-key
guest_env_var: ANTHROPIC_API_KEY
destinations:
- "api\\.anthropic\\.com"
resolver:
type: bearer_token
source: env
env_var: ANTHROPIC_API_KEY

The destinations field is required — it restricts credential substitution to api.anthropic.com only. Even if another host were somehow allowed by policy, the proxy would not inject the real API key for it.

Dockerfile

The base agentvisor-guest:*-minimal image does not include Node.js or the claude CLI. It is built on ubi9/ubi-minimal (Red Hat UBI 9), so the package manager is microdnf. The custom Dockerfile layers Node.js 18 and claude in:

FROM {{.Image}}

# Node.js 18 LTS (meets Claude Code's >=18 requirement) + git
RUN microdnf install -y git nodejs npm && microdnf clean all

RUN npm install -g @anthropic-ai/claude-code \
&& npm cache clean --force

COPY agent /app/agent

git is included because Claude Code requires it for many of its editing and diff workflows.

policies/domain.yml (highlights)

# Allow the Anthropic inference API and the Claude subscription/OAuth platform
annotations:
- name: "allowed_patterns"
value:
- "^api\\.anthropic\\.com(/.*)?$"
- "^platform\\.claude\\.com(/.*)?$"
- name: "blocked_patterns"
value:
- ".*\\.internal$"
- ".*\\.local$"
- "metadata\\.google\\..*"
- "169\\.254\\..*"

All internal networks (10.x, 192.168.x, 127.x, 0.0.0.0, localhost) are blocked via hardcoded checks in the Rego policy regardless of the annotations above.

Setup

agentvisor template create interactive/claude-code
cd claude-code

Export your Anthropic API key on the host (never put the real key inside the sandbox or in .env):

export ANTHROPIC_API_KEY=sk-ant-...

Run

Direct exec (development)

The CLI searches for agentvisor.yaml in the current working directory, $HOME/.config/agentvisor, or /etc/agentvisor. agentvisor template create scaffolds agentvisor.yaml into the project root, so running from that directory just works:

agentvisor exec .

Without Docker (no sandbox isolation, for local debugging):

agentvisor exec . --sandbox=none

With gVisor for stronger isolation (Linux only):

agentvisor exec . --sandbox=gvisor

Build and run interactively (production)

# Build the OCI image (embeds Node.js, claude CLI, and policies)
agentvisor build . -t claude-code-sandbox:latest

# Run interactively with Docker + gVisor
docker run -it --rm \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
-e AGENTVISOR_AUTHZ_TYPE=embedded \
-e AGENTVISOR_AUTHZ_EMBEDDED_POLICY_DOMAIN_FILES=/agent/policies/domain.yml \
-e ANTHROPIC_API_KEY \
claude-code-sandbox:latest \
exec /agent

Logging

Exec mode is silent by default — no logs appear on the terminal, keeping the interactive session clean:

# Write logs to a file (terminal stays clean)
agentvisor exec . --log-file /tmp/agentvisor.log

# Print logs to stderr
agentvisor exec . --verbose

Available Downcalls

FeatureAvailable
HTTP proxy (with credential substitution)Yes
MCP gatewayYes
A2A gatewayYes
Key-value storeYes
Log forwardingYes
CheckpointingNo
SSE streamingNo

Checkpointing and SSE streaming require Temporal workflows and the HTTP API, which exec mode intentionally omits.

Policy Highlights

Two domains are in the allowlist — the Anthropic inference API and the Claude subscription/OAuth platform:

- name: "allowed_patterns"
value:
- "^api\\.anthropic\\.com(/.*)?$"
- "^platform\\.claude\\.com(/.*)?$"

Claude Code may attempt to contact telemetry or update endpoints on startup. Those requests will be denied — that is expected and intentional. Claude Code falls back gracefully.

Validate the policy without running the agent:

mpe test decisions -d ./policies/domain.yml -i ./policies/test.yml

Customizing the Environment

Place a Dockerfile in the example directory to install additional tools into the sandbox:

FROM {{.Image}}

# ... existing Node.js + claude install ...

# Add extra tools (microdnf is the package manager in UBI 9 minimal):
RUN microdnf install -y ripgrep && microdnf clean all

See exec reference — Customizing the Sandbox Environment for the full list of template variables and options.

Troubleshooting

Terminal appears corrupted after exit

If the sandbox process exits abnormally, run reset to restore terminal settings.

Policy denied errors

Check the policy is allowing the endpoint your session needs:

AGENTVISOR_LOG_LEVEL=debug agentvisor exec . --verbose

For development only, bypass authorization entirely:

AGENTVISOR_AUTHZ_TYPE=allowall agentvisor exec .
danger

Never use AGENTVISOR_AUTHZ_TYPE=allowall in production.

See Also