Now in early access, book a 30-minute demo →
← Back to blog Guide

Deploying Claude Code Across a Fleet: Settings Hierarchy, MCP, and Memory (2026)

TL;DR
  • Managed settings win. A managed-settings.json at /Library/Application Support/ClaudeCode/, /etc/claude-code/, or C:\Program Files\ClaudeCode\ sits above command-line args and every user or project file - it is the only layer a developer cannot override.
  • Five settings layers resolve in a fixed order: managed, CLI args, .claude/settings.local.json, .claude/settings.json, then ~/.claude/settings.json. A deny at any layer can never be re-allowed below it.
  • MCP servers carry three scopes. Project servers live in a checked-in .mcp.json; user and local-project servers live in ~/.claude.json - and the local ones never show up in version control, so they are invisible to a repo scan.
  • Instruction files load automatically. Project CLAUDE.md, ~/.claude/CLAUDE.md, CLAUDE.local.md, and the first 200 lines or 25KB of MEMORY.md enter context every session, which makes a poisoned file persistent instructions.
  • Session transcripts are plaintext under ~/.claude/projects/ as JSONL, one file per session - useful for forensics, and a place secrets land if a developer pastes them.
  • The fleet gap: managed settings enforce policy per endpoint but give no central, queryable record of which machines run Claude Code, with which MCP servers attached, or what each tool call did. That record is what Anomity adds.

Once a few engineers prove out a coding agent, the decision lands on the platform team: standardize it or let it spread unmanaged. Deploying Claude Code across a fleet is less about installing a binary than about deciding the policy that governs it on every endpoint - and the honest starting point is that the controls are real but local, layered, and easy to misread. A single managed-settings file can disable bypass mode for ten thousand machines, yet nothing in that file tells you which of those machines connected a new MCP server yesterday. Before you can govern Claude Code, it belongs in the same fleet inventory as every other AI artifact your endpoints carry.

This guide is the practitioner's version of deploying Claude Code across a fleet: the five-layer settings hierarchy and which layer actually wins, how to vet and pin MCP servers when two of the three scopes never touch version control, the conventions for CLAUDE.md and MEMORY.md that load into context automatically, where session data sits under ~/.claude, and the precise point where the fleet-visibility gap opens. Every tool-behavior claim here is grounded in Anthropic's published Claude Code docs. The same patterns generalize to the other agents your developers run, covered in securing AI coding agents and CLIs.

Then we get to enforcement. Settings can deny a tool, but a deny is silent and per-machine; there is exactly one documented seam where an external policy can sit between intent and action and keep a record - Claude Code's PreToolUse hook - which is where runtime allow/deny/log decisions belong. Recent disclosures like the project-file RCE in CVE-2025-59536 are the reason a passive config push is not the whole job.

How does the settings hierarchy resolve, and which layer wins?

Claude Code reads configuration from five layers and resolves them in a fixed precedence. For a fleet, the only layer that matters as a hard boundary is managed settings: it sits above command-line arguments and cannot be overridden by any user or project file. The other four are where developers operate.

PrecedenceLayerPathWho controls it
1 (highest)Managed settingsOS-specific managed-settings.json (see next section)Org administrators; cannot be overridden
2Command-line argumentsFlags like --allowedTools, --add-dirThe developer, per session
3Local project settings.claude/settings.local.jsonThe developer; gitignored when Claude Code creates it
4Shared project settings.claude/settings.jsonThe team; committed to the repo
5 (lowest)User settings~/.claude/settings.jsonThe developer, across all projects

The trap is to read this as a simple top-down merge. Permission rules are not merged that way. Rules are evaluated deny, then ask, then allow, and a deny at any layer is final: if a tool is denied in managed settings, neither --allowedTools nor a project allow rule can re-enable it. The reverse holds too - a user-level deny blocks a project-level allow. So the right mental model is that managed settings define the floor of restriction, and lower layers can only tighten, never loosen. This is the same precedence detailed in how Claude Code permissions work, applied to a deployment instead of a single machine.

Where do managed settings live, and what should you put in them?

Managed settings are read from a fixed system path per platform. These are the files your MDM or configuration management ships to every endpoint:

PlatformManaged settings pathAlso read from
macOS/Library/Application Support/ClaudeCode/managed-settings.jsonPlist domain com.anthropic.claudecode
Linux / WSL/etc/claude-code/managed-settings.jsonmanaged-settings.d/ drop-in fragments
WindowsC:\Program Files\ClaudeCode\managed-settings.jsonHKLM\SOFTWARE\Policies\ClaudeCode registry key

The Linux managed-settings.d/ directory follows the systemd and sudoers drop-in convention, so different teams can maintain independent policy fragments without editing one shared file. A few managed-only keys are worth shipping fleet-wide on day one. Set permissions.disableBypassPermissionsMode to disable so a developer cannot flip into the prompt-skipping bypass mode we unpack in the dangerously-skip-permissions explainer, and permissions.disableAutoMode to block the research-preview auto mode. To make your central rules authoritative, set allowManagedPermissionRulesOnly to true, which prevents user and project settings from defining any allow, ask, or deny rule.

{
  "permissions": {
    "disableBypassPermissionsMode": "disable",
    "allowManagedPermissionRulesOnly": true,
    "deny": [
      "Bash(git push *)",
      "Read(.env)",
      "Read(**/.env)",
      "WebFetch"
    ],
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)"
    ]
  }
}

Two caveats the docs are explicit about. First, Bash patterns that try to constrain arguments are fragile - a rule like Bash(curl <github-url> *) does not catch curl -X GET, a different protocol, a redirect, or a variable holding the URL; the durable approach is to deny curl and wget outright and route allowed fetches through WebFetch(domain:...). Second, Read and Edit deny rules cover Claude's built-in file tools and recognized Bash file commands like cat and sed, but not a Python or Node script that opens a file itself. For OS-level enforcement across all processes you need the sandbox, not permission rules. These are exactly the hardening tradeoffs in the permissions and hooks hardening guide.

How do you vet MCP servers when two of three scopes never hit version control?

MCP is where the fleet surface expands the fastest, because every MCP server adds tools and, for stdio servers, a local process running with the user's privileges - the by-design behavior we trace in the Anthropic MCP stdio RCE writeup. The complication for vetting is that the three configuration scopes do not store servers in the same place.

ScopeStored inVisible in version control?Use for
Project.mcp.json at repo rootYes - designed to be committedServers the whole team should share
User~/.claude.jsonNoPersonal servers available across all your projects
Local~/.claude.json (per-project entry)NoPrivate, experimental, or credentialed servers

A repository scan sees the committed .mcp.json and nothing else. The user- and local-scoped servers a developer adds for themselves live only in ~/.claude.json on that endpoint, alongside OAuth session state and caches - invisible to anyone reading the repo. So a vetting process that only reviews .mcp.json in code review is structurally blind to most of the servers actually running on the fleet. The .mcp.json format does support ${VAR} and ${VAR:-default} substitution so credentials stay out of the committed file, which is the right pattern for shared servers, but it does nothing for the home-directory configs. Before you trust any server at any scope, the trust tiers and 2026 CVE wave in the MCP server security guide are the checklist to run against it.

What conventions should you set for CLAUDE.md and MEMORY.md?

Several instruction-bearing files load into context automatically every session, no prompt involved. Treat them as code that runs, because functionally they direct the agent:

  • Project CLAUDE.md (or .claude/CLAUDE.md) - project conventions, committed and reviewed like any source file.
  • User ~/.claude/CLAUDE.md - personal standing instructions that apply in every project on that endpoint.
  • CLAUDE.local.md - personal, uncommitted project notes.
  • Auto memory MEMORY.md - the first 200 lines or 25KB, whichever comes first, load at session start.

The permission system is enforced by Claude Code, not by the model - instructions in a CLAUDE.md shape what Claude tries to do but cannot grant or revoke access. That cuts both ways. It means a poisoned instruction file cannot directly bypass a deny rule, but it also means these files are an ideal place to plant persistent direction the developer never typed, which is the mechanism behind the project-file RCE and token exfiltration in CVE-2025-59536. For a fleet, set conventions that CLAUDE.md is reviewed like source, that secrets never go in any of these files, and that an unexpected change to ~/.claude/CLAUDE.md or MEMORY.md is a signal worth surfacing. The same untrusted-content-becomes-instructions chain drives the multi-agent attack in comment-and-control prompt injection.

What lives under ~/.claude, and why does it matter for the fleet?

Claude Code saves each conversation locally as a plaintext JSONL file under ~/.claude/projects/, one file per session, with every message, tool use, and result appended. That is what powers resume, fork, and rewind, and before any file edit Claude snapshots the contents so changes can be reverted. For an endpoint inventory, ~/.claude is the directory that ties everything together: settings.json, the user CLAUDE.md, ~/.claude.json with its MCP servers and OAuth state, and the session transcripts.

Two fleet consequences follow. First, the transcript is a genuine forensic artifact - after an incident you can reconstruct exactly which tool calls ran, in order. Second, it is also where secrets come to rest if a developer pastes a token or key into the conversation, because the JSONL is written verbatim to disk. Retention and clearing are configurable, but the data sits on the developer's machine by default. This is why collecting metadata only and redacting secrets on the endpoint, rather than shipping raw transcripts off the box, is the safer posture for any governance layer that reads this surface.

Where is the fleet-visibility gap?

Add up the controls and the gap is clear. Managed settings enforce policy on each endpoint and a deny rule will silently block a call. But a settings hierarchy answers "what is allowed here" - it does not answer the questions a security team and an auditor actually ask:

  • Which endpoints are running Claude Code right now, and at what version?
  • Which MCP servers, skills, and plugins are attached to each - including the user- and local-scoped ones that never reach version control?
  • What did each governed tool call decide, when, and why - in a record you can query months later?

None of those have an answer in managed-settings.json. A deny rule blocks and forgets; there is no central, queryable ledger. The whole point of deploying with governance is to close that gap, and the closest documented seam to do it is the PreToolUse hook, which is also where a passive inventory turns into active enforcement. For the auditing angle in depth, see auditing Claude Code across a fleet.

How Anomity governs Claude Code

Anomity is agentic endpoint security. On every managed endpoint it inventories the AI artifacts this guide walked through - AI agents, MCP servers, extensions, skills, plugins, secrets, hooks, and CLIs - and classifies them. So Claude Code itself, every MCP server regardless of scope (the project .mcp.json and the user- and local-scoped servers in ~/.claude.json alike), the skills and subagents in scope, and the CLAUDE.md, MEMORY.md, and hook files on disk all show up as named assets. That answers the fleet questions a settings file cannot: which endpoints run Claude Code, with which servers attached, and what changed since yesterday.

For agents that expose a hook, Anomity sits at Claude Code's PreToolUse hook and returns allow, deny, or log on each tool call before it runs. The decision is policy-driven and deterministic, not a per-developer prompt: a push to a non-allowlisted remote can be denied, a read of a sensitive path flagged for log-only, a routine edit allowed. Because Anomity collects metadata only and redacts secrets on the endpoint, the tool call and its context are evaluated without shipping the raw transcript or your secrets off the machine - exactly the posture the plaintext ~/.claude/projects/ data calls for.

Every one of those decisions lands in a queryable 90-day audit trail: which endpoint, which artifact, which tool call, what input metadata, and the allow/deny/log outcome with its reason. Decisions route to your SIEM, Slack, email, or Jira, so a denied git push, a newly seen user-scoped MCP server, or an unexpected change to a user CLAUDE.md becomes an alert your existing workflow already handles. Anomity is SOC 2 Type II, and it complements your Network, EDR, DLP, and GRC controls - it governs the AI agent layer those tools do not see, and it does it without developers noticing the friction. See how it works and the comparison for where it fits.

Standardizing the settings hierarchy, vetting every MCP server, and setting CLAUDE.md conventions is the first half of deploying Claude Code across a fleet; the second half is one place that inventories every endpoint, decides allow/deny/log at the PreToolUse hook, and keeps the 90-day record your auditors will ask for. If that is the gap on your fleet, request early access or start with the agentic AI governance guide.

Frequently asked questions

Where do Claude Code managed settings live on each OS?

Managed settings are read from a fixed system path per platform: on macOS, /Library/Application Support/ClaudeCode/managed-settings.json (plist domain com.anthropic.claudecode); on Linux and WSL, /etc/claude-code/managed-settings.json; on Windows, C:\Program Files\ClaudeCode\managed-settings.json plus the HKLM\SOFTWARE\Policies\ClaudeCode registry key. Linux and the system directory also support a managed-settings.d/ drop-in folder so separate teams can ship independent policy fragments. These files follow the same format as ordinary settings but cannot be overridden by user or project settings, which is why they are the right place for org-wide deny rules and for disabling bypass or auto mode.

What is the settings precedence order in Claude Code?

Five layers resolve from highest to lowest: managed settings, command-line arguments, local project settings (.claude/settings.local.json), shared project settings (.claude/settings.json), then user settings (~/.claude/settings.json). Managed settings cannot be overridden by anything, including CLI flags. Crucially, permission rules are not simply merged top-down: if a tool is denied at any layer, no layer below can allow it, because deny rules from every scope are evaluated before any allow rule. A user-level deny blocks a project-level allow and vice versa. For a fleet, that means an org deny rule in managed settings is durable regardless of what a developer puts in their own files.

How are MCP servers configured and where are they stored?

MCP servers have three scopes. Project-scoped servers are written to a .mcp.json file at the repository root, which is designed to be committed so a team shares the same servers. User-scoped and local-project-scoped servers are stored in ~/.claude.json, which also holds OAuth session state and per-project caches. The practical consequence for fleet vetting is that only project servers are visible to anyone scanning a repository. A local-scoped server a developer added for themselves lives only in their home directory and will not appear in version control, so a repo-only inventory misses it.

Which files does Claude Code load into context automatically?

Several instruction-bearing files load every session without a prompt: the project CLAUDE.md (or .claude/CLAUDE.md), the user-level ~/.claude/CLAUDE.md, a CLAUDE.local.md for personal project notes, and auto memory from MEMORY.md, where the first 200 lines or 25KB, whichever comes first, load at session start. Because these become standing instructions for the agent, a file an attacker can write to is a way to plant persistent direction that the developer never typed. The permission system does not police what these files say; it only governs which tools Claude is allowed to call, which is why instruction files and runtime enforcement are separate concerns.

Can managed settings stop a developer from using bypassPermissions mode?

Yes. Administrators set permissions.disableBypassPermissionsMode to disable in managed settings to prevent the bypassPermissions mode that skips prompts, and permissions.disableAutoMode to block the research-preview auto mode. Because these sit in managed settings, they cannot be overridden by user or project files or by CLI flags. You can also set allowManagedPermissionRulesOnly to true so user and project settings cannot define any allow, ask, or deny rules, leaving only the rules you ship centrally. These controls harden each endpoint, but they do not produce a record of what happened on it, which is a separate question from policy enforcement.

Where does Claude Code store session and conversation data?

Each session is written locally as a plaintext JSONL file under ~/.claude/projects/, with every message, tool use, and result appended. This is what powers resume, fork, and rewind. Before Claude edits a file it also snapshots the contents so changes can be reverted. For a fleet, two things follow: the transcript is a genuine forensic artifact you can reconstruct after an incident, and it is also a place secrets can come to rest if a developer pastes a token or a key into the conversation. Retention and clearing are configurable, and on-endpoint secret redaction matters precisely because this data sits on the developer's disk.

Why is a per-endpoint settings hierarchy not enough for fleet governance?

Managed settings, deny rules, and disabled bypass mode are real controls, but they are configuration that lives on each machine and produces no central, queryable answer to the questions an auditor asks: which endpoints run Claude Code right now, which MCP servers and skills are attached to each, and what did each governed tool call decide. A deny rule silently blocks a call and moves on. Fleet governance needs an inventory of the artifacts across every endpoint plus a durable, queryable record of allow, deny, and log decisions that your SIEM and ticketing already consume. That is the layer a settings hierarchy alone does not give you.

Ask AI about Anomity
ChatGPT Claude Perplexity Google AI Grok