Skip to content
73 changes: 58 additions & 15 deletions registry/coder/modules/claude-code/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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"

Expand All @@ -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"
Expand All @@ -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
Expand All @@ -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 and 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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
32 changes: 32 additions & 0 deletions registry/coder/modules/claude-code/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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 uses Coder's authentication."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
error_message = "claude_api_key cannot be provided when enable_aibridge is true. AI Bridge uses Coder's authentication."
error_message = "claude_api_key cannot be provided when enable_aibridge is true. AI Bridge automatically authenticates the client using their Coder credentials."

What do you think about something like this?

Same suggestion below.

}

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 uses Coder's authentication."
}
}

resource "coder_env" "claude_code_md_path" {
count = var.claude_md_path == "" ? 0 : 1
agent_id = var.agent_id
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
18 changes: 11 additions & 7 deletions registry/coder/modules/claude-code/scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 "--------------------------------"

Expand All @@ -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 "--------------------------------"

Expand Down Expand Up @@ -133,27 +135,25 @@ 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

local claude_config="$HOME/.claude.json"
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"
Expand All @@ -165,7 +165,6 @@ function configure_standalone_mode() {
"bypassPermissionsModeAccepted": true,
"hasAcknowledgedCostThreshold": true,
"hasCompletedOnboarding": true,
"primaryApiKey": "${CLAUDE_API_KEY:-}",
"projects": {
"$ARG_WORKDIR": {
"hasCompletedProjectOnboarding": true,
Expand All @@ -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
Comment on lines +178 to +181
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we get any benefit from adding the key to the file? Why not only rely on coder_env and set it as ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN instead?


echo "Standalone mode configured successfully"
}

Expand Down