diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 68714e0ef..1ac35872c 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -3,7 +3,7 @@ display_name: Claude Code description: Run the Claude Code agent in your workspace. icon: ../../../../.icons/claude.svg verified: true -tags: [agent, claude-code, ai, tasks, anthropic] +tags: [agent, claude-code, ai, tasks, anthropic, aibridge] --- # Claude Code @@ -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.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -45,7 +45,7 @@ This example shows how to configure the Claude Code module to run the agent behi ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_boundary = true @@ -61,17 +61,16 @@ This example shows how to configure the Claude Code module with an AI prompt, AP > When a specific `claude_code_version` (other than "latest") is provided, the module will install Claude Code via npm instead of the official installer. This allows for version pinning. The `claude_binary_path` variable can be used to specify where a pre-installed Claude binary is located. ```tf -data "coder_parameter" "ai_prompt" { - type = "string" - name = "AI Prompt" - default = "" - description = "Initial task prompt for Claude Code." - mutable = true +resource "coder_ai_task" "task" { + count = data.coder_workspace.me.start_count + app_id = module.claude-code.task_app_id } +data "coder_task" "me" {} + module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" @@ -83,7 +82,7 @@ module "claude-code" { claude_binary_path = "/opt/claude/bin" # Path to pre-installed Claude binary agentapi_version = "0.11.4" - ai_prompt = data.coder_parameter.ai_prompt.value + ai_prompt = data.coder_task.me.prompt model = "sonnet" permission_mode = "plan" @@ -108,7 +107,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 = "4.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" install_claude_code = true @@ -130,13 +129,57 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token } ``` +### Usage with AI Bridge Configuration + +For AI Bridge configuration set `enable_aibridge` to `true`. [AI Bridge](https://coder.com/docs/ai-coder/ai-bridge) is a Premium Coder feature that provides centralized LLM proxy management. + +#### Usage with tasks and AI Bridge + +```tf +resource "coder_ai_task" "task" { + count = data.coder_workspace.me.start_count + app_id = module.claude-code.task_app_id +} + +data "coder_task" "me" {} + +module "claude-code" { + source = "registry.coder.com/coder/claude-code/coder" + version = "4.5.0" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + ai_prompt = data.coder_task.me.prompt + enable_aibridge = true +} +``` + +#### Standalone usage with AI Bridge + +```tf +module "claude-code" { + source = "registry.coder.com/coder/claude-code/coder" + version = "4.5.0" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + enable_aibridge = true +} +``` + +When `enable_aibridge = true`, the module automatically sets: + +- `ANTHROPIC_BASE_URL` to `${data.coder_workspace.me.access_url}/api/v2/aibridge/anthropic` +- `ANTHROPIC_AUTH_TOKEN` to the workspace owner's session token + +This allows Claude Code to route API requests through Coder's AI Bridge instead of directly to Anthropic's API. +Template build will fail if either `claude_api_key` or `claude_code_oauth_token` is provided alongside `enable_aibridge = true`. + ### Usage with AWS Bedrock #### Prerequisites @@ -203,7 +246,7 @@ resource "coder_env" "bedrock_api_key" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" @@ -260,7 +303,7 @@ resource "coder_env" "google_application_credentials" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.4.1" + version = "4.5.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "claude-sonnet-4@20250514" diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index d0681af62..cdbadb681 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -228,6 +228,22 @@ variable "compile_boundary_from_source" { default = false } +variable "enable_aibridge" { + type = bool + description = "Use AI Bridge for Claude Code. https://coder.com/docs/ai-coder/ai-bridge" + default = false + + validation { + condition = !(var.enable_aibridge && length(var.claude_api_key) > 0) + error_message = "claude_api_key cannot be provided when enable_aibridge is true. AI Bridge automatically authenticates the client using their Coder credentials." + } + + validation { + condition = !(var.enable_aibridge && length(var.claude_code_oauth_token) > 0) + error_message = "claude_code_oauth_token cannot be provided when enable_aibridge is true. AI Bridge automatically authenticates the client using their Coder credentials." + } +} + resource "coder_env" "claude_code_md_path" { count = var.claude_md_path == "" ? 0 : 1 agent_id = var.agent_id @@ -281,6 +297,21 @@ resource "coder_env" "anthropic_model" { value = var.model } +resource "coder_env" "anthropic_base_url" { + count = var.enable_aibridge ? 1 : 0 + agent_id = var.agent_id + name = "ANTHROPIC_BASE_URL" + value = "${data.coder_workspace.me.access_url}/api/v2/aibridge/anthropic" +} + +# https://code.claude.com/docs/en/settings#environment-variables +resource "coder_env" "anthropic_auth_token" { + count = var.enable_aibridge ? 1 : 0 + agent_id = var.agent_id + name = "ANTHROPIC_AUTH_TOKEN" + value = data.coder_workspace_owner.me.session_token +} + locals { # we have to trim the slash because otherwise coder exp mcp will # set up an invalid claude config @@ -382,6 +413,7 @@ module "agentapi" { ARG_ALLOWED_TOOLS='${var.allowed_tools}' \ ARG_DISALLOWED_TOOLS='${var.disallowed_tools}' \ ARG_MCP='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ + ARG_ENABLE_AIBRIDGE='${var.enable_aibridge}' \ /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 5b9584cb4..a909e7676 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -18,6 +18,7 @@ ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-} ARG_MCP=$(echo -n "${ARG_MCP:-}" | base64 -d) ARG_ALLOWED_TOOLS=${ARG_ALLOWED_TOOLS:-} ARG_DISALLOWED_TOOLS=${ARG_DISALLOWED_TOOLS:-} +ARG_ENABLE_AIBRIDGE=${ARG_ENABLE_AIBRIDGE:-false} echo "--------------------------------" @@ -31,6 +32,7 @@ printf "ARG_MCP_APP_STATUS_SLUG: %s\n" "$ARG_MCP_APP_STATUS_SLUG" printf "ARG_MCP: %s\n" "$ARG_MCP" printf "ARG_ALLOWED_TOOLS: %s\n" "$ARG_ALLOWED_TOOLS" printf "ARG_DISALLOWED_TOOLS: %s\n" "$ARG_DISALLOWED_TOOLS" +printf "ARG_ENABLE_AIBRIDGE %s\n" "$ARG_ENABLE_AIBRIDGE" echo "--------------------------------" @@ -133,8 +135,8 @@ function setup_claude_configurations() { function configure_standalone_mode() { echo "Configuring Claude Code for standalone mode..." - if [ -z "${CLAUDE_API_KEY:-}" ]; then - echo "Note: CLAUDE_API_KEY not set, skipping authentication setup" + if [ -z "${CLAUDE_API_KEY:-}" ] && [ "$ARG_ENABLE_AIBRIDGE" = "false" ]; then + echo "Note: CLAUDE_API_KEY or enable_aibridge not set, skipping authentication setup" return fi @@ -142,18 +144,16 @@ function configure_standalone_mode() { local workdir_normalized workdir_normalized=$(echo "$ARG_WORKDIR" | tr '/' '-') - # Create or update .claude.json with minimal configuration for API key auth + # Create or update .claude.json with minimal configuration # This skips the interactive login prompt and onboarding screens if [ -f "$claude_config" ]; then echo "Updating existing Claude configuration at $claude_config" - jq --arg apikey "${CLAUDE_API_KEY:-}" \ - --arg workdir "$ARG_WORKDIR" \ + jq --arg workdir "$ARG_WORKDIR" \ '.autoUpdaterStatus = "disabled" | .bypassPermissionsModeAccepted = true | .hasAcknowledgedCostThreshold = true | .hasCompletedOnboarding = true | - .primaryApiKey = $apikey | .projects[$workdir].hasCompletedProjectOnboarding = true | .projects[$workdir].hasTrustDialogAccepted = true' \ "$claude_config" > "${claude_config}.tmp" && mv "${claude_config}.tmp" "$claude_config" @@ -165,7 +165,6 @@ function configure_standalone_mode() { "bypassPermissionsModeAccepted": true, "hasAcknowledgedCostThreshold": true, "hasCompletedOnboarding": true, - "primaryApiKey": "${CLAUDE_API_KEY:-}", "projects": { "$ARG_WORKDIR": { "hasCompletedProjectOnboarding": true, @@ -176,6 +175,11 @@ function configure_standalone_mode() { EOF fi + # Add API key only if set + if [ -n "${CLAUDE_API_KEY:-}" ]; then + jq --arg apikey "${CLAUDE_API_KEY}" '.primaryApiKey = $apikey' "$claude_config" > "${claude_config}.tmp" && mv "${claude_config}.tmp" "$claude_config" + fi + echo "Standalone mode configured successfully" }