[BUG] VS Code extension: session history ignores the config directory when `claudeCode.claudeProcessWrapper` is set
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
VS Code extension: session history ignores the config directory when claudeCode.claudeProcessWrapper is set
Component: Claude Code VS Code extension
Version: 2.1.284 (darwin-arm64), VS Code Insiders 1.140.0-insider, macOS 26.7
Severity: Past sessions vanish from the sidebar with no error, for every user of a process-wrapper setup. No data is lost.
Summary
When claudeCode.claudeProcessWrapper points to a wrapper that sets CLAUDE_CONFIG_DIR, the extension's session history list still reads ~/.claude/projects. It does not read the directory the CLI actually uses. The config directory reported by claude auth status --json is thrown away when a wrapper is set. An absolute CLAUDE_CONFIG_DIR in claudeCode.environmentVariables is also not used for the list. The only thing that works is having CLAUDE_CONFIG_DIR in VS Code's own launch environment, and a normal launch from the Dock or Finder never has it.
Why we use a wrapper
We run Claude Code in VS Code Insiders against AWS Bedrock with its own config directory (~/.claude-api), next to a personal subscription in regular VS Code (~/.claude). The wrapper sets CLAUDE_CONFIG_DIR and the Bedrock environment, then execs the bundled binary. We use a wrapper rather than a launch-time environment for two reasons: the launch environment is lost whenever Insiders restarts itself for an update, and the wrapper can refuse to start without Bedrock credentials.
What Should Happen?
Suggested fix
Any one of these would solve it for us:
- When
claudeCode.claudeProcessWrapperis set, honor theconfigDirectory(orprojectsDirectory) reported byclaude auth status --jsonfor the history list. If the reason for ignoring it is a trust concern, honoring it for listing alone would be enough. - Or: when an absolute
CLAUDE_CONFIG_DIRis inclaudeCode.environmentVariables, use it inl0()beforeprocess.envand the~/.claudefallback.vr()already computes this value for the CLI's environment. - At minimum, document that session history under a process wrapper follows VS Code's launch environment rather than the wrapper or
environmentVariables.
Workaround we are giving users
Past sessions can still be resumed from the terminal inside VS Code Insiders with claude --resume, which lists from the CLI's own config directory. Launching VS Code with CLAUDE_CONFIG_DIR in its environment isn't a workable instruction for our users. It is lost whenever VS Code restarts itself for an update. Setting it machine-wide with launchctl setenv would also redirect the separate VS Code install that uses the personal subscription.
Error Messages/Logs
Steps to Reproduce
Steps to reproduce
- Create a wrapper, for example
~/bin/claude-alt:
``bash``
#!/usr/bin/env bash
export CLAUDE_CONFIG_DIR="$HOME/.claude-alt"
exec "$@"
- In VS Code user settings:
``json``
"claudeCode.claudeProcessWrapper": "/Users/<you>/bin/claude-alt"
- Launch VS Code from the Dock, so
CLAUDE_CONFIG_DIRis not in its environment. - Open a folder and have a short conversation in the Claude panel. The transcript is written to
~/.claude-alt/projects/<folder>/<id>.jsonl, which is correct. - Run Developer: Reload Window and open the session history.
Expected: the conversation from step 4 is listed.
Actual: it is missing. The list shows whatever is in ~/.claude/projects/<folder>/, which is usually nothing, or sessions from a different account.
- Also add the directory to the settings and reload again:
``json`
"claudeCode.environmentVariables": [{ "name": "CLAUDE_CONFIG_DIR", "value": "/Users/<you>/.claude-alt" }]
CLAUDE_CONFIG_DIR`.
**Actual:** still missing. We confirmed this over two window reloads after the setting was saved. The extension host process restarted each time, and its environment had no
Based on the code below, the list should appear if VS Code is started with open -a "Visual Studio Code - Insiders" --env CLAUDE_CONFIG_DIR=$HOME/.claude-alt. We have not tested that yet.
Root cause (from the 2.1.284 bundle; minified names)
The history directory resolves as:
function l0(){ return Mg ?? eX() }
function eX(){ if(process.env.CLAUDE_CONFIG_DIR) return process.env.CLAUDE_CONFIG_DIR;
return H4.join(hG.homedir(), ".claude") }
function iW1(){ return H4.join(l0(), "projects") }
Mg is set only by rW1(...), and its only caller is refreshCliAuthStatus(). That function runs claude auth status --json through the wrapper, which correctly reports configDirectory. It then discards the value when a wrapper is in use:
let $ = this.getClaudeBinary(), J = $.viaProcessWrapper === !1, ...
...
if (!J) Z = { value: void 0 };
else if (typeof F === "object" && F !== null && "configDirectory" in F) Z = { value: F.configDirectory };
...
if (Z !== void 0) rW1(Z.value, ...)
With a wrapper, Mg is always undefined. l0() then falls back to the extension host's own process.env.CLAUDE_CONFIG_DIR, and after that to ~/.claude. claudeCode.environmentVariables is merged only into the spawned CLI's environment (q8()), never into l0(). listSdkSessions() then calls the default SDK listing (z2() returns undefined because l0() === eX()), which scans ~/.claude/projects.
The CLI's own projectsDirectory from the same probe is kept (cachedCliProjectsDirectory) and used for the resume precheck. So the extension resumes from the right directory but lists from the wrong one.
Claude Model
Opus
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.283
Platform
AWS Bedrock
Operating System
macOS
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
3 Comments
The extension is querying ~/.claude/projects while the wrapper writes transcripts under ~/.claude-api/projects. The files remain intact, but the VS Code Insiders list is reading from a different store.
I built the VS Code checks in claude-code-session-recovery (BasedGPT/claude-code-session-recovery). First check the global hidden-session list and the Insiders stores with this read-only audit:
~~~sh
python tools/sessions/audit_vscode_session_surfaces.py \
--projects-dir "$HOME/.claude-api/projects" \
--workspace-dir "$HOME/Library/Application Support/Code - Insiders/User/workspaceStorage" \
--global-state-db "$HOME/Library/Application Support/Code - Insiders/User/globalStorage/state.vscdb"
~~~
The audit prints counts and whether the global hidden-session list overlaps local transcripts; it does not print session IDs or write to either store. If it completes with a hidden-session overlap, stop there because a workspace cache injection cannot override that filter.
If the audit completes without a hidden-session overlap, preview the cache scan:
~~~sh
python tools/sessions/recover_vscode_sessions.py \
--projects-dir "$HOME/.claude-api/projects" \
--workspace-dir "$HOME/Library/Application Support/Code - Insiders/User/workspaceStorage"
~~~
This is a dry run. If it lists the affected sessions as missing from the cache, close VS Code Insiders fully and rerun that command with --apply. It backs up the cache and leaves the JSONL transcripts unchanged. If those sessions are already in the cache, the extension's directory choice is the unresolved part and a cache write will not help.
The tools are in BasedGPT/claude-code-session-recovery, where the audit and cache scan both support explicit Insiders and alternate-config paths.
Hope this helps, if my tools are able to help you, would appreciate a ⭐ :)
Still present in 2.1.289 (darwin-arm64). The discard is unchanged in
refreshCliAuthStatus():There is a second consequence that we think is worse than the missing history: restored tabs start new sessions. When a window reloads, or VS Code restarts, a panel tab whose session is not in that list does not resume. The webview sends
launch_claudewithoutresume, and the log showsSpawning Claude with SDK query function - cwd: …, /path/to/wrapper, resume: undefined. Every open conversation is replaced by an empty one on each restart. The transcripts are intact on disk, andclaude --resume <id>in a terminal still finds them.What we saw, with a wrapper that picks
CLAUDE_CONFIG_DIRfrom the folder a session starts in:~/.claude/projects/<slug>/, left over from before the wrapper. No session created after the switch was ever resumed on restore.codecommand that opened it. So when a folder is opened from a terminal where another folder's environment is loaded, the extension host has that folder'sCLAUDE_CONFIG_DIR. The list and the restore check then read a third config dir, neither~/.claudenor the one the wrapper uses.await_config_home_requestreturns at once and the tab still starts fresh, because nothing ever follows the config home under a wrapper.Requested fix: when
claudeCode.claudeProcessWrapperis set, use theconfigDirectory(orprojectsDirectory) reported byclaude auth status --jsonfor the session list. That is suggestion 1 above. Restored tabs should also wait for that probe before deciding a session cannot be resumed.Workaround, for anyone else hitting this:
~/.claude/projects/<slug>as a symlink to$CLAUDE_CONFIG_DIR/projects/<slug>for the directory it starts in.<slug>is the absolute real path with every non-alphanumeric character replaced by-. Windows started from the Dock then list and resume correctly.CLAUDE_CONFIG_DIRin the environment, for example withdirenv exec / code ….Some context on why we run two config dirs at all: we run two Claude Code setups side by side on the same Mac. Regular VS Code uses a personal Claude subscription with the default
~/.claude. VS Code Insiders routes Claude Code through Amazon Bedrock viaclaudeCode.claudeProcessWrapper, and the wrapper setsCLAUDE_CONFIG_DIR=~/.claude-apiso the two logins, settings and transcripts never mix. That's also why the~/.claude/projects/<slug>symlink above isn't an option for us: it would merge the two stores, and the subscription side would list (and could resume) Bedrock conversations.Confirmed on 2.1.289 that restore runs through the same list:
fF5resumes a saved tab only if its id is in the session list, otherwise it opensfresh_after_missing_saved. Our Insiders logs from before our workaround show zero restored resumes.One detail for anyone reading their logs: a panel tab is offered for restore only if its session was updated in the last 10 minutes (
AL0 = 600000). After an overnight restart, a blank tab is expected even when the list is correct.Our workaround, for setups with one alternate config dir per app (not per folder). On macOS, VS Code launched from the Dock or Spotlight copies the login shell's environment into the extension host, and every process an app launches carries
__CFBundleIdentifier. A window opened with thecodeCLI skips the login shell (VSCODE_CLI=1) and takes the calling terminal's environment instead, hence the function. In~/.zshrc:This needs a full quit and relaunch; Reload Window isn't enough. After that, both the history list and tab restore work, and the regular VS Code side is never touched. It can't do per-folder dirs like martaver's wrapper. The real fix is still suggestion 1: when a wrapper is set, use
configDirectoryfromclaude auth status --json.