From 91dcd9941c36e93c81a9632d46b63b0d512ad0e4 Mon Sep 17 00:00:00 2001 From: Max schwenk Date: Thu, 2 Apr 2026 15:09:28 -0400 Subject: [PATCH 1/4] feat: add auto permission mode and fix bypass permissions TOS prompt Add `auto` as a valid `permission_mode` option for the claude-code module, passing `--enable-auto-mode` to the CLI when selected. Also fix the bypass permissions TOS prompt appearing interactively by pre-seeding `bypassPermissionsModeAccepted` in `~/.claude.json` during install. This affects all task-based setups since the start script always passes `--dangerously-skip-permissions` when `report_tasks` is true. Workaround for: https://github.com/anthropics/claude-code/issues/25503 Co-Authored-By: Claude Opus 4.6 (1M context) --- registry/coder/modules/claude-code/README.md | 2 +- .../coder/modules/claude-code/main.test.ts | 19 +++++++++++ registry/coder/modules/claude-code/main.tf | 6 ++-- .../coder/modules/claude-code/main.tftest.hcl | 17 +++++++++- .../modules/claude-code/scripts/install.sh | 33 +++++++++++++++++++ .../modules/claude-code/scripts/start.sh | 3 ++ 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 5a2eacd64..ad0a0a8d1 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.8.2" + version = "4.9.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index 19ab98c04..3f05f1cd4 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -182,6 +182,25 @@ describe("claude-code", async () => { expect(startLog.stdout).toContain(`--permission-mode ${mode}`); }); + test("claude-auto-permission-mode", async () => { + const mode = "auto"; + const { id } = await setup({ + moduleVariables: { + permission_mode: mode, + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.claude-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain(`--permission-mode ${mode}`); + expect(startLog.stdout).toContain("--enable-auto-mode"); + }); + test("claude-model", async () => { const model = "opus"; const { coderEnvVars } = await setup({ diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index ba45d69cc..fd61c53e6 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -155,8 +155,8 @@ variable "permission_mode" { description = "Permission mode for the cli, check https://docs.anthropic.com/en/docs/claude-code/iam#permission-modes" default = "" validation { - condition = contains(["", "default", "acceptEdits", "plan", "bypassPermissions"], var.permission_mode) - error_message = "interaction_mode must be one of: default, acceptEdits, plan, bypassPermissions." + condition = contains(["", "default", "acceptEdits", "plan", "auto", "bypassPermissions"], var.permission_mode) + error_message = "interaction_mode must be one of: default, acceptEdits, plan, auto, bypassPermissions." } } @@ -423,6 +423,8 @@ module "agentapi" { ARG_MCP='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ ARG_MCP_CONFIG_REMOTE_PATH='${base64encode(jsonencode(var.mcp_config_remote_path))}' \ ARG_ENABLE_AIBRIDGE='${var.enable_aibridge}' \ + ARG_DANGEROUSLY_SKIP_PERMISSIONS='${var.dangerously_skip_permissions}' \ + ARG_PERMISSION_MODE='${var.permission_mode}' \ /tmp/install.sh EOT } diff --git a/registry/coder/modules/claude-code/main.tftest.hcl b/registry/coder/modules/claude-code/main.tftest.hcl index 66c79bab7..9c9df50f4 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -183,11 +183,26 @@ run "test_claude_code_permission_mode_validation" { } assert { - condition = contains(["", "default", "acceptEdits", "plan", "bypassPermissions"], var.permission_mode) + condition = contains(["", "default", "acceptEdits", "plan", "auto", "bypassPermissions"], var.permission_mode) error_message = "Permission mode should be one of the valid options" } } +run "test_claude_code_auto_permission_mode" { + command = plan + + variables { + agent_id = "test-agent-auto" + workdir = "/home/coder/test" + permission_mode = "auto" + } + + assert { + condition = var.permission_mode == "auto" + error_message = "Permission mode should be set to auto" + } +} + run "test_claude_code_with_boundary" { command = plan diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 0a2ba7033..524b10a53 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -22,6 +22,8 @@ ARG_MCP_CONFIG_REMOTE_PATH=$(echo -n "${ARG_MCP_CONFIG_REMOTE_PATH:-}" | base64 ARG_ALLOWED_TOOLS=${ARG_ALLOWED_TOOLS:-} ARG_DISALLOWED_TOOLS=${ARG_DISALLOWED_TOOLS:-} ARG_ENABLE_AIBRIDGE=${ARG_ENABLE_AIBRIDGE:-false} +ARG_DANGEROUSLY_SKIP_PERMISSIONS=${ARG_DANGEROUSLY_SKIP_PERMISSIONS:-false} +ARG_PERMISSION_MODE=${ARG_PERMISSION_MODE:-} export PATH="$ARG_CLAUDE_BINARY_PATH:$PATH" @@ -235,6 +237,37 @@ function report_tasks() { fi } +function accept_bypass_permissions() { + # Pre-accept the bypass permissions TOS prompt so it doesn't appear + # interactively. This is needed whenever --dangerously-skip-permissions or + # --permission-mode bypassPermissions will be used at start time. + # When report_tasks is true, the start script always passes + # --dangerously-skip-permissions, so we must also accept in that case. + # Workaround for: https://github.com/anthropics/claude-code/issues/25503 + local claude_config="$HOME/.claude.json" + + if [ -f "$claude_config" ]; then + jq '.bypassPermissionsModeAccepted = true' \ + "$claude_config" > "${claude_config}.tmp" && mv "${claude_config}.tmp" "$claude_config" + else + cat > "$claude_config" << 'EOF' +{ + "bypassPermissionsModeAccepted": true +} +EOF + fi + + echo "Pre-accepted bypass permissions mode prompt" +} + install_claude_code_cli setup_claude_configurations report_tasks + +# When bypass permissions will be used, pre-accept the TOS prompt. +# report_tasks=true always uses --dangerously-skip-permissions in start.sh. +if [ "$ARG_REPORT_TASKS" = "true" ] \ + || [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ] \ + || [ "$ARG_PERMISSION_MODE" = "bypassPermissions" ]; then + accept_bypass_permissions +fi diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index 5ccbc8fa1..154729616 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -180,6 +180,9 @@ function start_agentapi() { if [ -n "$ARG_PERMISSION_MODE" ]; then ARGS+=(--permission-mode "$ARG_PERMISSION_MODE") + if [ "$ARG_PERMISSION_MODE" = "auto" ]; then + ARGS+=(--enable-auto-mode) + fi fi if [ -n "$ARG_RESUME_SESSION_ID" ]; then From 368d0b2babb37d9e2e36f78acd4bc01616cfd7ec Mon Sep 17 00:00:00 2001 From: Max schwenk Date: Thu, 2 Apr 2026 15:16:03 -0400 Subject: [PATCH 2/4] fix: remove --enable-auto-mode flag, pre-accept auto mode prompt The --enable-auto-mode flag is unnecessary; --permission-mode auto works directly. Also pre-seed autoModeAccepted in ~/.claude.json to suppress the interactive "Enable auto mode?" confirmation prompt, matching the same pattern used for bypass permissions mode. Refactored accept_bypass_permissions into a generic accept_permission_mode function that handles both bypass and auto mode prompts. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../coder/modules/claude-code/main.test.ts | 1 - .../modules/claude-code/scripts/install.sh | 29 +++++++++---------- .../modules/claude-code/scripts/start.sh | 3 -- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/registry/coder/modules/claude-code/main.test.ts b/registry/coder/modules/claude-code/main.test.ts index 3f05f1cd4..b01e88327 100644 --- a/registry/coder/modules/claude-code/main.test.ts +++ b/registry/coder/modules/claude-code/main.test.ts @@ -198,7 +198,6 @@ describe("claude-code", async () => { "cat /home/coder/.claude-module/agentapi-start.log", ]); expect(startLog.stdout).toContain(`--permission-mode ${mode}`); - expect(startLog.stdout).toContain("--enable-auto-mode"); }); test("claude-model", async () => { diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 524b10a53..abb0df981 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -237,27 +237,20 @@ function report_tasks() { fi } -function accept_bypass_permissions() { - # Pre-accept the bypass permissions TOS prompt so it doesn't appear - # interactively. This is needed whenever --dangerously-skip-permissions or - # --permission-mode bypassPermissions will be used at start time. - # When report_tasks is true, the start script always passes - # --dangerously-skip-permissions, so we must also accept in that case. +function accept_permission_mode() { + # Pre-accept permission mode prompts so they don't appear interactively. + # Claude Code shows a confirmation dialog for bypass permissions and auto + # modes that blocks non-interactive/headless usage. # Workaround for: https://github.com/anthropics/claude-code/issues/25503 local claude_config="$HOME/.claude.json" + local jq_filter="$1" if [ -f "$claude_config" ]; then - jq '.bypassPermissionsModeAccepted = true' \ + jq "$jq_filter" \ "$claude_config" > "${claude_config}.tmp" && mv "${claude_config}.tmp" "$claude_config" else - cat > "$claude_config" << 'EOF' -{ - "bypassPermissionsModeAccepted": true -} -EOF + echo "{}" | jq "$jq_filter" > "$claude_config" fi - - echo "Pre-accepted bypass permissions mode prompt" } install_claude_code_cli @@ -269,5 +262,11 @@ report_tasks if [ "$ARG_REPORT_TASKS" = "true" ] \ || [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ] \ || [ "$ARG_PERMISSION_MODE" = "bypassPermissions" ]; then - accept_bypass_permissions + accept_permission_mode '.bypassPermissionsModeAccepted = true' + echo "Pre-accepted bypass permissions mode prompt" +fi + +if [ "$ARG_PERMISSION_MODE" = "auto" ]; then + accept_permission_mode '.autoModeAccepted = true' + echo "Pre-accepted auto mode prompt" fi diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index 154729616..5ccbc8fa1 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -180,9 +180,6 @@ function start_agentapi() { if [ -n "$ARG_PERMISSION_MODE" ]; then ARGS+=(--permission-mode "$ARG_PERMISSION_MODE") - if [ "$ARG_PERMISSION_MODE" = "auto" ]; then - ARGS+=(--enable-auto-mode) - fi fi if [ -n "$ARG_RESUME_SESSION_ID" ]; then From 850b65ab20efeeee4357bebadc027f488db20a73 Mon Sep 17 00:00:00 2001 From: Max schwenk Date: Fri, 3 Apr 2026 10:40:53 -0400 Subject: [PATCH 3/4] fix: address PR review - remove redundant bypass pre-seeding, keep auto mode Remove the separate accept_permission_mode function and bypass permissions pre-seeding (already handled by coder exp mcp configure and configure_standalone_mode). Add autoModeAccepted to configure_standalone_mode and as a post-install step for task mode. Remove --enable-auto-mode flag (--permission-mode auto is sufficient). Co-Authored-By: Claude Opus 4.6 (1M context) --- registry/coder/modules/claude-code/main.tf | 1 - .../modules/claude-code/scripts/install.sh | 33 ++++++++----------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index fd61c53e6..1b302662c 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -423,7 +423,6 @@ module "agentapi" { ARG_MCP='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ ARG_MCP_CONFIG_REMOTE_PATH='${base64encode(jsonencode(var.mcp_config_remote_path))}' \ ARG_ENABLE_AIBRIDGE='${var.enable_aibridge}' \ - ARG_DANGEROUSLY_SKIP_PERMISSIONS='${var.dangerously_skip_permissions}' \ ARG_PERMISSION_MODE='${var.permission_mode}' \ /tmp/install.sh EOT diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index abb0df981..c00773b5e 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -22,7 +22,6 @@ ARG_MCP_CONFIG_REMOTE_PATH=$(echo -n "${ARG_MCP_CONFIG_REMOTE_PATH:-}" | base64 ARG_ALLOWED_TOOLS=${ARG_ALLOWED_TOOLS:-} ARG_DISALLOWED_TOOLS=${ARG_DISALLOWED_TOOLS:-} ARG_ENABLE_AIBRIDGE=${ARG_ENABLE_AIBRIDGE:-false} -ARG_DANGEROUSLY_SKIP_PERMISSIONS=${ARG_DANGEROUSLY_SKIP_PERMISSIONS:-false} ARG_PERMISSION_MODE=${ARG_PERMISSION_MODE:-} export PATH="$ARG_CLAUDE_BINARY_PATH:$PATH" @@ -197,6 +196,7 @@ function configure_standalone_mode() { jq --arg workdir "$ARG_WORKDIR" --arg apikey "${CLAUDE_API_KEY:-}" \ '.autoUpdaterStatus = "disabled" | + .autoModeAccepted = true | .bypassPermissionsModeAccepted = true | .hasAcknowledgedCostThreshold = true | .hasCompletedOnboarding = true | @@ -209,6 +209,7 @@ function configure_standalone_mode() { cat > "$claude_config" << EOF { "autoUpdaterStatus": "disabled", + "autoModeAccepted": true, "bypassPermissionsModeAccepted": true, "hasAcknowledgedCostThreshold": true, "hasCompletedOnboarding": true, @@ -237,36 +238,28 @@ function report_tasks() { fi } -function accept_permission_mode() { - # Pre-accept permission mode prompts so they don't appear interactively. - # Claude Code shows a confirmation dialog for bypass permissions and auto - # modes that blocks non-interactive/headless usage. - # Workaround for: https://github.com/anthropics/claude-code/issues/25503 +function accept_auto_mode() { + # Pre-accept the auto mode TOS prompt so it doesn't appear interactively. + # Claude Code shows a confirmation dialog for auto mode that blocks + # non-interactive/headless usage. + # Note: bypassPermissions acceptance is already handled by + # coder exp mcp configure (task mode) and configure_standalone_mode. local claude_config="$HOME/.claude.json" - local jq_filter="$1" if [ -f "$claude_config" ]; then - jq "$jq_filter" \ + jq '.autoModeAccepted = true' \ "$claude_config" > "${claude_config}.tmp" && mv "${claude_config}.tmp" "$claude_config" else - echo "{}" | jq "$jq_filter" > "$claude_config" + echo '{"autoModeAccepted": true}' > "$claude_config" fi + + echo "Pre-accepted auto mode prompt" } install_claude_code_cli setup_claude_configurations report_tasks -# When bypass permissions will be used, pre-accept the TOS prompt. -# report_tasks=true always uses --dangerously-skip-permissions in start.sh. -if [ "$ARG_REPORT_TASKS" = "true" ] \ - || [ "$ARG_DANGEROUSLY_SKIP_PERMISSIONS" = "true" ] \ - || [ "$ARG_PERMISSION_MODE" = "bypassPermissions" ]; then - accept_permission_mode '.bypassPermissionsModeAccepted = true' - echo "Pre-accepted bypass permissions mode prompt" -fi - if [ "$ARG_PERMISSION_MODE" = "auto" ]; then - accept_permission_mode '.autoModeAccepted = true' - echo "Pre-accepted auto mode prompt" + accept_auto_mode fi From 12d353a980dadcb26a3c70a7507603184001bba3 Mon Sep 17 00:00:00 2001 From: Max schwenk Date: Fri, 3 Apr 2026 14:54:42 -0400 Subject: [PATCH 4/4] fix: bump version to 4.9.2 (patch) per review feedback Co-Authored-By: Claude Opus 4.6 (1M context) --- registry/coder/modules/claude-code/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index ad0a0a8d1..f5ba7d3e2 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.9.0" + version = "4.9.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx"