Skip to content

Commit 6fbaf73

Browse files
authored
Merge branch 'main' into aider-tasks-agentapi-support
2 parents ddef094 + cb990bb commit 6fbaf73

File tree

8 files changed

+108
-66
lines changed

8 files changed

+108
-66
lines changed

registry/coder-labs/templates/tasks-docker/main.tf

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ module "claude-code" {
2424
source = "registry.coder.com/coder/claude-code/coder"
2525
version = "2.0.0"
2626
agent_id = coder_agent.main.id
27-
agent_name = "main"
2827
folder = "/home/coder/projects"
2928
install_claude_code = true
3029
claude_code_version = "latest"
@@ -45,10 +44,9 @@ variable "anthropic_api_key" {
4544
sensitive = true
4645
}
4746
resource "coder_env" "anthropic_api_key" {
48-
agent_id = coder_agent.main.id
49-
agent_name = "main"
50-
name = "CODER_MCP_CLAUDE_API_KEY"
51-
value = var.anthropic_api_key
47+
agent_id = coder_agent.main.id
48+
name = "CODER_MCP_CLAUDE_API_KEY"
49+
value = var.anthropic_api_key
5250
}
5351

5452
# We are using presets to set the prompts, image, and set up instructions
@@ -176,22 +174,19 @@ data "coder_parameter" "preview_port" {
176174

177175
# Other variables for Claude Code
178176
resource "coder_env" "claude_task_prompt" {
179-
agent_id = coder_agent.main.id
180-
agent_name = "main"
181-
name = "CODER_MCP_CLAUDE_TASK_PROMPT"
182-
value = data.coder_parameter.ai_prompt.value
177+
agent_id = coder_agent.main.id
178+
name = "CODER_MCP_CLAUDE_TASK_PROMPT"
179+
value = data.coder_parameter.ai_prompt.value
183180
}
184181
resource "coder_env" "app_status_slug" {
185-
agent_id = coder_agent.main.id
186-
agent_name = "main"
187-
name = "CODER_MCP_APP_STATUS_SLUG"
188-
value = "ccw"
182+
agent_id = coder_agent.main.id
183+
name = "CODER_MCP_APP_STATUS_SLUG"
184+
value = "ccw"
189185
}
190186
resource "coder_env" "claude_system_prompt" {
191-
agent_id = coder_agent.main.id
192-
agent_name = "main"
193-
name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT"
194-
value = data.coder_parameter.system_prompt.value
187+
agent_id = coder_agent.main.id
188+
name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT"
189+
value = data.coder_parameter.system_prompt.value
195190
}
196191

197192
data "coder_provisioner" "me" {}
@@ -301,38 +296,27 @@ module "code-server" {
301296
# This ensures that the latest non-breaking version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production.
302297
version = "~> 1.0"
303298

304-
agent_id = coder_agent.main.id
305-
agent_name = "main"
306-
order = 1
307-
}
308-
309-
module "vscode" {
310-
count = data.coder_workspace.me.start_count
311-
source = "registry.coder.com/coder/vscode-desktop/coder"
312-
version = "1.1.0"
313-
agent_id = coder_agent.main.id
314-
agent_name = "main"
299+
agent_id = coder_agent.main.id
300+
order = 1
315301
}
316302

317303
module "windsurf" {
318-
count = data.coder_workspace.me.start_count
319-
source = "registry.coder.com/coder/windsurf/coder"
320-
version = "1.1.0"
321-
agent_id = coder_agent.main.id
322-
agent_name = "main"
304+
count = data.coder_workspace.me.start_count
305+
source = "registry.coder.com/coder/windsurf/coder"
306+
version = "1.1.0"
307+
agent_id = coder_agent.main.id
323308
}
324309

325310
module "cursor" {
326-
count = data.coder_workspace.me.start_count
327-
source = "registry.coder.com/coder/cursor/coder"
328-
version = "1.2.0"
329-
agent_id = coder_agent.main.id
330-
agent_name = "main"
311+
count = data.coder_workspace.me.start_count
312+
source = "registry.coder.com/coder/cursor/coder"
313+
version = "1.2.0"
314+
agent_id = coder_agent.main.id
331315
}
332316

333317
module "jetbrains" {
334318
count = data.coder_workspace.me.start_count
335-
source = "registry.coder.com/modules/coder/jetbrains/coder"
319+
source = "registry.coder.com/coder/jetbrains/coder"
336320
version = "~> 1.0"
337321
agent_id = coder_agent.main.id
338322
agent_name = "main"
@@ -368,7 +352,6 @@ resource "docker_volume" "home_volume" {
368352

369353
resource "coder_app" "preview" {
370354
agent_id = coder_agent.main.id
371-
agent_name = "main"
372355
slug = "preview"
373356
display_name = "Preview your app"
374357
icon = "${data.coder_workspace.me.access_url}/emojis/1f50e.png"

registry/coder/modules/claude-code/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude
1313
```tf
1414
module "claude-code" {
1515
source = "registry.coder.com/coder/claude-code/coder"
16-
version = "2.2.0"
16+
version = "2.2.1"
1717
agent_id = coder_agent.example.id
1818
folder = "/home/coder"
1919
install_claude_code = true
@@ -26,6 +26,9 @@ module "claude-code" {
2626
> this enables more functionality, it also means Claude Code can potentially execute commands with the same privileges as
2727
> the user running it. Use this module _only_ in trusted environments and be aware of the security implications.
2828
29+
> [!NOTE]
30+
> 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.
31+
2932
## Prerequisites
3033

3134
- You must add the [Coder Login](https://registry.coder.com/modules/coder-login) module to your template
@@ -83,7 +86,7 @@ resource "coder_agent" "main" {
8386
module "claude-code" {
8487
count = data.coder_workspace.me.start_count
8588
source = "registry.coder.com/coder/claude-code/coder"
86-
version = "2.2.0"
89+
version = "2.2.1"
8790
agent_id = coder_agent.example.id
8891
folder = "/home/coder"
8992
install_claude_code = true
@@ -101,7 +104,7 @@ Run Claude Code as a standalone app in your workspace. This will install Claude
101104
```tf
102105
module "claude-code" {
103106
source = "registry.coder.com/coder/claude-code/coder"
104-
version = "2.2.0"
107+
version = "2.2.1"
105108
agent_id = coder_agent.example.id
106109
folder = "/home/coder"
107110
install_claude_code = true

registry/coder/modules/claude-code/main.test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
afterEach,
44
expect,
55
describe,
6+
it,
67
setDefaultTimeout,
78
beforeAll,
89
} from "bun:test";
@@ -100,6 +101,7 @@ const writeAgentAPIMockControl = async ({
100101
interface SetupProps {
101102
skipAgentAPIMock?: boolean;
102103
skipClaudeMock?: boolean;
104+
extraVars?: Record<string, string>;
103105
}
104106

105107
const projectDir = "/home/coder/project";
@@ -112,6 +114,7 @@ const setup = async (props?: SetupProps): Promise<{ id: string }> => {
112114
install_claude_code: "false",
113115
agentapi_version: "preview",
114116
folder: projectDir,
117+
...props?.extraVars,
115118
},
116119
});
117120
await execContainer(id, ["bash", "-c", `mkdir -p '${projectDir}'`]);
@@ -335,6 +338,36 @@ describe("claude-code", async () => {
335338
id,
336339
"/home/coder/agentapi-mock.log",
337340
);
338-
expect(agentApiStartLog).toContain("AGENTAPI_ALLOWED_HOSTS: *");
341+
expect(agentApiStartLog).toContain("AGENTAPI_ALLOWED_HOSTS=*");
342+
});
343+
344+
describe("subdomain", async () => {
345+
it("sets AGENTAPI_CHAT_BASE_PATH when false", async () => {
346+
const { id } = await setup();
347+
const respModuleScript = await execModuleScript(id);
348+
expect(respModuleScript.exitCode).toBe(0);
349+
await expectAgentAPIStarted(id);
350+
const agentApiStartLog = await readFileContainer(
351+
id,
352+
"/home/coder/agentapi-mock.log",
353+
);
354+
expect(agentApiStartLog).toContain(
355+
"AGENTAPI_CHAT_BASE_PATH=/@default/default.foo/apps/ccw/chat",
356+
);
357+
});
358+
359+
it("does not set AGENTAPI_CHAT_BASE_PATH when true", async () => {
360+
const { id } = await setup({
361+
extraVars: { subdomain: "true" },
362+
});
363+
const respModuleScript = await execModuleScript(id);
364+
expect(respModuleScript.exitCode).toBe(0);
365+
await expectAgentAPIStarted(id);
366+
const agentApiStartLog = await readFileContainer(
367+
id,
368+
"/home/coder/agentapi-mock.log",
369+
);
370+
expect(agentApiStartLog).toMatch(/AGENTAPI_CHAT_BASE_PATH=$/m);
371+
});
339372
});
340373
});

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ variable "agentapi_version" {
106106
variable "subdomain" {
107107
type = bool
108108
description = "Whether to use a subdomain for the Claude Code app."
109-
default = true
109+
default = false
110110
}
111111

112112
locals {
113113
# we have to trim the slash because otherwise coder exp mcp will
114-
# set up an invalid claude config
114+
# set up an invalid claude config
115115
workdir = trimsuffix(var.folder, "/")
116116
encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : ""
117117
encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : ""
@@ -244,7 +244,7 @@ resource "coder_script" "claude_code" {
244244
245245
# Disable host header check since AgentAPI is proxied by Coder (which does its own validation)
246246
export AGENTAPI_ALLOWED_HOSTS="*"
247-
247+
248248
# Set chat base path for non-subdomain routing (only set if not using subdomain)
249249
export AGENTAPI_CHAT_BASE_PATH="${local.agentapi_chat_base_path}"
250250
@@ -295,4 +295,4 @@ resource "coder_ai_task" "claude_code" {
295295
sidebar_app {
296296
id = coder_app.claude_code_web.id
297297
}
298-
}
298+
}

registry/coder/modules/claude-code/testdata/agentapi-mock.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ if (
2222

2323
fs.writeFileSync(
2424
"/home/coder/agentapi-mock.log",
25-
`AGENTAPI_ALLOWED_HOSTS: ${process.env.AGENTAPI_ALLOWED_HOSTS}`,
25+
`AGENTAPI_ALLOWED_HOSTS=${process.env.AGENTAPI_ALLOWED_HOSTS}
26+
AGENTAPI_CHAT_BASE_PATH=${process.env.AGENTAPI_CHAT_BASE_PATH}`,
2627
);
2728

2829
console.log(`starting server on port ${port}`);

registry/coder/modules/goose/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Run the [Goose](https://block.github.io/goose/) agent in your workspace to gener
1313
```tf
1414
module "goose" {
1515
source = "registry.coder.com/coder/goose/coder"
16-
version = "2.1.1"
16+
version = "2.1.2"
1717
agent_id = coder_agent.example.id
1818
folder = "/home/coder"
1919
install_goose = true
@@ -79,7 +79,7 @@ resource "coder_agent" "main" {
7979
module "goose" {
8080
count = data.coder_workspace.me.start_count
8181
source = "registry.coder.com/coder/goose/coder"
82-
version = "2.1.1"
82+
version = "2.1.2"
8383
agent_id = coder_agent.example.id
8484
folder = "/home/coder"
8585
install_goose = true
@@ -123,4 +123,6 @@ Note: The indentation in the heredoc is preserved, so you can write the YAML nat
123123

124124
## Troubleshooting
125125

126+
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.
127+
126128
The module will create log files in the workspace's `~/.goose-module` directory. If you run into any issues, look at them for more information.

registry/coder/modules/goose/main.test.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
test,
33
afterEach,
44
describe,
5+
it,
56
setDefaultTimeout,
67
beforeAll,
78
expect,
@@ -253,22 +254,41 @@ describe("goose", async () => {
253254
expect(prompt.stderr).toContain("No such file or directory");
254255
});
255256

256-
test("subdomain-false", async () => {
257-
const { id } = await setup({
258-
agentapiMockScript: await loadTestFile(
259-
import.meta.dir,
260-
"agentapi-mock-print-args.js",
261-
),
262-
moduleVariables: {
263-
subdomain: "false",
264-
},
257+
describe("subdomain", async () => {
258+
it("sets AGENTAPI_CHAT_BASE_PATH when false", async () => {
259+
const { id } = await setup({
260+
agentapiMockScript: await loadTestFile(
261+
import.meta.dir,
262+
"agentapi-mock-print-args.js",
263+
),
264+
moduleVariables: {
265+
subdomain: "false",
266+
},
267+
});
268+
269+
await execModuleScript(id);
270+
271+
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
272+
expect(agentapiMockOutput).toContain(
273+
"AGENTAPI_CHAT_BASE_PATH=/@default/default.foo/apps/goose/chat",
274+
);
265275
});
266276

267-
await execModuleScript(id);
277+
it("does not set AGENTAPI_CHAT_BASE_PATH when true", async () => {
278+
const { id } = await setup({
279+
agentapiMockScript: await loadTestFile(
280+
import.meta.dir,
281+
"agentapi-mock-print-args.js",
282+
),
283+
moduleVariables: {
284+
subdomain: "true",
285+
},
286+
});
268287

269-
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
270-
expect(agentapiMockOutput).toContain(
271-
"AGENTAPI_CHAT_BASE_PATH=/@default/default.foo/apps/goose/chat",
272-
);
288+
await execModuleScript(id);
289+
290+
const agentapiMockOutput = await readFileContainer(id, agentapiStartLog);
291+
expect(agentapiMockOutput).toMatch(/AGENTAPI_CHAT_BASE_PATH=$/m);
292+
});
273293
});
274294
});

registry/coder/modules/goose/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ variable "agentapi_version" {
6969
variable "subdomain" {
7070
type = bool
7171
description = "Whether to use a subdomain for AgentAPI."
72-
default = true
72+
default = false
7373
}
7474

7575
variable "goose_provider" {

0 commit comments

Comments
 (0)