Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
db4cbed
feat(coder/modules/claude-code): add support for aibridge
35C4n0r Jan 13, 2026
11203a4
chore: bump version
35C4n0r Jan 13, 2026
2efe178
fix: use precondition instead of check
35C4n0r Jan 14, 2026
4963d31
fix: refactor and bun fmt
35C4n0r Jan 14, 2026
3328805
add validation block
35C4n0r Jan 14, 2026
4aad195
feat: add ARG_ENABLE_AIBRIDGE support to installation script and conf…
35C4n0r Jan 15, 2026
0ed44f4
feat: restore tests
35C4n0r Jan 15, 2026
3dbed9a
Merge branch 'main' into 35C4n0r/feat-claude-aibridge
35C4n0r Jan 15, 2026
3dfd968
bun fmt
35C4n0r Jan 15, 2026
2e76f43
bun fmt
35C4n0r Jan 15, 2026
a59a423
bun fmt
35C4n0r Jan 15, 2026
28fc496
bun fmt
35C4n0r Jan 15, 2026
8a4b5e3
bump version
35C4n0r Jan 15, 2026
f40c16d
feat: update validation error message
35C4n0r Jan 15, 2026
64a790c
chore: update README.md
35C4n0r Jan 16, 2026
a9d3304
Merge branch 'main' into 35C4n0r/feat-claude-aibridge
35C4n0r Jan 16, 2026
d6e77ae
chore: rearrange README.md
35C4n0r Jan 17, 2026
7829d11
Update registry/coder/modules/claude-code/README.md
35C4n0r Jan 19, 2026
85a83f1
chore: test
35C4n0r Jan 19, 2026
40fc90d
chore: test
35C4n0r Jan 19, 2026
2d3302b
Merge remote-tracking branch 'origin/35C4n0r/feat-claude-aibridge' in…
35C4n0r Jan 19, 2026
08bebf1
Apply suggestion from @Copilot
35C4n0r Jan 19, 2026
c5f8ffc
Apply suggestion from @Copilot
35C4n0r Jan 19, 2026
c8c01c8
feat: update Claude Code authentication to support AI Bridge integration
35C4n0r Jan 19, 2026
dce4cff
Update registry/coder/modules/claude-code/main.tf
35C4n0r Jan 19, 2026
495fdd1
Update registry/coder/modules/claude-code/main.tf
35C4n0r Jan 19, 2026
a866b16
feat: add terraform validation tests
35C4n0r Jan 19, 2026
adbc719
Merge remote-tracking branch 'origin/35C4n0r/feat-claude-aibridge' in…
35C4n0r Jan 19, 2026
2471c2f
wip
35C4n0r Jan 19, 2026
a22618a
wip
35C4n0r Jan 19, 2026
d86dca0
wip
35C4n0r Jan 19, 2026
87e04fd
wip
35C4n0r Jan 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 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
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 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
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

echo "Standalone mode configured successfully"
}

Expand Down