Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

feat: add claude code and Goose module #420

Merged
merged 34 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .icons/claude.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions .icons/goose.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 112 additions & 0 deletions claude-code/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
display_name: Claude Code
description: Run Claude Code in your workspace
icon: ../.icons/claude.svg
maintainer_github: coder
verified: true
tags: [agent, claude-code]
---

# Claude Code

Run the [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) agent in your workspace to generate code and perform tasks.

```tf
module "claude-code" {
source = "registry.coder.com/modules/claude-code/coder"
version = "1.0.31"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_claude_code = true
claude_code_version = "latest"
}
```

### Prerequisites

- Node.js and npm must be installed in your workspace to install Claude Code
- `screen` must be installed in your workspace to run Claude Code in the background
- You must add the [Coder Login](https://registry.coder.com/modules/coder-login) module to your template

The `codercom/oss-dogfood:latest` container image can be used for testing on container-based workspaces.

## Examples

### Run in the background and report tasks (Experimental)

> This functionality is in early access and subject to change. Do not run in
> production as it is unstable. Instead, deploy these changes into a demo or
> staging environment.
>
> Join our [Discord channel](https://discord.gg/coder) or
> [contact us](https://coder.com/contact) to get help or share feedback.

Your workspace must have `screen` installed to use this.

```tf
variable "anthropic_api_key" {
type = string
description = "The Anthropic API key"
sensitive = true
}

module "coder-login" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/coder-login/coder"
version = "1.0.31"
agent_id = coder_agent.example.id
}

data "coder_parameter" "ai_prompt" {
type = "string"
name = "AI Prompt"
default = ""
description = "Write a prompt for Claude Code"
mutable = true
}

# Set the prompt and system prompt for Claude Code via environment variables
resource "coder_agent" "main" {
# ...
env = {
CODER_MCP_CLAUDE_API_KEY = var.anthropic_api_key # or use a coder_parameter
CODER_MCP_CLAUDE_TASK_PROMPT = data.coder_parameter.ai_prompt.value
CODER_MCP_APP_STATUS_SLUG = "claude-code"
CODER_MCP_CLAUDE_SYSTEM_PROMPT = <<-EOT
You are a helpful assistant that can help with code.
EOT
}
}

module "claude-code" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/claude-code/coder"
version = "1.0.31"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_claude_code = true
claude_code_version = "0.2.57"

# Enable experimental features
experiment_use_screen = true
experiment_report_tasks = true
}
```

## Run standalone

Run Claude Code as a standalone app in your workspace. This will install Claude Code and run it directly without using screen or any task reporting to the Coder UI.

```tf
module "claude-code" {
source = "registry.coder.com/modules/claude-code/coder"
version = "1.0.31"
agent_id = coder_agent.example.id
folder = "/home/coder"
install_claude_code = true
claude_code_version = "latest"

# Icon is not available in Coder v2.20 and below, so we'll use a custom icon URL
icon = "https://registry.npmmirror.com/@lobehub/icons-static-png/1.24.0/files/dark/claude-color.png"
}
```
170 changes: 170 additions & 0 deletions claude-code/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
terraform {
required_version = ">= 1.0"

required_providers {
coder = {
source = "coder/coder"
version = ">= 0.17"
}
}
}

variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}

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 "icon" {
type = string
description = "The icon to use for the app."
default = "/icon/claude.svg"
}

variable "folder" {
type = string
description = "The folder to run Claude Code in."
default = "/home/coder"
}

variable "install_claude_code" {
type = bool
description = "Whether to install Claude Code."
default = true
}

variable "claude_code_version" {
type = string
description = "The version of Claude Code to install."
default = "latest"
}

variable "experiment_use_screen" {
type = bool
description = "Whether to use screen for running Claude Code in the background."
default = false
}

variable "experiment_report_tasks" {
type = bool
description = "Whether to enable task reporting."
default = false
}

# Install and Initialize Claude Code
resource "coder_script" "claude_code" {
agent_id = var.agent_id
display_name = "Claude Code"
icon = var.icon
script = <<-EOT
#!/bin/bash
set -e
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Install Claude Code if enabled
if [ "${var.install_claude_code}" = "true" ]; then
if ! command_exists npm; then
echo "Error: npm is not installed. Please install Node.js and npm first."
exit 1
fi
echo "Installing Claude Code..."
npm install -g @anthropic-ai/claude-code@${var.claude_code_version}
fi
if [ "${var.experiment_report_tasks}" = "true" ]; then
echo "Configuring Claude Code to report tasks via Coder MCP..."
coder exp mcp configure claude-code ${var.folder}
fi
# Run with screen if enabled
if [ "${var.experiment_use_screen}" = "true" ]; then
echo "Running Claude Code in the background..."
# Check if screen is installed
if ! command_exists screen; then
echo "Error: screen is not installed. Please install screen manually."
exit 1
fi
touch "$HOME/.claude-code.log"
# Ensure the screenrc exists
if [ ! -f "$HOME/.screenrc" ]; then
echo "Creating ~/.screenrc and adding multiuser settings..." | tee -a "$HOME/.claude-code.log"
echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc"
fi
if ! grep -q "^multiuser on$" "$HOME/.screenrc"; then
echo "Adding 'multiuser on' to ~/.screenrc..." | tee -a "$HOME/.claude-code.log"
echo "multiuser on" >> "$HOME/.screenrc"
fi
if ! grep -q "^acladd $(whoami)$" "$HOME/.screenrc"; then
echo "Adding 'acladd $(whoami)' to ~/.screenrc..." | tee -a "$HOME/.claude-code.log"
echo "acladd $(whoami)" >> "$HOME/.screenrc"
fi
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
screen -U -dmS claude-code bash -c '
cd ${var.folder}
claude --dangerously-skip-permissions | tee -a "$HOME/.claude-code.log"
exec bash
'
# Extremely hacky way to send the prompt to the screen session
# This will be fixed in the future, but `claude` was not sending MCP
# tasks when an initial prompt is provided.
screen -S claude-code -X stuff "$CODER_MCP_CLAUDE_TASK_PROMPT"
sleep 5
screen -S claude-code -X stuff "^M"
else
# Check if claude is installed before running
if ! command_exists claude; then
echo "Error: Claude Code is not installed. Please enable install_claude_code or install it manually."
exit 1
fi
fi
EOT
run_on_start = true
}

resource "coder_app" "claude_code" {
slug = "claude-code"
display_name = "Claude Code"
agent_id = var.agent_id
command = <<-EOT
#!/bin/bash
set -e
if [ "${var.experiment_use_screen}" = "true" ]; then
if screen -list | grep -q "claude-code"; then
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
echo "Attaching to existing Claude Code session." | tee -a "$HOME/.claude-code.log"
screen -xRR claude-code
else
echo "Starting a new Claude Code session." | tee -a "$HOME/.claude-code.log"
screen -S claude-code bash -c 'export LANG=en_US.UTF-8; export LC_ALL=en_US.UTF-8; claude --dangerously-skip-permissions | tee -a "$HOME/.claude-code.log"; exec bash'
fi
else
cd ${var.folder}
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
claude
fi
EOT
icon = var.icon
}
8 changes: 4 additions & 4 deletions filebrowser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ A file browser for your workspace.
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.31"
agent_id = coder_agent.example.id
}
```
Expand All @@ -30,7 +30,7 @@ module "filebrowser" {
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.31"
agent_id = coder_agent.example.id
folder = "/home/coder/project"
}
Expand All @@ -42,7 +42,7 @@ module "filebrowser" {
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.31"
agent_id = coder_agent.example.id
database_path = ".config/filebrowser.db"
}
Expand All @@ -54,7 +54,7 @@ module "filebrowser" {
module "filebrowser" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/modules/filebrowser/coder"
version = "1.0.29"
version = "1.0.31"
agent_id = coder_agent.example.id
agent_name = "main"
subdomain = false
Expand Down
Loading