VS Code Extension
Running Claude Code inside VS Code. Diagnostics, inline diffs, and the split between IDE and terminal sessions.
What it integrates#
The Claude Code VS Code extension embeds a Claude Code session inside the editor, surfacing it as a side-panel chat and wiring the editor’s existing primitives — open files, selection, diagnostics, diff viewer, terminal — into the conversation loop. The CLI underneath is the same claude binary you’d run in a terminal; the extension adds editor-aware affordances around it.
What the integration covers:
- Side-panel chat — a dedicated view container with a Claude Code session bound to the current workspace.
- Open-file awareness — the model knows which files you have open and which one is active. Selection is included as context when you start a turn while highlighting code.
- Inline diffs — proposed edits render as VS Code’s native diff view; you accept, reject, or edit-then-accept directly in the editor.
- Diagnostics piping — squiggles from language servers (TypeScript, Pyright, rust-analyzer, ESLint) are readable by Claude Code via a built-in diagnostics tool. “Fix all errors in the open file” becomes a one-turn request.
- Terminal integration —
Bashtool calls run in a VS Code integrated terminal so you see them streaming inline with the conversation. - Keybindings — start a turn, accept the next edit, reject an edit, open the panel — all bindable.
- Workspace trust — extension respects VS Code’s workspace-trust model; in untrusted workspaces it disables write-capable tooling.
What it does not do: replace the CLI. The extension uses the same claude binary, the same settings layers, the same MCP servers. A session you start in the panel and one you start in ~/.zshrc’s terminal are the same product with a different UI layer.
Setup#
Prerequisites#
- VS Code 1.85 or later (Cursor and other forks may also work; the extension targets the upstream VS Code API).
- The
claudeCLI installed and authenticated. See Installation and First Run. - A workspace open (the extension is workspace-aware; opening it without a folder gives you a narrower experience).
Install#
# From the VS Code Marketplace via CLIcode --install-extension anthropic.claude-codeOr open the Extensions view (Cmd+Shift+X / Ctrl+Shift+X), search “Claude Code”, install.
After install, a Claude icon appears in the activity bar. Click it (or run Claude Code: Open Panel from the command palette) to start a session.
First-run flow#
- Open a workspace.
- Click the Claude Code icon in the activity bar.
- If
claude auth statusis already green, the panel opens directly. If not, the extension prompts you to authenticate; it shells out toclaude auth loginin an integrated terminal. - The panel is now bound to this workspace; subsequent turns share the same session until you clear it.
Keybindings worth setting#
The defaults are conservative; the highest-leverage rebinds:
[ { "key": "cmd+i", "command": "claude-code.startTurn", "when": "editorTextFocus" }, { "key": "cmd+shift+a", "command": "claude-code.acceptEdit", "when": "claude-code.editPending" }, { "key": "cmd+shift+r", "command": "claude-code.rejectEdit", "when": "claude-code.editPending" }, { "key": "cmd+shift+c", "command": "claude-code.focusPanel" }]cmd+i mirrors the muscle memory of inline-AI editors; the Accept/Reject bindings remove the round-trip to the panel for routine confirms.
Settings#
The extension’s settings live in settings.json under the claude-code.* namespace:
{ "claude-code.model": "claude-opus-4-7", "claude-code.permissionMode": "default", "claude-code.diff.autoOpen": true, "claude-code.diagnostics.includeInContext": true, "claude-code.terminal.integrated": true, "claude-code.statusLine.show": true}These are user-level by default. Project-level overrides go in .vscode/settings.json; team-shared overrides go in .vscode/settings.json under source control.
Capabilities#
Inline diff workflow#
When Claude Code proposes an edit, the extension renders it in VS Code’s native diff view rather than dumping the patch into the chat. Three actions:
- Accept — applies the change to the working copy.
- Reject — discards the change; the session continues without it.
- Accept and continue — applies and signals the model that this branch is settled; useful when a turn proposed multiple edits and you want to keep them all.
Multi-file edits open a chained diff view: navigate file-by-file, accept each, then a single “all applied” notification.
Diagnostics-driven fixes#
The extension exposes a Diagnostics tool that returns the active language server’s findings for an open file (or the workspace). Phrasings the model handles well:
- “Fix the TypeScript errors in this file.”
- “Look at the squiggles in
parser.tsand tell me which are real bugs.” - “Suppress the
no-unused-varswarnings that are intentional and fix the rest.”
The diagnostics-included-in-context setting (claude-code.diagnostics.includeInContext) adds a compact summary to every turn. Cheap on tokens; expensive on annoyance if you have a noisy linter, so it’s opt-in.
Selection as context#
If you have code selected when you type a prompt, the extension prepends the selection (with file path and line range) to the turn. Useful for “explain this”, “rewrite this for clarity”, “find callers of this function” — the model knows what “this” refers to.
Open editors as the working set#
The model treats currently-open editors as a hint for what you’re working on. It still uses Read/Edit on disk paths, but file picks and prose like “the other file I had open” resolve correctly.
Terminal output streaming#
Bash tool calls run in an integrated terminal panel and stream live. The chat shows a collapsed header (“ran pnpm test”) and you click to expand. This matches the CLI behaviour but with proper terminal rendering — colour, progress bars, ANSI sequences all work.
Notebooks#
.ipynb files render with their cells; the model has a NotebookEdit tool that operates at the cell level. Editing cell 42 in a notebook is a first-class operation, not a “edit this giant JSON file” hack.
Configuration#
Where settings come from#
The precedence, top wins:
.vscode/settings.jsonin the workspace (committed) — team-shared..vscode/settings.jsonfor the workspace (user, not committed) — uncommon.- User-level
settings.json— your personal defaults. - Extension defaults.
CLI-level Claude Code settings (~/.claude/settings.json and .claude/settings.json in the repo) still apply — the extension shells out to the same binary, which reads the same config. The split:
- Editor concerns (which keybinding, whether diffs auto-open, whether diagnostics enrich every turn) — VS Code settings.
- CLI concerns (which model, which permission rules, which MCP servers, which hooks) — Claude Code settings.
Per-workspace overrides#
A project that uses a specific model (say, a model fine-tuned on internal docs via the Bedrock provider) can pin it in .vscode/settings.json:
{ "claude-code.model": "claude-opus-4-7", "claude-code.permissionMode": "plan"}This overrides the user-level default for sessions started in this workspace, leaving other projects untouched.
Workspace trust#
VS Code asks whether you trust a folder on first open. The extension respects the answer:
- Trusted — full tool surface; edits, Bash, MCP servers all work.
- Restricted — read-only tools only; Edit, Write, Bash are disabled; MCP servers don’t load.
This is a real defence against opening a hostile repo (a downloaded ZIP with a malicious .claude/settings.json that adds a sketchy MCP server). Don’t trust folders you haven’t reviewed.
Status line in the editor#
The extension’s status bar surfaces the model, the active session’s token usage, and the current permission mode. Click each segment to change it without leaving the editor:
- Model segment — switch between configured models for this workspace.
- Permission segment — toggle between default / accept-edits / plan / bypass.
- Tokens — see the running session cost; click for a breakdown.
Failure modes#
The recurring failures with the VS Code integration:
claudebinary not on PATH from inside VS Code. VS Code launched from a GUI on macOS doesn’t inherit your shell’s PATH. The extension can’t findclaudeand shows “binary not found.” Fix: install theShell Command: Install 'code' command in PATHonce and ensureclaudelives in a directory referenced by/etc/pathsor the global launchd env; or setclaude-code.cliPathexplicitly to the absolute path.- Diagnostics tool returns nothing. The language server hasn’t finished indexing yet. Wait for the “Initialising” notification to clear; try again.
- Diff view shows the wrong file. The model edited file A; the diff view opened on file B because file B was the last active editor. Click the file in the chat header to re-target; the model still has the correct path.
- Extension panel goes blank after a long session. Webview process crashed. Reload the window (
Cmd+Rin the panel, or Developer: Reload Window). The session is preserved if the CLI didn’t crash; you keep your transcript. - Hooks don’t fire from inside VS Code. They do — but the hook script runs with VS Code’s environment, not your shell’s. PATH differences mean a
pythonscript that works in the terminal can fail. Use absolute paths in hook commands or setPATHexplicitly. - MCP servers fail to start. Same root cause as above: the env launching MCP servers is VS Code’s env. Set required env vars in
claude-code.envor in user-level launchctl on macOS. - Selection is empty but you thought you had one. VS Code clears selection on focus loss; if you clicked the panel before submitting, your selection is gone. Either type the prompt before clicking, or use the Send Selection command.
- Terminal session and panel session diverge. Two
claudesessions running side by side. They share~/.claude/settings.jsonbut each has its own conversation state. Not a bug, but a source of “why didn’t the other one know?”
Security and permissions#
What the extension gains access to#
When you grant the extension workspace trust, Claude Code inherits the same permissions you have:
- Read and write every file in the workspace.
- Run shell commands with your user’s privileges.
- Reach any network endpoint your machine can reach.
- Use any MCP server configured for this workspace.
VS Code’s process model means the extension itself is not a sandbox. It runs in the editor’s extension host, and the CLI it spawns has full user privileges.
Settings come from the workspace#
A repo can ship .vscode/settings.json and .claude/settings.json under source control. Both are read on workspace open if you trust the workspace. The implications:
- Pulling a repo with malicious settings is the same as installing it.
- A
.claude/settings.jsonwith anmcpServersblock referencing an attacker-controlled binary will run that binary as you.
Mitigation: never trust a workspace you haven’t reviewed for these files. The extension warns when settings are loaded from a workspace the first time; don’t dismiss it absent-mindedly.
Auth state is shared with the CLI#
The OAuth token Claude Code uses lives in your OS keychain, accessible to anything running as you. The extension does not provide additional isolation. If you log out from one (claude auth logout in the terminal), you log out everywhere.
Permission modes apply#
The four permission modes are the same as in the CLI:
VS Code extension
- Diff view for previewing edits.
- Diagnostics auto-fed into context.
- Selection auto-included.
- Status-bar quick toggle for permission mode.
- Better for: incremental edits, code review, debugging.
Terminal CLI
- Full screen real estate for the session transcript.
- Headless mode and scripting available.
- Faster keyboard-only flow once the muscle memory is there.
- Works over SSH.
- Better for: long-running sessions, autonomous loops, anything CI-shaped.
In practice most users run both — extension for daily editing, CLI for headless runs and long sessions.
Per-workspace allowlists matter more in the IDE#
The IDE’s lower friction makes it easy to allowlist things you’d think harder about in the terminal. Resist allowlisting Bash(*); resist setting permissionMode: bypass. Both make the editor feel snappier and both significantly raise blast radius if the session ever ingests untrusted content.
What the extension is doing under the hood
The extension is a thin layer over the same claude binary you’d run in a shell. Specifically:
- On panel open, it spawns
claude --ide-modeas a child process and pipes a JSON-RPC channel over stdio (similar to MCP itself, but in the other direction — the editor is the server here, exposing IDE-specific tools to the CLI). - The IDE-side tools include
vscode_diagnostics,vscode_open_file,vscode_show_diff. The CLI invokes them and the extension routes them to VS Code’s API. - Edits come back as patches the extension routes through the diff view rather than directly applying.
- Bash tool calls open an integrated terminal; the extension parses the output stream and forwards it to the session.
This architecture means the extension is replaceable — JetBrains IDEs use the same claude --ide-mode protocol with a different IDE-side implementation. The CLI is the constant.
Related integrations#