Skip to content

Claude Code

中文文档

Claude Code is a terminal-based AI coding agent developed by Anthropic. It runs commands, edits files, and executes code in your terminal.

This guide shows how to keep Claude Code running on your host while transparently redirecting every Bash command it runs into an isolated CubeSandbox MicroVM, using a PreToolUse hook. The model never sees the sandbox layer, and no prompt or workflow changes are required.

Why a hook

MCP- or SDK-based sandboxing depends on the agent choosing a sandbox tool; a plain Bash tool call still lands on the host. A PreToolUse hook intercepts the tool call itself, so Bash isolation is transparent and complete — there is no path for a command to skip it.

Architecture

Claude Code (host)
    ├── Read / Write / Edit ─────────────► host project files

    └── Bash ──► PreToolUse hook ──► cubesandbox_exec ──► CubeAPI ──► MicroVM
                 (cubesandbox_rewrite.py)                 (:3000)     └─ reusable per session

Only the Bash tool is redirected. Read, Write, and Edit keep operating on host files, so Claude Code edits your project locally while its shell commands run in a throwaway kernel/filesystem/network.

Integration Target and Version

ComponentVersion
Claude CodeAny release with PreToolUse hook support
cubesandbox Python SDKInstalled via requirements.txt
Python3.9+ on the host running Claude Code

Prerequisites

  • Running CubeSandbox deployment with CubeAPI reachable (e.g. http://127.0.0.1:3000)
  • Python 3.9+ on the host running Claude Code
  • A CubeSandbox template to launch sandboxes from (see Template below)

Template

The hook runs arbitrary Bash commands in the sandbox, so the template only needs to be a general-purpose code sandbox — Claude Code itself does not need to be installed inside it. The stock sandbox-code image works:

bash
cubemastercli tpl create-from-image \
  --image cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest \
  --writable-layer-size 2G \
  --expose-port 49999 \
  --expose-port 49983 \
  --probe 49999

Use the resulting template ID (STATUS: READY in cubemastercli tpl list) as CUBE_TEMPLATE_ID below.

Install the hook

From the example directory:

bash
python3 -m pip install -r requirements.txt
cp .env.example .env
# Set CUBE_API_URL and CUBE_TEMPLATE_ID in .env

cd hooks
./install.sh

Restart Claude Code after installation. The installer merges a Bash matcher into ~/.claude/settings.json without replacing your other settings, and writes only whitelisted CUBE_* values to the hook configuration — it never copies LLM provider API keys.

Now use Claude Code normally: every Bash command it issues executes inside a MicroVM.

How it works

  1. cubesandbox_rewrite.py (the hook) receives the PreToolUse payload. For a Bash call it rewrites tool_input.command to an invocation of the executor with the original command as a single shlex-quoted argument, and returns it via updatedInput. Nothing in the original command can execute on the host. Non-Bash tools pass through. Every Bash command is wrapped unconditionally; if an already-wrapped executor invocation is fed back through the hook, the nested invocation simply fails inside the sandbox (the host hook path does not exist there), never on the host.

  2. cubesandbox_exec.py (the executor) reuses one sandbox per Claude Code session_id (mapping stored under ~/.cache/cubesandbox-hook/, guarded by a per-session file lock), replays the persisted working directory and exported environment, runs the command in the MicroVM, and returns stdout/stderr and the exit code after the command finishes (buffered, not streamed).

Host project mount

On the first call in a session, the hook can request a read-only mount of Claude Code's project directory at the same path in the sandbox. Add the project root to CubeMaster's host-mount allowlist:

yaml
extra_conf:
  allowed_host_mount_prefixes:
    - "/data/shared/"
    - "/home/you/projects/"

hostPath is resolved on the scheduled Cubelet node, not on the machine running Claude Code. The shared view works only when Claude Code is co-located with that Cubelet, or the project already lives at the identical absolute path on every eligible Cubelet. The hook does not upload or synchronize a local project to a remote deployment; do not allowlist a client-only path that could refer to unrelated Cubelet data.

This hook covers the Bash tool only. Read, Write, and Edit still access the host, and the mount is read-only so sandbox commands cannot write project files or build artifacts. If CubeMaster rejects the mount, execution falls back to a sandbox without it; Bash stays isolated but loses filesystem consistency with the host-side tools.

Security properties

  • Fail-closed — if the hook cannot rewrite a call safely, it exits non-zero and blocks the command rather than letting it run on the host.
  • Injection-safe — the original command is passed as one shlex-quoted argument, so shell metacharacters and newlines can never break out onto the host.
  • Unconditional wrapping — every Bash call is rewritten; an already-wrapped executor invocation fed back through the hook simply fails inside the sandbox (the host hook path does not exist there), never on the host.
  • Auto-approval — the hook answers permissionDecision: "allow" for rewritten Bash calls, so Claude Code's per-command approval prompt is suppressed; use --permission-mode / hooks policy accordingly.
  • No credential leakage — the installer copies only whitelisted CUBE_* values into the hook config.

Reset and uninstall

bash
# Drop the sandbox bound to a session (fresh sandbox next call)
python3 ~/.claude/hooks/cubesandbox_exec.py --reset --session <session-id>

# Remove the hook from ~/.claude/settings.json
cd hooks
./install.sh --uninstall

Key Code Snippets

Hook matcher in ~/.claude/settings.json

The installer merges a Bash matcher group like this into your settings (with your absolute home path):

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/home/you/.claude/hooks/cubesandbox_rewrite.py || exit 2"
          }
        ]
      }
    ]
  }
}

Manual hook test

bash
echo '{"tool_name":"Bash","cwd":"/tmp","session_id":"t","tool_input":{"command":"whoami"}}' \
  | python3 ~/.claude/hooks/cubesandbox_rewrite.py

Caveats

  • Read/Write/Edit stay on the host. Only Bash tool calls are redirected; Claude Code's file edits keep hitting your host project files.
  • Serialized Bash within a session. Concurrent Bash calls in one session are serialized through a per-session lock — they run one at a time, not in parallel.
  • Buffered output. stdout/stderr are returned only after the command finishes; long-running commands show no incremental output.
  • Auto-approval. The hook answers permissionDecision: "allow" for rewritten Bash calls, so Claude Code's per-command approval prompt is suppressed — set --permission-mode / hooks policy accordingly.
  • Persisted environment is scrubbed. Exported variables persist between commands, but BASH_ENV, ENV, LD_PRELOAD, and PROMPT_COMMAND are scrubbed from the persisted environment.

Troubleshooting

Bash commands still run on the host

The hook is not registered, or Claude Code was not restarted. Verify ~/.claude/settings.json has a PreToolUse Bash matcher pointing at ~/.claude/hooks/cubesandbox_rewrite.py, then restart Claude Code. You can test the hook directly:

bash
echo '{"tool_name":"Bash","cwd":"/tmp","session_id":"t","tool_input":{"command":"whoami"}}' \
  | python3 ~/.claude/hooks/cubesandbox_rewrite.py

the cubesandbox SDK is required

Install dependencies into the Python environment Claude Code uses: pip install -r requirements.txt.

CUBE_TEMPLATE_ID is not set / Template not found

Set CUBE_TEMPLATE_ID in .env to a READY template (cubemastercli tpl list), then re-run hooks/install.sh.

Host mount rejected

The path is not in allowed_host_mount_prefixes, or does not exist on the scheduled Cubelet. Add the prefix to CubeMaster extra_conf, ensure co-location, or accept the no-mount fallback.

Example Repository

See the full runnable example at examples/claude-code-integration/, which includes:

  • hooks/cubesandbox_rewrite.py — the PreToolUse hook that rewrites Bash calls
  • hooks/cubesandbox_exec.py — the executor: per-session MicroVM reuse and shell-state persistence
  • hooks/install.sh — idempotent install / uninstall
  • tests/ — tests for the hook rewrite, executor, and install lifecycle

References