[FEATURE] Settings.json parent directory traversal for monorepos
Problem
When working in a monorepo subdirectory (e.g., /repo/packages/app/), Claude Code only looks for .claude/settings.json in the current working directory. It does not traverse parent directories to find shared settings at the repo root.
This means you either need to:
- Duplicate settings in every subdirectory
- Always launch Claude Code from the repo root
- Use global user settings (
~/.claude/settings.json) which apply to all projects
Proposed Solution
Claude Code should traverse parent directories (up to the git root or filesystem root) looking for .claude/settings.json files, similar to how many tools handle config files (e.g., .gitignore, tsconfig.json, .eslintrc).
Settings could be merged with deeper directories taking precedence, or the first found settings file could be used.
Use Case
In a monorepo with multiple packages/services, you want shared settings (allowed tools, MCP servers, permissions) defined once at the repo root, while still being able to work from within subdirectories.
Related Issues
- #2365 - Better Monorepo Support (MCP and commands)
- #374 - MCP repo scope
- #705 - Nested CLAUDE.md context
- #3146 - Configure additional directories via settings files
This issue focuses specifically on settings.json lookup behavior, complementing the related requests for MCP, commands, and CLAUDE.md parent directory support.
19 Comments
Workaround: Using Mise for per-project environment variables
While waiting for native parent directory traversal, you can use Mise to manage per-project environment variables that Claude Code will pick up.
Setup
```bash
# Install (macOS)
brew install mise
# Add to ~/.zshrc or ~/.bashrc
eval "$(mise activate zsh)"
```
.mise.tomlat your repo root:```toml
[env]
_.file = ".env" # optional: load secrets from .env
# Claude Code OTEL config (example)
CLAUDE_CODE_ENABLE_TELEMETRY = "1"
OTEL_METRICS_EXPORTER = "otlp"
OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318"
```
cdinto any subdirectory, mise automatically injects env vars from parent.mise.tomlfiles.Why this works
Mise traverses parent directories and merges configs - exactly what we're requesting for
settings.json. This covers environment variable needs but not Claude Code-specific settings like allowed tools or MCP servers.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.
I'm still interested in this addition
Adding another use case beyond monorepos:
Multi-Client Consultancy Setup
As a consultant working with multiple clients, my repository structure is:
Current limitation: When I
cd ~/Repositories/client-a/repo-1and runclaude, onlyCLAUDE.mdis picked up from the parent client directory. Thesettings.jsonand.mcp.jsonat client level are ignored.Desired behavior: Parent directory traversal for
settings.jsonand.mcp.json(similar to howCLAUDE.mdalready works), with repo-level configs taking precedence for overrides.This would allow:
Currently the only workarounds are symlinks (which break repo-level overrides) or duplicating config in every repo.
For organizations, it would be very helpful if Claude discovered
settings.jsonin parent directories.In our organization, we all check out our code in the
~/sablierdirectory on our machines. It would be great if Claude could be made to always look up the.claude/settings.jsonfile under~/sablier/.claude/settings.jsonwhenever a project under~/sablier/**is opened.+1 on this. I'd like to propose expanding the scope beyond
settings.jsonto cover the entire.claudedirectory: skills, agents, commands, andCLAUDE.mdfiles.The directory walk-up should apply to all configuration types, not just settings. Here's the full picture:
Current behavior — console opened at
company/backend/service-a:| Priority | Path |
|----------|------|
| 2 (highest) |
company/backend/service-a/.claude|| 1 (lowest) |
~/.claude|Proposed behavior:
| Priority | Path |
|----------|------|
| 4 (highest) |
company/backend/service-a/.claude|| 3 |
company/backend/.claude|| 2 |
company/.claude|| 1 (lowest) |
~/.claude|This means settings, skills, agents, commands, and
CLAUDE.mdat each ancestor level are loaded and merged, with deeper directories taking precedence.Why this matters for multi-repo workspaces:
Opening Claude Code in
company/backend/service-awould automatically inherit company-wide standards + backend conventions + service-specific config — no duplication needed.This is consistent with how
.gitignore,.editorconfig,.eslintrc, and.npmrchandle hierarchical config. It's also fully backward compatible (users with only~/.claude+project/.claudesee no change).Nice to have: A
root: trueflag (like ESLint) to stop the upward traversal at a specific level.Related: #11626, #12259, #4275, #4442
We need this feature. Permissions are so annoying. I like to break up my work into folders and creating a new folder in a project means I have to approve everything again or manually copy the settings.
My use case: VS Code multi-root workspaces
I have a monorepo with multiple projects (server/, frontend/, shared/) added as separate folders in a .code-workspace file. When I use the Claude Code VS Code extension, it always picks the first folder in the workspace as its working directory — regardless of which project I'm actually working on.
This causes several problems:
Settings pollution: Permission changes and .claude/settings.local.json updates go into server/.claude/ even when I'm working on frontend tasks.
Third-party tool confusion: Other extensions (e.g. Entire.io) that rely on the same root directory also write their data into the wrong project folder.
No isolation: The agent has unrestricted access to all workspace folders when I often want it scoped to just one project.
What I'd like: A workingDirectory setting in the VS Code extension configuration (or per-folder workspace settings) that lets me explicitly control where Claude Code operates. Ideally, it should be configurable per workspace folder in .code-workspace:
Or even better — Claude Code should automatically detect the active editor's workspace folder and switch context accordingly, similar to how VS Code's built-in terminal does it with terminal.integrated.cwd.
Parent directory traversal for settings.json (the original ask of this issue) would partially help, but the core problem for multi-root workspace users is that the working directory itself is hardcoded to the first folder.
Same problem here
Use case: I have ~/dev/work/.claude/settings.json configured with AWS Bedrock settings for my company. Under ~/dev/work/ I have multiple repos (join-api/, web-app/, etc.). When I cd into any of these and run claude, the parent settings are not found — each project would need its own copy.
Outside ~/dev/work/, I use my personal Pro subscription, so user-level settings (~/.claude/settings.json) isn't the right place for the Bedrock config.
Current workarounds
None are clean:
For now, I've added a zsh wrapper that preserves settings from parent directories.
Works great for my use case. Different parent directories with different settings.
CWD, collects all parent.claude/settings.jsonfiles.claude/settings.local.json(Claude auto-gitignores it without .gitignore)settings.local.jsonwith delta changesThe script is here.
You can work around this with a Notification hook that copies the repo-root settings into subdirectories at session start:
If the main thing you need inherited is permission allow-lists, a PreToolUse hook in
~/.claude/settings.jsonis simpler — it applies globally regardless of which subdirectory you're in. No symlinks needed.The symlink approach is most useful when you have MCP servers, custom hooks, or other project-level settings defined at the monorepo root.
Strong +1. The current behavior makes "project scope" effectively indistinguishable from "local scope" the moment you
cdinto any subdirectory — which is most of the time in a real repo. Installing a plugin at project scope and having it silently disappear when launching fromsrc/orpackages/foo/is deeply surprising and undermines the whole point of project-level config.Every other tool in the ecosystem (git, npm, pnpm, cargo, tsconfig, .gitignore, direnv, editorconfig) walks up to find the project root. Claude Code not doing so means users have to either:
.claude/into every subdir (gross),This isn't a nice-to-have — it's a core correctness issue with the plugin/settings model. Please prioritize.
Another pain point in the same vein: because there's no upward traversal, users end up with
.claude/settings.local.json(and.claude/directories generally) scattered across subdirectories of a single repo — one per directory they happened to launch from. It's a footgun:find . -name settings.local.jsonand diff them..gitignorehas to cover arbitrary depths).Upward traversal fixes this by giving the repo exactly one
.claude/at the root, the way every other tool works.One more — and this one is arguably the worst part: the
/plugininstall prompt literally describes project scope as "Install for all collaborators on this repository". That wording makes a concrete promise about repo-wide reach. The actual behavior is "install for collaborators who happen to launch claude from this exact directory," which is a completely different thing.So this isn't just missing traversal — it's a mismatch between the documented contract in the UI and the implementation. Either the traversal needs to be added to match the promise, or the wording needs to change to something honest like "Install for collaborators who launch from this directory." The current state misleads every user who reads the prompt.
I’m seeing the same issue, but for project subagents.
Docs say
.claude/agents/are discovered by walking up from the current working directory:https://code.claude.com/docs/en/sub-agents
Repro:
```bash
mkdir -p parent/.claude/agents parent/child
# add any valid agent in parent/.claude/agents/test-agent.md
cd parent/child
claude agents # test-agent is visible
git init
claude agents # test-agent is no longer visible
So discovery appears to stop at the nearest .git root. This affects monorepos/workspaces where shared .claude/agents or .claude/skills live in a parent directory.
There are other path traversal issues with subagents, sometimes they can't use project LSP servers either.
Gonna add on here for
.mcp.jsonas well, as it lives outside of.claudedirectly. We are generally symlinking it into the sub-repo ($SUB_PROJECT_ROOT/.mcp.jsonis a link to$PROJECT_ROOT/.mcp.json), however usingclaude mcp add ...clobbers the symlink and writes it in$SUB_PROJECT_ROOT/.mcp.jsonas a regular file :(As this doesn't seem to be anything which actually goes through the agent, I can't catch it as a
PreToolUsehook etc etc as I could withWrite|Editusages which do similar things.Let's get on with this. It's important.
It is a security issue being created. Claude should never escape the current root folder (except for some well known locations). The already implemented breakouts to parent directories should be removed.
Please stay into the bounding context of the folder where claude is started