the short answer
Start with five things: turn off bypass and auto modes, make managed permission rules the only ones that count, allowlist MCP servers by URL or command, set a minimum Claude Code version that supports every key you use, and send telemetry to your collector. Add a short deny list for secrets and, if you run a policy engine, a PreToolUse hook with onFailure: "block". Deliver it by file or MDM and verify with /status.
- macOS
/Library/Application Support/ClaudeCode/managed-settings.jsonor thecom.anthropic.claudecodedomain- Linux / WSL
/etc/claude-code/managed-settings.json- Windows
C:\Program Files\ClaudeCode\managed-settings.json, or a REG_SZ value namedSettingsunderHKLM\SOFTWARE\Policies\ClaudeCode- Verify
/statusshowsSetting sources: Enterprise managed settings (...)- Verified
- Against Claude Code docs, October 21, 2026
The Baseline
Replace the org UUID, MCP servers, collector endpoint and binary path (which failproofai on a managed machine). "onFailure": "block" (Claude Code 2.1.295+) makes the hook fail closed: without it, a crashing, missing or timed-out hook lets the tool call through. The version floor is set to the newest version any key here needs.
The hook command is the form failproofai config writes into ~/.claude/settings.json. Registering it in managed settings is your configuration, not a documented Failproof install path. The template locks only the pre-tool gate: keep the user-scope install from failproofai config, which also registers PostToolUse (the default sanitize-* output redaction), Stop (the require-*-before-stop checks), UserPromptSubmit and session events. With both present, the pre-tool check runs twice per call; talk to us about a managed deployment that registers it once.
{
"permissions": {
"disableBypassPermissionsMode": "disable",
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Read(~/.aws/credentials)",
"Read(~/.ssh/**)"
]
},
"disableAutoMode": "disable",
"allowManagedPermissionRulesOnly": true,
"allowManagedMcpServersOnly": true,
"allowedMcpServers": [
{ "serverUrl": "https://api.githubcopilot.com/*" },
{ "serverUrl": "https://mcp.internal.example.com/*" },
{ "serverCommand": ["npx", "-y", "@company/mcp-internal"] }
],
"requiredMinimumVersion": "2.1.295",
"forceLoginMethod": "claudeai",
"forceLoginOrgUUID": "00000000-0000-0000-0000-000000000000",
"cleanupPeriodDays": 30,
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://otel-collector.example.com"
},
"hooks": {
"PreToolUse": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "/usr/local/bin/failproofai --hook PreToolUse", "onFailure": "block" }] }
]
}
}About allowManagedHooksOnly
allowManagedHooksOnly: true blocks user, project and local hooks; only managed hooks, Agent SDK hooks and hooks from plugins force-enabled in managed settings run. Failproof’s default install puts its Claude Code hooks at user scope, so turning this key on switches those hooks off. The template registers only PreToolUse, so output redaction, Stop checks and session capture would stop even with the template in place. Only set it once the managed hook is in place and verified, or talk to us about a managed deployment.
What Each Key Does
| Key | Effect | Note |
|---|---|---|
permissions.disableBypassPermissionsMode | Rejects bypass mode and --dangerously-skip-permissions | Value is the string "disable"; verify on your version |
disableAutoMode | Turns off auto mode | String "disable"; also accepted as permissions.disableAutoMode |
allowManagedPermissionRulesOnly | Ignores allow, ask and deny rules from user, project, local and --settings | Does not lock MCP servers |
allowManagedMcpServersOnly + allowedMcpServers | Only listed servers can be added; built-in servers and organization-delivered managed servers are exempt, and the denylist still applies to them | Once any serverUrl (or serverCommand) entry exists, remote (or stdio) servers must match one; a serverName entry no longer admits them |
requiredMinimumVersion | Blocks startup below a version | Managed only; the key itself needs 2.1.163+, onFailure needs 2.1.295+ |
forceLoginMethod, forceLoginOrgUUID | Only sign in to your org | Only a managed source enforces the org pin |
env | Sets telemetry variables | Repositories cannot change or turn off exporter settings that managed settings set |
permissions.deny with Read(...) | Blocks Read, Edit and Write and recognised Bash file commands (cat, head, sed, redirections) on those paths | Not scripts that open files themselves |
Path Prefixes Trip People Up
Sandbox paths use normal conventions (/ is absolute), which differs from permission rules. Test each rule on a real machine.
| Prefix | Means in permission rules |
|---|---|
./path or bare | Relative to the working directory |
~/path | Home directory |
//path | Absolute path |
/path | Relative to the settings source, not absolute (project: working directory; user: ~/.claude) |
One Managed Source per Fleet
Managed sources rank server-managed, then MDM, then file, then HKCU, and by default ("first-wins") the first source with a policy key wins for most keys. Since v2.1.242 you can set managedSourcesBehavior to "merge". Pick one source, or set merge explicitly, so a console change never silently replaces your file. See managed settings not enforced.
Where It Applies
- On the machine: the terminal CLI, the VS Code and JetBrains extensions, the desktop app’s Code tab and Agent SDK sessions read managed settings.
- Anthropic-hosted cloud sessions do not read a device’s file or MDM profile; their policy has to come from server-managed settings.
- Claude Tag sessions do not receive server-managed settings; Cowork is configured separately.
Optional: Lock the Sandbox On
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"allowUnsandboxedCommands": false,
"filesystem": { "denyRead": ["~/.aws/credentials", "~/.ssh"] },
"network": { "allowManagedDomainsOnly": true, "allowedDomains": ["github.com", "*.npmjs.org"] }
}
}FAQ
Does this stop agents running destructive commands?
Only the ones a text pattern can describe. Effects like terraform destroy inside a script need a policy engine; that is what the hook is for.
Can developers override it?
Not from their own settings files. A developer with local admin rights can edit the managed file, so redeploy it from MDM on a schedule.
Why not keep the hook at user scope?
User-scope hooks can be edited by the user, and without onFailure: "block" a failed hook lets calls through. A managed hook with onFailure: "block" is the stronger setup.
Sources
Checked against the sources below on October 21, 2026. Harness settings, hook capabilities and cloud features change between versions.
- Claude Code docs: Deploy managed settings
- Claude Code docs: Settings reference
- Claude Code docs: Configure permissions
- Claude Code docs: Hooks reference
- Claude Code docs: Monitoring usage (OpenTelemetry)
- Claude Code docs: Configure the sandboxed Bash tool
- Failproof AI docs: Agent harnesses and enforcement capability
- Failproof AI docs: Failure behavior