Claude Code Enterprise Setup: Managed Settings and Policy
When a few engineers use Claude Code, each person's ~/.claude/settings.json is enough. When a company rolls it out to hundreds, someone has to make sure every session blocks reads of .env, cannot switch to bypass mode, uses approved models, and reports usage, and that no developer can quietly turn those off. Claude Code's answer is managed settings: a settings layer that sits above every user and project file and that only administrators control.
This guide follows Anthropic's admin documentation. It covers the settings hierarchy, the two ways to deliver a managed policy (from the claude.ai admin console, or onto each device through MDM or a system file), a starter policy, model restrictions, OpenTelemetry, and how to check that a policy actually reached a machine. It ends with the gaps, because a managed policy that silently does not apply is worse than none: you believe a control exists when it does not.
For the permission rules a policy contains, see Claude Code Permissions. For routing traffic through your own proxy, see Claude Code Gateway Routing and Security.
Where managed settings sit
Claude Code reads settings from five levels. When the same key is set in several, the higher level wins:
1. Managed settings: from the claude.ai admin console, an MDM profile, or a managed-settings.json file. Set by your organisation.
2. Command line: claude --settings '<json or file>' for one session.
3. Local project: .claude/settings.local.json, personal and not committed.
4. Shared project: .claude/settings.json, committed to the repository.
5. User: ~/.claude/settings.json, across all of one person's projects.
Managed settings use the same JSON shape as settings.json, so anything you can put in a user file you can usually enforce centrally: permission rules, hooks, environment variables, model choice, sandbox options. A few keys only take effect from managed settings and are ignored anywhere else. They exist to stop lower levels from adding their own exceptions:
allowManagedPermissionRulesOnly: ignore permission rules from user, project, and local files and from--allowedTools.allowManagedHooksOnly: run only hooks defined in managed settings.allowManagedMcpServersOnlywithallowedMcpServers: limit MCP servers to an approved list.strictKnownMarketplaces: limit which plugin marketplaces users can add.
Quick reference
- Permission rules from different levels combine; with deny-first evaluation, a managed deny cannot be undone by a user allow rule.
- There are documented exceptions where a stricter value from a lower level still counts, so 'highest wins' is the rule for ordinary keys, not for every security setting.
- Run
/statusin a session to see which managed source is active, and/permissionsto see the effective rules and where each came from.
Remember this
Managed settings are the top layer. Pair them with the managed-only keys, or users can still add their own allow rules and hooks underneath.
Two ways to deliver the policy
Server-managed settings are JSON you paste into the claude.ai admin console. Clients fetch them from api.anthropic.com when users sign in with an eligible credential, such as a Team or Enterprise login, and cache them at ~/.claude/remote-settings.json. You need no device-management tooling, which makes this the practical choice for unmanaged laptops and the only one that reaches cloud sessions.
Endpoint-managed settings live on the device:
- macOS: the
com.anthropic.claudecodemanaged-preferences domain (a configuration profile), or/Library/Application Support/ClaudeCode/managed-settings.json. - Windows: a
Settingsvalue (REG_SZ) underHKLM\SOFTWARE\Policies\ClaudeCode, orC:\Program Files\ClaudeCode\managed-settings.json. - Linux and WSL:
/etc/claude-code/managed-settings.json.
Next to the file you can add a managed-settings.d/ directory. Claude Code merges managed-settings.json first and then every *.json file in that directory in alphabetical order, so the security team can own 20-security.json while the platform team owns 10-telemetry.json.
If several managed sources exist, Claude Code by default uses the first one that delivers a policy key, checking server-managed settings first, then MDM, then files. It does not merge them, apart from a few documented exceptions such as env, which merges per variable. Setting managedSourcesBehavior: "merge" in the highest source opts into combining them.
| Server-managed | Endpoint-managed | |
|---|---|---|
| Configured in | claude.ai: Organization settings > Claude Code > Managed settings | MDM profile, HKLM registry value, or managed-settings.json |
| Requires | Teams or Enterprise plan, Owner or Primary Owner role | A way to put files or profiles on every device |
| Refresh | At startup, then hourly during a session | MDM: startup and every 30 minutes; file: reloaded on change |
| Cloud sessions | Applies | Does not reach Anthropic-hosted cloud sessions |
| Bedrock, Vertex, Foundry | Fetch skipped | Applies |
| Tamper resistance | Client-side; cached copy is editable | OS can block user edits on managed devices |
| Per-group policy | Not supported: one policy for the whole organisation | Different files or profiles per device group |
Quick reference
- Many organisations use both: server-managed for cloud sessions and unmanaged devices, endpoint-managed on MDM-enrolled laptops for stronger tamper resistance.
- Because the default is first-source-wins, a server-managed policy with a single key hides your entire MDM policy on that machine. Mirror the important keys, or use the merge opt-in deliberately.
- Claude Code no longer reads the legacy Windows path
C:\ProgramData\ClaudeCode\managed-settings.json. Deploy toC:\Program Files\ClaudeCode\. - Only Owners and Primary Owners can edit server-managed settings, and changes apply to everyone in the organisation, so treat edits like a production change.
Remember this
Use server-managed settings to reach every login, including cloud sessions, and endpoint-managed settings where you need the OS to protect the policy.
A starter policy and what each key does
Start small. This policy keeps secrets out of reads, removes bypass mode, makes the managed rules the only rules, and allows two model families:
1{2 "permissions": {3 "deny": [4 "Read(./.env)",5 "Read(./.env.*)",6 "Read(./secrets/**)",7 "Read(~/.aws/**)"8 ],9 "disableBypassPermissionsMode": "disable"10 },11 "allowManagedPermissionRulesOnly": true,12 "availableModels": ["sonnet", "haiku"]13}- The deny rules use the normal
Tool(specifier)syntax and apply in every permission mode. disableBypassPermissionsModeremovesbypassPermissionsmode and--dangerously-skip-permissions.permissions.disableAutoModedoes the same for auto mode if you are not ready for the classifier.allowManagedPermissionRulesOnlystops users and repositories from adding their own allow rules. This is strict: every command developers want pre-approved must now be in the managed policy, or they will see more prompts.availableModelsrestricts model selection, covered in the next section.
Expect to add allow rules after a week of feedback, for example Bash(npm test *), Bash(pnpm *), or Bash(git diff *).
Quick reference
- Bash deny rules match command text.
Bash(curl *)does not catch/usr/bin/curlorsh -c 'curl ...'. For network control that does not depend on text, use the sandbox withallowManagedDomainsOnly. - Settings that run commands (
apiKeyHelper,statusLine, hooks) and manyenvvariables trigger a security approval dialog for users of server-managed settings. A user who rejects it cannot start Claude Code. - A managed CLAUDE.md delivered with the
claudeMdkey needs no approval, because it is instructions rather than a command. - Validate a policy change with
claude doctoron a test machine before saving it for the whole organisation.
Remember this
Deny the few things that must never happen, remove bypass mode, and expect to add allow rules once people report prompts.
Restricting models: availableModels is not the whole story
availableModels takes model families (sonnet), version prefixes (claude-sonnet-4-5), or full model IDs. It applies wherever a user can choose a model: /model, the --model flag, ANTHROPIC_MODEL, and the model setting. Lower settings levels cannot add to a managed list.
What happens to a blocked choice depends on where it was made. /model rejects the switch with an error. --model, ANTHROPIC_MODEL, or the model setting are replaced at startup with a warning, and the session starts on the default model.
Two details catch administrators out:
1. model is an initial choice, not enforcement. Users can open /model and pick Default, which resolves to the account's runtime default.
2. The Default option is outside availableModels unless you say otherwise. Set enforceAvailableModels: true (Claude Code v2.1.175 or later) to extend the allowlist to Default as well.
1{2 "model": "claude-sonnet-4-5",3 "availableModels": ["claude-sonnet-4-5", "haiku"],4 "enforceAvailableModels": true5}On Claude Enterprise, admins can also disable models and set an organisation default in the claude.ai admin console. That control travels with the account's entitlements, separately from the availableModels list in settings.
Quick reference
deniedModelsandavailableModelsMatch: "exact"(v2.1.283 or later) block a specific release that a family entry would otherwise allow.- On Bedrock, Vertex, or Foundry, server-managed settings do not arrive, so deliver
availableModelsthrough MDM or a managed settings file there. maxEffortLevelcaps the effort level on any plan and provider, which also bounds cost per request.
Remember this
Use availableModels with enforceAvailableModels, and deliver it on every channel your developers actually use.
Usage and cost reporting with OpenTelemetry
Claude Code exports metrics and events over OpenTelemetry. Turn it on for everyone by putting the variables in the managed env block:
1{2 "env": {3 "CLAUDE_CODE_ENABLE_TELEMETRY": "1",4 "OTEL_METRICS_EXPORTER": "otlp",5 "OTEL_LOGS_EXPORTER": "otlp",6 "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",7 "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.internal:4317"8 }9}Metrics include claude_code.session.count, claude_code.token.usage, claude_code.cost.usage (USD), claude_code.lines_of_code.count, claude_code.commit.count, claude_code.pull_request.count, and claude_code.active_time.total. Each carries attributes such as organization.id, user.account_uuid, user.email, and session.id, so you can group usage by person or team in your own backend. Events cover prompts, API requests and errors, tool decisions, and permission-mode changes.
Defaults favour privacy. Prompt text is redacted unless you set OTEL_LOG_USER_PROMPTS=1, and tool arguments are left out unless you set OTEL_LOG_TOOL_DETAILS=1. Decide with your legal and security teams before turning either on: prompts and tool arguments can contain source code, customer data, and secrets.
Quick reference
- Claude Code has no default OTLP protocol. Set
OTEL_EXPORTER_OTLP_PROTOCOLor the signal-specific variable, or the exporter sends nothing. - Cost values are estimates calculated by the client, not invoices. Reconcile against billing before using them for chargeback.
- OpenTelemetry exporter changes apply at the next launch, not to running sessions.
- A non-empty
OTEL_EXPORTER_OTLP_ENDPOINTin server-managed settings shows users the approval dialog, because it redirects data off the machine.
Remember this
Managed env turns telemetry on for everyone; keep prompt and tool-detail logging off unless you have a reason and a retention policy.
Verify the policy reached each machine
A saved policy is not a delivered policy. Check on a real machine, with a real user login, after every change:
1. Ask the user to restart Claude Code. If the policy has hooks or env values that need approval, they should see the security dialog.
2. Run claude doctor and read the Managed settings (remote) line (v2.1.248 or later). It says whether settings loaded, whether the organisation has none, whether the fetch failed and a cached policy applies, or why the fetch was skipped.
3. Run /permissions and confirm the managed deny rules are listed.
4. Try something the policy forbids: read .env, start with --dangerously-skip-permissions, or /model to a blocked model. Each should fail.
5. If delivery fails, run claude --debug-file /tmp/cc.log and search the log for Remote settings.
If a missing policy must stop work rather than allow it, set forceRemoteSettingsRefresh: true. Claude Code then blocks at startup until it has fetched fresh settings and exits if it cannot. That is fail-closed, and it means an outage of api.anthropic.com or a proxy misconfiguration stops every developer, so allow that endpoint through your network first.
Quick reference
- Without
forceRemoteSettingsRefresh, a first launch with no cache waits up to five seconds for the fetch on sign-in; otherwise the session can start before the policy loads. - Most settings changes apply to running sessions within the hourly refresh.
model, OpenTelemetry exporters, and removing anenvvariable apply only at the next launch. - Audit events for changes to server-managed settings are available through the compliance API or audit log export; ask your Anthropic account team for access.
Remember this
Verify with claude doctor and a blocked action on a real machine, not by reading the admin console.
Where a managed policy does not apply
Anthropic's documentation is direct about this: server-managed settings are a client-side control, not a security boundary. The common gaps:
- The fetch is skipped. If a user's shell exports
CLAUDE_CODE_USE_BEDROCK,CLAUDE_CODE_USE_VERTEX, another provider variable, or a non-defaultANTHROPIC_BASE_URL, Claude Code does not fetch server-managed settings. Keys from anapiKeyHelperscript do not trigger the fetch either. Versions older than the feature never fetch. - The wrong organisation. A session gets the policy of the organisation that owns its credential. A Claude Console API key belongs to a Console organisation, separate from your claude.ai Teams or Enterprise organisation, so a CI job using it does not receive your policy. Use
claude setup-tokenfor an OAuth token tied to your organisation, or deploy a managed settings file to the CI runner. - Local tampering. A user who edits the cached settings file gets the edited version at startup until the next fetch restores it. A user running a modified client can bypass any client-side control.
The stronger options are endpoint-managed settings on MDM-enrolled devices, where the OS stops users from editing the file, and controls outside Claude Code itself: credentials scoped to what the developer may touch, network egress rules, and tenant restrictions that stop logins to personal accounts.
Quick reference
claude doctorand/statusreport a skipped fetch and its cause, which is the quickest way to find a stray provider variable.- A server-managed
envblock cannot clear a provider variable exported in the shell, because the block arrives through the fetch that the export prevents. - Server-managed settings apply the same policy to everyone. If teams need different rules, use endpoint-managed files per device group, or the project-level
.claude/settings.jsonfor rules that do not need to be tamper-proof.
Remember this
Know which sessions skip the policy. For anything that must hold against a determined user, enforce it outside the client too.
Hands-on: pilot a policy on one machine
Before touching the whole organisation, test the policy where you can see everything.
1. On a test Linux VM or container, write the starter policy from this guide to /etc/claude-code/managed-settings.json.
2. Start claude as a normal user. Run /status and /permissions and confirm the managed source and rules.
3. Try to read .env, start with --dangerously-skip-permissions, and switch to a model outside availableModels.
4. Switch to Manual mode with Shift+Tab, add .claude/settings.json in a project with "allow": ["Bash(curl *)"], and ask Claude to run curl example.com. With allowManagedPermissionRulesOnly, the project rule is ignored and you still get a prompt.
5. Export CLAUDE_CODE_USE_BEDROCK=1 in the shell, run claude doctor, and read what it says about the server-managed fetch.
Pass criterion: every forbidden action in steps 3 and 4 fails or prompts, /permissions shows only managed rules, and you can explain the step 5 output to your security team.
Quick reference
- If
/permissionsshows no managed rules, check the file path and JSON validity; trailing commas make the whole file invalid. - Repeat steps 2 to 4 with the same policy in the claude.ai admin console and a Team login to compare the two channels.
- Write down the allow rules your pilot users ask for in the first week; they become version two of the policy.
Remember this
Pilot on one machine with deliberate failures before you save a policy for the whole organisation.
Key takeaway
Enterprise Claude Code setup comes down to one layer: managed settings, which outrank every user, project, and command-line setting. Deliver them from the claude.ai admin console to reach every eligible login and cloud session, or onto devices through MDM and managed-settings.json where you need the OS to protect them. Use the managed-only keys so users cannot add exceptions underneath, restrict models with availableModels plus enforceAvailableModels, and turn on OpenTelemetry through the managed env block.
Then verify with claude doctor and a blocked action, and be clear about the gaps: provider variables and custom base URLs skip the server fetch, Console API keys belong to a different organisation, and any client-side policy can be bypassed by a modified client. For the sandbox and network controls that hold outside the client, see Claude Code Sandboxing and Isolation; for compliance requirements, see Claude Code Enterprise Security and Compliance.
Practice (45 min): run the five-step pilot above, then write the one-page policy proposal you would send to your security team, listing each key and the failure it prevents.
References
- Claude Code docs: Configure server-managed settings — checked Oct 17, 2026
- Claude Code docs: Deploy managed settings — checked Oct 17, 2026
- Claude Code docs: Model configuration — checked Oct 17, 2026
- Claude Code docs: Monitoring usage with OpenTelemetry — checked Oct 17, 2026
Shoaib Hossain
Lead Author & Systems ArchitectSoftware engineer and distributed systems architect specializing in backend scalability, cloud-native infrastructure, databases, and AI engineering workflows. Author and maintainer of Core Concept Learning.
Related Articles
Explore this topic