Claude Sandbox for VS Code
README.md
# Claude Sandbox for VS Code
Makes VS Code the IDE of a Claude Code session running inside
[claude-sandbox](https://github.com/DiamondLightSource/claude-sandbox): Claude
sees your selection, shows proposed edits as diffs to accept or reject, and
reads the workspace's diagnostics. It speaks Claude Code's IDE protocol (MCP
over a WebSocket), the role Anthropic's own extension plays for an
unsandboxed Claude. The full design, protocol notes and security rules are in
[docs/design.md](docs/design.md).
## Install
The extension runs in a devcontainer. Install **Claude Sandbox for VS Code**
from the Extensions view, or add `diamondlightsource.claude-sandbox-vscode` to
the devcontainer's `customizations.vscode.extensions`.
To install a GitHub release instead, run this from a devcontainer terminal
with VS Code attached:
```sh
curl -fsSLO https://github.com/DiamondLightSource/claude-sandbox-vscode/releases/latest/download/claude-sandbox-vscode.vsix
code --install-extension claude-sandbox-vscode.vsix
```
Or download the `.vsix` from the
[releases page](https://github.com/DiamondLightSource/claude-sandbox-vscode/releases)
and use **Extensions → ⋯ → Install from VSIX…**. Repeat to update.
It needs claude-sandbox 5.0.0 or later. If it is missing or older, a
notification offers **Install**, which runs
`uvx --no-cache --from 'claude-sandbox>=5.1.0' claude-sandbox install --minimal`
(with sudo when not root) in a terminal you can watch. uvx is taken only from
`/usr/local/bin`, `/usr/bin` or `~/.cargo/bin`, never from `PATH`. The
extension tells you (at most daily) when a newer claude-sandbox is on PyPI but
never upgrades it.
## Usage
- **Start**: **Claude Sandbox: Start** (command palette, the `Claude:` status
bar item, or `Ctrl+Alt+C Ctrl+Alt+C`) opens Claude in a terminal beside
your editor, sandboxed and linked to this window. Claude runs in, and can
write, one workspace folder: in a multi-root workspace Start asks which (the
last one chosen comes first), or right-click a folder in the Explorer and
choose **Start**. The status bar goes from `waiting` to `connected`. Exiting Claude,
closing its tab or reloading the window ends the session.
- **Presets**: select text, right-click **Claude Sandbox**, or press
`Ctrl+Alt+C` then `E` Explain, `R` Reword, `T` Tighten, `P` My presets,
`M` Mention (inserts `@file#L1-3` without sending), `V` Review All. With
text selected, **Refactor…** (`Ctrl+Shift+R`) and `Ctrl+.` list your
presets then Explain, Reword, Tighten and Mention; with no selection they
offer Mention, for the whole file. To drop Copilot's entries from
those menus, set `github.copilot.editor.enableCodeActions` to `false`. A
preset is typed only when Claude's input box is showing; while Claude is
working or asking you something you get a warning instead. Claude sees
your selection, or the cursor's file and line, for files in Claude's folder
and its peers (the folders beside it, such as the rest of `/workspaces`,
which the sandbox can read but not write); presets and Mention send those
over the link, and name any other file with a typed `@path`. The commands
reach the session started in the same VS Code window: a folder open in
another window has its own.
- **Changed this session**: the side bar lists files changed while the
session ran (your own saves excluded, and only those git shows a change
for). Click one for a diff against HEAD, tick **Mark as reviewed**, or
**Review All Changes** to open them in the multi-file diff editor, then step
with **Next/Previous Change** (`F8`/`Shift+F8` in that editor or the view,
VS Code 1.106+). Right-click a file (or a selection) to open it, stage
it, revert it to HEAD, reveal it or copy its path; **Revert All Changes
to HEAD** is in the view's `…` menu. Staging and reverting are done by VS
Code's Git extension, as Source Control's Stage and Discard are.
- **Reviewing edits**: with `claudeSandbox.reviewEdits` on, every `Edit`,
`Write` and `NotebookEdit` (in auto mode too) opens as a diff to accept or
reject. Edits made through the shell are not caught; the changes view
still lists them.
Settings (user scope only):
| Setting | Default | Purpose |
| --- | --- | --- |
| `claudeSandbox.extraArgs` | `[]` | Extra Claude Code arguments, e.g. `["--model", "opus"]` |
| `claudeSandbox.presets` | `[]` | Your presets: `[{"title": "Summarise", "prompt": "…"}]` |
| `claudeSandbox.autoOpenDiffs` | `false` | Open each change's diff as it happens |
| `claudeSandbox.reviewEdits` | `false` | Ask before file-edit tools, showing each as a diff |
**Claude Sandbox: Copy launch command (advanced)** copies a
`claude --settings '…'` to link a Claude you start by hand instead.
## How it works
The extension listens on a 0600 Unix socket in the folder Claude runs in,
which the jail can see. **Start** runs the sandbox's `claude` through a small
Python pty relay (so the extension knows when the input box is up), with
`--settings` hooks that, inside the jail, bridge `127.0.0.1:<port>` to the
socket with `socat` and write Claude Code's IDE lock file. Claude connects,
the token is checked, and the extension serves four MCP tools: `openDiff`,
`close_tab`, `closeAllDiffTabs`, `getDiagnostics`. One linked session per
window. Details: [docs/design.md](docs/design.md).
## Security
The extension host runs outside the sandbox with your privileges, so every
message from the sandbox is treated as hostile
([trust boundary](docs/design.md#trust-boundary)):
- Only the four tools above; nothing that runs code, opens URLs or writes
files. Accept hands the text back for Claude to write from inside the
sandbox.
- `openDiff` reads only real workspace paths outside `.git`, without
following symlinks.
- Diagnostics, selections and mentions are sent only for files in Claude's
folder and its peers, which the sandbox can read anyway; never for files
under your home folder.
- Presets are typed only into Claude's input box (read from a virtual
screen), never into a menu, as one bracketed paste with control characters
removed.
- The WebSocket server is hand-written with no runtime dependencies and caps
message size, connections, queued output and idle clients.
Every rule has a test in `test/hostile/` or `test/unit/`
([mapping](docs/design.md#rule--test)).
**Out of scope:** a workspace the sandbox can write can attack VS Code through
`.vscode/settings.json` or `.git/config` whether or not this extension is
installed. Keep such workspaces untrusted in Workspace Trust, or review those
files before reopening.
## Development
Linux, Node 22.18+, `socat` and Python 3 for the tests. The repository's
devcontainer has all of them, installs claude-sandbox and the Marketplace
release of this extension, and runs `npm ci`; its
**Run Extension** launch configuration opens an Extension Development Host
with the development build.
```sh
npm ci
npm run lint # Biome: format and lint check (npm run format fixes)
npm run typecheck
npm test # test/unit and test/hostile
npm run build # dist/extension.cjs
npm run package # .vsix
npm run install:dev # install this build over the Marketplace copy, as the next patch version
```
`install:dev` packages the working tree as one patch above the newest release tag
(0.8.0 gives 0.8.1), so the Extensions view shows it is a development build, and
installs it over the Marketplace copy. Run it from a devcontainer terminal, where
`code` is available, then reload the window. A VSIX installed this way is pinned:
VS Code stops auto-updating it, even when a newer release comes out. To go back to
the Marketplace build, uninstall it
(`code --uninstall-extension diamondlightsource.claude-sandbox-vscode`) and reload,
or rebuild the devcontainer.
Before a release, [docs/test-charter.md](docs/test-charter.md) is an
exploratory check of the packaged extension in a real VS Code, for what the
tests above cannot see.
## Releasing
Create a GitHub release with a new tag `X.Y.Z` (no `v` prefix) on `main`, or
just push the tag: `.github/workflows/release.yml` tests and attaches the
`.vsix` to the release, creating it if there is none. A suffixed tag such as `0.2.0-rc1`
makes a GitHub pre-release only. With the repository variable
`MARKETPLACE_PUBLISH` set to `true`, other tags are also published to the
Marketplace, signing in via GitHub OIDC with the `marketplace` environment's
`AZURE_CLIENT_ID` and `AZURE_TENANT_ID`. Without it, upload the release's
`.vsix` by hand on the publisher's page at
<https://marketplace.visualstudio.com/manage>.
## License
MIT, Copyright (c) 2026 Diamond Light Source Ltd.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive