Split monolithic ~/.claude.json by scope and move it into the config directory
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
- 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 undocumentedCLAUDE_CONFIG_DIRenv var, which itself has a long tail of partial-support bugs (#81278, #74393, #79233, …). - 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).
- Scope confusion —
claude mcp adddefaults 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. - 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
- Move the file inside the config directory (default
~/.claude/), and documentCLAUDE_CONFIG_DIRwhile at it. - 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.jsonnext to the transcripts that already live there
- Transparent migration on first run (read old
~/.claude.jsonif 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.jsonand 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