Split monolithic ~/.claude.json by scope and move it into the config directory

Status Open
Reported on v2.1.212
Maintainer reply None cached
Activity 0 comments · opened Aug 1, 2026

Problem

~/.claude.json is a single monolithic state file sitting in the home directory root, outside the ~/.claude/ config directory. Per the docs (Settings page): "Other configuration is stored in ~/.claude.json. This file contains your OAuth session, [MCP server](/docs/en/mcp) configurations for user and local scopes, per-project state (allowed tools, trust settings), and various caches."

So one file mixes data with completely different scopes and lifecycles:

  • user-scope config: user-scope MCP servers, OAuth session
  • project-scope state: local-scope MCP servers, trust decisions, allowed tools, per-project caches — for every project ever opened

Why this hurts

  1. Home-dir clutter — the file (plus ~/.claude.json.backup.*) lives outside ~/.claude/. Previously requested in #22260 (closed as duplicate) and commonly worked around via the undocumented CLAUDE_CONFIG_DIR env var, which itself has a long tail of partial-support bugs (#81278, #74393, #79233, …).
  2. Unbounded growth — per-project state accumulates for all projects; the file grows to thousands of lines, and every scope shares its fate: a corruption or bad edit of one project's entry risks user-wide state (OAuth session included).
  3. Scope confusionclaude mcp add defaults to local scope, which users reasonably expect to land somewhere project-bound, yet it writes into the same global home-root file as user scope. Discovering "why did my per-project server end up in ~/.claude.json?" costs real time.
  4. No per-project portability — project-bound state can't be inspected, backed up, migrated, or deleted per project; removing a project leaves its state embedded forever.

Proposal

  1. Move the file inside the config directory (default ~/.claude/), and document CLAUDE_CONFIG_DIR while at it.
  2. Split by scope:
  • user scope (OAuth session, user-scope MCP servers) → e.g. ~/.claude/state.json
  • project scope (local-scope MCP servers, trust, allowed tools, caches) → per-project files, e.g. ~/.claude/projects/<project-hash>/state.json next to the transcripts that already live there
  1. Transparent migration on first run (read old ~/.claude.json if present, write new layout), keeping one release of backward compatibility for external tooling.

Addendum: make the storage location a user choice

Beyond relocating/splitting the file, please add an option to choose where project-bound data lives, e.g.:

{ "projectStateLocation": "project" }   // default: "user"

With "project", all project-bound data — local-scope MCP servers, allowed tools, caches, session transcripts, plans — is stored under the project's own .claude/ directory (gitignored local files, like the existing .claude/settings.local.json pattern), instead of ~/.claude.json and ~/.claude/projects/<hash>/.

Rationale — storing project data outside the project has no upside for self-owned repositories:

  • Lifecycle mismatch: today deleting a project leaves its state embedded in ~/.claude.json and orphaned transcript dirs under ~/.claude/projects/<hash>/ forever; there is no cleanup command. Registry-style residue.
  • No portability: copying a project folder to another machine should carry its configuration and history with it. Currently the meaningful state stays behind in the user profile.
  • Self-containment: a repo configured once should be fully self-sufficient — .claude/ in the project already exists; storing per-project data anywhere else just creates a second mechanism for the same scope.

Security-sensitive records (workspace trust, .mcp.json approvals) can stay user-side by default — users who treat their repos as their own responsibility already have opt-ins like enableAllProjectMcpServers to skip re-approval.

Environment

  • Claude Code 2.1.212
  • Windows 10 Pro 10.0.19045

View original on GitHub ↗