# Agent image for OpenShell sandboxes on an exe.dev VM: Claude Code and # Codex, set up to reach models through the VM's exe.dev LLM integration # (via the relay at host.openshell.internal:11435). No API key is in this # image; "exe-gateway" below is a placeholder, not a secret. FROM node:24-bookworm-slim RUN apt-get update \ && apt-get install -y --no-install-recommends bash ca-certificates curl git procps python3 ripgrep \ && rm -rf /var/lib/apt/lists/* RUN npm install -g @anthropic-ai/claude-code @openai/codex # Claude Code: models through the relay. COPY <<'JSON' /etc/claude-code/managed-settings.json { "apiKeyHelper": "echo exe-gateway", "env": { "ANTHROPIC_BASE_URL": "http://host.openshell.internal:11435", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1" } } JSON # Claude Code's first-run check calls api.anthropic.com, which the sandbox # can't reach, so this wrapper marks onboarding as done in a new home. RUN rm /usr/local/bin/claude COPY --chmod=755 <<'SH' /usr/local/bin/claude #!/bin/sh [ -e "$HOME/.claude.json" ] || echo '{"hasCompletedOnboarding": true}' > "$HOME/.claude.json" exec /usr/local/lib/node_modules/@anthropic-ai/claude-code/bin/claude.exe "$@" SH # Codex: the same relay. OpenShell is the sandbox, so Codex skips its own. COPY <<'TOML' /etc/codex/config.toml model_provider = "exe-llm" sandbox_mode = "danger-full-access" [model_providers.exe-llm] name = "exe.dev LLM integration" base_url = "http://host.openshell.internal:11435/v1" requires_openai_auth = false supports_websockets = false TOML USER node