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 sessionOnly 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
| Component | Version |
|---|---|
| Claude Code | Any release with PreToolUse hook support |
| cubesandbox Python SDK | Installed via requirements.txt |
| Python | 3.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:
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 49999Use the resulting template ID (STATUS: READY in cubemastercli tpl list) as CUBE_TEMPLATE_ID below.
Install the hook
From the example directory:
python3 -m pip install -r requirements.txt
cp .env.example .env
# Set CUBE_API_URL and CUBE_TEMPLATE_ID in .env
cd hooks
./install.shRestart 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
cubesandbox_rewrite.py(the hook) receives thePreToolUsepayload. For aBashcall it rewritestool_input.commandto an invocation of the executor with the original command as a singleshlex-quoted argument, and returns it viaupdatedInput. Nothing in the original command can execute on the host. Non-Bashtools 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.cubesandbox_exec.py(the executor) reuses one sandbox per Claude Codesession_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:
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
# 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 --uninstallKey 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):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/home/you/.claude/hooks/cubesandbox_rewrite.py || exit 2"
}
]
}
]
}
}Manual hook test
echo '{"tool_name":"Bash","cwd":"/tmp","session_id":"t","tool_input":{"command":"whoami"}}' \
| python3 ~/.claude/hooks/cubesandbox_rewrite.pyCaveats
- Read/Write/Edit stay on the host. Only
Bashtool 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, andPROMPT_COMMANDare 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:
echo '{"tool_name":"Bash","cwd":"/tmp","session_id":"t","tool_input":{"command":"whoami"}}' \
| python3 ~/.claude/hooks/cubesandbox_rewrite.pythe 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— thePreToolUsehook that rewrites Bash callshooks/cubesandbox_exec.py— the executor: per-session MicroVM reuse and shell-state persistencehooks/install.sh— idempotent install / uninstalltests/— tests for the hook rewrite, executor, and install lifecycle
References
- Claude Code hooks documentation: https://docs.anthropic.com/en/docs/claude-code/hooks
- Runnable example:
examples/claude-code-integration/ - Project quickstart: Quickstart