VS Code Tunnel
Run VS Code Server in tunnel mode inside an AgentVisor™ sandbox using agentvisor exec — connect from the vscode.dev web client or a desktop VS Code, with policy-enforced HTTP access restricting traffic to VS Code infrastructure and GitHub.
Difficulty: Expert
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 execto run a long-lived network service (not just a shell) inside the sandbox - Pre-baking a large download (the VS Code Server, ~100 MB) into the guest image at build time instead of fetching it at runtime
- A custom entrypoint script that copies a read-only rootfs asset into a writable tmpfs before exec'ing the real command
- Raising the guest's file-size limits (
guest.fsize_soft_limit/fsize_hard_limit) for a workload that needs to write large files - Writing an MPE policy with a large but still-enumerated allowlist (tunnel relay, CDN, marketplace, GitHub, Microsoft login)
Prerequisites
Build AgentVisor (if running from the repository):
make build
GitHub account for tunnel authentication. On first run, the VS Code CLI prompts you to authenticate via GitHub device flow (a URL and code displayed in your terminal).
No Temporal or Ollama required — interactive sessions run without workflow orchestration.
Project Structure
vscode-tunnel/
├── mav-agent-config.yaml # Interactive provider + entrypoint.sh
├── entrypoint.sh # Copies the pre-downloaded server into tmpfs, then execs `code tunnel`
├── agentvisor.yaml # Raised guest fsize limits; credential brokering left commented out
├── Dockerfile # Installs Node.js 18, VS Code CLI, and pre-downloads VS Code Server
├── .dockerignore # Excludes policies/, *.md, agentvisor.yaml from build context
└── policies/
├── domain.yml # MPE PolicyDomain — VS Code infrastructure + GitHub only
└── test.yml # Policy test cases
mav-agent-config.yaml
framework:
provider: interactive
command: ["/app/agent/entrypoint.sh"]
env:
TERM: xterm-256color
VSCODE_CLI_DATA_DIR: /tmp/vscode-cli
The command is a script, not the code binary directly — see entrypoint.sh below.
entrypoint.sh
#!/bin/sh
set -e
# Copy the pre-downloaded VS Code Server from the read-only rootfs
# into the writable CLI data directory on tmpfs. The server needs to
# write log.txt, pid.txt, and other files alongside the binary, so a
# symlink to the read-only rootfs doesn't work — we need a full copy.
mkdir -p /tmp/vscode-cli
cp -a /opt/vscode-server/servers /tmp/vscode-cli/servers
exec code tunnel --accept-server-license-terms "$@"
The guest's rootfs is read-only (see Sandbox Modes), but the VS Code Server needs a writable directory to run in. The Dockerfile pre-downloads the server into /opt/vscode-server at build time; this script copies it into the tmpfs-backed VSCODE_CLI_DATA_DIR at session start so the tunnel doesn't have to download ~100 MB on every run.
agentvisor.yaml
guest:
fsize_soft_limit: 524288000 # 500MB
fsize_hard_limit: 1073741824 # 1GB
VS Code Server extraction needs a larger per-process file size limit than the runtime default. Credential brokering is left commented out in this file — tunnel authentication uses GitHub device flow, not an API key.
Run
agentvisor template create interactive/vscode-tunnel
cd vscode-tunnel
agentvisor exec .
For local debugging without Docker sandbox:
agentvisor exec . --sandbox=none
First-Run Authentication
On first launch, the VS Code CLI displays a GitHub device flow prompt:
To grant access to the server, please log into https://github.com/login/device
and use code XXXX-XXXX
- Open the URL in your browser
- Enter the code shown in your terminal
- Authorize the VS Code tunnel
After authentication, the CLI prints a vscode.dev URL. Open it in your browser to connect your VS Code client to the sandboxed environment.
Subsequent runs reuse the cached authentication token (stored in the sandbox's ephemeral filesystem — re-authentication is needed after each sandbox rebuild).
How the Tunnel Works
Browser (vscode.dev)
↕ WebSocket
Microsoft Tunnel Relay (*.tunnels.api.visualstudio.com)
↕ WebSocket
AgentVisor Sandbox
└─ VS Code Server (pre-downloaded into the guest image)
└─ Terminal, file system, extensions — all inside the sandbox
All traffic between VS Code Server and the relay is outbound from the sandbox. The policy ensures only VS Code infrastructure and GitHub are reachable — no other hosts can be contacted.
Policy Highlights
The allowlist is broader than it might look at first glance — it covers the tunnel relay, the VS Code Server/extension CDN, the marketplace, GitHub, Microsoft's device-flow login endpoint, and (since the guest image also bundles the Claude Code and Codex CLIs) the Anthropic and OpenAI APIs:
- name: "allowed_patterns"
value:
# Anthropic API (Claude Code)
- "^api\\.anthropic\\.com(/.*)?$"
- "^platform\\.claude\\.com(/.*)?$"
- "^statsig\\.anthropic\\.com(/.*)?$"
# OpenAI API (Codex)
- "^api\\.openai\\.com(/.*)?$"
# VS Code tunnel relay and data plane
- "^global\\.rel\\.tunnels\\.api\\.visualstudio\\.com(/.*)?$"
- "^[a-z0-9.-]+\\.tunnels\\.api\\.visualstudio\\.com(/.*)?$"
# VS Code Server download and CDN
- "^update\\.code\\.visualstudio\\.com(/.*)?$"
- "^az764295\\.vo\\.msecnd\\.net(/.*)?$"
- "^[a-z0-9.-]+\\.vscode-cdn\\.net(/.*)?$"
- "^[a-z0-9.-]+\\.vscode-unpkg\\.net(/.*)?$"
# Extension marketplace
- "^marketplace\\.visualstudio\\.com(/.*)?$"
- "^[a-z0-9.-]+\\.gallerycdn\\.vsassets\\.io(/.*)?$"
# GitHub (tunnel authentication + extension repos)
- "^github\\.com(/.*)?$"
- "^api\\.github\\.com(/.*)?$"
# Microsoft login (device flow for tunnel auth)
- "^login\\.microsoftonline\\.com(/.*)?$"
- "^login\\.live\\.com(/.*)?$"
The Dockerfile installs @anthropic-ai/claude-code and @openai/codex globally so they're available as terminal tools inside the tunneled session, but this template doesn't preconfigure credential brokering for either — set ANTHROPIC_API_KEY / OPENAI_API_KEY directly on the host and export them into the sandbox, or add proxy.credentials entries to agentvisor.yaml for symbolic-token substitution (see the Claude Code example).
All internal networks and cloud metadata endpoints are blocked regardless of the allowlist above (hardcoded checks in the Rego policy, same pattern as Claude Code).
Customizing the Environment
The Dockerfile in this directory does three things: installs Node.js 18 and the AI coding CLIs, installs the VS Code CLI standalone binary (architecture-aware), and pre-downloads the matching VS Code Server build so it doesn't need to fetch it at runtime. To add further tools, extend the existing microdnf install step or append a new RUN line:
FROM {{.Image}}
# ... existing Node.js / VS Code CLI / server pre-download steps ...
RUN microdnf install -y python3 && microdnf clean all
COPY agent /app/agent
See exec reference — Customizing the Sandbox Environment for the full list of template variables.
Troubleshooting
Policy denied — extension downloads or telemetry
VS Code extensions may attempt to reach hosts not in the allowlist. These will be denied by the policy. Most functionality works without these — extensions degrade gracefully.
agentvisor exec . --verbose 2>&1 | grep -i deny
Tunnel authentication fails
The GitHub device flow requires outbound HTTPS to github.com and login.microsoftonline.com. If authentication fails, verify the policy allows these domains:
agentvisor exec . --verbose 2>&1 | grep -i "github\|microsoft"
Terminal corrupted after exit
If the sandbox process exits abnormally, run reset to restore your terminal.
Logs
By default exec mode is silent — no logs appear on the terminal so they don't pollute the interactive session:
# Write logs to a file (terminal stays clean)
agentvisor exec . --log-file /tmp/agentvisor.log
# Print logs to stderr
agentvisor exec . --verbose
See Also
- Claude Code — the same
interactiveprovider with credential brokering for a single API - Simple Shell — the minimum
interactiveprovider configuration - agentvisor exec CLI reference
- Sandbox Modes