Reverse-Engineering Claude Desktop's Enterprise Configuration
What I Was Looking For
Claude Code supports Bedrock through an environment variable—set CLAUDE_CODE_USE_BEDROCK=1 and go. But Claude Desktop is a different story. Anthropic’s docs say Desktop connects to their API directly, and if you want Bedrock or Vertex, use the CLI. I wanted to know if that was the whole picture.
So I unpacked the app. Claude Desktop ships as an Electron app, and the application code lives in /Applications/Claude.app/Contents/Resources/app.asar. The asar format is just an archive—you can extract it with npx asar extract app.asar ./unpacked and read the JavaScript directly. I did this on v1.1617.0 (April 2026) and found a complete configuration schema for routing Desktop inference through AWS Bedrock. Not a stub. A full implementation with validation logic, authentication options, credential helpers, and token budgeting—all wired into the app’s startup flow.
How It Works
When inferenceProvider is set to "bedrock", the app bypasses its normal OAuth-based connection to api.anthropic.com and routes everything through your Bedrock endpoint instead. Anthropic calls this “third-party mode” internally.
The trade-off: in third-party mode, the Chat tab disappears. That tab is a webview to claude.ai that requires Anthropic’s OAuth—it can’t function with a third-party backend. What’s left is the Code tab only. The app becomes a GUI wrapper around the embedded Claude Code CLI, routed through your configured provider. If you want a Bedrock-backed chat experience, this isn’t it.
The config uses macOS CFPreferences—the same system MDM tools like Jamf and Mosyle use to push managed preferences. The app reads config through two mechanisms: first the CFPreferences API (where MDM-pushed profiles land), then a plist file fallback at ~/Library/Preferences/com.anthropic.Claude.plist. On Windows, it reads from the registry at HKCU\SOFTWARE\Policies\Claude and HKLM\SOFTWARE\Policies\Claude.
For local testing, you set values with defaults write:
defaults write com.anthropic.Claude inferenceProvider -string "bedrock"
defaults write com.anthropic.Claude inferenceBedrockRegion -string "us-west-2"
defaults write com.anthropic.Claude inferenceBedrockProfile -string "default"
defaults write com.anthropic.Claude inferenceModels -string '["us.anthropic.claude-sonnet-4-6-v1"]'
Those four fields are the minimum. The inferenceModels field is required for Bedrock—the binary’s own doc string states that only the gateway provider auto-discovers models. Without it, the Code tab has no models to offer. Quit and relaunch after changing these values. To undo, defaults delete com.anthropic.Claude <key> for each one.
The Full Inference Schema
| Key | Type | Required | Description |
|---|---|---|---|
inferenceProvider |
bedrock |
Yes | Activates third-party mode |
inferenceBedrockRegion |
string | Yes | AWS region (e.g. us-west-2) |
inferenceBedrockProfile |
string | One of profile or token | AWS named profile from ~/.aws/config |
inferenceBedrockBearerToken |
string | One of profile or token | Alternative auth. Redacted in logs |
inferenceModels |
JSON array | Yes | Model IDs or aliases. First entry is the default |
inferenceBedrockAwsDir |
string | No | Custom ~/.aws path. Copied into sandbox at session start |
inferenceBedrockBaseUrl |
URL | No | Custom or VPC endpoint |
inferenceCredentialHelper |
string | No | External credential script path |
inferenceCredentialHelperTtlSec |
int | No | Credential cache TTL in seconds |
inferenceMaxTokensPerWindow |
int | No | Token budget per rolling window |
inferenceTokenWindowHours |
int (1–720) | No | Rolling window duration in hours |
The token budgeting fields are the most interesting part of this table. inferenceMaxTokensPerWindow and inferenceTokenWindowHours implement a rolling budget that lets an admin cap per-user token consumption—and this doesn’t exist in the CLI at all. Based on the source comments, these were added in v1.3.0, later than the rest of the schema.
The credential helper and bearer token options tell you who this is built for. You wouldn’t bother with an external credential executable and a cache TTL unless you’re integrating with a secrets manager. You wouldn’t use bearer tokens instead of AWS profiles unless you’re vending short-lived tokens from a central service and don’t want AWS credentials on end-user machines.
The validation logic requires auth (either a bearer token or a profile name) and a valid AWS region:
(inferenceBedrockBearerToken is non-empty OR inferenceBedrockProfile is set)
AND inferenceBedrockRegion matches /^[a-z]{2}(-[a-z]+)+-\d{1,2}$/
Not Just Bedrock
The inferenceProvider field accepts four values: "gateway" (custom LLM gateway), "vertex" (Google Vertex AI), "bedrock" (AWS Bedrock), and "foundry" (Azure Foundry). All four are present in the source with version annotations placing them at v1.2.0. Only the gateway provider auto-discovers available models—the other three require inferenceModels to be set explicitly.
The Enterprise Management Surface
The inference config is one part of a larger enterprise schema. Every key is annotated with scopes: ["3p"] in the source, marking it as a third-party/enterprise feature.
The security-relevant ones: allowedWorkspaceFolders restricts which directories can be opened, disabledBuiltinTools removes specific tools from the agent, requireCoworkFullVmSandbox forces VM sandbox mode, and coworkEgressAllowedHosts defines which hosts the sandbox can reach over the network. None of these exist in the CLI. An admin can also push MCP server configurations centrally via managedMcpServers, control update policies with disableAutoUpdates and autoUpdaterEnforcementHours, kill telemetry, and scope data storage per organization with deploymentOrganizationUuid.
Put together, this is a full MDM management surface. An IT team can push these via Jamf or Intune, route all inference through the company’s Bedrock account, cap token usage, lock down the sandbox, and enforce update policies—without touching the user’s machine directly.
Desktop vs CLI
The two systems are deliberately independent. When Claude Desktop spawns its embedded Claude Code process, it strips the CLI’s environment variables and injects its own:
// Stripped
delete e.CLAUDE_CODE_USE_BEDROCK
delete e.CLAUDE_CODE_USE_VERTEX
delete e.CLAUDE_CODE_USE_FOUNDRY
// Injected
CLAUDE_CODE_ENTRYPOINT: "claude-desktop"
ANTHROPIC_BASE_URL: t.apiHost
CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST: "1"
Having CLAUDE_CODE_USE_BEDROCK=1 in your shell does not affect Desktop, and Desktop’s config does not affect the CLI. The CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST flag tells the embedded CLI that the host app is managing the provider—don’t try to configure it yourself.
The feature gap between the two:
| Aspect | Claude Code CLI | Claude Desktop |
|---|---|---|
| Config method | Environment variables | CFPreferences / plist / registry |
| Activation | CLAUDE_CODE_USE_BEDROCK=1 |
inferenceProvider: "bedrock" |
| Auth | AWS profile / env credentials | Profile or bearer token |
| Token budgeting | Not available | Rolling window with configurable hours |
| Credential helper | Not available | External script with cache TTL |
| Workspace restrictions | Not available | allowedWorkspaceFolders |
| Tool restrictions | Not available | disabledBuiltinTools |
| Network egress control | Not available | coworkEgressAllowedHosts |
Testing It with AWS SSO
I tested this with an existing AWS SSO profile. The setup: an SSO profile in ~/.aws/config, an active SSO session, Bedrock model access enabled in the account, and the four defaults write commands above.
[default]
sso_start_url = https://your-org.awsapps.com/start
sso_region = us-west-2
sso_account_id = 123456789012
sso_role_name = YourRole
region = us-west-2
After aws sso login and restarting Claude Desktop, the Chat tab was gone. The Code tab loaded and routed inference through Bedrock. The experience is functionally identical to using claude --dangerously-skip-permissions in a terminal, except it’s in a native window with the Desktop UI chrome.
Watch for SSO credential expiry. The inferenceBedrockAwsDir path gets copied into the app sandbox at session start. If your SSO token expires mid-session, Claude Desktop won’t pick up new credentials until you restart it. SSO tokens typically expire in 1 to 12 hours depending on your org’s configuration.
One logging quirk: main.log at ~/Library/Logs/Claude/ uses winston with 10MB rotation, but in third-party mode the new session may not write to it consistently. The native swift.log is more reliable for debugging. Enterprise config loading logs at debug level as "Enterprise config loaded: %o" with sensitive fields redacted.
What’s Next
The implementation is complete and shipping in every copy of Claude Desktop—validation logic, auth paths, credential helpers, sandbox controls, the full CFPreferences integration. It’s undocumented publicly, which suggests either limited availability for enterprise customers or an unannounced launch.
For individual developers who already use Bedrock through the CLI, the Desktop route gives you a GUI and token budgeting but takes away the Chat tab. I’ll probably stick with the CLI. But for an IT team deploying Claude to a fleet of machines and needing centralized cost controls, sandbox lockdown, and managed MCP servers pushed through Jamf—this is exactly what that looks like.
References
- Claude Code with AWS Bedrock — Official CLI Bedrock integration docs
- Anthropic Claude Models — Model IDs for
inferenceModelsconfiguration - Apple CFPreferences — macOS managed preferences system used for Desktop config
- asar archive format — Electron app packaging format;
npx asar extractto unpack