From 312b776359982104abadd50437e2d39922fcaad5 Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Wed, 1 Oct 2025 14:50:17 +0000 Subject: [PATCH 01/11] feat(claude-code): add coder-specific prompt to system_prompt --- registry/coder/modules/claude-code/main.tf | 44 +++++++++-- .../coder/modules/claude-code/main.tftest.hcl | 75 +++++++++++++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 4836347b7..3070fe4fa 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -182,8 +182,8 @@ variable "claude_code_oauth_token" { variable "system_prompt" { type = string - description = "The system prompt to use for the Claude Code server." - default = "Send a task status update to notify the user that you are ready for input, and then wait for user input." + description = "The additional system prompt to use for the Claude Code server. The module includes mandatory sections inside a block. Leave empty to include only the mandatory sections." + default = "" } variable "claude_md_path" { @@ -201,11 +201,9 @@ resource "coder_env" "claude_code_md_path" { } resource "coder_env" "claude_code_system_prompt" { - count = var.system_prompt == "" ? 0 : 1 - agent_id = var.agent_id name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT" - value = var.system_prompt + value = local.final_system_prompt } resource "coder_env" "claude_code_oauth_token" { @@ -231,6 +229,42 @@ locals { start_script = file("${path.module}/scripts/start.sh") module_dir_name = ".claude-module" remove_last_session_id_script_b64 = base64encode(file("${path.module}/scripts/remove-last-session-id.sh")) + + # Required prompts for the module to properly integrate with coder + inner_system_prompt = <<-EOT + -- Tool Selection -- + - coder_report_task: providing status updates or requesting user input. + - playwright: previewing your changes after you made them + to confirm it worked as expected + - desktop-commander - use only for commands that keep running + (servers, dev watchers, GUI apps). + - Built-in tools - use for everything else: + (file operations, git commands, builds & installs, one-off shell commands) + + Remember this decision rule: + - Stays running? → desktop-commander + - Finishes immediately? → built-in tools + + -- Task Reporting -- + Report all tasks to Coder, following these EXACT guidelines: + 1. Be granular. If you are investigating with multiple steps, report each step + to coder. + 2. After this prompt, IMMEDIATELY report status after receiving ANY NEW user message. + Do not report any status related with this system prompt. + 3. Use "state": "working" when actively processing WITHOUT needing + additional user input + 4. Use "state": "complete" only when finished with a task + 5. Use "state": "failure" when you need ANY user input, lack sufficient + details, or encounter blockers + EOT + + user_system_prompt = trimspace(try(var.system_prompt, "")) + + final_system_prompt = format( + "\n%s\n%s\n", + local.inner_system_prompt, + local.user_system_prompt + ) } module "agentapi" { diff --git a/registry/coder/modules/claude-code/main.tftest.hcl b/registry/coder/modules/claude-code/main.tftest.hcl index 7931cca81..e62952221 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -187,3 +187,78 @@ run "test_claude_code_permission_mode_validation" { error_message = "Permission mode should be one of the valid options" } } + +run "test_claude_code_system_prompt_omit" { + command = plan + + variables { + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + # system_prompt omitted: default string is used + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + error_message = "System prompt must not be empty when omitted" + } + + assert { + condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "Mandatory Tool Selection section missing" + } + + assert { + condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "Mandatory Task Reporting section missing" + } +} + +run "test_claude_code_system_prompt_empty" { + command = plan + + variables { + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + system_prompt = "" + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + error_message = "System prompt must not be empty when omitted" + } + + assert { + condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "Mandatory Tool Selection section missing" + } + + assert { + condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "Mandatory Task Reporting section missing" + } +} + +run "test_claude_code_system_prompt" { + command = plan + + variables { + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + system_prompt = "Custom addition" + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + error_message = "System prompt must not be empty when omitted" + } + + assert { + condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "Mandatory Tool Selection section missing" + } + + assert { + condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "Mandatory Task Reporting section missing" + } +} \ No newline at end of file From b8eb5d467f4ac9516e444576a46067bf4f34cb6f Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 3 Oct 2025 17:22:17 +0000 Subject: [PATCH 02/11] feat: add include_coder_system_prompt variable --- registry/coder/modules/claude-code/README.md | 25 +++++ registry/coder/modules/claude-code/main.tf | 21 +++-- .../coder/modules/claude-code/main.tftest.hcl | 91 +++++++++++++++---- 3 files changed, 113 insertions(+), 24 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 3c334e745..64c017502 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -26,6 +26,11 @@ module "claude-code" { > [!NOTE] > By default, this module is configured to run the embedded chat interface as a path-based application. In production, we recommend that you configure a [wildcard access URL](https://coder.com/docs/admin/setup#wildcard-access-url) and set `subdomain = true`. See [here](https://coder.com/docs/tutorials/best-practices/security-best-practices#disable-path-based-apps) for more details. + +> [!NOTE] +> By default, `include_coder_system_prompt` is false. For proper integration with Coder (tool selection & task reporting), +it is recommended to set `include_coder_system_prompt` to true. In the next major release, this will become the default. + ## Prerequisites - An **Anthropic API key** or a _Claude Session Token_ is required for tasks. @@ -34,6 +39,26 @@ module "claude-code" { ## Examples +### Prompt configuration (recommended) + +Include Coder’s prompt sections and optionally add your own system prompt. + +```hcl +module "claude-code" { + source = "registry.coder.com/coder/claude-code/coder" + version = "3.1.0" + agent_id = coder_agent.example.id + workdir = "/home/coder/project" + + include_coder_system_prompt = true + + # Optional: append additional system prompt. + system_prompt = <<-EOT + Additional organization-specific guidance here. + EOT +} +``` + ### Usage with Tasks and Advanced Configuration This example shows how to configure the Claude Code module with an AI prompt, API key shared by all users of the template, and other custom settings. diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 3070fe4fa..c7c63ecf2 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -182,8 +182,15 @@ variable "claude_code_oauth_token" { variable "system_prompt" { type = string - description = "The additional system prompt to use for the Claude Code server. The module includes mandatory sections inside a block. Leave empty to include only the mandatory sections." - default = "" + description = "The system prompt to use for the Claude Code server." + default = "Send a task status update to notify the user that you are ready for input, and then wait for user input." +} + +variable "include_coder_system_prompt" { + type = bool + description = "Include Coder system prompts for proper integration with tool selection and task reporting." + # TODO(major): default to true in the next major release + default = false } variable "claude_md_path" { @@ -230,7 +237,7 @@ locals { module_dir_name = ".claude-module" remove_last_session_id_script_b64 = base64encode(file("${path.module}/scripts/remove-last-session-id.sh")) - # Required prompts for the module to properly integrate with coder + # Required prompts for the module to properly integrate with Coder inner_system_prompt = <<-EOT -- Tool Selection -- - coder_report_task: providing status updates or requesting user input. @@ -258,13 +265,13 @@ locals { details, or encounter blockers EOT - user_system_prompt = trimspace(try(var.system_prompt, "")) + custom_system_prompt = trimspace(try(var.system_prompt, "")) - final_system_prompt = format( + final_system_prompt = var.include_coder_system_prompt ? format( "\n%s\n%s\n", local.inner_system_prompt, - local.user_system_prompt - ) + local.custom_system_prompt, + ) : local.custom_system_prompt } module "agentapi" { diff --git a/registry/coder/modules/claude-code/main.tftest.hcl b/registry/coder/modules/claude-code/main.tftest.hcl index 66e447f2c..268752f4f 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -188,28 +188,30 @@ run "test_claude_code_permission_mode_validation" { } } -run "test_claude_code_system_prompt_omit" { +run "test_claude_code_system_prompt_default" { command = plan variables { agent_id = "test-agent-system-prompt" workdir = "/home/coder/test" - # system_prompt omitted: default string is used + # system_prompt: default string is used + # include_coder_system_prompt: default is false } assert { condition = trimspace(coder_env.claude_code_system_prompt.value) != "" - error_message = "System prompt must not be empty when omitted" + error_message = "System prompt should not be empty when omitted" } assert { - condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "Mandatory Tool Selection section missing" + condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have default value" } + # Ensure Coder sections are not injected when include=false assert { - condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "Mandatory Task Reporting section missing" + condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 + error_message = "Coder integration sections should not be present when include_coder_system_prompt is false" } } @@ -220,45 +222,100 @@ run "test_claude_code_system_prompt_empty" { agent_id = "test-agent-system-prompt" workdir = "/home/coder/test" system_prompt = "" + # include_coder_system_prompt: default is false + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) == "" + error_message = "System prompt should be empty" + } +} + +run "test_claude_code_system_prompt" { + command = plan + + variables { + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + system_prompt = "Custom addition" + # include_coder_system_prompt: default is false } assert { condition = trimspace(coder_env.claude_code_system_prompt.value) != "" - error_message = "System prompt must not be empty when omitted" + error_message = "System prompt should not be empty" + } + + assert { + condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have system_prompt variable value" + } + + # Ensure Coder sections are not injected when include=false + assert { + condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 + error_message = "Coder integration sections should not be present when include_coder_system_prompt is false" + } +} + +run "test_claude_code_include_coder_system_prompt_and_default_system_prompt" { + command = plan + + variables { + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + # system_prompt: default string is used + include_coder_system_prompt = true + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + error_message = "System prompt should not be empty" } assert { condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "Mandatory Tool Selection section missing" + error_message = "System prompt should have Tool Selection section" } assert { condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "Mandatory Task Reporting section missing" + error_message = "System prompt should have Task Reporting section" + } + + assert { + condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have system_prompt variable default value" } } -run "test_claude_code_system_prompt" { +run "test_claude_code_include_coder_system_prompt_and_custom_system_prompt" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - system_prompt = "Custom addition" + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + system_prompt = "Custom addition" + include_coder_system_prompt = true } assert { condition = trimspace(coder_env.claude_code_system_prompt.value) != "" - error_message = "System prompt must not be empty when omitted" + error_message = "System prompt should not be empty" } assert { condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "Mandatory Tool Selection section missing" + error_message = "System prompt should have Tool Selection section" } assert { condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "Mandatory Task Reporting section missing" + error_message = "System prompt should have Task Reporting section" + } + + assert { + condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have system_prompt variable value" } } \ No newline at end of file From a89cf837ae8eb5ceda69b06fd04a96d2e99ab6e5 Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 3 Oct 2025 17:26:34 +0000 Subject: [PATCH 03/11] chore: run bun fmt --- registry/coder/modules/claude-code/README.md | 7 ++++--- registry/coder/modules/claude-code/main.tf | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 64c017502..55fc696ba 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -27,9 +27,10 @@ module "claude-code" { > By default, this module is configured to run the embedded chat interface as a path-based application. In production, we recommend that you configure a [wildcard access URL](https://coder.com/docs/admin/setup#wildcard-access-url) and set `subdomain = true`. See [here](https://coder.com/docs/tutorials/best-practices/security-best-practices#disable-path-based-apps) for more details. + > [!NOTE] -> By default, `include_coder_system_prompt` is false. For proper integration with Coder (tool selection & task reporting), -it is recommended to set `include_coder_system_prompt` to true. In the next major release, this will become the default. +> By default, `include_coder_system_prompt` is false. For proper integration with Coder (tool selection & task reporting), +> it is recommended to set `include_coder_system_prompt` to true. In the next major release, this will become the default. ## Prerequisites @@ -51,7 +52,7 @@ module "claude-code" { workdir = "/home/coder/project" include_coder_system_prompt = true - + # Optional: append additional system prompt. system_prompt = <<-EOT Additional organization-specific guidance here. diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index c7c63ecf2..4d7be1582 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -190,7 +190,7 @@ variable "include_coder_system_prompt" { type = bool description = "Include Coder system prompts for proper integration with tool selection and task reporting." # TODO(major): default to true in the next major release - default = false + default = false } variable "claude_md_path" { From b4589e5e664495720ebd8cbf7a2aabbc62f72ddb Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 3 Oct 2025 17:38:06 +0000 Subject: [PATCH 04/11] chore: improve description --- registry/coder/modules/claude-code/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 4d7be1582..506008e52 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -188,7 +188,7 @@ variable "system_prompt" { variable "include_coder_system_prompt" { type = bool - description = "Include Coder system prompts for proper integration with tool selection and task reporting." + description = "Include Coder system prompts for proper integration with tool selection and task reporting. Defaults to false for backward compatibility, will default to true in the next major release." # TODO(major): default to true in the next major release default = false } From 592e40c227ef23eb2f49e91c785e67df2d02284d Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 11:08:31 +0000 Subject: [PATCH 05/11] chore: rename variable to report_tasks_system_prompt --- registry/coder/modules/claude-code/README.md | 12 ++-- registry/coder/modules/claude-code/main.tf | 20 ++---- .../coder/modules/claude-code/main.tftest.hcl | 61 ++++++++++++++----- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 55fc696ba..fc5184f73 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -29,8 +29,10 @@ module "claude-code" { > [!NOTE] -> By default, `include_coder_system_prompt` is false. For proper integration with Coder (tool selection & task reporting), -> it is recommended to set `include_coder_system_prompt` to true. In the next major release, this will become the default. +> +> By default, `report_tasks_system_prompt` is false. +> When `report_tasks` is true, it is recommended to set `report_tasks_system_prompt` to true to inject the Coder system prompt to ensure proper task-reporting integration. +> If `report_tasks` is false, this setting has no effect. In the next major release, the default for `report_tasks_system_prompt` will be true. ## Prerequisites @@ -42,7 +44,7 @@ module "claude-code" { ### Prompt configuration (recommended) -Include Coder’s prompt sections and optionally add your own system prompt. +Include Coder’s prompt section for task reporting and optionally add your own system prompt. ```hcl module "claude-code" { @@ -51,7 +53,9 @@ module "claude-code" { agent_id = coder_agent.example.id workdir = "/home/coder/project" - include_coder_system_prompt = true + # Configure Coder's task reporting + report_tasks = true + report_tasks_system_prompt = true # Optional: append additional system prompt. system_prompt = <<-EOT diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 506008e52..80f069bf9 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -186,10 +186,11 @@ variable "system_prompt" { default = "Send a task status update to notify the user that you are ready for input, and then wait for user input." } -variable "include_coder_system_prompt" { +variable "report_tasks_system_prompt" { type = bool - description = "Include Coder system prompts for proper integration with tool selection and task reporting. Defaults to false for backward compatibility, will default to true in the next major release." + description = "Include the Coder system prompt for task reporting when report_tasks is true. Defaults to false for backward compatibility, will default to true in the next major release." # TODO(major): default to true in the next major release + # Related to PR: https://github.com/coder/registry/pull/443 default = false } @@ -237,20 +238,10 @@ locals { module_dir_name = ".claude-module" remove_last_session_id_script_b64 = base64encode(file("${path.module}/scripts/remove-last-session-id.sh")) - # Required prompts for the module to properly integrate with Coder + # Required prompts for the module to properly report task status to Coder inner_system_prompt = <<-EOT -- Tool Selection -- - coder_report_task: providing status updates or requesting user input. - - playwright: previewing your changes after you made them - to confirm it worked as expected - - desktop-commander - use only for commands that keep running - (servers, dev watchers, GUI apps). - - Built-in tools - use for everything else: - (file operations, git commands, builds & installs, one-off shell commands) - - Remember this decision rule: - - Stays running? → desktop-commander - - Finishes immediately? → built-in tools -- Task Reporting -- Report all tasks to Coder, following these EXACT guidelines: @@ -267,7 +258,8 @@ locals { custom_system_prompt = trimspace(try(var.system_prompt, "")) - final_system_prompt = var.include_coder_system_prompt ? format( + # Only include coder system prompts if report_tasks and report_tasks_system_prompt are enabled + final_system_prompt = var.report_tasks && var.report_tasks_system_prompt ? format( "\n%s\n%s\n", local.inner_system_prompt, local.custom_system_prompt, diff --git a/registry/coder/modules/claude-code/main.tftest.hcl b/registry/coder/modules/claude-code/main.tftest.hcl index 268752f4f..d3f129142 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -194,8 +194,8 @@ run "test_claude_code_system_prompt_default" { variables { agent_id = "test-agent-system-prompt" workdir = "/home/coder/test" + # report_tasks_system_prompt: default is false # system_prompt: default string is used - # include_coder_system_prompt: default is false } assert { @@ -211,7 +211,7 @@ run "test_claude_code_system_prompt_default" { # Ensure Coder sections are not injected when include=false assert { condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 - error_message = "Coder integration sections should not be present when include_coder_system_prompt is false" + error_message = "Coder integration sections should not be present when report_tasks_system_prompt is false" } } @@ -219,10 +219,10 @@ run "test_claude_code_system_prompt_empty" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + # report_tasks_system_prompt: default is false system_prompt = "" - # include_coder_system_prompt: default is false } assert { @@ -235,10 +235,10 @@ run "test_claude_code_system_prompt" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + # report_tasks_system_prompt: default is false system_prompt = "Custom addition" - # include_coder_system_prompt: default is false } assert { @@ -254,18 +254,19 @@ run "test_claude_code_system_prompt" { # Ensure Coder sections are not injected when include=false assert { condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 - error_message = "Coder integration sections should not be present when include_coder_system_prompt is false" + error_message = "Coder integration sections should not be present when report_tasks_system_prompt is false" } } -run "test_claude_code_include_coder_system_prompt_and_default_system_prompt" { +run "test_claude_code_report_tasks_system_prompt_and_default_system_prompt" { command = plan variables { agent_id = "test-agent-system-prompt" workdir = "/home/coder/test" + # report_tasks: default is true + report_tasks_system_prompt = true # system_prompt: default string is used - include_coder_system_prompt = true } assert { @@ -289,14 +290,15 @@ run "test_claude_code_include_coder_system_prompt_and_default_system_prompt" { } } -run "test_claude_code_include_coder_system_prompt_and_custom_system_prompt" { +run "test_claude_code_report_tasks_system_prompt_and_custom_system_prompt" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - system_prompt = "Custom addition" - include_coder_system_prompt = true + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + # report_tasks: default is true + report_tasks_system_prompt = true + system_prompt = "Custom addition" } assert { @@ -314,6 +316,33 @@ run "test_claude_code_include_coder_system_prompt_and_custom_system_prompt" { error_message = "System prompt should have Task Reporting section" } + assert { + condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have system_prompt variable value" + } +} + +run "test_claude_code_report_tasks_disabled" { + command = plan + + variables { + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + report_tasks = false + report_tasks_system_prompt = true + system_prompt = "Custom addition" + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + error_message = "System prompt should not be empty" + } + + assert { + condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 + error_message = "Coder integration sections should not be present when report_task is false" + } + assert { condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 error_message = "System prompt should have system_prompt variable value" From 4b57b950f8e7f1252d90984213ece466f29f68bd Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 12:00:42 +0000 Subject: [PATCH 06/11] chore: update TODO comments --- registry/coder/modules/claude-code/main.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 80f069bf9..e51a3ebf1 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -190,7 +190,8 @@ variable "report_tasks_system_prompt" { type = bool description = "Include the Coder system prompt for task reporting when report_tasks is true. Defaults to false for backward compatibility, will default to true in the next major release." # TODO(major): default to true in the next major release - # Related to PR: https://github.com/coder/registry/pull/443 + # Context PR: https://github.com/coder/registry/pull/443 + # See discussion for the `report_tasks` variable definition: https://github.com/coder/registry/pull/443#discussion_r2405788746 default = false } From f5fc708209616becdd819c5a2fe634a63d966c2e Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 12:08:48 +0000 Subject: [PATCH 07/11] chore: bump module version (minor) --- registry/coder/modules/claude-code/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index fc5184f73..ad850bb50 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 = "3.0.1" + version = "3.1.0" agent_id = coder_agent.example.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -49,7 +49,7 @@ Include Coder’s prompt section for task reporting and optionally add your own ```hcl module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.1.0" + version = "3.1.0" agent_id = coder_agent.example.id workdir = "/home/coder/project" @@ -79,7 +79,7 @@ data "coder_parameter" "ai_prompt" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.0.1" + version = "3.1.0" agent_id = coder_agent.example.id workdir = "/home/coder/project" @@ -115,7 +115,7 @@ Run and configure Claude Code as a standalone CLI in your workspace. ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.0.1" + version = "3.1.0" agent_id = coder_agent.example.id workdir = "/home/coder" install_claude_code = true @@ -138,7 +138,7 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.0.1" + version = "3.1.0" agent_id = coder_agent.example.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token From 13dfa53f7af59bb04f7af33907e7e27ae7955eef Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 18:05:29 +0000 Subject: [PATCH 08/11] fix: remove report_tasks_system_prompt variable --- registry/coder/modules/claude-code/README.md | 8 -- registry/coder/modules/claude-code/main.tf | 27 ++--- .../coder/modules/claude-code/main.tftest.hcl | 106 ++++++------------ 3 files changed, 45 insertions(+), 96 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index ad850bb50..bdeb2db3b 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -26,14 +26,6 @@ module "claude-code" { > [!NOTE] > By default, this module is configured to run the embedded chat interface as a path-based application. In production, we recommend that you configure a [wildcard access URL](https://coder.com/docs/admin/setup#wildcard-access-url) and set `subdomain = true`. See [here](https://coder.com/docs/tutorials/best-practices/security-best-practices#disable-path-based-apps) for more details. - - -> [!NOTE] -> -> By default, `report_tasks_system_prompt` is false. -> When `report_tasks` is true, it is recommended to set `report_tasks_system_prompt` to true to inject the Coder system prompt to ensure proper task-reporting integration. -> If `report_tasks` is false, this setting has no effect. In the next major release, the default for `report_tasks_system_prompt` will be true. - ## Prerequisites - An **Anthropic API key** or a _Claude Session Token_ is required for tasks. diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index e51a3ebf1..dd21199f5 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -186,15 +186,6 @@ variable "system_prompt" { default = "Send a task status update to notify the user that you are ready for input, and then wait for user input." } -variable "report_tasks_system_prompt" { - type = bool - description = "Include the Coder system prompt for task reporting when report_tasks is true. Defaults to false for backward compatibility, will default to true in the next major release." - # TODO(major): default to true in the next major release - # Context PR: https://github.com/coder/registry/pull/443 - # See discussion for the `report_tasks` variable definition: https://github.com/coder/registry/pull/443#discussion_r2405788746 - default = false -} - variable "claude_md_path" { type = string description = "The path to CLAUDE.md." @@ -240,7 +231,7 @@ locals { remove_last_session_id_script_b64 = base64encode(file("${path.module}/scripts/remove-last-session-id.sh")) # Required prompts for the module to properly report task status to Coder - inner_system_prompt = <<-EOT + report_tasks_system_prompt = <<-EOT -- Tool Selection -- - coder_report_task: providing status updates or requesting user input. @@ -259,12 +250,16 @@ locals { custom_system_prompt = trimspace(try(var.system_prompt, "")) - # Only include coder system prompts if report_tasks and report_tasks_system_prompt are enabled - final_system_prompt = var.report_tasks && var.report_tasks_system_prompt ? format( - "\n%s\n%s\n", - local.inner_system_prompt, - local.custom_system_prompt, - ) : local.custom_system_prompt + # Only include coder system prompts if report_tasks is enabled + inner_system_prompt = format( + "%s%s", + var.report_tasks ? format("\n%s\n", local.report_tasks_system_prompt) : "", + trimspace(local.custom_system_prompt) != "" ? format("\n%s\n", local.custom_system_prompt) : "", + ) + final_system_prompt = trimspace(local.inner_system_prompt) != "" ? format( + "%s", + local.inner_system_prompt + ) : "" } module "agentapi" { diff --git a/registry/coder/modules/claude-code/main.tftest.hcl b/registry/coder/modules/claude-code/main.tftest.hcl index d3f129142..95388ea40 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -194,50 +194,26 @@ run "test_claude_code_system_prompt_default" { variables { agent_id = "test-agent-system-prompt" workdir = "/home/coder/test" - # report_tasks_system_prompt: default is false # system_prompt: default string is used } assert { condition = trimspace(coder_env.claude_code_system_prompt.value) != "" - error_message = "System prompt should not be empty when omitted" + error_message = "System prompt should not be empty" } assert { condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 error_message = "System prompt should have default value" } - - # Ensure Coder sections are not injected when include=false - assert { - condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 - error_message = "Coder integration sections should not be present when report_tasks_system_prompt is false" - } -} - -run "test_claude_code_system_prompt_empty" { - command = plan - - variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - # report_tasks_system_prompt: default is false - system_prompt = "" - } - - assert { - condition = trimspace(coder_env.claude_code_system_prompt.value) == "" - error_message = "System prompt should be empty" - } } run "test_claude_code_system_prompt" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - # report_tasks_system_prompt: default is false + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" system_prompt = "Custom addition" } @@ -250,23 +226,15 @@ run "test_claude_code_system_prompt" { condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 error_message = "System prompt should have system_prompt variable value" } - - # Ensure Coder sections are not injected when include=false - assert { - condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 - error_message = "Coder integration sections should not be present when report_tasks_system_prompt is false" - } } -run "test_claude_code_report_tasks_system_prompt_and_default_system_prompt" { +run "test_claude_report_tasks_default" { command = plan variables { agent_id = "test-agent-system-prompt" workdir = "/home/coder/test" # report_tasks: default is true - report_tasks_system_prompt = true - # system_prompt: default string is used } assert { @@ -274,6 +242,17 @@ run "test_claude_code_report_tasks_system_prompt_and_default_system_prompt" { error_message = "System prompt should not be empty" } + # Ensure system prompt is wrapped by + assert { + condition = startswith(trimspace(coder_env.claude_code_system_prompt.value), "") + error_message = "System prompt should start with " + } + assert { + condition = endswith(trimspace(coder_env.claude_code_system_prompt.value), "") + error_message = "System prompt should end with " + } + + # Ensure Coder sections are injected when report_tasks=true (default) assert { condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 error_message = "System prompt should have Tool Selection section" @@ -283,22 +262,16 @@ run "test_claude_code_report_tasks_system_prompt_and_default_system_prompt" { condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 error_message = "System prompt should have Task Reporting section" } - - assert { - condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have system_prompt variable default value" - } } -run "test_claude_code_report_tasks_system_prompt_and_custom_system_prompt" { +run "test_claude_report_tasks_disabled" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - # report_tasks: default is true - report_tasks_system_prompt = true - system_prompt = "Custom addition" + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + report_tasks = false + # system_prompt: default string is used } assert { @@ -306,45 +279,34 @@ run "test_claude_code_report_tasks_system_prompt_and_custom_system_prompt" { error_message = "System prompt should not be empty" } + # Ensure system prompt is wrapped by assert { - condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have Tool Selection section" + condition = startswith(trimspace(coder_env.claude_code_system_prompt.value), "") + error_message = "System prompt should start with " } - assert { - condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have Task Reporting section" + condition = endswith(trimspace(coder_env.claude_code_system_prompt.value), "") + error_message = "System prompt should end with " } assert { - condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have system_prompt variable value" + condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have default value" } } -run "test_claude_code_report_tasks_disabled" { +run "test_claude_report_tasks_disabled_empty_system_prompt" { command = plan variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - report_tasks = false - report_tasks_system_prompt = true - system_prompt = "Custom addition" - } - - assert { - condition = trimspace(coder_env.claude_code_system_prompt.value) != "" - error_message = "System prompt should not be empty" - } - - assert { - condition = length(regexall("-- Tool Selection --|-- Task Reporting --", coder_env.claude_code_system_prompt.value)) == 0 - error_message = "Coder integration sections should not be present when report_task is false" + agent_id = "test-agent-system-prompt" + workdir = "/home/coder/test" + report_tasks = false + system_prompt = "" } assert { - condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have system_prompt variable value" + condition = trimspace(coder_env.claude_code_system_prompt.value) == "" + error_message = "System prompt should be empty" } } \ No newline at end of file From 5d92e093a9b154c7947c80af4f3a18ed0541744a Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 18:08:25 +0000 Subject: [PATCH 09/11] chore: bump module version (patch) --- registry/coder/modules/claude-code/README.md | 30 +++----------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index bdeb2db3b..952e3d73f 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 = "3.1.0" + version = "3.0.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -34,28 +34,6 @@ module "claude-code" { ## Examples -### Prompt configuration (recommended) - -Include Coder’s prompt section for task reporting and optionally add your own system prompt. - -```hcl -module "claude-code" { - source = "registry.coder.com/coder/claude-code/coder" - version = "3.1.0" - agent_id = coder_agent.example.id - workdir = "/home/coder/project" - - # Configure Coder's task reporting - report_tasks = true - report_tasks_system_prompt = true - - # Optional: append additional system prompt. - system_prompt = <<-EOT - Additional organization-specific guidance here. - EOT -} -``` - ### Usage with Tasks and Advanced Configuration This example shows how to configure the Claude Code module with an AI prompt, API key shared by all users of the template, and other custom settings. @@ -71,7 +49,7 @@ data "coder_parameter" "ai_prompt" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.1.0" + version = "3.0.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" @@ -107,7 +85,7 @@ Run and configure Claude Code as a standalone CLI in your workspace. ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.1.0" + version = "3.0.2" agent_id = coder_agent.example.id workdir = "/home/coder" install_claude_code = true @@ -130,7 +108,7 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "3.1.0" + version = "3.0.2" agent_id = coder_agent.example.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token From e0502017ae086e454ff521f8899bf991a6d236f0 Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 18:40:34 +0000 Subject: [PATCH 10/11] chore: address comments --- registry/coder/modules/claude-code/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index dd21199f5..24ba58aa9 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -183,7 +183,7 @@ variable "claude_code_oauth_token" { variable "system_prompt" { type = string description = "The system prompt to use for the Claude Code server." - default = "Send a task status update to notify the user that you are ready for input, and then wait for user input." + default = "" } variable "claude_md_path" { From 9e6dcc8e11e3879b60c0786ef77de95f52ecc431 Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Mon, 6 Oct 2025 18:56:56 +0000 Subject: [PATCH 11/11] chore: address comments --- registry/coder/modules/claude-code/main.tf | 12 ++--- .../coder/modules/claude-code/main.tftest.hcl | 46 +------------------ 2 files changed, 5 insertions(+), 53 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 24ba58aa9..6fbdc72b0 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -248,18 +248,12 @@ locals { details, or encounter blockers EOT - custom_system_prompt = trimspace(try(var.system_prompt, "")) - # Only include coder system prompts if report_tasks is enabled - inner_system_prompt = format( - "%s%s", + custom_system_prompt = trimspace(try(var.system_prompt, "")) + final_system_prompt = format("%s%s", var.report_tasks ? format("\n%s\n", local.report_tasks_system_prompt) : "", - trimspace(local.custom_system_prompt) != "" ? format("\n%s\n", local.custom_system_prompt) : "", + local.custom_system_prompt != "" ? format("\n%s\n", local.custom_system_prompt) : "" ) - final_system_prompt = trimspace(local.inner_system_prompt) != "" ? format( - "%s", - local.inner_system_prompt - ) : "" } module "agentapi" { diff --git a/registry/coder/modules/claude-code/main.tftest.hcl b/registry/coder/modules/claude-code/main.tftest.hcl index 95388ea40..9999c1b11 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -188,26 +188,6 @@ run "test_claude_code_permission_mode_validation" { } } -run "test_claude_code_system_prompt_default" { - command = plan - - variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - # system_prompt: default string is used - } - - assert { - condition = trimspace(coder_env.claude_code_system_prompt.value) != "" - error_message = "System prompt should not be empty" - } - - assert { - condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have default value" - } -} - run "test_claude_code_system_prompt" { command = plan @@ -232,7 +212,7 @@ run "test_claude_report_tasks_default" { command = plan variables { - agent_id = "test-agent-system-prompt" + agent_id = "test-agent-report-tasks" workdir = "/home/coder/test" # report_tasks: default is true } @@ -268,10 +248,9 @@ run "test_claude_report_tasks_disabled" { command = plan variables { - agent_id = "test-agent-system-prompt" + agent_id = "test-agent-report-tasks" workdir = "/home/coder/test" report_tasks = false - # system_prompt: default string is used } assert { @@ -288,25 +267,4 @@ run "test_claude_report_tasks_disabled" { condition = endswith(trimspace(coder_env.claude_code_system_prompt.value), "") error_message = "System prompt should end with " } - - assert { - condition = length(regexall("Send a task status update to notify the user that you are ready for input, and then wait for user input.", coder_env.claude_code_system_prompt.value)) > 0 - error_message = "System prompt should have default value" - } -} - -run "test_claude_report_tasks_disabled_empty_system_prompt" { - command = plan - - variables { - agent_id = "test-agent-system-prompt" - workdir = "/home/coder/test" - report_tasks = false - system_prompt = "" - } - - assert { - condition = trimspace(coder_env.claude_code_system_prompt.value) == "" - error_message = "System prompt should be empty" - } } \ No newline at end of file