From 4f8b5fc94f75d63cfdd0b3fdf746c33e39adea81 Mon Sep 17 00:00:00 2001 From: evgeniy-scherbina Date: Mon, 26 Jan 2026 09:34:05 -0500 Subject: [PATCH 1/5] feat: use coder boundary subcommand --- registry/coder/modules/claude-code/README.md | 44 ++++++++++++++++--- registry/coder/modules/claude-code/main.tf | 7 +++ .../modules/claude-code/scripts/start.sh | 27 +++++++++--- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 8e98a880a..437a15277 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -42,14 +42,46 @@ By default, Claude Code automatically resumes existing conversations when your w This example shows how to configure the Claude Code module to run the agent behind a process-level boundary that restricts its network access. +By default, when `enable_boundary = true`, the module uses `coder boundary` subcommand (provided by Coder) without requiring any installation. You can also choose to install boundary from a release version or compile from source. + +#### Using coder boundary subcommand (default) + +```tf +module "claude-code" { + source = "registry.coder.com/coder/claude-code/coder" + version = "4.6.0" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + enable_boundary = true + # use_boundary_directly defaults to false, so coder boundary subcommand is used +} +``` + +#### Installing boundary binary from release + +```tf +module "claude-code" { + source = "registry.coder.com/coder/claude-code/coder" + version = "4.6.0" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + enable_boundary = true + use_boundary_directly = true + boundary_version = "v0.5.1" +} +``` + +#### Compiling from source (for developers) + ```tf module "claude-code" { - source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" - agent_id = coder_agent.main.id - workdir = "/home/coder/project" - enable_boundary = true - boundary_version = "v0.5.1" + source = "registry.coder.com/coder/claude-code/coder" + version = "4.6.0" + agent_id = coder_agent.main.id + workdir = "/home/coder/project" + enable_boundary = true + compile_boundary_from_source = true + boundary_version = "main" # or any git ref (tag, commit, branch) } ``` diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index 3a1128b48..8c4bd08e2 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -234,6 +234,12 @@ variable "compile_boundary_from_source" { default = false } +variable "use_boundary_directly" { + type = bool + description = "Whether to use boundary binary directly instead of coder boundary subcommand. When false (default), uses coder boundary subcommand. When true, installs and uses boundary binary from release." + default = false +} + variable "enable_aibridge" { type = bool description = "Use AI Bridge for Claude Code. https://coder.com/docs/ai-coder/ai-bridge" @@ -389,6 +395,7 @@ module "agentapi" { ARG_ENABLE_BOUNDARY='${var.enable_boundary}' \ ARG_BOUNDARY_VERSION='${var.boundary_version}' \ ARG_COMPILE_FROM_SOURCE='${var.compile_boundary_from_source}' \ + ARG_USE_BOUNDARY_DIRECTLY='${var.use_boundary_directly}' \ ARG_CODER_HOST='${local.coder_host}' \ /tmp/start.sh EOT diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index c3c320209..131c56b0c 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -16,6 +16,7 @@ ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} ARG_ENABLE_BOUNDARY=${ARG_ENABLE_BOUNDARY:-false} ARG_BOUNDARY_VERSION=${ARG_BOUNDARY_VERSION:-"main"} ARG_COMPILE_FROM_SOURCE=${ARG_COMPILE_FROM_SOURCE:-false} +ARG_USE_BOUNDARY_DIRECTLY=${ARG_USE_BOUNDARY_DIRECTLY:-false} ARG_CODER_HOST=${ARG_CODER_HOST:-} echo "--------------------------------" @@ -30,12 +31,13 @@ printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" printf "ARG_ENABLE_BOUNDARY: %s\n" "$ARG_ENABLE_BOUNDARY" printf "ARG_BOUNDARY_VERSION: %s\n" "$ARG_BOUNDARY_VERSION" printf "ARG_COMPILE_FROM_SOURCE: %s\n" "$ARG_COMPILE_FROM_SOURCE" +printf "ARG_USE_BOUNDARY_DIRECTLY: %s\n" "$ARG_USE_BOUNDARY_DIRECTLY" printf "ARG_CODER_HOST: %s\n" "$ARG_CODER_HOST" echo "--------------------------------" function install_boundary() { - if [ "${ARG_COMPILE_FROM_SOURCE:-false}" = "true" ]; then + if [ "$ARG_COMPILE_FROM_SOURCE" = "true" ]; then # Install boundary by compiling from source echo "Compiling boundary from source (version: $ARG_BOUNDARY_VERSION)" @@ -52,14 +54,16 @@ function install_boundary() { # Build the binary make build - # Install binary and wrapper script (optional) + # Install binary sudo cp boundary /usr/local/bin/ - sudo cp scripts/boundary-wrapper.sh /usr/local/bin/boundary-run - sudo chmod +x /usr/local/bin/boundary-run - else + sudo chmod +x /usr/local/bin/boundary + elif [ "$ARG_USE_BOUNDARY_DIRECTLY" = "true" ]; then # Install boundary using official install script echo "Installing boundary using official install script (version: $ARG_BOUNDARY_VERSION)" curl -fsSL https://raw.githubusercontent.com/coder/boundary/main/install.sh | bash -s -- --version "$ARG_BOUNDARY_VERSION" + else + # Use coder boundary subcommand (default) - no installation needed + echo "Using coder boundary subcommand (provided by Coder)" fi } @@ -212,15 +216,24 @@ function start_agentapi() { printf "Running claude code with args: %s\n" "$(printf '%q ' "${ARGS[@]}")" - if [ "${ARG_ENABLE_BOUNDARY:-false}" = "true" ]; then + if [ "$ARG_ENABLE_BOUNDARY" = "true" ]; then install_boundary printf "Starting with coder boundary enabled\n" BOUNDARY_ARGS+=() + # Determine which boundary command to use + if [ "$ARG_COMPILE_FROM_SOURCE" = "true" ] || [ "$ARG_USE_BOUNDARY_DIRECTLY" = "true" ]; then + # Use boundary binary directly (from compilation or release installation) + BOUNDARY_CMD=("boundary") + else + # Use coder boundary subcommand (default) + BOUNDARY_CMD=("coder" "boundary") + fi + agentapi server --type claude --term-width 67 --term-height 1190 -- \ - boundary-run "${BOUNDARY_ARGS[@]}" -- \ + "${BOUNDARY_CMD[@]}" "${BOUNDARY_ARGS[@]}" -- \ claude "${ARGS[@]}" else agentapi server --type claude --term-width 67 --term-height 1190 -- claude "${ARGS[@]}" From 16578b7bb6798701cef38ad1851eb32aa0b68459 Mon Sep 17 00:00:00 2001 From: evgeniy-scherbina Date: Mon, 26 Jan 2026 16:25:08 -0500 Subject: [PATCH 2/5] fix: coder boundary permissions --- registry/coder/modules/claude-code/scripts/start.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index 131c56b0c..552fade9d 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -229,7 +229,13 @@ function start_agentapi() { BOUNDARY_CMD=("boundary") else # Use coder boundary subcommand (default) - BOUNDARY_CMD=("coder" "boundary") + # Copy coder binary to coder-no-caps. Copying strips CAP_NET_ADMIN capabilities + # from the binary, which is necessary because boundary doesn't work with + # privileged binaries (you can't launch privileged binaries inside network + # namespaces unless you have sys_admin). + CODER_NO_CAPS="$(dirname $(which coder))/coder-no-caps" + cp "$(which coder)" "$CODER_NO_CAPS" + BOUNDARY_CMD=("$CODER_NO_CAPS" "boundary") fi agentapi server --type claude --term-width 67 --term-height 1190 -- \ From b00899817ae425131b5ab3330bc2dd59a23f7019 Mon Sep 17 00:00:00 2001 From: evgeniy-scherbina Date: Mon, 26 Jan 2026 17:09:30 -0500 Subject: [PATCH 3/5] docs: update docs --- registry/coder/modules/claude-code/README.md | 34 ++------------------ 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index 437a15277..f010c8b33 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -42,9 +42,7 @@ By default, Claude Code automatically resumes existing conversations when your w This example shows how to configure the Claude Code module to run the agent behind a process-level boundary that restricts its network access. -By default, when `enable_boundary = true`, the module uses `coder boundary` subcommand (provided by Coder) without requiring any installation. You can also choose to install boundary from a release version or compile from source. - -#### Using coder boundary subcommand (default) +By default, when `enable_boundary = true`, the module uses `coder boundary` subcommand (provided by Coder) without requiring any installation. ```tf module "claude-code" { @@ -53,37 +51,11 @@ module "claude-code" { agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_boundary = true - # use_boundary_directly defaults to false, so coder boundary subcommand is used -} -``` - -#### Installing boundary binary from release - -```tf -module "claude-code" { - source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" - agent_id = coder_agent.main.id - workdir = "/home/coder/project" - enable_boundary = true - use_boundary_directly = true - boundary_version = "v0.5.1" } ``` -#### Compiling from source (for developers) - -```tf -module "claude-code" { - source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" - agent_id = coder_agent.main.id - workdir = "/home/coder/project" - enable_boundary = true - compile_boundary_from_source = true - boundary_version = "main" # or any git ref (tag, commit, branch) -} -``` +> [!NOTE] +> For developers: The module also supports installing boundary from a release version (`use_boundary_directly = true`) or compiling from source (`compile_boundary_from_source = true`). These are escape hatches for development and testing purposes. ### Usage with AI Bridge From 87d24c99a77a1b6aeed4151ef1ddbe49bc753cb8 Mon Sep 17 00:00:00 2001 From: evgeniy-scherbina Date: Tue, 27 Jan 2026 09:05:45 -0500 Subject: [PATCH 4/5] chore: bump claude-code module version --- registry/coder/modules/claude-code/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/registry/coder/modules/claude-code/README.md b/registry/coder/modules/claude-code/README.md index f010c8b33..984830f92 100644 --- a/registry/coder/modules/claude-code/README.md +++ b/registry/coder/modules/claude-code/README.md @@ -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.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -47,7 +47,7 @@ By default, when `enable_boundary = true`, the module uses `coder boundary` subc ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_boundary = true @@ -68,7 +68,7 @@ For tasks integration with AI Bridge, add `enable_aibridge = true` to the [Usage ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_aibridge = true @@ -97,7 +97,7 @@ data "coder_task" "me" {} module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_api_key = "xxxx-xxxxx-xxxx" @@ -118,7 +118,7 @@ This example shows additional configuration options for version pinning, custom ```tf module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" @@ -174,7 +174,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.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" install_claude_code = true @@ -196,7 +196,7 @@ variable "claude_code_oauth_token" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" claude_code_oauth_token = var.claude_code_oauth_token @@ -269,7 +269,7 @@ resource "coder_env" "bedrock_api_key" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "global.anthropic.claude-sonnet-4-5-20250929-v1:0" @@ -326,7 +326,7 @@ resource "coder_env" "google_application_credentials" { module "claude-code" { source = "registry.coder.com/coder/claude-code/coder" - version = "4.6.0" + version = "4.7.0" agent_id = coder_agent.main.id workdir = "/home/coder/project" model = "claude-sonnet-4@20250514" From ff967aee1f392c38a7ba06d8b9ffe83b4e1a4a22 Mon Sep 17 00:00:00 2001 From: evgeniy-scherbina Date: Tue, 27 Jan 2026 09:12:17 -0500 Subject: [PATCH 5/5] ci: fix linter --- registry/coder/modules/claude-code/scripts/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index 552fade9d..f64c77c11 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -233,7 +233,7 @@ function start_agentapi() { # from the binary, which is necessary because boundary doesn't work with # privileged binaries (you can't launch privileged binaries inside network # namespaces unless you have sys_admin). - CODER_NO_CAPS="$(dirname $(which coder))/coder-no-caps" + CODER_NO_CAPS="$(dirname "$(which coder)")/coder-no-caps" cp "$(which coder)" "$CODER_NO_CAPS" BOUNDARY_CMD=("$CODER_NO_CAPS" "boundary") fi