# Claude Code Enterprise Rollout — Push ACP to Every Seat with Managed Settings

A complete managed-settings.json that puts ACP on every Claude Code seat with no device management: managed settings force-enable the ACP plugin from its marketplace, lock hooks to managed sources, set the enrollment flag, and allowlist the MCP endpoint, delivered from the claude.ai admin console, an MDM profile, the Windows registry, or a system file.

# Roll ACP out to every Claude Code seat

Claude Code has the cleanest rollout of the four harnesses: managed settings can force-enable a plugin from a marketplace, and Claude Code fetches it at startup. Nothing is copied to any machine, and the claude.ai admin console can deliver the whole thing without MDM. Anthropic's [managed settings](https://code.claude.com/docs/en/managed-settings), [admin setup](https://code.claude.com/docs/en/admin-setup), [hooks](https://code.claude.com/docs/en/hooks), [managed MCP](https://code.claude.com/docs/en/managed-mcp), and [plugin marketplaces](https://code.claude.com/docs/en/plugin-marketplaces) pages are the source for every key below. Read the [shape all four harnesses share](/docs/enterprise) first if you haven't.

## Before you push

1. Claim your company domain on the ACP workspace's Team page so enrollments land in your workspace ([why](/docs/enterprise#who-each-call-is-attributed-to)).
2. Decide the posture for unenrolled seats. The sample sets `ACP_REQUIRE_ENROLLMENT` to `1` in the managed `env`, so a seat with no credential blocks each tool call with the enrollment step. Remove the key for the self-serve posture (run, warn, log).
3. Note what `allowManagedHooksOnly` takes with it: user, project, local, and plugin hooks other than managed-enabled plugins stop running, and status-line and file-suggestion settings narrow to managed. If teams rely on their own hooks, start without it and add it once you've read the audit stream.

## The managed settings

```json
{
  "extraKnownMarketplaces": {
    "acp": {
      "source": { "source": "github", "repo": "agentic-control-plane/claude-code-acp-plugin" }
    }
  },
  "enabledPlugins": {
    "agentic-control-plane@acp": true
  },
  "allowManagedHooksOnly": true,
  "env": {
    "ACP_REQUIRE_ENROLLMENT": "1"
  },
  "allowedMcpServers": [
    { "serverUrl": "https://api.agenticcontrolplane.com/*" }
  ],
  "permissions": {
    "disableBypassPermissionsMode": "disable"
  }
}
```

What each key does:

- **`extraKnownMarketplaces`** registers ACP's marketplace, the same one the self-serve installer adds with `claude plugin marketplace add agentic-control-plane/claude-code-acp-plugin`. Pair it with `strictKnownMarketplaces` if you want this to be the only marketplace users can add.
- **`enabledPlugins`** force-enables the plugin. Plugins enabled in managed settings can't be disabled from user settings, and the plugin's `PreToolUse`, `PostToolUse`, and `SessionStart` hooks come with it. The plugin runs the same `govern.mjs` the installer writes to `~/.acp`.
- **`allowManagedHooksOnly`** blocks hooks from every other source. Hooks from plugins force-enabled in managed `enabledPlugins` are exempt, which is exactly the ACP case.
- **`env`** applies to every session and its subprocesses, so the plugin's hook sees `ACP_REQUIRE_ENROLLMENT` without any per-machine wrapper.
- **`allowedMcpServers`** permits ACP's endpoint by URL. It doesn't add the server; see below.
- **`disableBypassPermissionsMode`** removes `--dangerously-skip-permissions`. Not an ACP key, but every fleet should set it: ACP's hook runs regardless, and this closes the harness-side hole next to it.

## Deliver it

Four mechanisms, highest priority first. Within the managed tier the first source that supplies a key wins, unless the top source sets `managedSourcesBehavior` to `merge`.

| Mechanism | Where | Notes |
|---|---|---|
| Server-managed | claude.ai admin console (or a self-hosted gateway) | No MDM. Polled by clients. Shell-command settings such as hooks in the settings body prompt an approval dialog in interactive sessions; a plugin enabled from a marketplace is how this sample avoids that. |
| OS policy | macOS: `com.anthropic.claudecode` managed preferences · Windows: `HKLM\SOFTWARE\Policies\ClaudeCode`, a `REG_SZ` value named `Settings` holding the JSON | Same top-level keys, nested as plist dictionaries on macOS. Managed preferences means a configuration profile from your MDM: the same keys written to a user's own defaults with `defaults import` are ignored (checked on 2.1.260, where the debug log shows the MDM load finding nothing). |
| System file | macOS `/Library/Application Support/ClaudeCode/managed-settings.json` · Linux and WSL `/etc/claude-code/managed-settings.json` · Windows `C:\Program Files\ClaudeCode\managed-settings.json` | Plus a `managed-settings.d/` directory merged alphabetically. Claude Code doesn't read the old `C:\ProgramData\ClaudeCode` path. |
| Windows user registry | `HKCU\SOFTWARE\Policies\ClaudeCode` | Only when nothing above supplies the key. |

Managed settings sit above user, project, local, and `--settings` values. Array keys such as `permissions.deny` merge, so developers can add rules but not remove yours.

## The MCP endpoint

The allowlist entry above permits ACP's server; it doesn't add it. Two ways to get it onto seats:

- **Each user adds it** with one command and signs in with MCP OAuth in the browser. Attribution comes with the sign-in.

  ```bash
  claude mcp add --transport http acp https://api.agenticcontrolplane.com/mcp
  ```

- **`managed-mcp.json`** at the same system path as `managed-settings.json` pushes server definitions to every seat. It makes that list the *only* servers Claude Code loads and can't be delivered through server-managed settings, so use it only if you intend to own the whole MCP list:

  ```json
  {
    "mcpServers": {
      "acp": { "type": "http", "url": "https://api.agenticcontrolplane.com/mcp" }
    }
  }
  ```

The hook is what enforces policy on every tool call; the MCP server adds read-only introspection tools and one that drafts a rule for a human to confirm.

## Each person enrolls once

The pushed settings identify no one. Each developer opens [cloud.agenticcontrolplane.com/plugin/authorize](https://cloud.agenticcontrolplane.com/plugin/authorize), signs in with their work identity, and pastes the one line it shows:

```bash
echo 'gsk_…' > ~/.acp/credentials
```

Until they do, with `ACP_REQUIRE_ENROLLMENT` set every tool call is denied with that instruction in the message.

## If marketplace access is blocked

Air-gapped or egress-restricted fleets that can't reach GitHub for the plugin can run the hook directly from managed settings instead. Your MDM drops `govern.mjs` and a wrapper into a managed directory, as on the [Codex](/docs/enterprise/codex#step-1-put-the-script-in-a-managed-directory) and [Cursor](/docs/enterprise/cursor#step-1-put-the-script-on-the-machine) pages, with `ACP_CLIENT=claude-code-plugin` in the wrapper, and managed settings declare it:

```json
{
  "allowManagedHooksOnly": true,
  "hooks": {
    "PreToolUse":  [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "/etc/acp/claude-hook.sh", "timeout": 5 }] }],
    "PostToolUse": [{ "matcher": ".*", "hooks": [{ "type": "command", "command": "/etc/acp/claude-hook.sh", "timeout": 5 }] }]
  }
}
```

Delivered server-managed, hooks in the settings body prompt a one-time approval dialog in interactive sessions; delivered by file or OS policy they don't.

## What you'll see

- `/status` inside Claude Code names the setting source that won: `(remote)`, `(plist)` or `(HKLM)`, `(file)` or `(drop-ins)`.
- Console rows with client `claude-code-plugin`, one per person, with subagent chains attributed to their parent session.
- On an unenrolled seat: `[ACP] Not enrolled…` and the call doesn't run.

## What's verified and what isn't

The plugin, its hooks, and the enrollment gate are what every self-serve install runs today. The managed-settings keys above are taken from Anthropic's published reference as of September 2026, linked at the top. What we have checked on a machine: Claude Code looks for the system file at the macOS path above on every start and loads the macOS preferences domain only as managed (MDM) preferences. What we have not yet done: pushed this file through a claude.ai enterprise admin console or an MDM profile ourselves. The issue tracking that is [gatewaystack-connect #943](https://github.com/davidcrowe/gatewaystack-connect/issues/943).

## Related

- [Enterprise rollout: the shape all harnesses share](/docs/enterprise)
- [Claude Code integration](/integrations/claude-code) — the self-serve install
- [Claude Code native controls](/controls/claude-code)
- Anthropic: [Managed settings](https://code.claude.com/docs/en/managed-settings) · [Admin setup](https://code.claude.com/docs/en/admin-setup) · [Managed MCP](https://code.claude.com/docs/en/managed-mcp) · [Plugin marketplaces](https://code.claude.com/docs/en/plugin-marketplaces)
