From d057a820c1cb22bd109df74d0408f810a19a9b45 Mon Sep 17 00:00:00 2001 From: Susana Ferreira Date: Tue, 7 Oct 2025 10:09:49 +0100 Subject: [PATCH] feat(claude-code): add coder-specific prompt to system_prompt (#443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description This PR updates the `claude-code` module to automatically include the Coder task-reporting system prompt whenever `report_tasks = true`, and to wrap the final system prompt in `` when non-empty. Previously, users needed to manually include this content in their system prompts to enable proper task reporting. When `report_tasks = true`, the system prompt is prepended with the Coder task-reporting, and any user `system_prompt` (if provided) is appended after it, ensuring consistent integration without manual copy/paste. When `report_tasks = false`, the module includes only the user `system_prompt` (if any). If both `report_tasks = false` and `system_prompt` is empty, the system prompt sent to Claude is empty. ## Type of Change - [ ] New module - [x] Bug fix - [ ] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder/modules/claude-code` **New version:** `v3.0.2` **Breaking change:** [] Yes [x] No ## Testing & Validation - [x] Tests pass (`bun test`) - [x] Code formatted (`bun run fmt`) - [x] Changes tested locally Related to internal slack thread: https://codercom.slack.com/archives/C0992H8HGCS/p1759317555713269 --------- Co-authored-by: DevCats --- registry/coder/modules/claude-code/main.tf | 31 ++++++- .../coder/modules/claude-code/main.tftest.hcl | 81 +++++++++++++++++++ 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 4836347b..6fbdc72b 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" { @@ -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,31 @@ 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 report task status to Coder + report_tasks_system_prompt = <<-EOT + -- Tool Selection -- + - coder_report_task: providing status updates or requesting user input. + + -- 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 + + # Only include coder system prompts if report_tasks is enabled + 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) : "", + local.custom_system_prompt != "" ? format("\n%s\n", 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 c48923cf..9999c1b1 100644 --- a/registry/coder/modules/claude-code/main.tftest.hcl +++ b/registry/coder/modules/claude-code/main.tftest.hcl @@ -187,3 +187,84 @@ run "test_claude_code_permission_mode_validation" { error_message = "Permission mode should be one of the valid options" } } + +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 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" + } +} + +run "test_claude_report_tasks_default" { + command = plan + + variables { + agent_id = "test-agent-report-tasks" + workdir = "/home/coder/test" + # report_tasks: default is true + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + 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" + } + + assert { + condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0 + error_message = "System prompt should have Task Reporting section" + } +} + +run "test_claude_report_tasks_disabled" { + command = plan + + variables { + agent_id = "test-agent-report-tasks" + workdir = "/home/coder/test" + report_tasks = false + } + + assert { + condition = trimspace(coder_env.claude_code_system_prompt.value) != "" + 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 " + } +} \ No newline at end of file