Prelude

Consider a platform engineering team with forty developers who have adopted Claude Code. Productivity has climbed sharply. The engineering manager is thrilled. Then the CISO walks in, asks one question, and the room goes quiet.

"How do you know what it's doing?"

Nobody has an answer. Each developer has configured Claude Code independently. Some have granted it full Bash access. Others have installed MCP servers from unknown sources. A few have written custom hooks that pipe session data to personal endpoints. There is no central policy, no audit trail, and no way to enforce one retroactively.

This scenario plays out in organisations everywhere right now. Claude Code is powerful enough that developers adopt it on their own. But individual adoption without central governance creates exactly the kind of security gaps that keep CISOs awake at night.

This guide is the answer to that question. Not a policy document. A technical walkthrough of how to deploy Claude Code across an organisation with centrally managed settings that developers cannot override, permissions that follow the principle of least privilege, and hooks that give you a complete audit trail of every session.

The Problem

The core tension is simple. Developers want autonomy. Security teams want control. Claude Code sits directly in that tension because it is an AI agent that can read files, execute commands, make network requests, and modify code.

Without central management, every developer's Claude Code installation is a standalone island. Each person decides for themselves what Claude can access, what commands it can run, what data it can touch. There is no way for the organisation to say "these are our standards" and have that enforced at the tool level.

The default Claude Code permissions system is designed for individual developers. It has a tiered permission model where read-only tools like file reads and Grep need no approval, Bash commands need approval on first use, and file modifications need approval each session. That is sensible for a solo developer. It is inadequate for an organisation with fifty or five hundred developers who all need to follow the same data handling policies.

The gap between individual configuration and enterprise policy is where managed settings live.

The Journey

Understanding the Settings Hierarchy

The first thing to understand is that Claude Code has a clear precedence hierarchy for settings. From highest to lowest priority, the levels are managed settings, command line arguments, local project settings in .claude/settings.local.json, shared project settings in .claude/settings.json, and user settings in ~/.claude/settings.json.

Managed settings sit at the top. They cannot be overridden by any level below them, including command line arguments. A developer cannot bypass them with a flag, a local config file, or a project-level override. They are the ceiling.

This is the foundation everything else builds on. If you configure a deny rule in managed settings, no developer can undo it. If you set allowManagedHooksOnly to true, no developer can add their own hooks. The hierarchy is not a suggestion. It is enforced by the runtime.

Settings Precedence Reference

Priority Level Typical path or source Who can write it Overridable by
1 (highest) Managed settings Server policy, MDM profile, or managed-settings.json at OS system path Admin / MDM / Anthropic console Nothing
2 Command line flags claude --permission-mode ... at invocation Developer, but blocked by managed flags Managed settings
3 Local project .claude/settings.local.json in repo (gitignored) Individual developer Managed, CLI flags
4 Shared project .claude/settings.json in repo Project maintainer via PR Managed, CLI, local
5 (lowest) User settings ~/.claude/settings.json Individual developer Every level above

Data source: Claude Code Settings documentation, as of 2026-04. Permalink: systemprompt.io/guides/enterprise-claude-code-managed-settings#settings-precedence-reference.

Deploying Managed Settings Across Your Fleet

The managed-settings.json file lives in a system directory that requires administrator privileges to modify. The paths differ by operating system.

On macOS, the file goes to /Library/Application Support/ClaudeCode/managed-settings.json. On Linux and WSL, it goes to /etc/claude-code/managed-settings.json. On Windows, it goes to C:\Program Files\ClaudeCode\managed-settings.json.

These are not in the user's home directory. They are not in the project folder. They are in system-level paths that regular developers cannot write to without elevated privileges.

You have three delivery mechanisms to choose from.

File-based deployment is the simplest. Script the file drop using Ansible, Chef, Puppet, or a plain shell script. Copy managed-settings.json to the appropriate system path. This works for any organisation that already manages system configuration through automation.

MDM deployment uses platform-native management. On macOS, deploy through Jamf, Kandji, or any MDM that supports managed preferences, using the domain com.anthropic.claudecode. On Windows, push settings through Group Policy or Microsoft Intune via the HKLM\SOFTWARE\Policies\ClaudeCode registry key with a Settings value containing the JSON configuration.

Server-managed settings push configuration remotely from the Claude.ai admin console with no file on disk at all. This is the cleanest option for organisations already managing their Anthropic subscription centrally.

Only one managed source wins. The precedence within the managed tier is server-managed first, then MDM and OS-level policies, then the managed-settings.json file. Sources do not merge. The highest-priority source that exists is the one that takes effect.

The Permissions Model That Actually Works

Most teams get the permissions model wrong on day one. The instinct is to start open and block specific things. "Let developers do everything except these dangerous commands." That is a losing game.

Every new tool, every new script, every new pattern needs someone to remember to add it to the blocklist. Something always slips through. The blocklist grows forever and still has gaps.

The better approach is allowlisting. Start with nothing permitted. Add only what your team actually needs. The permissions documentation supports this through a clear rule evaluation order where deny rules are checked first, then ask rules, then allow rules. The first matching rule wins.

A practical starting configuration for a managed-settings.json looks like this.

{
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test *)",
      "Bash(npm run build)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)",
      "Bash(curl *)",
      "Bash(wget *)",
      "Read(./.env)",
      "Read(//**/credentials*)"
    ]
  },
  "allowManagedPermissionRulesOnly": true
}

The critical line is allowManagedPermissionRulesOnly. When this is true, user and project settings cannot define their own allow, ask, or deny rules. Only the rules in managed settings apply. A developer cannot override your permissions at any level.

Without that flag, a developer could add "allow": ["Bash"] to their user settings and grant themselves unrestricted Bash access. With the flag enabled, their user-level permission rules are simply ignored.

One important detail about Bash wildcard patterns. The space before the asterisk matters. Bash(ls *) matches ls -la but not lsof, because the space enforces a word boundary. Bash(ls*) without the space matches both. Claude Code is also aware of shell operators, so a rule like Bash(npm run *) will not accidentally allow npm run test && rm -rf /.

Locking Down Hooks

Hooks are one of the most powerful features in Claude Code. They are also one of the biggest security surface areas. A hook is a user-defined shell command, HTTP endpoint, or LLM prompt that executes automatically at specific points in a Claude Code session.

There are multiple hook events. PreToolUse fires before Claude uses any tool and can approve, deny, or modify the tool call. PostToolUse fires after a tool completes. Notification fires when Claude produces a status notification. Stop fires when Claude finishes its response. SubagentStop fires when a subagent completes. And several more.

In an unmanaged environment, any developer can define hooks in their user settings, project settings, or through plugins. A malicious or misconfigured hook could exfiltrate data through an HTTP endpoint, modify tool inputs to bypass security policies, or silently alter Claude's outputs.

The fix is one setting in your managed-settings.json.

{
  "allowManagedHooksOnly": true
}

When allowManagedHooksOnly is enabled, every user-defined hook, every project hook, and every plugin hook is blocked. Only the managed hooks run. The developer sees them running in their session but cannot modify, disable, or add their own.

Hooks snapshot at session start. Even if someone modified a settings file mid-session, the changes do not take effect until the next session. Claude Code warns the developer and requires review before anything applies. This prevents malicious pull requests that sneak hook changes into .claude/settings.json from taking effect immediately.

Building Your Audit Trail with HTTP Hooks

Now that only managed hooks can run, you can use them to build an audit trail that covers every session. HTTP hooks send the event's JSON input as a POST request to your endpoint, with the response using the same JSON output format as command hooks.

Here is a managed hook configuration that sends every tool use to your logging endpoint.

{
  "hooks": {
    "PostToolUse": [
      {
        "type": "http",
        "url": "https://audit.yourcompany.com/claude-code/tool-use",
        "matcher": "",
        "timeout": 5000,
        "headers": {
          "Authorization": "Bearer $AUDIT_API_KEY",
          "X-Developer-Email": "$DEVELOPER_EMAIL"
        },
        "allowedEnvVars": ["AUDIT_API_KEY", "DEVELOPER_EMAIL"]
      }
    ],
    "Stop": [
      {
        "type": "http",
        "url": "https://audit.yourcompany.com/claude-code/session-end",
        "timeout": 5000,
        "headers": {
          "Authorization": "Bearer $AUDIT_API_KEY"
        },
        "allowedEnvVars": ["AUDIT_API_KEY"]
      }
    ]
  }
}

The headers field supports environment variable interpolation, but only for variables explicitly listed in allowedEnvVars. This prevents accidental secret leakage. Even if a hook configuration references $AWS_SECRET_KEY, it resolves to empty unless explicitly approved in the allowedEnvVars list.

You can further restrict this globally with httpHookAllowedEnvVars in managed settings. Each hook's own allowedEnvVars list is intersected with the global list. If the global list does not include a variable, no hook can access it regardless of its own configuration.

For URL restrictions, allowedHttpHookUrls whitelists which URLs hooks can target. An empty array blocks all HTTP hooks. This prevents any hook from reaching an endpoint you have not explicitly approved.

Controlling MCP Servers and Network Access

MCP servers are another surface area that needs central control. An MCP server is an external tool provider that Claude Code can connect to, giving it capabilities like database access, API integrations, or file system operations beyond the working directory.

In managed settings, allowManagedMcpServersOnly restricts which MCP servers are available. When enabled, only the servers listed in your managed MCP configuration can be used. Denied servers still merge from all sources, so you can blocklist at any level.

For network access, the sandbox configuration provides OS-level enforcement. The sandbox.network.allowManagedDomainsOnly setting ensures that only domains listed in managed settings are accessible. Non-allowed domains are blocked automatically without even prompting the developer.

{
  "allowManagedMcpServersOnly": true,
  "sandbox": {
    "network": {
      "allowManagedDomainsOnly": true,
      "allowedDomains": [
        "api.github.com",
        "registry.npmjs.org",
        "audit.yourcompany.com"
      ]
    }
  }
}

This creates a layered defence. Permissions control what Claude decides to do. The sandbox controls what actually happens at the OS level, even if a prompt injection bypasses Claude's decision-making.

Plugin Management with allowManagedPluginsOnly

Claude Code plugins are a powerful extension mechanism, but in enterprise environments they represent an uncontrolled surface area. Each plugin can inject system prompts, add MCP servers, register hooks, and modify Claude's behaviour. Without central control, any developer can install any plugin from any marketplace.

The allowManagedPluginsOnly setting restricts plugin installation to a centrally defined list. When enabled, developers cannot install plugins through /plugin install or by adding marketplace entries to their user or project settings. Only plugins listed in the managed configuration are available.

{
  "allowManagedPluginsOnly": true,
  "enabledPlugins": [
    "typescript-lsp@claude-plugins-official",
    "commit-commands@claude-plugins-official",
    "pr-review-toolkit@claude-plugins-official",
    "security-guidance@claude-plugins-official"
  ]
}

This is the plugin equivalent of allowManagedPermissionRulesOnly. The managed list becomes the complete set of available plugins. Developers can see which plugins are enabled through /status, but they cannot modify the list.

Combine this with allowManagedMcpServersOnly to close both extension surfaces simultaneously. Plugins that bundle their own MCP servers are subject to both restrictions: the plugin must be in the managed plugin list, and any MCP servers it provides must be in the managed MCP server list.

For organisations evaluating new plugins, the recommended workflow is: a security team member installs the plugin in an isolated environment, reviews its permissions, checks its source code, and if approved, adds it to the managed configuration. The plugin is then available to all developers through the next settings deployment.

Policy Capabilities Matrix

Capability Managed flag / field What it controls Least-privilege alignment
Allow list permissions.allow Commands, tools, and read paths permitted without prompting NIST AC-6 least privilege enumeration
Deny list permissions.deny Operations always blocked (evaluated first) AC-6 deny-by-default for sensitive paths
Rule lockdown allowManagedPermissionRulesOnly Blocks user/project allow/ask/deny rules AC-6 non-bypassable enforcement
Hook lockdown allowManagedHooksOnly Blocks user/project/plugin hooks AU-2 trusted audit event source
MCP lockdown allowManagedMcpServersOnly Restricts tool providers to approved servers CM-7 least functionality
Plugin lockdown allowManagedPluginsOnly Restricts plugins to approved marketplace entries CM-7 least functionality
Env var allowlist httpHookAllowedEnvVars Variables hooks may interpolate into outbound requests SC-28 protect data at rest and in transit
Hook URL allowlist allowedHttpHookUrls Destination URLs hooks may reach SC-7 boundary protection
Network sandbox sandbox.network.allowManagedDomainsOnly OS-level domain enforcement SC-7 boundary protection
Bypass block disableBypassPermissionsMode Disables --dangerously-skip-permissions AC-3 enforced access

Data source: Claude Code Settings documentation and Claude Code Permissions documentation, cross-mapped to NIST SP 800-53 Rev. 5, as of 2026-04. Permalink: systemprompt.io/guides/enterprise-claude-code-managed-settings#policy-capabilities-matrix.

Phased Rollout Playbook

Deploying managed settings across an entire engineering team in a single step is tempting but risky. If the initial configuration is too restrictive, developers lose productivity and push back hard. If it is too permissive, you have not solved the governance problem. A phased rollout gives you the data to get the balance right.

Week 1-2: Audit mode. Deploy managed settings with permissive allow rules and an HTTP audit hook that logs every tool use. Do not restrict anything yet. The goal is to collect data on what developers actually do with Claude Code. Which commands do they run? Which files do they edit? Which MCP servers do they use? Which plugins are installed?

{
  "hooks": {
    "PostToolUse": [
      {
        "type": "http",
        "url": "https://audit.yourcompany.com/claude-code/baseline",
        "matcher": "",
        "timeout": 5000,
        "headers": { "Authorization": "Bearer $AUDIT_API_KEY" },
        "allowedEnvVars": ["AUDIT_API_KEY"]
      }
    ]
  }
}

Week 3: Analyse and draft. Review the audit data. Identify the commands and patterns that appear in more than 80% of developer sessions. These become your allow rules. Identify patterns that should never happen (accessing credentials, pushing to main, running destructive commands). These become your deny rules. Draft your permissions configuration based on real usage, not assumptions.

Week 4: Pilot group. Deploy the full managed configuration to a pilot group of 5-10 developers. These should be developers who are heavy Claude Code users and who will provide honest feedback. Enable allowManagedPermissionRulesOnly and allowManagedHooksOnly for this group. Monitor the audit logs for blocked operations. Every blocked operation is either a rule that needs adjustment or a behaviour that should genuinely be blocked. Talk to the developers to find out which.

Week 5-6: Iterate and expand. Adjust the configuration based on pilot feedback. Expand to additional teams. Each expansion should be a new team, not the whole company. If a team has unusual requirements (data science teams that need different Bash commands, infrastructure teams that need kubectl access), create team-specific allow rules and document why they differ from the standard.

Week 7+: Full deployment. Once three or more teams are running on managed settings without significant blockers, deploy to everyone. At this point you have real data showing the configuration works, pilot feedback proving it does not cripple productivity, and a process for handling exceptions.

The most common mistake is skipping the audit phase and guessing at what developers need. The second most common mistake is not having an escalation path for blocked operations. Define a process (a Slack channel, a Jira form, a quick email to the platform team) where developers can request exceptions. Review and respond within the same business day. A managed settings deployment that blocks a developer for an entire day because nobody can approve an exception is a deployment that gets rolled back.

Rollout Phase Reference

Phase Duration Population Lockdown flags enabled Primary KPIs Exit criteria
Audit 2 weeks All developers (observe only) None; hooks in log-only mode Hook delivery rate, tool call volume per developer, most-used allow patterns 10k+ events captured; allow-list draft reviewed
Pilot 1-2 weeks Ringed cohort (5-10 volunteers) allowManagedPermissionRulesOnly, allowManagedHooksOnly Blocked-operation rate, exception-request latency, developer NPS < 5% unjustified blocks; median exception response < 4h
Ringed 2 weeks One team at a time Pilot flags + allowManagedMcpServersOnly, allowManagedPluginsOnly Block rate trend, audit trail completeness, config drift events 3+ teams running without rollback; zero unresolved P1 tickets
Full Ongoing Entire engineering org All lockdown flags + disableBypassPermissionsMode + sandbox.network.allowManagedDomainsOnly 100% session coverage in audit log, exception SLA compliance, policy review cadence Quarterly policy review scheduled; SIEM ingestion validated

Data source: structure derived from Anthropic Claude Code enterprise documentation and established ringed-deployment guidance aligned with NIST SP 800-53 AC-6, as of 2026-04. Permalink: systemprompt.io/guides/enterprise-claude-code-managed-settings#rollout-phase-reference.

Monitoring and Alerting for Hook Health

Managed hooks are infrastructure. Like any infrastructure, they need monitoring. A broken audit hook means gaps in your compliance trail. A slow PreToolUse hook means every developer's session feels sluggish. A failing HTTP endpoint means events are being silently dropped.

Monitor your audit endpoint availability. If your HTTP hooks send events to an audit endpoint, monitor that endpoint independently with your existing uptime monitoring (Datadog, PagerDuty, Pingdom, or equivalent). A 500 error from the endpoint does not break the developer's session, but it does create a gap in your audit trail. Set up alerts for error rates above 1% and for latency above 3 seconds.

Track hook failure rates. If your audit endpoint receives events, it knows what it should be receiving. Compare the number of events received per developer per day against the expected baseline from your audit phase. A sudden drop in events from a specific developer may indicate that their managed settings are not loading correctly (invalid JSON, wrong file path, or a conflicting MDM configuration).

Alert on configuration drift. Use the ConfigChange hook event to detect when configuration files change during active sessions. This catches both accidental modifications and deliberate attempts to circumvent managed settings. The alert should go to the platform team, not just to a log file.

{
  "hooks": {
    "ConfigChange": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "https://alerts.yourcompany.com/claude-code/config-change",
            "timeout": 3000,
            "headers": { "Authorization": "Bearer $ALERT_TOKEN" },
            "allowedEnvVars": ["ALERT_TOKEN"]
          }
        ]
      }
    ]
  }
}

Cost and Token Management via Managed Settings

For organisations with large Claude Code deployments, token usage and AI costs are a genuine budget concern. Managed settings provide indirect controls that limit cost exposure without capping individual developer productivity. For the full set of individual-level cost reduction techniques that complement these organisational controls, see our guide on Claude Code cost optimisation.

Restrict model access. If your Anthropic plan includes multiple models, you can use managed settings to restrict which models developers can use. Higher-capability models cost more per token. Restricting daily development work to a cost-effective model while allowing the more capable model only for specific workflows keeps costs predictable.

Limit scope of operations. The most expensive Claude Code sessions are the ones where Claude reads hundreds of files, executes dozens of commands, and generates massive diffs. Permission rules that restrict file reads to the project's source directory and deny access to large binary directories (node_modules, .git objects, build artifacts) reduce the context window usage that drives token costs.

Audit token-intensive patterns. Your PostToolUse audit hooks capture every tool invocation. Analyse this data for token-intensive patterns: developers who routinely ask Claude to read entire directories, sessions that generate and discard large amounts of code, and workflows that could be made more efficient. This data informs both training and configuration changes.

Deny wasteful patterns. Some Bash commands trigger expensive operations that generate massive output. Commands like cat on large files, find / without path restrictions, or git log without limits can fill Claude's context window with irrelevant data. Deny rules for these patterns reduce token waste:

{
  "permissions": {
    "deny": [
      "Bash(cat //**/node_modules/**)",
      "Bash(find / *)",
      "Bash(git log --all --oneline)"
    ]
  }
}

The goal is not to micromanage usage but to prevent the small number of patterns that account for disproportionate cost. Most developers never trigger these patterns intentionally. The deny rules catch accidental cases and AI-initiated commands that would otherwise consume tokens without adding value.

Compliance and Audit Requirements

Managed settings are not just a security convenience. For many organisations, they are a compliance requirement. If your company is SOC 2 certified, undergoing ISO 27001 audits, or subject to GDPR obligations around automated data processing, you need demonstrable controls over AI agent behaviour.

SOC 2 Trust Services Criteria require that organisations define and enforce access controls for systems that process customer data. An unmanaged Claude Code installation where each developer sets their own permissions does not meet that bar. Managed settings give you a single, auditable configuration that proves every developer's Claude Code session operates under the same policy. Your auditor can inspect one file and understand what the agent can and cannot do.

For GDPR compliance, the key concern is automated processing of personal data. If Claude Code reads files that contain customer information, you need to demonstrate that the processing is controlled and limited. Deny rules that block access to production data directories, combined with audit hooks that log every file read, give you the evidence trail that Article 30 record-keeping requires.

ISO 27001 Annex A controls around access management (A.9) and operations security (A.12) map directly to managed settings capabilities. The permissions allowlist satisfies access control requirements. The hook-based audit trail satisfies logging and monitoring requirements. The disableBypassPermissionsMode setting satisfies the requirement that security controls cannot be circumvented by end users.

Beyond formal compliance, many organisations have internal security policies that require all developer tools to be centrally managed. Managed settings turn Claude Code from an unmanaged developer tool into a centrally governed one, which is often the difference between "approved for use" and "blocked by security" in enterprise procurement reviews. If your organisation needs a governance layer that sits above managed settings and adds transport-layer enforcement, SIEM-compatible audit logs, and role-based access control across all AI agent activity, systemprompt.io provides that as a single self-hosted binary. If your organisation is evaluating AI coding tools at the feature and workflow level, our Claude Code vs Cursor comparison covers enterprise governance, security controls, and deployment models side by side.

Deployment Patterns in Practice

The choice of deployment mechanism depends on what your organisation already uses for system configuration management.

Git-based configuration management works well for teams that treat infrastructure as code. Store your managed-settings.json in a dedicated repository alongside other system configurations. Use a CI/CD pipeline to validate the JSON on every pull request, run a schema check against the Claude Code settings schema, and deploy the file to target machines through your existing provisioning tooling. This gives you version history, peer review on policy changes, and rollback capability.

MDM distribution for macOS through Jamf or Kandji is the cleanest option for organisations with Apple fleets. Create a configuration profile targeting the com.anthropic.claudecode preference domain. The JSON settings map directly to the profile payload. Push updates through your MDM console and they take effect on each developer machine at next check-in. This approach also gives you MDM-level reporting on which machines have received the configuration.

Windows Group Policy distribution follows the standard GPO workflow. Create a new GPO, navigate to Computer Configuration > Administrative Templates, and set the registry value at HKLM\SOFTWARE\Policies\ClaudeCode\Settings with your JSON configuration as the string value. Link the GPO to the appropriate organisational unit. For Intune-managed devices, deploy the same registry key through a configuration profile.

CI/CD validation is worth adding regardless of your deployment mechanism. If your team also runs Claude Code in GitHub Actions for automated PR review, the managed settings file should be validated in the same pipeline that tests those workflows. A simple pipeline step that runs python -m json.tool managed-settings.json catches syntax errors before they reach developer machines. A more thorough check validates that every permission rule follows the correct Tool(pattern) syntax and that all hook URLs are reachable. Deploying invalid JSON to the managed settings path silently breaks the configuration, which means developers fall back to their own settings with no central control. Catching errors in the pipeline prevents that.

The Complete Enterprise Lockdown

Bringing all of this together, here is a full managed-settings.json that represents a production enterprise deployment.

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git commit *)",
      "Bash(* --version)",
      "Bash(* --help *)"
    ],
    "deny": [
      "Bash(git push --force *)",
      "Bash(curl *)",
      "Bash(wget *)",
      "Bash(rm -rf *)",
      "Read(./.env)",
      "Read(//**/credentials*)",
      "Read(///**/.ssh/**)"
    ]
  },
  "allowManagedPermissionRulesOnly": true,
  "allowManagedHooksOnly": true,
  "allowManagedMcpServersOnly": true,
  "disableBypassPermissionsMode": "disable",
  "sandbox": {
    "network": {
      "allowManagedDomainsOnly": true,
      "allowedDomains": [
        "api.github.com",
        "registry.npmjs.org",
        "audit.yourcompany.com"
      ]
    }
  },
  "hooks": {
    "PostToolUse": [
      {
        "type": "http",
        "url": "https://audit.yourcompany.com/claude-code/tool-use",
        "matcher": "",
        "timeout": 5000,
        "headers": {
          "Authorization": "Bearer $AUDIT_API_KEY"
        },
        "allowedEnvVars": ["AUDIT_API_KEY"]
      }
    ]
  }
}

Every layer is enforced centrally. Permissions are managed-only. Hooks are managed-only. MCP servers are managed-only. Bypass mode is disabled. Network access is restricted to approved domains. An audit hook captures every tool use. Nothing is left to the individual developer's configuration.

Developers verify their managed settings source by running /status in Claude Code. They can see what policies apply to their session. They just cannot change them.

Troubleshooting Common Deployment Issues

Even a well-planned deployment runs into problems. Here are the issues that come up most often and how to resolve them.

Malformed JSON in managed-settings.json. If the file contains invalid JSON, Claude Code cannot parse it. The result is that managed settings are silently ignored and developers fall back to their own user and project settings. This is the worst failure mode because it looks like everything is working while no central policy is actually enforced. Always validate your JSON before deployment. Run python -m json.tool managed-settings.json or use jq . managed-settings.json as a pre-deployment check. If developers report that /status shows no managed settings source, invalid JSON is the first thing to investigate.

MDM and file-based settings both present. If you have both an MDM-delivered configuration and a managed-settings.json file on the same machine, only one wins. The precedence within the managed tier is server-managed first, then MDM, then the file. The sources do not merge. If your MDM configuration has permissions but no hooks, and your file has hooks but no permissions, the MDM configuration wins entirely and the hooks from the file are ignored. Pick one delivery mechanism per machine and stick with it.

Permission rules not matching as expected. The most common cause is wildcard confusion. Remember that Bash(git *) matches git status and git diff --staged but not gitk, because the space before the asterisk creates a word boundary. If a developer reports that a command they expect to be allowed is being blocked, check whether the pattern in your allow rule actually matches the full command string. Ask the developer to share the exact command that was blocked. Then test the pattern against it. Also remember that rule evaluation is deny first, then ask, then allow. If you have a deny rule that matches more broadly than you intended, it takes precedence over any allow rule.

Developers cannot see managed settings in /status. This usually means the file is in the wrong path or has incorrect file permissions. On macOS, verify the file is at /Library/Application Support/ClaudeCode/managed-settings.json and is world-readable. On Linux, check /etc/claude-code/managed-settings.json. On Windows, check C:\Program Files\ClaudeCode\managed-settings.json. The file needs to be readable by the developer's user account, even though it should not be writable by them. A file owned by root with 644 permissions is the correct setup on macOS and Linux.

Audit hooks returning errors. If your HTTP audit hook endpoint is unreachable or returns an error, the hook fails but Claude Code continues operating. Hooks do not block the session on failure by default. This means a network outage at your audit endpoint does not break developer productivity, but it does create a gap in your audit trail. Monitor your audit endpoint's availability independently. If you need hooks to be blocking, where a failed hook prevents the tool use from proceeding, use a PreToolUse hook instead of PostToolUse. A PreToolUse hook that returns an error will block the tool call entirely.

Settings changes not taking effect mid-session. This is by design. Claude Code snapshots hook and settings configuration at session start. If you push an updated managed-settings.json while a developer has an active session, they will not see the changes until they start a new session. For urgent policy changes, you may need to communicate to developers that they should restart their Claude Code sessions. There is no remote kill switch for active sessions through managed settings alone.

The Lesson

Enterprise AI agent management is not a policy document. It is a centrally deployed configuration that intercepts every critical agent action, enforces your data handling rules, and gives you a complete audit trail.

The organisations that are deploying Claude Code successfully are not the ones with the most restrictive policies. They are the ones that found the right balance. Developers still have autonomy within their working directory. They can still use Claude Code for everything it is good at. But the guardrails are non-negotiable and centrally enforced.

The managed settings system is what makes this possible. Not trust. Not training. Not documentation that people might read. A configuration hierarchy where the organisation's policies sit at the top and cannot be overridden at any level below.

If your team is using Claude Code without managed settings, every developer is making independent security decisions about an AI agent that can execute arbitrary commands. For a solo developer, that is fine. For a team of ten or more, it is a risk that grows with every person you onboard.

The good news is that the infrastructure exists today. The managed settings documentation covers every option. The permissions model supports fine-grained control. The hooks system gives you the audit trail. All that remains is deploying it.

Conclusion

The CISO who asks "how do you know what it's doing?" is asking the right question at the wrong time. The answer should already exist before the question comes up.

A managed-settings.json file deployed to every developer machine through your existing MDM or configuration management gives you that answer. Every permission rule, every hook, every MCP server, every network domain is defined centrally and enforced by the runtime. The audit trail captures what happened. The permissions ensure only approved actions are possible.

Start with a minimal allowlist. Deploy the managed settings file to a test group. Enable the audit hooks and review what Claude Code actually does during a typical development session. Expand the allowlist based on real usage, not assumptions. Then roll it out to everyone. For a detailed week-by-week rollout plan covering team onboarding, training, and scaling beyond the initial pilot, see our organisation rollout guide.

Enterprise adoption of AI coding agents is not a question of whether. It is a question of how. And the how is managed settings.