[BUG] claudeCode.usePythonEnvironment silently no-ops when claudeCode.useTerminal is enabled
Summary
claudeCode.usePythonEnvironment (default true) is only honored on the SDK spawn path used by the native UI. When claudeCode.useTerminal is true, Claude is launched in a VS Code integrated terminal instead, and that path never consults the setting — so the workspace's Python environment is silently not activated. Nothing surfaces to indicate the setting has been bypassed.
The two settings read as independent, but enabling terminal mode disables Python environment activation as a side effect.
Observed
In a workspace with a .venv and that interpreter selected, running under claudeCode.useTerminal: true with usePythonEnvironment left at its true default:
VIRTUAL_ENVis unset in theclaudeprocess environment..venv/binis absent fromPATH.pythonresolves to my pyenv shim rather than.venv/bin/python.
Inspecting the environment of the claude node process directly (65 variables visible, PATH among them) confirms no VIRTUAL_ENV and no .venv entry. The Python extension is definitely active in that process and has an interpreter selected for the workspace — VSCODE_PYTHON_AUTOACTIVATE_GUARD=1, PYTHONSTARTUP and VSCODE_DEBUGPY_ADAPTER_ENDPOINTS are all present in the same environment — so the documented "Requires the Python extension" dependency is satisfied.
Where it diverges
From extension.js in anthropic.claude-code-2.1.263-darwin-arm64 (minified, lightly trimmed):
The SDK spawn path reads the setting and builds an environment from it:
let {pathToClaudeCodeExecutable: Z, executableArgs: D, env: O} = this.getClaudeBinary(),
L = P1("usePythonEnvironment") ?? !0,
M = L ? await Wu$(O) : O;
if (L && M !== O) {
let j = ["PATH", "VIRTUAL_ENV", "CONDA_PREFIX", "CONDA_DEFAULT_ENV"];
for (let R of j) if (M[R] !== O[R]) this.output.info(`Python env: ${R}=${M[R]}`)
}
N.pathToClaudeCodeExecutable = Z, N.executableArgs = D, N.env = M;
Wu$ is the helper that performs the activation:
let W = z.executable?.sysPrefix || (z.executable?.uri ? y2.dirname(y2.dirname(z.executable.uri.fsPath)) : void 0);
if (!W) return $;
let K = {...$};
K.VIRTUAL_ENV = W;
let U = process.platform === "win32" ? y2.join(W, "Scripts") : y2.join(W, "bin"),
G = K.PATH || process.env.PATH || "";
return K.PATH = `${U}${y2.delimiter}${G}`, console.log(`Python environment activated: VIRTUAL_ENV=${W}`), K
The terminal path builds its environment independently, and it contains exactly one variable:
C0.window.createTerminal({
name: process.env.CLAUDE_CODE_TERMINAL_TITLE || "Claude Code",
iconPath: ...,
location: W,
isTransient: !0,
env: {NoDefaultCurrentDirectoryInExePath: "1"}
})
No Wu$ call, no usePythonEnvironment lookup, no VIRTUAL_ENV.
Repro
- Open a Python workspace containing a
.venvand select that interpreter. - Leave
claudeCode.usePythonEnvironmentat its default (true). - Set
claudeCode.useTerminal: true. - Open Claude and inspect the environment —
VIRTUAL_ENVis unset andcommand -v pythondoes not resolve into.venv/bin. - Set
claudeCode.useTerminal: false, reload the window, and repeat step 4 —VIRTUAL_ENVis now set to the workspace.venv, and.venv/binis prepended toPATH.
Both halves are observed rather than inferred. Same workspace, same selected interpreter, usePythonEnvironment left at its default throughout; the only variable changed is useTerminal. Reading the claude process environment directly:
With useTerminal: true — 65 variables visible, no VIRTUAL_ENV, no .venv entry in PATH. Parent process is the integrated terminal's /bin/zsh -il.
With useTerminal: false — 69 variables visible, VIRTUAL_ENV=<workspace>/.venv, and PATH begins <workspace>/.venv/bin:.... Parent process is the extension host, and the executable is resources/native-binary/claude.
That matches the code paths above exactly: the SDK spawn applies Wu$ and the terminal spawn does not.
Expected
Either the terminal path honors usePythonEnvironment and contributes the same VIRTUAL_ENV / PATH that Wu$ produces, or the setting's description notes that it does not apply in terminal mode. Silently no-opping is the bad case: python, pip and pytest invoked from Claude resolve against whatever interpreter happens to be first on PATH, with no indication that the environment the user selected was skipped.
Impact
Low visibility rather than high severity. Anyone driving tooling through explicit paths (.venv/bin/pytest and so on) never notices. Anyone who types a bare python or pytest gets the wrong interpreter silently, which in a project pinned to a specific Python version can produce confusing failures a long way from the cause.
Environment
- Claude Code CLI 2.1.252, VS Code extension 2.1.263 (darwin-arm64)
ms-python.python2026.4.0- macOS 26.6.2 (Apple silicon), zsh
claudeCode.useTerminal: true,claudeCode.usePythonEnvironmentunset (defaulttrue)
Related
Turned up while investigating #80657, where the same useTerminal: true configuration causes the Python extension's terminal.sendText() activation command to land in Claude's prompt input instead of a shell. The two are separate defects with a shared trigger, and together they compound: terminal mode disables the activation mechanism that works, and exposes the one that doesn't. Details and the process-level evidence are in https://github.com/anthropics/claude-code/issues/80657#issuecomment-5586877297.