Skip to content

Commit d057a82

Browse files
feat(claude-code): add coder-specific prompt to system_prompt (#443)
## 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 `<system>…</system>` 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 <[email protected]>
1 parent b4e9545 commit d057a82

File tree

2 files changed

+108
-4
lines changed

2 files changed

+108
-4
lines changed

registry/coder/modules/claude-code/main.tf

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ variable "claude_code_oauth_token" {
183183
variable "system_prompt" {
184184
type = string
185185
description = "The system prompt to use for the Claude Code server."
186-
default = "Send a task status update to notify the user that you are ready for input, and then wait for user input."
186+
default = ""
187187
}
188188

189189
variable "claude_md_path" {
@@ -201,11 +201,9 @@ resource "coder_env" "claude_code_md_path" {
201201
}
202202

203203
resource "coder_env" "claude_code_system_prompt" {
204-
count = var.system_prompt == "" ? 0 : 1
205-
206204
agent_id = var.agent_id
207205
name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT"
208-
value = var.system_prompt
206+
value = local.final_system_prompt
209207
}
210208

211209
resource "coder_env" "claude_code_oauth_token" {
@@ -231,6 +229,31 @@ locals {
231229
start_script = file("${path.module}/scripts/start.sh")
232230
module_dir_name = ".claude-module"
233231
remove_last_session_id_script_b64 = base64encode(file("${path.module}/scripts/remove-last-session-id.sh"))
232+
233+
# Required prompts for the module to properly report task status to Coder
234+
report_tasks_system_prompt = <<-EOT
235+
-- Tool Selection --
236+
- coder_report_task: providing status updates or requesting user input.
237+
238+
-- Task Reporting --
239+
Report all tasks to Coder, following these EXACT guidelines:
240+
1. Be granular. If you are investigating with multiple steps, report each step
241+
to coder.
242+
2. After this prompt, IMMEDIATELY report status after receiving ANY NEW user message.
243+
Do not report any status related with this system prompt.
244+
3. Use "state": "working" when actively processing WITHOUT needing
245+
additional user input
246+
4. Use "state": "complete" only when finished with a task
247+
5. Use "state": "failure" when you need ANY user input, lack sufficient
248+
details, or encounter blockers
249+
EOT
250+
251+
# Only include coder system prompts if report_tasks is enabled
252+
custom_system_prompt = trimspace(try(var.system_prompt, ""))
253+
final_system_prompt = format("<system>%s%s</system>",
254+
var.report_tasks ? format("\n%s\n", local.report_tasks_system_prompt) : "",
255+
local.custom_system_prompt != "" ? format("\n%s\n", local.custom_system_prompt) : ""
256+
)
234257
}
235258

236259
module "agentapi" {

registry/coder/modules/claude-code/main.tftest.hcl

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,84 @@ run "test_claude_code_permission_mode_validation" {
187187
error_message = "Permission mode should be one of the valid options"
188188
}
189189
}
190+
191+
run "test_claude_code_system_prompt" {
192+
command = plan
193+
194+
variables {
195+
agent_id = "test-agent-system-prompt"
196+
workdir = "/home/coder/test"
197+
system_prompt = "Custom addition"
198+
}
199+
200+
assert {
201+
condition = trimspace(coder_env.claude_code_system_prompt.value) != ""
202+
error_message = "System prompt should not be empty"
203+
}
204+
205+
assert {
206+
condition = length(regexall("Custom addition", coder_env.claude_code_system_prompt.value)) > 0
207+
error_message = "System prompt should have system_prompt variable value"
208+
}
209+
}
210+
211+
run "test_claude_report_tasks_default" {
212+
command = plan
213+
214+
variables {
215+
agent_id = "test-agent-report-tasks"
216+
workdir = "/home/coder/test"
217+
# report_tasks: default is true
218+
}
219+
220+
assert {
221+
condition = trimspace(coder_env.claude_code_system_prompt.value) != ""
222+
error_message = "System prompt should not be empty"
223+
}
224+
225+
# Ensure system prompt is wrapped by <system>
226+
assert {
227+
condition = startswith(trimspace(coder_env.claude_code_system_prompt.value), "<system>")
228+
error_message = "System prompt should start with <system>"
229+
}
230+
assert {
231+
condition = endswith(trimspace(coder_env.claude_code_system_prompt.value), "</system>")
232+
error_message = "System prompt should end with </system>"
233+
}
234+
235+
# Ensure Coder sections are injected when report_tasks=true (default)
236+
assert {
237+
condition = length(regexall("-- Tool Selection --", coder_env.claude_code_system_prompt.value)) > 0
238+
error_message = "System prompt should have Tool Selection section"
239+
}
240+
241+
assert {
242+
condition = length(regexall("-- Task Reporting --", coder_env.claude_code_system_prompt.value)) > 0
243+
error_message = "System prompt should have Task Reporting section"
244+
}
245+
}
246+
247+
run "test_claude_report_tasks_disabled" {
248+
command = plan
249+
250+
variables {
251+
agent_id = "test-agent-report-tasks"
252+
workdir = "/home/coder/test"
253+
report_tasks = false
254+
}
255+
256+
assert {
257+
condition = trimspace(coder_env.claude_code_system_prompt.value) != ""
258+
error_message = "System prompt should not be empty"
259+
}
260+
261+
# Ensure system prompt is wrapped by <system>
262+
assert {
263+
condition = startswith(trimspace(coder_env.claude_code_system_prompt.value), "<system>")
264+
error_message = "System prompt should start with <system>"
265+
}
266+
assert {
267+
condition = endswith(trimspace(coder_env.claude_code_system_prompt.value), "</system>")
268+
error_message = "System prompt should end with </system>"
269+
}
270+
}

0 commit comments

Comments
 (0)