From 3cf926c2df91472a6aae7476f7957e06ccbb66e6 Mon Sep 17 00:00:00 2001 From: stl314159 Date: Thu, 2 Apr 2026 16:28:43 +0000 Subject: [PATCH] feat: add agentapi_port pass-through to all agent modules All 12 agent modules that use AgentAPI hardcode port 3284 for the MCP server config, preventing multiple agents from running on the same Coder agent. This adds an `agentapi_port` variable to each module and replaces the hardcoded port with the parameterized value. Modules updated: claude-code, goose, amazon-q, aider, kiro-cli, sourcegraph-amp, gemini, cursor-cli, copilot, auggie, codex, opencode. Additional codex fixes: - Guard coder_env.openai_api_key with count condition - Remove unconditional codex --version call - Fix codex_model description and validation error messages - Update provider version to >= 2.13 Adds proxmox-vm template with random_integer port assignment for running claude-code, codex, and opencode side by side. Co-Authored-By: Claude Opus 4.6 (1M context) --- registry/coder-labs/modules/auggie/main.tf | 8 + .../modules/auggie/scripts/install.sh | 2 +- registry/coder-labs/modules/codex/main.tf | 15 +- .../coder-labs/modules/codex/main.tftest.hcl | 2 +- .../modules/codex/scripts/install.sh | 3 +- registry/coder-labs/modules/copilot/main.tf | 8 + .../modules/copilot/scripts/install.sh | 4 +- .../coder-labs/modules/cursor-cli/main.tf | 8 + .../modules/cursor-cli/scripts/install.sh | 2 +- registry/coder-labs/modules/gemini/main.tf | 10 +- .../modules/gemini/scripts/install.sh | 2 +- registry/coder-labs/modules/opencode/main.tf | 8 + .../modules/opencode/scripts/install.sh | 2 +- .../modules/sourcegraph-amp/main.tf | 9 +- registry/coder/modules/aider/main.tf | 6 + registry/coder/modules/amazon-q/main.tf | 8 + .../coder/modules/amazon-q/scripts/install.sh | 2 +- registry/coder/modules/claude-code/main.tf | 8 + .../modules/claude-code/scripts/install.sh | 2 +- registry/coder/modules/goose/main.tf | 9 +- registry/harleylrn/modules/kiro-cli/main.tf | 8 + .../modules/kiro-cli/scripts/install.sh | 2 +- .../proxmox-vm/cloud-init.yaml.tftpl | 47 ++ .../stl314159/templates/proxmox-vm/main.tf | 459 ++++++++++++++++++ 24 files changed, 616 insertions(+), 18 deletions(-) create mode 100644 registry/stl314159/templates/proxmox-vm/cloud-init.yaml.tftpl create mode 100644 registry/stl314159/templates/proxmox-vm/main.tf diff --git a/registry/coder-labs/modules/auggie/main.tf b/registry/coder-labs/modules/auggie/main.tf index 8ecb3ba0a..24d73ab40 100644 --- a/registry/coder-labs/modules/auggie/main.tf +++ b/registry/coder-labs/modules/auggie/main.tf @@ -163,6 +163,12 @@ variable "cli_app_display_name" { default = "Auggie CLI" } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + resource "coder_env" "auggie_session_auth" { agent_id = var.agent_id name = "AUGMENT_SESSION_AUTH" @@ -196,6 +202,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash set -o errexit @@ -227,6 +234,7 @@ module "agentapi" { ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \ ARG_AUGGIE_RULES='${base64encode(var.rules)}' \ ARG_MCP_CONFIG='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/coder-labs/modules/auggie/scripts/install.sh b/registry/coder-labs/modules/auggie/scripts/install.sh index b2f80ebe9..1917bd484 100644 --- a/registry/coder-labs/modules/auggie/scripts/install.sh +++ b/registry/coder-labs/modules/auggie/scripts/install.sh @@ -85,7 +85,7 @@ function create_coder_mcp() { "command": "coder", "env": { "CODER_MCP_APP_STATUS_SLUG": "${ARG_MCP_APP_STATUS_SLUG}", - "CODER_MCP_AI_AGENTAPI_URL": "http://localhost:3284", + "CODER_MCP_AI_AGENTAPI_URL": "http://localhost:${ARG_AGENTAPI_PORT:-3284}", "CODER_AGENT_URL": "${CODER_AGENT_URL:-}", "CODER_AGENT_TOKEN": "${CODER_AGENT_TOKEN:-}" } diff --git a/registry/coder-labs/modules/codex/main.tf b/registry/coder-labs/modules/codex/main.tf index b5f71cb3c..6c54ccb1c 100644 --- a/registry/coder-labs/modules/codex/main.tf +++ b/registry/coder-labs/modules/codex/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.12" + version = ">= 2.13" } } } @@ -88,7 +88,7 @@ variable "model_reasoning_effort" { default = "" validation { condition = contains(["", "none", "minimal", "low", "medium", "high", "xhigh"], var.model_reasoning_effort) - error_message = "model_reasoning_effort must be one of: none, low, medium, high." + error_message = "model_reasoning_effort must be one of: none, minimal, low, medium, high, xhigh." } } @@ -134,9 +134,15 @@ variable "agentapi_version" { default = "v0.12.1" } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + variable "codex_model" { type = string - description = "The model for Codex to use. Defaults to gpt-5.3-codex." + description = "The model for Codex to use. Defaults to gpt-5.4." default = "gpt-5.4" } @@ -207,6 +213,7 @@ variable "use_boundary_directly" { } resource "coder_env" "openai_api_key" { + count = var.openai_api_key != "" ? 1 : 0 agent_id = var.agent_id name = "OPENAI_API_KEY" value = var.openai_api_key @@ -254,6 +261,7 @@ module "agentapi" { install_agentapi = var.install_agentapi agentapi_subdomain = var.subdomain agentapi_version = var.agentapi_version + agentapi_port = var.agentapi_port enable_state_persistence = var.enable_state_persistence pre_install_script = var.pre_install_script post_install_script = var.post_install_script @@ -300,6 +308,7 @@ module "agentapi" { ARG_CODEX_START_DIRECTORY='${local.workdir}' \ ARG_MODEL_REASONING_EFFORT='${var.model_reasoning_effort}' \ ARG_CODEX_INSTRUCTION_PROMPT='${base64encode(var.codex_system_prompt)}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/coder-labs/modules/codex/main.tftest.hcl b/registry/coder-labs/modules/codex/main.tftest.hcl index 1237df5de..1b2feaecc 100644 --- a/registry/coder-labs/modules/codex/main.tftest.hcl +++ b/registry/coder-labs/modules/codex/main.tftest.hcl @@ -100,7 +100,7 @@ run "test_aibridge_disabled_with_api_key" { } assert { - condition = coder_env.openai_api_key.value == "test-key" + condition = coder_env.openai_api_key[0].value == "test-key" error_message = "OpenAI API key should be set correctly" } } diff --git a/registry/coder-labs/modules/codex/scripts/install.sh b/registry/coder-labs/modules/codex/scripts/install.sh index 9a191a024..65b4f7d7e 100644 --- a/registry/coder-labs/modules/codex/scripts/install.sh +++ b/registry/coder-labs/modules/codex/scripts/install.sh @@ -129,7 +129,7 @@ append_mcp_servers_section() { ARG_CODER_MCP_APP_STATUS_SLUG="" CODER_MCP_AI_AGENTAPI_URL="" else - CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" fi cat << EOF >> "$config_path" @@ -219,7 +219,6 @@ EOF } install_codex -codex --version populate_config_toml add_instruction_prompt_if_exists diff --git a/registry/coder-labs/modules/copilot/main.tf b/registry/coder-labs/modules/copilot/main.tf index 2837961f5..b5093c5ed 100644 --- a/registry/coder-labs/modules/copilot/main.tf +++ b/registry/coder-labs/modules/copilot/main.tf @@ -189,6 +189,12 @@ variable "enable_aibridge_proxy" { } } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + variable "aibridge_proxy_auth_url" { type = string description = "AI Bridge Proxy URL with authentication. Use the proxy_auth_url output from the aibridge-proxy module." @@ -290,6 +296,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash @@ -329,6 +336,7 @@ module "agentapi" { ARG_EXTERNAL_AUTH_ID='${var.external_auth_id}' \ ARG_COPILOT_VERSION='${var.copilot_version}' \ ARG_COPILOT_MODEL='${var.copilot_model}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/coder-labs/modules/copilot/scripts/install.sh b/registry/coder-labs/modules/copilot/scripts/install.sh index 44c480e3a..d424e4e2f 100644 --- a/registry/coder-labs/modules/copilot/scripts/install.sh +++ b/registry/coder-labs/modules/copilot/scripts/install.sh @@ -147,7 +147,7 @@ setup_coder_mcp_server() { set -e export CODER_MCP_APP_STATUS_SLUG="${ARG_MCP_APP_STATUS_SLUG}" -export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" +export CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" export CODER_AGENT_URL="${CODER_AGENT_URL}" export CODER_AGENT_TOKEN="${CODER_AGENT_TOKEN}" @@ -218,7 +218,7 @@ configure_coder_integration() { if [ "$ARG_REPORT_TASKS" = "true" ] && [ -n "$ARG_MCP_APP_STATUS_SLUG" ]; then echo "Configuring Copilot task reporting..." export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" - export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" echo "✓ Coder MCP server configured for task reporting" else echo "Task reporting disabled or no app status slug provided." diff --git a/registry/coder-labs/modules/cursor-cli/main.tf b/registry/coder-labs/modules/cursor-cli/main.tf index 4363f3585..d6ea47b68 100644 --- a/registry/coder-labs/modules/cursor-cli/main.tf +++ b/registry/coder-labs/modules/cursor-cli/main.tf @@ -108,6 +108,12 @@ variable "post_install_script" { default = null } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + locals { app_slug = "cursorcli" install_script = file("${path.module}/scripts/install.sh") @@ -148,6 +154,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash set -o errexit @@ -176,6 +183,7 @@ module "agentapi" { ARG_MODULE_DIR_NAME='${local.module_dir_name}' \ ARG_FOLDER='${var.folder}' \ ARG_CODER_MCP_APP_STATUS_SLUG='${local.app_slug}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/coder-labs/modules/cursor-cli/scripts/install.sh b/registry/coder-labs/modules/cursor-cli/scripts/install.sh index 5477f07dd..d9633aa49 100644 --- a/registry/coder-labs/modules/cursor-cli/scripts/install.sh +++ b/registry/coder-labs/modules/cursor-cli/scripts/install.sh @@ -70,7 +70,7 @@ set -e # --- Set environment variables --- export CODER_MCP_APP_STATUS_SLUG="${ARG_CODER_MCP_APP_STATUS_SLUG}" -export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" +export CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" export CODER_AGENT_URL="${CODER_AGENT_URL}" export CODER_AGENT_TOKEN="${CODER_AGENT_TOKEN}" diff --git a/registry/coder-labs/modules/gemini/main.tf b/registry/coder-labs/modules/gemini/main.tf index dbc81bc79..ee82a4a04 100644 --- a/registry/coder-labs/modules/gemini/main.tf +++ b/registry/coder-labs/modules/gemini/main.tf @@ -126,6 +126,12 @@ variable "enable_yolo_mode" { default = false } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + resource "coder_env" "gemini_api_key" { agent_id = var.agent_id name = "GEMINI_API_KEY" @@ -158,7 +164,7 @@ locals { "enabled": true, "env": { "CODER_MCP_APP_STATUS_SLUG": "${local.app_slug}", - "CODER_MCP_AI_AGENTAPI_URL": "http://localhost:3284" + "CODER_MCP_AI_AGENTAPI_URL": "http://localhost:${var.agentapi_port}" }, "name": "Coder", "timeout": 3000, @@ -193,6 +199,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port install_script = <<-EOT #!/bin/bash set -o errexit @@ -207,6 +214,7 @@ module "agentapi" { ADDITIONAL_EXTENSIONS='${base64encode(replace(var.additional_extensions != null ? var.additional_extensions : "", "'", "'\\''"))}' \ GEMINI_START_DIRECTORY='${var.folder}' \ GEMINI_SYSTEM_PROMPT='${base64encode(var.gemini_system_prompt)}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT start_script = <<-EOT diff --git a/registry/coder-labs/modules/gemini/scripts/install.sh b/registry/coder-labs/modules/gemini/scripts/install.sh index 7b70a6af4..b1953de06 100644 --- a/registry/coder-labs/modules/gemini/scripts/install.sh +++ b/registry/coder-labs/modules/gemini/scripts/install.sh @@ -142,7 +142,7 @@ function add_system_prompt_if_exists() { function configure_mcp() { export CODER_MCP_APP_STATUS_SLUG="gemini" - export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" coder exp mcp configure gemini "${GEMINI_START_DIRECTORY}" } diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf index df7f946f2..2115178e8 100644 --- a/registry/coder-labs/modules/opencode/main.tf +++ b/registry/coder-labs/modules/opencode/main.tf @@ -89,6 +89,12 @@ variable "agentapi_version" { default = "v0.11.2" } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + variable "ai_prompt" { type = string description = "Initial task prompt for OpenCode." @@ -163,6 +169,7 @@ module "agentapi" { module_dir_name = local.module_dir_name install_agentapi = var.install_agentapi agentapi_version = var.agentapi_version + agentapi_port = var.agentapi_port pre_install_script = var.pre_install_script post_install_script = var.post_install_script start_script = <<-EOT @@ -194,6 +201,7 @@ module "agentapi" { ARG_WORKDIR='${local.workdir}' \ ARG_AUTH_JSON='${var.auth_json != null ? base64encode(replace(var.auth_json, "'", "'\\''")) : ""}' \ ARG_OPENCODE_CONFIG='${var.config_json != null ? base64encode(replace(var.config_json, "'", "'\\''")) : ""}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh index 473e5ac49..b74341126 100755 --- a/registry/coder-labs/modules/opencode/scripts/install.sh +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -94,7 +94,7 @@ setup_coder_mcp_server() { # Set environment variables based on task reporting setting echo "Configuring OpenCode task reporting" export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" - export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" echo "Coder integration configured for task reporting" # Add coder MCP server configuration to the JSON file diff --git a/registry/coder-labs/modules/sourcegraph-amp/main.tf b/registry/coder-labs/modules/sourcegraph-amp/main.tf index 13b25ec08..62eaf94b0 100644 --- a/registry/coder-labs/modules/sourcegraph-amp/main.tf +++ b/registry/coder-labs/modules/sourcegraph-amp/main.tf @@ -160,6 +160,12 @@ variable "mcp" { default = null } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + variable "mode" { type = string description = "Set the agent mode (free, rush, smart) — controls the model, system prompt, and tool selection. Default: smart" @@ -192,7 +198,7 @@ locals { "args" = ["exp", "mcp", "server"] "env" = { "CODER_MCP_APP_STATUS_SLUG" = var.report_tasks == true ? local.app_slug : "" - "CODER_MCP_AI_AGENTAPI_URL" = var.report_tasks == true ? "http://localhost:3284" : "" + "CODER_MCP_AI_AGENTAPI_URL" = var.report_tasks == true ? "http://localhost:${var.agentapi_port}" : "" "CODER_AGENT_TOKEN" = data.external.env.result.CODER_AGENT_TOKEN "CODER_AGENT_URL" = data.external.env.result.CODER_AGENT_URL } @@ -237,6 +243,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash set -o errexit diff --git a/registry/coder/modules/aider/main.tf b/registry/coder/modules/aider/main.tf index 70274cb88..93d50d8ae 100644 --- a/registry/coder/modules/aider/main.tf +++ b/registry/coder/modules/aider/main.tf @@ -182,6 +182,11 @@ variable "base_aider_config" { default = null } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} locals { app_slug = "aider" @@ -246,6 +251,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash set -o errexit diff --git a/registry/coder/modules/amazon-q/main.tf b/registry/coder/modules/amazon-q/main.tf index 1fec87da2..f1880fafc 100644 --- a/registry/coder/modules/amazon-q/main.tf +++ b/registry/coder/modules/amazon-q/main.tf @@ -171,6 +171,12 @@ variable "agentapi_chat_based_path" { default = false } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + # Expose status slug to the agent environment resource "coder_env" "status_slug" { agent_id = var.agent_id @@ -231,6 +237,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash @@ -265,6 +272,7 @@ module "agentapi" { ARG_CODER_MCP_APP_STATUS_SLUG='${local.app_slug}' \ ARG_CODER_MCP_INSTRUCTIONS='${base64encode(local.coder_mcp_instructions)}' \ ARG_REPORT_TASKS='${var.report_tasks}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/coder/modules/amazon-q/scripts/install.sh b/registry/coder/modules/amazon-q/scripts/install.sh index f8e43e763..1eda8e3b9 100644 --- a/registry/coder/modules/amazon-q/scripts/install.sh +++ b/registry/coder/modules/amazon-q/scripts/install.sh @@ -134,7 +134,7 @@ function configure_agent() { --agent "$ARG_AGENT_NAME" \ --args "exp,mcp,server,--allowed-tools,coder_report_task,--instructions,'$ARG_CODER_MCP_INSTRUCTIONS_DECODED'" \ --env "CODER_MCP_APP_STATUS_SLUG=${ARG_CODER_MCP_APP_STATUS_SLUG}" \ - --env "CODER_MCP_AI_AGENTAPI_URL=http://localhost:3284" \ + --env "CODER_MCP_AI_AGENTAPI_URL=http://localhost:${ARG_AGENTAPI_PORT:-3284}" \ --env "CODER_AGENT_URL=${CODER_AGENT_URL}" \ --env "CODER_AGENT_TOKEN=${CODER_AGENT_TOKEN}" \ --force || echo "Warning: Failed to add Coder MCP server" diff --git a/registry/coder/modules/claude-code/main.tf b/registry/coder/modules/claude-code/main.tf index ba45d69cc..625ceeaf4 100644 --- a/registry/coder/modules/claude-code/main.tf +++ b/registry/coder/modules/claude-code/main.tf @@ -267,6 +267,12 @@ variable "enable_state_persistence" { default = true } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + resource "coder_env" "claude_code_md_path" { count = var.claude_md_path == "" ? 0 : 1 agent_id = var.agent_id @@ -379,6 +385,7 @@ module "agentapi" { install_agentapi = var.install_agentapi agentapi_version = var.agentapi_version enable_state_persistence = var.enable_state_persistence + agentapi_port = var.agentapi_port pre_install_script = var.pre_install_script post_install_script = var.post_install_script start_script = <<-EOT @@ -423,6 +430,7 @@ module "agentapi" { ARG_MCP='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ ARG_MCP_CONFIG_REMOTE_PATH='${base64encode(jsonencode(var.mcp_config_remote_path))}' \ ARG_ENABLE_AIBRIDGE='${var.enable_aibridge}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /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 0a2ba7033..cf9337ca0 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -228,7 +228,7 @@ function report_tasks() { if [ "$ARG_REPORT_TASKS" = "true" ]; then echo "Configuring Claude Code to report tasks via Coder MCP..." export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" - export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:${ARG_AGENTAPI_PORT:-3284}" coder exp mcp configure claude-code "$ARG_WORKDIR" else configure_standalone_mode diff --git a/registry/coder/modules/goose/main.tf b/registry/coder/modules/goose/main.tf index b7db4f990..3e27a096e 100644 --- a/registry/coder/modules/goose/main.tf +++ b/registry/coder/modules/goose/main.tf @@ -94,6 +94,12 @@ variable "post_install_script" { default = null } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + variable "additional_extensions" { type = string description = "Additional extensions configuration in YAML format to append to the config." @@ -113,7 +119,7 @@ coder: enabled: true envs: CODER_MCP_APP_STATUS_SLUG: ${local.app_slug} - CODER_MCP_AI_AGENTAPI_URL: http://localhost:3284 + CODER_MCP_AI_AGENTAPI_URL: http://localhost:${var.agentapi_port} name: Coder timeout: 3000 type: stdio @@ -158,6 +164,7 @@ module "agentapi" { post_install_script = var.post_install_script start_script = local.start_script folder = local.folder + agentapi_port = var.agentapi_port install_script = <<-EOT #!/bin/bash set -o errexit diff --git a/registry/harleylrn/modules/kiro-cli/main.tf b/registry/harleylrn/modules/kiro-cli/main.tf index b5034b4af..91a6902be 100644 --- a/registry/harleylrn/modules/kiro-cli/main.tf +++ b/registry/harleylrn/modules/kiro-cli/main.tf @@ -171,6 +171,12 @@ variable "agentapi_chat_based_path" { default = false } +variable "agentapi_port" { + type = number + description = "The port for the AgentAPI server." + default = 3284 +} + # Expose status slug to the agent environment resource "coder_env" "status_slug" { agent_id = var.agent_id @@ -232,6 +238,7 @@ module "agentapi" { agentapi_version = var.agentapi_version pre_install_script = var.pre_install_script post_install_script = var.post_install_script + agentapi_port = var.agentapi_port start_script = <<-EOT #!/bin/bash @@ -266,6 +273,7 @@ module "agentapi" { ARG_CODER_MCP_APP_STATUS_SLUG='${local.app_slug}' \ ARG_CODER_MCP_INSTRUCTIONS='${base64encode(local.coder_mcp_instructions)}' \ ARG_REPORT_TASKS='${var.report_tasks}' \ + ARG_AGENTAPI_PORT='${var.agentapi_port}' \ /tmp/install.sh EOT } diff --git a/registry/harleylrn/modules/kiro-cli/scripts/install.sh b/registry/harleylrn/modules/kiro-cli/scripts/install.sh index 5cbbb3fe8..71bf87fad 100644 --- a/registry/harleylrn/modules/kiro-cli/scripts/install.sh +++ b/registry/harleylrn/modules/kiro-cli/scripts/install.sh @@ -134,7 +134,7 @@ function configure_agent() { --agent "$ARG_AGENT_NAME" \ --args "exp,mcp,server,--allowed-tools,coder_report_task,--instructions,'$ARG_CODER_MCP_INSTRUCTIONS_DECODED'" \ --env "CODER_MCP_APP_STATUS_SLUG=${ARG_CODER_MCP_APP_STATUS_SLUG}" \ - --env "CODER_MCP_AI_AGENTAPI_URL=http://localhost:3284" \ + --env "CODER_MCP_AI_AGENTAPI_URL=http://localhost:${ARG_AGENTAPI_PORT:-3284}" \ --env "CODER_AGENT_URL=${CODER_AGENT_URL}" \ --env "CODER_AGENT_TOKEN=${CODER_AGENT_TOKEN}" \ --force || echo "Warning: Failed to add Coder MCP server" diff --git a/registry/stl314159/templates/proxmox-vm/cloud-init.yaml.tftpl b/registry/stl314159/templates/proxmox-vm/cloud-init.yaml.tftpl new file mode 100644 index 000000000..826d95aba --- /dev/null +++ b/registry/stl314159/templates/proxmox-vm/cloud-init.yaml.tftpl @@ -0,0 +1,47 @@ +#cloud-config +hostname: ${hostname} + +users: + - name: coder + groups: sudo + shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + lock_passwd: true + +package_update: true +packages: + - qemu-guest-agent + - curl + - git + - build-essential + - python3 + - python3-pip + - python3-venv + - unzip + - jq + +runcmd: + - systemctl enable qemu-guest-agent + - systemctl start qemu-guest-agent + + # Install Node.js 22.x + - curl -fsSL https://deb.nodesource.com/setup_22.x | bash - + - apt-get install -y nodejs + + # Install GitHub CLI + - curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /usr/share/keyrings/githubcli-archive-keyring.gpg + - echo "deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list + - apt-get update && apt-get install -y gh + +%{ if install_docker == "true" ~} + # Install Docker Engine and Compose + - curl -fsSL https://get.docker.com | sh + - usermod -aG docker coder +%{ endif ~} + + # Bootstrap Coder agent using official init script + - | + echo "${coder_init_script_b64}" | base64 -d > /tmp/coder-init.sh + chmod +x /tmp/coder-init.sh + export CODER_AGENT_TOKEN="${coder_agent_token}" + sudo -u coder --preserve-env=CODER_AGENT_TOKEN /tmp/coder-init.sh diff --git a/registry/stl314159/templates/proxmox-vm/main.tf b/registry/stl314159/templates/proxmox-vm/main.tf new file mode 100644 index 000000000..e85f90c4e --- /dev/null +++ b/registry/stl314159/templates/proxmox-vm/main.tf @@ -0,0 +1,459 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + proxmox = { + source = "bpg/proxmox" + version = ">= 0.78.0" + } + random = { + source = "hashicorp/random" + } + } +} + +provider "coder" {} + +provider "proxmox" { + endpoint = var.proxmox_api_url + api_token = "${var.proxmox_token_id}=${var.proxmox_token_secret}" + insecure = true + + ssh { + username = "terraform" + private_key = var.proxmox_ssh_private_key + + node { + name = "pve01" + address = "10.200.0.36" + } + node { + name = "pve02" + address = "10.200.0.37" + } + node { + name = "pve03" + address = "10.200.0.38" + } + } +} + +# ============================================================================= +# Template variables (set during coder templates push) +# ============================================================================= + +variable "proxmox_api_url" { + type = string +} + +variable "proxmox_token_id" { + type = string + sensitive = true +} + +variable "proxmox_token_secret" { + type = string + sensitive = true +} + +variable "proxmox_ssh_private_key" { + type = string + sensitive = true +} + +# ============================================================================= +# Coder data sources +# ============================================================================= + +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +# ============================================================================= +# Workspace parameters +# ============================================================================= + +data "coder_parameter" "node" { + name = "node" + display_name = "Proxmox Node" + type = "string" + default = "pve01" + mutable = false + order = 1 + option { + name = "pve01" + value = "pve01" + } + option { + name = "pve02" + value = "pve02" + } + option { + name = "pve03" + value = "pve03" + } +} + +data "coder_parameter" "cpu_cores" { + name = "cpu_cores" + display_name = "CPU Cores" + type = "number" + default = 4 + mutable = true + order = 2 +} + +data "coder_parameter" "memory_mb" { + name = "memory_mb" + display_name = "Memory (MB)" + type = "number" + default = 8192 + mutable = true + order = 3 +} + +data "coder_parameter" "disk_size_gb" { + name = "disk_size_gb" + display_name = "Disk Size (GB)" + type = "number" + default = 32 + mutable = true + order = 4 + validation { + min = 10 + max = 100 + monotonic = "increasing" + } +} + +data "coder_parameter" "git_url" { + name = "git_url" + display_name = "Git Repository URL" + type = "string" + default = "" + description = "HTTPS clone URL. Leave blank to skip cloning." + mutable = false + order = 10 +} + +data "coder_parameter" "git_branch" { + name = "git_branch" + display_name = "Git Branch" + type = "string" + default = "" + description = "Branch to clone. Leave blank for the default branch." + mutable = false + order = 11 +} + +data "coder_parameter" "git_folder_name" { + name = "git_folder_name" + display_name = "Folder Name" + type = "string" + default = "" + description = "Destination folder name. Leave blank to use the repository name." + mutable = false + order = 12 +} + +data "coder_parameter" "git_base_dir" { + name = "git_base_dir" + display_name = "Base Directory" + type = "string" + default = "" + description = "Parent directory for the clone. Defaults to $HOME." + mutable = false + order = 13 +} + +data "coder_parameter" "git_depth" { + name = "git_depth" + display_name = "Clone Depth" + type = "number" + default = 0 + description = "Shallow clone depth. 0 for full clone." + mutable = false + order = 14 +} + +data "coder_parameter" "install_docker" { + name = "install_docker" + display_name = "Docker & Compose" + type = "bool" + default = "false" + description = "Install Docker Engine and Docker Compose. The coder user is added to the docker group." + mutable = false + order = 5 +} + +# ============================================================================= +# Locals +# ============================================================================= + +locals { + hostname = lower(data.coder_workspace.me.name) + vm_name = "coder-${lower(data.coder_workspace_owner.me.name)}-${local.hostname}" + repo_name = data.coder_parameter.git_url.value != "" ? (data.coder_parameter.git_folder_name.value != "" ? data.coder_parameter.git_folder_name.value : replace(element(split("/", data.coder_parameter.git_url.value), length(split("/", data.coder_parameter.git_url.value)) - 1), ".git", "")) : "" + git_base = data.coder_parameter.git_base_dir.value != "" ? data.coder_parameter.git_base_dir.value : "/home/coder" + workdir = local.repo_name != "" ? "${local.git_base}/${local.repo_name}" : "/home/coder" +} + +# ============================================================================= +# Coder agent +# ============================================================================= + +resource "coder_agent" "main" { + arch = "amd64" + os = "linux" + dir = local.workdir + + startup_script_behavior = "non-blocking" + + metadata { + display_name = "CPU Usage" + key = "cpu_usage" + script = "coder stat cpu" + interval = 10 + timeout = 1 + order = 1 + } + + metadata { + display_name = "RAM Usage" + key = "ram_usage" + script = "coder stat mem" + interval = 10 + timeout = 1 + order = 2 + } + + metadata { + display_name = "Disk Usage" + key = "disk_usage" + script = "coder stat disk" + interval = 600 + timeout = 30 + order = 3 + } +} + +# ============================================================================= +# Cloud-init snippet (OS-level setup only) +# ============================================================================= + +resource "proxmox_virtual_environment_file" "cloud_init" { + content_type = "snippets" + datastore_id = "ceph-pve" + node_name = data.coder_parameter.node.value + + source_raw { + data = templatefile("${path.module}/cloud-init.yaml.tftpl", { + hostname = local.vm_name + coder_agent_token = coder_agent.main.token + coder_init_script_b64 = base64encode(coder_agent.main.init_script) + install_docker = data.coder_parameter.install_docker.value + }) + file_name = "${local.vm_name}.yaml" + } +} + +# ============================================================================= +# Proxmox VM (persists across stop/start, destroyed on workspace delete) +# ============================================================================= + +resource "proxmox_virtual_environment_vm" "agent" { + name = local.vm_name + node_name = data.coder_parameter.node.value + pool_id = "coder" + + clone { + node_name = "pve01" + vm_id = 101 + full = true + retries = 5 + } + + cpu { + cores = data.coder_parameter.cpu_cores.value + sockets = 1 + type = "host" + } + + memory { + dedicated = data.coder_parameter.memory_mb.value + } + + agent { + enabled = true + } + + scsi_hardware = "virtio-scsi-pci" + boot_order = ["scsi0", "ide2"] + + disk { + interface = "scsi0" + datastore_id = "local-lvm" + size = data.coder_parameter.disk_size_gb.value + discard = "on" + ssd = true + } + + network_device { + bridge = "vmbrDMZ" + model = "virtio" + } + + vga { + type = "serial0" + } + + serial_device { + device = "socket" + } + + initialization { + type = "nocloud" + datastore_id = "local-lvm" + + user_data_file_id = proxmox_virtual_environment_file.cloud_init.id + + ip_config { + ipv4 { + address = "dhcp" + } + } + } + + tags = ["coder", "workspace", local.vm_name] + + on_boot = true + started = data.coder_workspace.me.start_count > 0 + + lifecycle { + ignore_changes = [ + disk[0].size, + ] + } + + depends_on = [proxmox_virtual_environment_file.cloud_init] +} + +# ============================================================================= +# Modules — Workspace utilities +# ============================================================================= + +module "coder-login" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/coder-login/coder" + version = "1.1.1" + agent_id = coder_agent.main.id +} + +module "git-config" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/git-config/coder" + version = "1.0.33" + agent_id = coder_agent.main.id +} + +module "git-commit-signing" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/git-commit-signing/coder" + version = "1.0.32" + agent_id = coder_agent.main.id +} + +module "dotfiles" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/dotfiles/coder" + version = "1.4.1" + agent_id = coder_agent.main.id +} + +module "personalize" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/personalize/coder" + version = "1.0.32" + agent_id = coder_agent.main.id +} + +# ============================================================================= +# Modules — Git +# ============================================================================= + +module "git-clone" { + count = data.coder_parameter.git_url.value != "" ? data.coder_workspace.me.start_count : 0 + source = "registry.coder.com/coder/git-clone/coder" + version = "1.2.3" + agent_id = coder_agent.main.id + url = data.coder_parameter.git_url.value + base_dir = data.coder_parameter.git_base_dir.value != "" ? data.coder_parameter.git_base_dir.value : null + branch_name = data.coder_parameter.git_branch.value != "" ? data.coder_parameter.git_branch.value : null + folder_name = data.coder_parameter.git_folder_name.value != "" ? data.coder_parameter.git_folder_name.value : null + depth = data.coder_parameter.git_depth.value +} + +# ============================================================================= +# Modules — IDEs and file access +# ============================================================================= + +module "code-server" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/code-server/coder" + version = "1.4.4" + agent_id = coder_agent.main.id + folder = local.workdir +} + +module "cursor" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/cursor/coder" + version = "1.4.1" + agent_id = coder_agent.main.id + folder = local.workdir +} + +module "filebrowser" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/filebrowser/coder" + version = "1.1.4" + agent_id = coder_agent.main.id +} + +# ============================================================================= +# Modules — Coding Agents (all installed, configure at runtime) +# ============================================================================= + +module "claude-code" { + count = data.coder_workspace.me.start_count + source = "git::https://github.com/stl314159/coder-registry.git//registry/coder/modules/claude-code?ref=main" + agent_id = coder_agent.main.id + workdir = local.workdir + permission_mode = "bypassPermissions" +} + +resource "random_integer" "codex_port" { + min = 3300 + max = 3399 +} + +module "codex" { + count = data.coder_workspace.me.start_count + source = "git::https://github.com/stl314159/coder-registry.git//registry/coder-labs/modules/codex?ref=main" + agent_id = coder_agent.main.id + workdir = local.workdir + agentapi_port = random_integer.codex_port.result +} + +resource "random_integer" "opencode_port" { + min = 3400 + max = 3499 +} + +module "opencode" { + count = data.coder_workspace.me.start_count + source = "git::https://github.com/stl314159/coder-registry.git//registry/coder-labs/modules/opencode?ref=main" + agent_id = coder_agent.main.id + workdir = local.workdir + agentapi_port = random_integer.opencode_port.result +}