feat(claude-code): add managed_settings input for policy delivery via /etc/claude-code#863
feat(claude-code): add managed_settings input for policy delivery via /etc/claude-code#863morganl-ant wants to merge 4 commits intocoder:mainfrom
Conversation
|
This would need rebasing after #861 is merged. Thanks for your contribution. |
… /etc/claude-code Re-authored on top of the post-coder#861 install-only module. Adds a managed_settings variable that the install script writes to /etc/claude-code/managed-settings.d/10-coder.json. Claude Code reads this drop-in directory at startup with the highest configuration precedence, so template authors get an admin-controlled policy file that users inside the workspace cannot override. The mechanism is a local file read with no API call, so it works identically for the Anthropic API, AWS Bedrock, Google Vertex AI, and AI Gateway. Compared to the original PR against v4.x, this drops the deprecation shim for permission_mode/allowed_tools/disallowed_tools (those vars are gone in v5) and the start.sh changes (start.sh is gone). The ~/.claude.json policy-key removal is also dropped from this PR scope since the surrounding configure_standalone_mode logic changed substantially in coder#861; can revisit separately if wanted.
913224b to
4b83931
Compare
…ude.json These flags pre-accept the permission-mode confirmation dialogs in a user-writable file. Permission posture is the managed_settings input's job (delivered via /etc/claude-code/managed-settings.d/, root-owned, not user-overridable). Onboarding-bypass keys (hasCompletedOnboarding, hasAcknowledgedCostThreshold, project trust) stay since there is no managed-settings equivalent for those.
| .autoModeAccepted = true | | ||
| .bypassPermissionsModeAccepted = true | |
There was a problem hiding this comment.
Why did we remove this? AFAIK, these were needed for skipping the welcome wizard.
There was a problem hiding this comment.
I think the reason they are removing them is because you are able to set these same behaviors through managed settings. Which is probably better than us pre-seeding it for all users in this hacky unobservable way.
Although I think we should probably test this a bit more before committing since we want to make sure this won't introduce too big of a behavioral shift in the module for users who have this running in a task workflow.
There was a problem hiding this comment.
This serves the standalone mode, which we need to set anyway when a user provides a workdir. I don't see how that would work if we remove this. I am all good if we can do it more systematically. But if a user starts Claude via coder_script in a specific workdir, they should not be greeted with a config wizard.
There was a problem hiding this comment.
You know I think you are right here. These are mostly just for the dialogue boxes unless they get suppressed now somehow.
| managed_settings = { | ||
| permissions = { | ||
| defaultMode = "acceptEdits" | ||
| disableBypassPermissionsMode = "disable" | ||
| deny = ["Bash(rm -rf*)"] |
There was a problem hiding this comment.
@matifali for reference this is how you would pass similar behavior through managed settings rather than pre-seeding it.
So essentially someone could set defaultMode=auto and same with the rest for claude-code running for tasks and this would work over even the settings.json
|
Everything looks good here for me @morganl-ant I will go ahead and test this and approve it from my end once done. |
|
I have tested this and it works properly with agentapi/tasks provided you do the following in the new module |
|
@DevelopmentCats, I guess we can safely remove (deprecate) the |
Yeah we definitely can if the only thing that was holding us back was project level configs. |
Resolve conflict in main.test.ts: keep both managed-settings tests (from this PR) and telemetry tests (from coder#862/main).
|
@matifali I think we are good to merge this. If we decide later that we want to add back the part where we auto fill the config info the managed settings to bypass the prompts by default, but its probably fine to let the users or administrator decide what they need for the managed settings in the module to make it perform how they'd like. Especially with the move to agents. |
|
@DevelopmentCats Can you test the |
Yeah I will test and provide a picture |
|
@DevelopmentCats can also update example with required settings (if needed) |
|
@morganl-ant Is there a way to suppress either of these Claude-Code CLI alerts through a setting that can be done through
|


Problem
The module configures Claude Code's permission posture by reaching around the permission system rather than through it:
scripts/install.shwritesbypassPermissionsModeAccepted,autoModeAccepted, andprimaryApiKeydirectly into the user-writable~/.claude.json. Any process in the workspace can read the API key or flip the acceptance flags back.scripts/start.shadds--dangerously-skip-permissionsto every task launch, even when the template author set an explicitpermission_mode. The README has to carry a security warning telling people the module bypasses permission checks.permission_mode,allowed_tools, anddisallowed_toolseach plumb through a different ad-hoc path (CLI flag,codersubcommand) instead of a single policy surface.Change
Add a
managed_settingsinput that renders to/etc/claude-code/managed-settings.d/10-coder.json. Claude Code reads that drop-in directory at startup with the highest configuration precedence (above~/.claude/settings.jsonand project settings), so template authors get an admin-controlled policy file that users inside the workspace cannot override. The mechanism is a local file read with no API call, so it works identically for the Anthropic API, AWS Bedrock, Google Vertex AI, and AI Bridge / AI Gateway.Supporting changes:
install.shwrites the policy file (root-owned, 0644) and stops writingbypassPermissionsModeAccepted,autoModeAccepted, andprimaryApiKeyinto~/.claude.json. The API key is already exported viacoder_envasCLAUDE_API_KEY; duplicating it on disk is unnecessary.hasCompletedOnboardingstays because there is no env-var alternative for it.start.shonly adds--dangerously-skip-permissionsfor tasks when no explicitpermission_modeis set (same fix as fix(claude-code): don't pass --dangerously-skip-permissions in auto mode #846; included here so this PR is self-contained, happy to drop if fix(claude-code): don't pass --dangerously-skip-permissions in auto mode #846 lands first).permission_mode,allowed_tools, anddisallowed_toolsare marked deprecated and shimmed intomanaged_settings.permissionsfor one release whenmanaged_settingsis not provided.Relationship to #861
#861 strips this module to install-and-configure and removes
permission_mode/allowed_tools/disallowed_toolsoutright.managed_settingsis the natural replacement for those: it is install-time (survives thestart.shremoval), it covers everything the dropped variables did plushooks,env,model,apiKeyHelper, and the rest of the settings schema, and it does not require the module to know anything about how Claude is launched. If #861 lands first I will rebase this on top and drop the deprecation shim and thestart.shhunk.Validation
terraform fmt/terraform validatecleanclaude-managed-settings-written,claude-managed-settings-legacy-shim,claude-no-policy-keys-in-claudejson, plus an assertion inclaude-auto-permission-modethat--dangerously-skip-permissionsis absent when a mode is set/etc/claude-code/managed-settings.d/*.jsonprecedence in the Claude Code CLI sourceCloses #818. Relates to #284, #846, #861.
Disclosure: I work at Anthropic on the Claude Code team. Happy to adjust scope or split this further if that is easier to review.