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 and the claude CLI; policies are
# excluded by .dockerignore — mount them at runtime, as shown below)
agentvisor build . -t claude-code-sandbox:latest

# Run interactively with Docker + gVisor
docker run -it --rm \
--security-opt seccomp=unconfined \
--security-opt apparmor=unconfined \
-v $(pwd)/policies:/etc/agentvisor/policies:ro \
-e AGENTVISOR_AUTHZ_TYPE=embedded \
-e AGENTVISOR_AUTHZ_EMBEDDED_POLICY_DOMAIN_FILES=/etc/agentvisor/policies/domain.yml \
-e AGENTVISOR_LICENSE_KEY="${AGENTVISOR_LICENSE_KEY}" \
-e ANTHROPIC_API_KEY \
claude-code-sandbox:latest

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​

See Interactive Examples: Available Downcalls for which host-to-guest operations are available in exec mode (all except checkpointing and SSE streaming, which require Temporal workflows and the HTTP API).

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. See Troubleshooting Guide: Policy Evaluation Errors for debugging steps and the development-only allowall bypass (never use in production).

See Also​