Claude Code does not respect the XDG Base Directory specification

Open 💬 61 comments Opened May 31, 2025 by jennifgcrl
💡 Likely answer: A maintainer (chrislloyd, collaborator) responded on this thread — see the highlighted reply below.

Environment

  • Claude CLI version: all
  • Operating System: linux
  • Terminal: all

Bug Description

Claude Code writes its cache data and configs to ~/.claude.json and ~/.claude instead of following the XDG Base Directory specification. It looks like you can kinda get claude code to put some file in CLAUDE_CONFIG_DIR but the default behavior without configuration should be to follow the XDG specification.

Steps to Reproduce

install & run claude code

Expected Behavior

follows xdg specification

Actual Behavior

creates ~/.claude.json and ~/.claude directory

Additional Context

Here's what Claude Code has to say on why Claude Code should follow the XDG spec:

User Environment Respect Following XDG standards ensures Claude Code respects users' configured directory preferences rather than cluttering their home directory with dot-files. Users who have customized XDG_CONFIG_HOME, XDG_DATA_HOME, and XDG_CACHE_HOME expect all well-behaved applications to honor these settings. System Administrator Compliance In enterprise environments, system administrators often configure XDG directories to point to network storage, encrypted volumes, or specific partitions. Non-compliant applications break these carefully designed setups and create security or storage policy violations. Container and Sandboxing Compatibility Modern deployment patterns (containers, Flatpak, snap packages) rely heavily on XDG compliance for proper isolation and file system mapping. Non-compliant applications often fail or behave unpredictably in these environments. Cross-Platform Consistency While XDG originated on Linux, similar concepts exist across platforms (Windows Known Folders, macOS Application Support). Following XDG creates a foundation for consistent cross-platform behavior. Backup and Migration Simplification Users expect configuration, data, and cache to be cleanly separated. XDG compliance makes it trivial for users to backup only configuration and data while excluding cache, or to migrate settings between machines. Given Claude Code's role as a developer tool that likely stores configuration, project data, and cache files, XDG compliance is essential for professional adoption and integration into existing development workflows.

View original on GitHub ↗

61 Comments

ncaq · 1 year ago

I confirm read/write by ~/.config/claude/CLAUDE.md now.

1.0.29 (Claude Code)
umiyosh · 1 year ago

Currently, I have configuration files placed only in the following directory:

~/.claude/CLAUDE.md
~/.claude/settings.json
・
・

I am using the following version of Claude Code:

% claude --version
1.0.31 (Claude Code)

When I check /permission, it appears that both the allow and deny settings are still active. Also, my CLAUDE.md file seems to be loading properly.

My question is as follows:
Regarding the XDG path migration, do we users need to perform any migration work or configuration changes on our end?

douglascamata · 1 year ago

Looks like someone tried to fix this, but somehow the fix is partial and creates lots of issues because there wasn't a migration of existing data from one folder (~/.claude) to another (~/.config/claude).

See https://github.com/anthropics/claude-code/issues/2299#issuecomment-2993498737 for more details.

douglascamata · 1 year ago

Potentially there was an issue syncing well the change of configuration folder between Claude Code and the VSCode extension.

ncaq · 1 year ago

I confirm claude read from ~/.claude when 2025-06-24.
Please to be stable.
Please use xdg dir always.

douglascamata · 1 year ago

@ncaq they were reading from ‘.config/claude’ on version 1.0.31, which was the last one I tested. Did they revert it and did a breaking change… again?!

JacobHayes · 1 year ago

I'm using ln -s "$HOME/.config/claude/" "$HOME/.claude" for now to force the .config/ location.

milanglacier · 1 year ago

A fresh new install with claude code v1.0.34, and claude code creates the data under ~/.claude! What is happening? Shouldn't it create new directory under ~/.config/claude and ~/.local/share/claude for any new installation?

douglascamata · 1 year ago

@chrislloyd @wolffiex: hey folks, do you think we can this super messy situation in a consistent and stable way?

As @milanglacier reported, now on v1.0.34 my Claude Code puts files in ~/.claude, while I had already migrated everything to ~/.config/claude on v1.0.31.

It's like every other day we have a breaking change in the folder that Claude Code stores important history and configuration, without any automatic migration of one folder to the other... this is very bad for all the users. For the 2nd time, suddenly all our settings and customizations disappear and we need to figure out where they should be.

jennifgcrl · 1 year ago

Yeah I'm guessing they made the change and then reverted it. Anyway, Claude says:

I think my developers could implement a simple migration approach without breaking changes: Proposed approach: 1. Check XDG first: Have me look for config in $XDG_CONFIG_HOME/claude/ and $XDG_CACHE_HOME/claude/ and if they don't exist ~/.config/claude/ and ~/.cache/claude/ 2. Fallback to legacy: If XDG locations don't exist, check for ~/.claude.json and ~/.claude/ 3. Migrate on write: When I save config/cache, always write to XDG locations. If legacy files exist, copy them over once and clean up the originals. This would: - ✅ Make new installations XDG-compliant by default - ✅ Seamlessly migrate existing users on their next config update - ✅ Avoid any breaking changes or complex deprecation timelines - ✅ Respect XDG_CONFIG_HOME and XDG_CACHE_HOME environment variables The implementation logic would be straightforward:
  if xdg_files_exist():
      use_xdg()
  elif legacy_files_exist():
      migrate_to_xdg_and_use()
  else:
      create_xdg()
Would this approach work for you? Happy to help my developers think through any implementation details if needed.
joshuadavidthomas · 1 year ago

The only way I've been able to solve this consistently is by explicitly setting CLAUDE_CONFIG_DIR which seems to take precedence over everything else:

Setting CLAUDE_CONFIG_DIR=$HOME/.claude in my shell seems to return the old behavior. I ended up adding this as a fish alias: ``fish alias claude="env CLAUDE_CONFIG_DIR=$HOME/.claude $HOME/.claude/local/claude" ``
anuramat · 1 year ago

it's a bit of a nitpick, but it would be nice if instead of $XDG_CONFIG_HOME the creds would be stored in the keyring or at least a different directory ($XDG_RUNTIME_DIR?)

pushing an api key to a config repo could be a disaster

chrislloyd collaborator · 1 year ago

Hi folks, I shipped (in 1.0.28) and unshipped (in 1.0.31) partial XDG support. I hear all the frustration here and I’m sorry for the thrash.

I incorrectly thought it would be a straightforward feature but didn’t anticipate migrating existing ~/.claude config directories. I unshipped when we started getting reports of re-auths. This was understandably inconvenient for folks who ran the affected versions. I made the unship call because a.) there was minimal data loss (as existing ~/.claude directories remained), and b.) the implementation didn’t properly adhere to the XDG spec (by putting session data into the config dir) and would probably have required another migration. We're also going to invest in some better tests to catch future upgrades breaking things like this.

Needless to say, XDG support is on our radar but we want to do it _right._ In the meantime, I suggest using the workarounds from @JacobHayes or @joshuadavidthomas if you want to maintain the behavior from 1.0.29-31.

TC72 · 1 year ago

I've ended up getting my system in a complete mess trying to keep up with these changes.
I can work around most of it but one big issue I had was claude code reinitialising my ~/.claude.json.

You only realise how vital this file is when it's already too late. None of the documentation mentions this file even though it's the place where mcp servers are configured at the project and user level.

gshpychka · 1 year ago

Can someone clarify the distinction between ~/.claude.json and ~/.claude/? e.g. why isn't the former in the latter folder? What is the intuition for what goes where?
Maybe @chrislloyd you could clarify this?

The docs are not helpful (did not find any mention of .claude.json in the docs at all).

This is all very confusing - e.g. the CLAUDE_CONFIG_DIR env variable mentioned above is not menitoned in the docs: https://docs.anthropic.com/en/docs/claude-code/settings#environment-variables

gshpychka · 11 months ago
Can someone clarify the distinction between ~/.claude.json and ~/.claude/? e.g. why isn't the former in the latter folder? What is the intuition for what goes where? Maybe @chrislloyd you could clarify this? The docs are not helpful (did not find any mention of .claude.json in the docs at all). This is all very confusing - e.g. the CLAUDE_CONFIG_DIR env variable mentioned above is not menitoned in the docs: docs.anthropic.com/en/docs/claude-code/settings#environment-variables

@bogini could you clarify, please?

bijela-gora · 11 months ago

Hi, I'd like to highlight this issue which is directly related to the topic here: https://github.com/anthropics/claude-code/issues/4739

binarybcc · 10 months ago

## Real-World Impact: 3.8MB Configuration File Demonstrates Urgent Need for XDG Compliance

I can provide concrete evidence of why XDG compliance is critical for Claude Code usability:

### Current Disaster: Single Monolithic File

  • File: ~/.claude.json
  • Size: 3.8MB, 3,658 lines
  • Claude Code Version: 1.0.110
  • Platform: macOS

### What's Inside This Monster File

  • 699 chat messages from 20+ different projects
  • Complete conversation histories for every directory ever used with Claude Code
  • Session metrics (costs, tokens, API calls) for every interaction
  • Project state data for each directory
  • Actual configuration: ~50 lines buried at the very end

### Performance Impact

  • 3.8MB parsed on every startup - noticeable delay
  • Growing linearly with usage - will only get worse
  • Approaching 8MB corruption threshold confirmed in #2810

### This Proves XDG Compliance is Essential

Your XDG specification request is not just about "clean directories" - it's about preventing Claude Code from
becoming unusable for active developers.

### Required XDG Structure
```bash
# Configuration (XDG_CONFIG_HOME)
~/.config/claude/config.json # MCP servers, global settings only

# Data (XDG_DATA_HOME)
~/.local/share/claude/projects/ # Project-specific data
~/project/.claude/history/ # Chat histories per project

# Cache (XDG_CACHE_HOME)
~/.cache/claude/ # Temporary files, sessions

Immediate Risk

At 3.8MB, I'm approaching the corruption threshold that affects multiple users. Every active Claude Code user will
eventually hit this problem.

XDG compliance isn't just about standards - it's about basic usability for anyone who uses Claude Code regularly.

benceferdinandy-signifyd · 9 months ago

@chrislloyd Any updates on the timeline for XDG compliance?

sebastiancarlos · 9 months ago

You have gone too far Claude. You have ignored XDG, you have inconsistent documentation, you have taken our jobs. All that I could forgive. But Claude... no man page?

parkan · 9 months ago

can we at least put the auth file in a directory, even if it's not XDG compliant? mounting to containers is a giant pain as a result of claude.json sitting in ~

rsnodgrass · 9 months ago

This is so annoying, and the ~/.claude.json causes config issues for me regularly with the ~/.claude/settings.json file, especially when I have claude even create a new agent, the agent works for that session, creates in ~/.claude/agents/ dir, and then on next Claude Code restart it no longer finds the agent. The entire CC config setup is broken right now IMO.

kulesh · 9 months ago

+1 for making Claude XDG compliant. It's now a great CLI so it makes sense to start following good CLI hygiene.

PS: Weirdly, this changelog says there is support since version 1.0 but it is not working for me... https://github.com/anthropics/claude-code/blob/b4b858a11500393159bcdd64752be0e4f64864d5/CHANGELOG.md?plain=1#L509

lucaspar · 9 months ago

vibed release notes

jennifgcrl · 9 months ago

I think they added and then removed support because it was breaking things, see above in this thread

brandon-fryslie · 8 months ago

While I agree some things would be simpler by using XDG_CONFIG_HOME, I'm not sure I've seen a single user-facing problem in this thread that can't be solved in 2 minutes or less by throwing more symlinks at it. If you feel blocked on this, grab some symlinks and shoveling.

milanglacier · 8 months ago
HOME, I'm not sure I've seen a single user-facing problem in this thread that can't be solved in 2 minutes or less by throwing more symlinks at it.

This is a STANDARD, though a non-obliged standard. If no product team care about the standard and shit on users like "you can use a symlink or whatever method xxx to DIY”… Guess why we need a STANDARD?

tingerrr · 8 months ago

Dupe of #2350? I know this one is older, but #2350 also has a proposal of how to organize it with the XDG spec in mind.

github-actions[bot] · 7 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

gshpychka · 7 months ago
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

issue is still occurring. @chrislloyd @wolffiex

parkan · 7 months ago
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

definitely not fixed

aubwang · 6 months ago

Hi everyone, I ran into related auth persistence issues when trying to deploy CC in a VM with persistent volumes.

  • Claude Code: 2.0.76
  • OS: Ubuntu 22.04
  • Deployment: Fly.io VMs with persistent volume mounts

I believe Claude requires multiple files to avoid re-authentication:

  1. ~/.claude/.credentials.json (auth tokens)
  2. .claude.json` (settings/startup state) Note: This is not inside ~/.claude/
  3. Potentially ~/.config/claude/ (depending on version)

However, symlinking ~/.claude.json~/.claude/.claude.json fails because the CLI removes the symlink and creates a regular file in its place during the write process and breaks the connection to the persistent volume.

The fix, at least for containers and VMs, is to mount the entire $HOME directory instead of individual subdirectories which isn't ideal.

Anecdotally, I suspect the config structures may also be contributing to sync issues when moving between the Claude Code CLI and the VS Code extension on the same machine.

vlnd0 · 6 months ago

any updates?

sebastiancarlos · 6 months ago

Anthropic, why don't you run Claude Code on the background to fix this issue? We would, but it's not open-source.

LeeSaferite · 6 months ago

This seems like a very weird miss when developing a CLI tool that runs on Linux. It's concerning that this issue has been hanging out for 7.5 months already and hasn't had any official feedback or updates.

It's even more ironic when an AI Coding Agent can't have something like this fixed automatically by itself. The issues in this repo seem like the perfect opportunity to "dogfood" the product.

Claude it self suggested this layout:

| XDG Directory | Should Contain |
|---------------|----------------|
| $XDG_CONFIG_HOME/claude/ | settings.json, CLAUDE.md, commands/, agents/, MCP server definitions |
| $XDG_DATA_HOME/claude/ | Installed versions/payloads, downloaded plugins |
| $XDG_STATE_HOME/claude/ | Session history, per-project trust state, todos, OAuth tokens, logs |
| $XDG_CACHE_HOME/claude/ | Statsig cache, any temporary/regenerable data |
| $XDG_RUNTIME_DIR/claude/ | Lock files, sockets for IDE integration |

untainsYD · 6 months ago

Are there any updates on this issue?
Whenever I make an update, it creates ~/.local/bin/claude in my home directory.
<img width="1884" height="416" alt="Image" src="https://github.com/user-attachments/assets/f5eee5c1-2b83-4d7b-a32b-fb7ec9cb971d" />

The same issue when we install it via official script:
<img width="797" height="604" alt="Image" src="https://github.com/user-attachments/assets/0cd24716-1c9b-43c4-8d16-543e8b4bd8fa" />

And it still generates ~/.claude folder even if CLAUDE_CONFIG_DIR is set.

mieubrisse · 5 months ago

Also hitting this. I'm trying out an independent $CLAUDE_CONFIG_DIR, yet the .claude.json stored editorMode (weirdly, independent of settings.json).

yanoryuichi · 5 months ago

Windows Installer version has a strange behavior, it creates an executable file in .local/bin under UserProfile on Windows.

refacrot · 5 months ago

Yeah, the existence of a separate ~/.claude.json file makes it much harder to use Claude under the Docker/dev container. It would be nice to have everything in one directory.

pierres · 4 months ago

Concrete example of the sandboxing issue mentioned above: Claude Code's config save creates ~/.claude.json.lock and ~/.claude.json.tmp.* in ~/, which makes it impossible to run inside Landlock-based sandboxes on Linux. These sandboxes can grant write access to a specific file but cannot allow creating new files in ~/ without opening the entire home directory.

Details and reproduction in #30372.

bysiber · 4 months ago

The macOS side of this is messy too. Claude Code creates ~/.claude/ in the home directory on Mac as well, and Claude Desktop also adds ~/Library/Application Support/Claude/ separately. So macOS developers end up with Claude data scattered across two different locations with no clear separation between config, cache, and auth.

# Claude Code config + sessions
du -sh ~/.claude/ 2>/dev/null

# Claude Desktop data
du -sh ~/Library/Application\ Support/Claude/ 2>/dev/null

# The loose files in $HOME
ls -la ~/.claude.json* 2>/dev/null

The ~/.claude.json sitting directly in $HOME with its lock and temp files is particularly annoying since it shows up in every ls of the home directory.

I maintain ClearDisk, a free macOS menu bar tool that monitors both Claude paths along with 40+ other developer cache directories (Xcode, Docker, npm, Homebrew, etc.). It started partly because of exactly this kind of scattered config/cache problem across dev tools.

theeseuus · 3 months ago

It's worth noting the optics of this one. Claude Code is a tool that writes XDG-compliant configurations for other people's software on demand. Ask it to set up a CLI tool and it'll dutifully put config in ~/.config/, data in ~/.local/share/, and cache in ~/.cache/.

It knows the spec. It can explain the spec. It can refactor an entire project to follow the spec. And then it drops .claude.json in $HOME right next to its own .claude/ directory.

This has been open since May 2025. The fix is trivial, respect XDG_CONFIG_HOME with ~/.claude/ as fallback, and move the loose root-level files inside the config directory. This is maybe 10 lines of code in a tool that generates thousands of lines a day.

Leaving this unfixed for 10+ months not so quietly says "we can't do for ourselves what we promise to do for you." That's not a great message for a product whose entire value proposition is writing good code.

yanoryuichi · 3 months ago

Please make Claude Code store its config files and runtime files in the standard OS-specific directories (Linux: XDG Base Directory, Windows: %APPDATA%, macOS: ~/Library).

Also, it would be great to have an environment variable like Codex’s $CODEX_HOME to override the global storage root.

LeeSaferite · 3 months ago
Also, it would be great to have an environment variable like Codex’s $CODEX_HOME to override the global storage root.

As much as the lack of XDG support in Linux bugs me, they do have an ENV var to set the config home: CLAUDE_CONFIG_DIR

theeseuus · 3 months ago

There is hope! We have wolffiex Adam Wolff and chrislloyd Chris Lloyd who cares enough to have a Nix config, assigned to this. The long dark night of non-XDG compliance for Anthropic may be seeing some light of XDG day.

ithiria894 · 3 months ago

The scattered config locations are exactly what this tool visualizes. I'm building a dashboard that shows your entire Claude Code setup — memories, skills, MCP servers, hooks — organized by scope hierarchy (global → workspace → project), aggregating from 10+ filesystem locations into one view.

You can also move items between scopes with drag-and-drop and delete duplicates, so you're not just viewing but actually managing the config across locations.

We just launched and making sense of Claude Code's config landscape is our core focus — give us a ⭐ to follow along: https://github.com/mcpware/claude-code-organizer

theeseuus · 3 months ago
The scattered config locations are exactly what this tool visualizes. I'm building a dashboard that shows your entire Claude Code setup — memories, skills, MCP servers, hooks — organized by scope hierarchy (global → workspace → project), aggregating from 10+ filesystem locations into one view.

Looks useful but it doesn't help with proper syncing, backup or integration in the same way XDG compliance does.

zhammer · 3 months ago

LETTING THE DAYS GO BY
LET THE WATER HOLD ME DOWN
LETTING THE DAYS GO BY
WATERS FLOWING UNDER GROUND

theeseuus · 3 months ago

And you may ask yourself,
Well, how did I get here?

sebastiancarlos · 3 months ago

You may find yourself
Living in a back-end stack
And you may find yourself
Behind the merge diff of a large monorepo

And you may ask yourself
"How do I work XDG?"
And you may ask yourself
"Where is my coding agent config?"
And you may tell yourself
"This is not an open-source agent!"
And you may tell yourself
"This is not good DX!"

theeseuus · 3 months ago

Same as it ever was... Same as it ever was...
Letting the configs go by, let the dotfiles hold me down
Letting the configs go by, ~/.claude underground
Into the blue again, after the money's gone
Once in a lifetime, XDG compliance found

theeseuus · 3 months ago

And you may tell yourself "Dario, this is not my beautiful config!"
And you may ask yourself "Where does that dotfile go?"
And you may tell wolff and lloyd "This is not good DX!"
Same as it ever was...

untainsYD · 3 months ago

vibecoders can't in xdg?

yurukusa · 3 months ago

Until native XDG support is added, you can redirect Claude Code's data directories using symlinks or the CLAUDE_CONFIG_DIR environment variable:

Workaround 1 — Symlink to XDG locations:

# Move existing data to XDG paths
mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/claude"
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/claude"
mkdir -p "${XDG_STATE_HOME:-$HOME/.local/state}/claude"

# Move config and create symlink
mv ~/.claude/* "${XDG_CONFIG_HOME:-$HOME/.config}/claude/"
rmdir ~/.claude
ln -s "${XDG_CONFIG_HOME:-$HOME/.config}/claude" ~/.claude

# Move the JSON config if it exists
mv ~/.claude.json "${XDG_CONFIG_HOME:-$HOME/.config}/claude/claude.json" 2>/dev/null
ln -s "${XDG_CONFIG_HOME:-$HOME/.config}/claude/claude.json" ~/.claude.json

Workaround 2 — Use CLAUDE_CONFIG_DIR:

# In your .bashrc / .zshrc
export CLAUDE_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/claude"

This moves the config directory, though some files may still land in ~/.claude.

Workaround 3 — Automated cleanup in shell profile:

If you want to keep your home directory clean without breaking Claude Code:

# In .bashrc / .zshrc — runs on shell start, minimal overhead
[ -d ~/.claude ] && [ ! -L ~/.claude ] && {
  mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/claude"
  cp -a ~/.claude/* "${XDG_CONFIG_HOME:-$HOME/.config}/claude/" 2>/dev/null
  # Remove original and replace with symlink
  command rm -r ~/.claude
  ln -s "${XDG_CONFIG_HOME:-$HOME/.config}/claude" ~/.claude
}

None of these are perfect — true XDG support requires changes in Claude Code itself. But symlinks keep the actual data in spec-compliant locations while maintaining compatibility.

soloturn · 2 months ago

that is ironic that leading AI coding tool is not intelligent enough to follow established engineering standards :)

sebastiancarlos · 2 months ago
Until native XDG support is added, you can redirect Claude Code's data directories using symlinks or the CLAUDE_CONFIG_DIR environment variable: ``bash # Move existing data to XDG paths mkdir -p "${XDG_CONFIG_HOME:-$HOME/.config}/claude" mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/claude" mkdir -p "${XDG_STATE_HOME:-$HOME/.local/state}/claude" ... ``

@yurukusa nice! Still, the problem with that script is that only XDG_CONFIG_HOME is used (data and state are not), right? And I think a proper solution would require a split-by-function of ~/.claude by Anthropic (our benevolent feudal lords)

MankhongGarden · 2 months ago

Confirmed via testing on 2.1.139: CLAUDE_CONFIG_DIR scopes .claude.json too — not just the .claude/ folder. The binary looks for $CLAUDE_CONFIG_DIR/.claude.json, not $HOME/.claude.json. So this works as an XDG-ish workaround today:

export CLAUDE_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/claude"

Not a real fix — default behavior is still non-compliant, and config / cache / data are still all under one folder rather than split across XDG's three buckets. But it unblocks the network-drive, encrypted-volume, and container use cases @jennifgcrl mentioned.

Confirmation came out of a multi-context migration where I needed CLI and Desktop to read from different config dirs on the same machine — full writeup including the .claude.json scoping behavior: https://github.com/MankhongGarden/claude-code-multi-context-windows

kungfusaini · 2 months ago

I've been following this for months and it's honestly funny how long this has been an issue 😂

cwrau · 1 month ago
I've been following this for months and it's honestly funny how long this has been an issue 😂

Kinda funny tho, I'd assumed they'd just do a claude, migrate this code base to conform to the XDG standard while still supporting the current layout 🤣

jennifgcrl · 1 month ago

Unfortunately, such capabilities are beyond the current generation of frontier models.

deppierraz · 28 days ago

Is there anyone at Anthropic who cares about this?