Repository navigation
Description
Problem
With MCP, "project work goes to the VM" is only guidance: the server's instructions and core.guidance (mcp/boxery-mcp.mjs:266). Claude Code, Codex and opencode keep their own built-in shell tool, and models often fall back to it. You find out afterwards that npm install or a test run happened on the laptop. That is the outcome boxery exists to prevent.
ARCHITECTURE.md ("Design decisions") explains why boxery doesn't override built-ins: the old pi extension that replaced bash/read/write/edit conflicted with other extensions. Claude Code's PreToolUse hooks and opencode's tool.execute.before don't have that problem. They sit in front of the built-in tool without replacing it, and they're opt-in user config.
Proposal
boxery hook install claude-code|opencode [--mode guard|redirect], plus boxery hook uninstall …. It edits the agent's settings idempotently and leaves other hooks alone. The hook is active only when a VM is pinned for the session (BOXERY_VM, or a pin file the MCP server writes when a VM is selected); with nothing pinned it does nothing.
-
guard(default). Deny the built-inBashcall with a reason the model sees: "this session is pinned to VMdemo; run it withvm_bash(orvm_jobsfor long-running commands)". An allowlist (git status,git diff,ls, … configurable, empty by default) stays local. This makes the guidance actually enforced, and it can't cause the problem below. -
redirect. Rewrite the command toboxery run NAME --cwd <mapped dir> -- bash -c '<original>'viaupdatedInput. The original command travels as one argument, so it can't run on the host. If the hook can't rewrite a call safely, it denies it rather than letting it run locally.The catch:
Read/Write/Editstill act on laptop files, so the commands run against whatever is in the VM's copy of the project. Redirect is only correct together with a sync step (boxery cp, or the sync idea from boxery sync: push a local checkout's state into the VM #9). The docs must say so, and the hook should warn when the VM's tree is behind.
Codex has no comparable hook today; document it as guidance-only.
Prior art
CubeSandbox ships both variants as examples:
- Claude Code
PreToolUsehook: rewrites everyBashcall withupdatedInput, quotes the original command as a singleshlexargument, denies when it can't rewrite safely, keeps one sandbox persession_id, and persistscd/exportbetween calls. - opencode plugin: the same through
tool.execute.before, plus a per-session lock.
Their README states the motivation directly: an integration that relies on the agent choosing a sandbox tool still lets a plain shell call land on the host.
Their redirect mode has the same split between local files and remote commands. They work around it with a read-only host mount, which is only possible when the agent runs on the sandbox host. That is why guard is the safer default for boxery.
Acceptance criteria
boxery hook install claude-codeis idempotent, keeps existing hooks, anduninstallremoves only boxery's entry.- With a pinned VM, built-in
Bashis denied with a message namingvm_bash; without a pinned VM, the hook allows every call. - Redirect mode: a command containing quotes,
;,$(…)and newlines runs only in the VM. Unit tests feed the hook script recordedPreToolUsepayloads. docs/mcp.mddocuments both modes and the file-sync caveat.
This issue was generated by Claude Code using Claude Opus 5.5 (CubeSandbox comparison, 2026-11-01, at 2b2520b).
Activity