diff --git a/registry/coder/modules/aider/README.md b/registry/coder/modules/aider/README.md
index 6380fd40b..0652fe2cd 100644
--- a/registry/coder/modules/aider/README.md
+++ b/registry/coder/modules/aider/README.md
@@ -1,6 +1,6 @@
---
display_name: Aider
-description: Run Aider AI pair programming in your workspace
+description: Install and configure Aider AI pair programming in your workspace
icon: ../../../../.icons/aider.svg
verified: true
tags: [agent, ai, aider]
@@ -8,61 +8,44 @@ tags: [agent, ai, aider]
# Aider
-Run [Aider](https://aider.chat) AI pair programming in your workspace. This module installs Aider with AgentAPI for seamless Coder Tasks Support.
+Install and configure [Aider](https://aider.chat) AI pair programming in your workspace. Starting Aider is left to the caller (template command, IDE launcher, or a custom `coder_script`).
```tf
-variable "api_key" {
- type = string
- description = "API key"
- sensitive = true
+locals {
+ aider_workdir = "/home/coder/project"
}
module "aider" {
source = "registry.coder.com/coder/aider/coder"
- version = "2.0.1"
+ version = "2.0.2"
agent_id = coder_agent.main.id
- api_key = var.api_key
+ api_key = xxxx-xxxx-xxxx-xxxx"
ai_provider = "google"
model = "gemini"
}
+
+resource "coder_app" "aider" {
+ agent_id = coder_agent.main.id
+ slug = "aider"
+ display_name = "Aider"
+ icon = "/icon/aider.svg"
+ open_in = "slim-window"
+ command = <<-EOT
+ #!/bin/bash
+ set -e
+ cd ${local.aider_workdir}
+ aider --model module.aider.model
+ EOT
+}
```
+> [!WARNING]
+> If upgrading from v2.x.x of this module: v3 is a major refactor that drops support for [Coder Tasks](https://coder.com/docs/ai-coder/tasks). We plan to add those back in a follow-up. Keep using v2.x.x if you depend on them.
+
## Prerequisites
- pipx is automatically installed if not already available
-## Usage Example
-
-```tf
-data "coder_parameter" "ai_prompt" {
- name = "AI Prompt"
- description = "Write an initial prompt for Aider to work on."
- type = "string"
- default = ""
- mutable = true
-}
-
-variable "gemini_api_key" {
- type = string
- description = "Gemini API key"
- sensitive = true
-}
-
-module "aider" {
- source = "registry.coder.com/coder/aider/coder"
- version = "2.0.1"
- agent_id = coder_agent.main.id
- api_key = var.gemini_api_key
- install_aider = true
- workdir = "/home/coder"
- ai_provider = "google"
- model = "gemini"
- install_agentapi = true
- ai_prompt = data.coder_parameter.ai_prompt.value
- system_prompt = "..."
-}
-```
-
### Using a custom provider
```tf
@@ -75,12 +58,12 @@ variable "custom_api_key" {
module "aider" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/aider/coder"
- version = "2.0.1"
+ version = "2.0.2"
agent_id = coder_agent.main.id
workdir = "/home/coder"
ai_provider = "custom"
- custom_env_var_name = "MY_CUSTOM_API_KEY"
- model = "custom-model"
+ custom_env_var_name = "OPENROUTER_API_KEY"
+ model = "openrouter/anthropic/claude-3-haiku"
api_key = var.custom_api_key
}
```
@@ -105,11 +88,8 @@ For a complete and up-to-date list of supported aliases and models, please refer
## Troubleshooting
- If `aider` is not found, ensure `install_aider = true` and your API key is valid
-- Logs are written under `/home/coder/.aider-module/` (`install.log`, `agentapi-start.log`) for debugging
-- If AgentAPI fails to start, verify that your container has network access and executable permissions for the scripts
+- Logs are written under `.coder-modules/coder/aider/logs/install.log` (`install.log`) for debugging
## References
- [Aider Documentation](https://aider.chat/docs)
-- [AgentAPI Documentation](https://github.com/coder/agentapi)
-- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents)
diff --git a/registry/coder/modules/aider/main.test.ts b/registry/coder/modules/aider/main.test.ts
index c0aa51df1..814d2e7a6 100644
--- a/registry/coder/modules/aider/main.test.ts
+++ b/registry/coder/modules/aider/main.test.ts
@@ -83,38 +83,6 @@ describe("Aider", async () => {
await expectAgentAPIStarted(id);
});
- test("api-key", async () => {
- const apiKey = "test-api-key-123";
- const { id } = await setup({
- moduleVariables: {
- api_key: apiKey,
- model: "gemini",
- },
- });
- await execModuleScript(id);
- const resp = await readFileContainer(
- id,
- "/home/coder/.aider-module/agentapi-start.log",
- );
- expect(resp).toContain("API key provided!");
- });
-
- test("custom-folder", async () => {
- const workdir = "/tmp/aider-test";
- const { id } = await setup({
- moduleVariables: {
- workdir,
- model: "gemini",
- },
- });
- await execModuleScript(id);
- const resp = await readFileContainer(
- id,
- "/home/coder/.aider-module/install.log",
- );
- expect(resp).toContain(workdir);
- });
-
test("pre-post-install-scripts", async () => {
const { id } = await setup({
moduleVariables: {
@@ -126,12 +94,12 @@ describe("Aider", async () => {
await execModuleScript(id);
const preLog = await readFileContainer(
id,
- "/home/coder/.aider-module/pre_install.log",
+ "/home/coder/.coder-modules/coder/aider/logs/pre_install.log",
);
expect(preLog).toContain("pre-install-script");
const postLog = await readFileContainer(
id,
- "/home/coder/.aider-module/post_install.log",
+ "/home/coder/.coder-modules/coder/aider/logs/post_install.log",
);
expect(postLog).toContain("post-install-script");
});
diff --git a/registry/coder/modules/aider/main.tf b/registry/coder/modules/aider/main.tf
index 70274cb88..d7d48c642 100644
--- a/registry/coder/modules/aider/main.tf
+++ b/registry/coder/modules/aider/main.tf
@@ -18,18 +18,6 @@ data "coder_workspace" "me" {}
data "coder_workspace_owner" "me" {}
-variable "order" {
- type = number
- description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)."
- default = null
-}
-
-variable "group" {
- type = string
- description = "The name of a group that this app belongs to."
- default = null
-}
-
variable "icon" {
type = string
description = "The icon to use for the app."
@@ -42,36 +30,6 @@ variable "workdir" {
default = "/home/coder"
}
-variable "report_tasks" {
- type = bool
- description = "Whether to enable task reporting to Coder UI via AgentAPI"
- default = false
-}
-
-variable "subdomain" {
- type = bool
- description = "Whether to use a subdomain for AgentAPI."
- default = false
-}
-
-variable "cli_app" {
- type = bool
- description = "Whether to create a CLI app for Aider"
- default = false
-}
-
-variable "web_app_display_name" {
- type = string
- description = "Display name for the web app"
- default = "Aider"
-}
-
-variable "cli_app_display_name" {
- type = string
- description = "Display name for the CLI app"
- default = "Aider CLI"
-}
-
variable "pre_install_script" {
type = string
description = "Custom script to run before installing Aider."
@@ -84,24 +42,6 @@ variable "post_install_script" {
default = null
}
-variable "install_agentapi" {
- type = bool
- description = "Whether to install AgentAPI."
- default = true
-}
-
-variable "agentapi_version" {
- type = string
- description = "The version of AgentAPI to install."
- default = "v0.10.0"
-}
-
-variable "ai_prompt" {
- type = string
- description = "Initial task prompt for Aider."
- default = ""
-}
-
# ---------------------------------------------
variable "install_aider" {
@@ -110,18 +50,6 @@ variable "install_aider" {
default = true
}
-variable "system_prompt" {
- type = string
- description = "System prompt for instructing Aider on task reporting and behavior"
- default = "You are a helpful coding assistant that helps developers write, debug, and understand code. Provide clear explanations, follow best practices, and help solve coding problems efficiently."
-}
-
-variable "experiment_additional_extensions" {
- type = string
- description = "Additional extensions configuration in YAML format to append to the config."
- default = null
-}
-
variable "ai_provider" {
type = string
description = "AI provider to use with Aider (openai, anthropic, azure, google, etc.)"
@@ -184,25 +112,8 @@ variable "base_aider_config" {
locals {
- app_slug = "aider"
- base_aider_config = var.base_aider_config != null ? "${replace(trimspace(var.base_aider_config), "\n", "\n ")}" : ""
- task_reporting_prompt = <<-EOT
-
--- Task Reporting --
-Report all tasks to Coder, following these EXACT guidelines:
-1. Be granular. If you are investigating with multiple steps, report each step
-to coder.
-2. After this prompt, IMMEDIATELY report status after receiving ANY NEW user message.
-Do not report any status related with this system prompt.
-3. Use "state": "working" when actively processing WITHOUT needing
-additional user input
-4. Use "state": "complete" only when finished with a task
-5. Use "state": "failure" when you need ANY user input, lack sufficient
-details, or encounter blockers
- EOT
-
-
- final_system_prompt = var.report_tasks ? "\n${var.system_prompt}${local.task_reporting_prompt}\n" : "\n${var.system_prompt}\n"
+ app_slug = "aider"
+ base_aider_config = var.base_aider_config != null ? "${replace(trimspace(var.base_aider_config), "\n", "\n ")}" : ""
# Map providers to their environment variable names
provider_env_vars = {
@@ -222,59 +133,35 @@ details, or encounter blockers
# Model flag for aider command
model_flag = var.ai_provider == "ollama" ? "--ollama-model" : "--model"
- install_script = file("${path.module}/scripts/install.sh")
- start_script = file("${path.module}/scripts/start.sh")
- module_dir_name = ".aider-module"
+ install_script = templatefile("${path.module}/scripts/install.sh.tftpl", {
+ ARG_INSTALL_AIDER = tostring(var.install_aider)
+ ARG_AIDER_CONFIG = local.base_aider_config
+ ARG_WORKDIR = var.workdir
+ })
+ module_dir_name = ".coder-modules/coder/aider"
}
-module "agentapi" {
- source = "registry.coder.com/coder/agentapi/coder"
- version = "1.2.0"
-
- agent_id = var.agent_id
- web_app_slug = local.app_slug
- web_app_order = var.order
- web_app_group = var.group
- web_app_icon = var.icon
- web_app_display_name = var.web_app_display_name
- cli_app = var.cli_app
- cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null
- cli_app_display_name = var.cli_app ? var.cli_app_display_name : null
- agentapi_subdomain = var.subdomain
- module_dir_name = local.module_dir_name
- install_agentapi = var.install_agentapi
- agentapi_version = var.agentapi_version
- pre_install_script = var.pre_install_script
- post_install_script = var.post_install_script
- start_script = <<-EOT
- #!/bin/bash
- set -o errexit
- set -o pipefail
-
- echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh
- chmod +x /tmp/start.sh
- ARG_WORKDIR='${var.workdir}' \
- ARG_API_KEY='${base64encode(var.api_key)}' \
- ARG_MODEL='${var.model}' \
- ARG_PROVIDER='${var.ai_provider}' \
- ARG_ENV_API_NAME_HOLDER='${local.env_var_name}' \
- ARG_SYSTEM_PROMPT='${base64encode(local.final_system_prompt)}' \
- ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \
- /tmp/start.sh
- EOT
+resource "coder_env" "aider_api_key" {
+ count = var.api_key != "" ? 1 : 0
+ agent_id = var.agent_id
+ name = local.env_var_name
+ value = var.api_key
+}
- install_script = <<-EOT
- #!/bin/bash
- set -o errexit
- set -o pipefail
+module "coder_utils" {
+ source = "registry.coder.com/coder/coder-utils/coder"
+ version = "0.0.1"
- echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
- chmod +x /tmp/install.sh
- ARG_WORKDIR='${var.workdir}' \
- ARG_INSTALL_AIDER='${var.install_aider}' \
- ARG_REPORT_TASKS='${var.report_tasks}' \
- ARG_AIDER_CONFIG="$(echo -n '${base64encode(local.base_aider_config)}' | base64 -d)" \
- /tmp/install.sh
- EOT
+ agent_id = var.agent_id
+ module_directory = "$HOME/${local.module_dir_name}"
+ display_name_prefix = "Aider"
+ icon = var.icon
+ pre_install_script = var.pre_install_script
+ post_install_script = var.post_install_script
+ install_script = local.install_script
}
+output "scripts" {
+ description = "Ordered list of coder exp sync names for the coder_script resources this module actually creates, in run order (pre_install, install, post_install). Scripts that were not configured are absent from the list."
+ value = module.coder_utils.scripts
+}
\ No newline at end of file
diff --git a/registry/coder/modules/aider/main.tftest.hcl b/registry/coder/modules/aider/main.tftest.hcl
index 281bde866..6eace2591 100644
--- a/registry/coder/modules/aider/main.tftest.hcl
+++ b/registry/coder/modules/aider/main.tftest.hcl
@@ -21,16 +21,6 @@ run "test_aider_basic" {
condition = var.install_aider == true
error_message = "install_aider should default to true"
}
-
- assert {
- condition = var.install_agentapi == true
- error_message = "install_agentapi should default to true"
- }
-
- assert {
- condition = var.report_tasks == false
- error_message = "report_tasks should default to false"
- }
}
run "test_with_api_key" {
@@ -55,14 +45,10 @@ run "test_custom_options" {
variables {
agent_id = "test-agent-789"
workdir = "/home/coder/custom"
- order = 5
- group = "development"
icon = "/icon/custom.svg"
model = "4o"
ai_prompt = "Help me write better code"
install_aider = false
- install_agentapi = false
- agentapi_version = "v0.10.0"
api_key = ""
base_aider_config = "read:\n - CONVENTIONS.md"
}
@@ -72,11 +58,6 @@ run "test_custom_options" {
error_message = "Order variable should be set to 5"
}
- assert {
- condition = var.group == "development"
- error_message = "Group variable should be set to 'development'"
- }
-
assert {
condition = var.icon == "/icon/custom.svg"
error_message = "Icon variable should be set to custom icon"
@@ -96,16 +77,6 @@ run "test_custom_options" {
condition = var.install_aider == false
error_message = "install_aider should be set to false"
}
-
- assert {
- condition = var.install_agentapi == false
- error_message = "install_agentapi should be set to false"
- }
-
- assert {
- condition = var.agentapi_version == "v0.10.0"
- error_message = "AgentAPI version should be set to 'v0.10.0'"
- }
}
run "test_with_scripts" {
diff --git a/registry/coder/modules/aider/scripts/install.sh b/registry/coder/modules/aider/scripts/install.sh.tftpl
similarity index 65%
rename from registry/coder/modules/aider/scripts/install.sh
rename to registry/coder/modules/aider/scripts/install.sh.tftpl
index b2244aa01..5d7179d5b 100644
--- a/registry/coder/modules/aider/scripts/install.sh
+++ b/registry/coder/modules/aider/scripts/install.sh.tftpl
@@ -7,13 +7,14 @@ command_exists() {
}
# Inputs
-ARG_WORKDIR=${ARG_WORKDIR:-/home/coder}
-ARG_INSTALL_AIDER=${ARG_INSTALL_AIDER:-true}
-ARG_AIDER_CONFIG=${ARG_AIDER_CONFIG:-}
+ARG_WORKDIR='${ARG_WORKDIR}'
+ARG_INSTALL_AIDER='${ARG_INSTALL_AIDER}'
+ARG_AIDER_CONFIG='${ARG_AIDER_CONFIG}'
echo "--------------------------------"
-echo "Install flag: $ARG_INSTALL_AIDER"
-echo "Workspace: $ARG_WORKDIR"
+printf "ARG_WORKDIR: %s\n" "$${ARG_WORKDIR}"
+printf "ARG_INSTALL_AIDER: %s\n" "$${ARG_INSTALL_AIDER}"
+printf "ARG_AIDER_CONFIG: %s\n" "$${ARG_AIDER_CONFIG}"
echo "--------------------------------"
function install_aider() {
@@ -21,8 +22,8 @@ function install_aider() {
sudo apt-get install -y pipx
echo "pipx installed!"
pipx ensurepath
- mkdir -p "$ARG_WORKDIR/.local/bin"
- export PATH="$HOME/.local/bin:$ARG_WORKDIR/.local/bin:$PATH"
+ mkdir -p "$${ARG_WORKDIR}/.local/bin"
+ export PATH="$HOME/.local/bin:$${ARG_WORKDIR}/.local/bin:$PATH"
if ! command_exists aider; then
echo "Installing Aider via pipx..."
@@ -33,12 +34,12 @@ function install_aider() {
}
function configure_aider_settings() {
- if [ -n "${ARG_AIDER_CONFIG}" ]; then
+ if [ -n "$${ARG_AIDER_CONFIG}" ]; then
echo "Configuring Aider environment variables and model"
mkdir -p "$HOME/.config/aider"
- echo "$ARG_AIDER_CONFIG" > "$HOME/.config/aider/.aider.conf.yml"
+ echo "$${ARG_AIDER_CONFIG}" > "$HOME/.config/aider/.aider.conf.yml"
echo "Aider config created at $HOME/.config/aider/.aider.conf.yml"
else
printf "No Aider environment variables or model configured\n"
diff --git a/registry/coder/modules/aider/scripts/start.sh b/registry/coder/modules/aider/scripts/start.sh
deleted file mode 100644
index 1bd18ffa6..000000000
--- a/registry/coder/modules/aider/scripts/start.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-set -euo pipefail
-
-# Ensure pipx-installed apps are in PATH
-export PATH="$HOME/.local/bin:$PATH"
-
-ARG_WORKDIR=${ARG_WORKDIR:-/home/coder}
-ARG_API_KEY=$(echo -n "${ARG_API_KEY:-}" | base64 -d)
-ARG_SYSTEM_PROMPT=$(echo -n "${ARG_SYSTEM_PROMPT:-}" | base64 -d 2> /dev/null || echo "")
-ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d 2> /dev/null || echo "")
-ARG_MODEL=${ARG_MODEL:-}
-ARG_PROVIDER=${ARG_PROVIDER:-}
-ARG_ENV_API_NAME_HOLDER=${ARG_ENV_API_NAME_HOLDER:-}
-
-echo "--------------------------------"
-echo "Provider: $ARG_PROVIDER"
-echo "Model: $ARG_MODEL"
-echo "--------------------------------"
-
-if [ -n "$ARG_API_KEY" ]; then
- printf "API key provided!\n"
- export $ARG_ENV_API_NAME_HOLDER=$ARG_API_KEY
-else
- printf "API key not provided.\n"
-fi
-
-build_initial_prompt() {
- local initial_prompt=""
- if [ -n "$ARG_AI_PROMPT" ]; then
- if [ -n "$ARG_SYSTEM_PROMPT" ]; then
- initial_prompt="$ARG_SYSTEM_PROMPT $ARG_AI_PROMPT"
- else
- initial_prompt="$ARG_AI_PROMPT"
- fi
- fi
- echo "$initial_prompt"
-}
-
-start_agentapi() {
- echo "Starting in directory: $ARG_WORKDIR"
- cd "$ARG_WORKDIR"
-
- local initial_prompt
- initial_prompt=$(build_initial_prompt)
- if [ -n "$initial_prompt" ]; then
- echo "Starting agentapi with initial prompt"
- agentapi server -I="$initial_prompt" --type aider --term-width=67 --term-height=1190 -- aider --model $ARG_MODEL --yes-always
- else
- agentapi server --term-width=67 --term-height=1190 -- aider --model $ARG_MODEL --yes-always
- fi
-}
-
-# TODO: Implement MCP server for coder when Aider support MCP servers.
-
-start_agentapi