|
| 1 | +terraform { |
| 2 | +required_providers { |
| 3 | +coder={ |
| 4 | + source="coder/coder" |
| 5 | + version="2.7.0" |
| 6 | + } |
| 7 | +docker={ |
| 8 | + source="kreuzwerker/docker" |
| 9 | + } |
| 10 | + } |
| 11 | +} |
| 12 | + |
| 13 | +data"coder_parameter""ai_prompt" { |
| 14 | +type="string" |
| 15 | +name="AI Prompt" |
| 16 | +default="" |
| 17 | +description="Write a prompt for Claude Code" |
| 18 | +mutable=true |
| 19 | +} |
| 20 | + |
| 21 | +module"claude-code" { |
| 22 | +source="registry.coder.com/modules/claude-code/coder" |
| 23 | +agent_id=coder_agent.main.id |
| 24 | +folder="/home/coder" |
| 25 | +install_claude_code=true |
| 26 | +claude_code_version="0.2.74" |
| 27 | +agentapi_version="v0.2.3" |
| 28 | + |
| 29 | +# experiment_pre_install_script = <<-EOT |
| 30 | +# gh auth setup-git |
| 31 | +# EOT |
| 32 | + |
| 33 | +# experiment_post_install_script = <<-EOT |
| 34 | +# npm i -g @executeautomation/playwright-mcp-server@1.0.1 @wonderwhy-er/desktop-commander@0.1.19 |
| 35 | + |
| 36 | +# claude mcp add playwright playwright-mcp-server |
| 37 | +# claude mcp add desktop-commander desktop-commander |
| 38 | + |
| 39 | +# cd $(dirname $(which playwright-mcp-server)) |
| 40 | +# cd $(dirname $(readlink playwright-mcp-server)) |
| 41 | +# sudo sed -i 's/headless = false/headless = true/g' toolHandler.js |
| 42 | +# EOT |
| 43 | + |
| 44 | + |
| 45 | +# Icon is not available in Coder v2.20 and below, so we'll use a custom icon URL |
| 46 | +icon="https://uxwing.com/wp-content/themes/uxwing/download/brands-and-social-media/claude-ai-icon.png" |
| 47 | +# Enable experimental features |
| 48 | +# experiment_use_screen = true |
| 49 | +experiment_report_tasks=true |
| 50 | +} |
| 51 | + |
| 52 | + |
| 53 | +locals { |
| 54 | +username=data.coder_workspace_owner.me.name |
| 55 | +} |
| 56 | + |
| 57 | +variable"docker_socket" { |
| 58 | +default="" |
| 59 | +description="(Optional) Docker socket URI" |
| 60 | +type=string |
| 61 | +} |
| 62 | + |
| 63 | +provider"docker" { |
| 64 | +# Defaulting to null if the variable is an empty string lets us have an optional variable without having to set our own default |
| 65 | +host=var.docker_socket!=""? var.docker_socket:null |
| 66 | +} |
| 67 | + |
| 68 | +data"coder_provisioner""me" {} |
| 69 | +data"coder_workspace""me" {} |
| 70 | +data"coder_workspace_owner""me" {} |
| 71 | + |
| 72 | +resource"coder_agent""main" { |
| 73 | +arch=data.coder_provisioner.me.arch |
| 74 | +os="linux" |
| 75 | +startup_script=<<-EOT |
| 76 | + set -e |
| 77 | +
|
| 78 | + # Prepare user home with default files on first start. |
| 79 | + if [ ! -f ~/.init_done ]; then |
| 80 | + cp -rT /etc/skel ~ |
| 81 | + touch ~/.init_done |
| 82 | + fi |
| 83 | +
|
| 84 | + # Add any commands that should be executed at workspace startup (e.g install requirements, start a program, etc) here |
| 85 | + EOT |
| 86 | + |
| 87 | +# These environment variables allow you to make Git commits right away after creating a |
| 88 | +# workspace. Note that they take precedence over configuration defined in ~/.gitconfig! |
| 89 | +# You can remove this block if you'd prefer to configure Git manually or using |
| 90 | +# dotfiles. (see docs/dotfiles.md) |
| 91 | +env={ |
| 92 | + GIT_AUTHOR_NAME=coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) |
| 93 | + GIT_AUTHOR_EMAIL="${data.coder_workspace_owner.me.email}" |
| 94 | + GIT_COMMITTER_NAME=coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) |
| 95 | + GIT_COMMITTER_EMAIL="${data.coder_workspace_owner.me.email}" |
| 96 | + CLAUDE_CODE_USE_BEDROCK="1" |
| 97 | + AWS_REGION="us-east-2" |
| 98 | + AWS_ACCESS_KEY_ID="MARCIN_KEY_ID" |
| 99 | + AWS_SECRET_ACCESS_KEY="MARCIN_SECRET" |
| 100 | + CODER_MCP_APP_STATUS_SLUG="claude-code" |
| 101 | + CODER_MCP_CLAUDE_TASK_PROMPT= data.coder_parameter.ai_prompt.value |
| 102 | + CODER_MCP_CLAUDE_SYSTEM_PROMPT=<<-EOT |
| 103 | + Hey! The user will provide you with a prompt of something to create. Create it the best you can. |
| 104 | +
|
| 105 | + If web app: |
| 106 | + - ALWAYS use port 3000 so the user has a consistent preview to see their work |
| 107 | + - If the dev server is already running, kill the dev server to run on port 3000. |
| 108 | + - Avoid building the project for production. Just use dev servers (and ALWAYS VIA desktop-commander as mentioned below) |
| 109 | + - When you think you have finished, you should use Playwright to review the HTML to ensure it is working as expected. |
| 110 | + - Feel free to fix anything bad you see. |
| 111 | +
|
| 112 | + Always run long-running commands (e.g. `pnpm dev` or `npm run dev`) using desktop-commander so it runs it in the background and users can prompt you. Other short-lived commands (build, test, cd, write, read, view, etc) can run normally. |
| 113 | +
|
| 114 | + Never run the dev server without desktop-commander. This will cause you to stall and get stuck. |
| 115 | +
|
| 116 | + For previewing, always use the dev server for fast feedback loops (never do a full Next.js build, for exmaple). Next.js or simple HTML/static |
| 117 | + is preferred for web applications, but pick the best framework for the job. |
| 118 | +
|
| 119 | + The dev server will be on localhost:3000 and NEVER start on another port. The user depends on localhost:3000. If the dev |
| 120 | + server crashes for some reason, kill port 3000 (or the desktop-commander session) and restart it. |
| 121 | +
|
| 122 | + After large changes, use Playwright to ensure your changes work (preview localhost:3000). Take a screenshot, look at the screenshot. Also look at the HTML output from Playwright. If there are errors or something looks "off," fix it. |
| 123 | +
|
| 124 | + Whenever waiting for a PR review, keep on retrying indefinitely until you get a review. Even if requests are timing out. |
| 125 | +
|
| 126 | + Aim to autonomously investigate and solve issues the user gives you |
| 127 | + and test your work, whenever possible. |
| 128 | +
|
| 129 | + Avoid shortcuts like mocking tests. When you get stuck, you can ask the user |
| 130 | + but opt for autonomy. |
| 131 | +
|
| 132 | + Report every single task to Coder so that we can help you and understand where you are at |
| 133 | + following these EXACT guidelines: |
| 134 | +
|
| 135 | + 1. Be granular. If you are doing multiple steps, report each step |
| 136 | + to coder. |
| 137 | + 2. IMMEDIATELY report status after receiving ANY user message |
| 138 | + 3. Use "state": "working" when actively processing WITHOUT needing |
| 139 | + additional user input |
| 140 | + 4. Use "state": "complete" only when finished with a task |
| 141 | + 5. Use "state": "failure" when you need ANY user input, lack sufficient |
| 142 | + details, or encounter blockers |
| 143 | +
|
| 144 | +
|
| 145 | + In your summary: |
| 146 | + - Be specific about what you're doing |
| 147 | + - Clearly indicate what information you need from the user when in |
| 148 | + "failure" state |
| 149 | + - Keep it under 160 characters |
| 150 | + - Make it actionable |
| 151 | +
|
| 152 | + When reporting URLs to Coder, do not use localhost. Instead, run `env | grep CODER) | and a URL like https://preview--dev--CODER_WORKSPACE_NAME--CODER_WORKSPACE_OWNER--apps.dev.coder.com/ but with it replaces with the proper env vars. That proxies port 3000. |
| 153 | + EOT |
| 154 | + } |
| 155 | + |
| 156 | +# The following metadata blocks are optional. They are used to display |
| 157 | +# information about your workspace in the dashboard. You can remove them |
| 158 | +# if you don't want to display any information. |
| 159 | +# For basic resources, you can use the `coder stat` command. |
| 160 | +# If you need more control, you can write your own script. |
| 161 | +metadata { |
| 162 | +display_name="CPU Usage" |
| 163 | +key="0_cpu_usage" |
| 164 | +script="coder stat cpu" |
| 165 | +interval=10 |
| 166 | +timeout=1 |
| 167 | + } |
| 168 | + |
| 169 | +metadata { |
| 170 | +display_name="RAM Usage" |
| 171 | +key="1_ram_usage" |
| 172 | +script="coder stat mem" |
| 173 | +interval=10 |
| 174 | +timeout=1 |
| 175 | + } |
| 176 | + |
| 177 | +metadata { |
| 178 | +display_name="Home Disk" |
| 179 | +key="3_home_disk" |
| 180 | +script="coder stat disk --path $${HOME}" |
| 181 | +interval=60 |
| 182 | +timeout=1 |
| 183 | + } |
| 184 | + |
| 185 | +metadata { |
| 186 | +display_name="CPU Usage (Host)" |
| 187 | +key="4_cpu_usage_host" |
| 188 | +script="coder stat cpu --host" |
| 189 | +interval=10 |
| 190 | +timeout=1 |
| 191 | + } |
| 192 | + |
| 193 | +metadata { |
| 194 | +display_name="Memory Usage (Host)" |
| 195 | +key="5_mem_usage_host" |
| 196 | +script="coder stat mem --host" |
| 197 | +interval=10 |
| 198 | +timeout=1 |
| 199 | + } |
| 200 | + |
| 201 | +metadata { |
| 202 | +display_name="Load Average (Host)" |
| 203 | +key="6_load_host" |
| 204 | +# get load avg scaled by number of cores |
| 205 | +script=<<EOT |
| 206 | + echo "`cat /proc/loadavg | awk '{ print $1 }'` `nproc`" | awk '{ printf "%0.2f", $1/$2 }' |
| 207 | + EOT |
| 208 | +interval=60 |
| 209 | +timeout=1 |
| 210 | + } |
| 211 | + |
| 212 | +metadata { |
| 213 | +display_name="Swap Usage (Host)" |
| 214 | +key="7_swap_host" |
| 215 | +script=<<EOT |
| 216 | + free -b | awk '/^Swap/ { printf("%.1f/%.1f", $3/1024.0/1024.0/1024.0, $2/1024.0/1024.0/1024.0) }' |
| 217 | + EOT |
| 218 | +interval=10 |
| 219 | +timeout=1 |
| 220 | + } |
| 221 | +} |
| 222 | + |
| 223 | +# See https://registry.coder.com/modules/code-server |
| 224 | +module"code-server" { |
| 225 | +count=data.coder_workspace.me.start_count |
| 226 | +source="registry.coder.com/modules/code-server/coder" |
| 227 | + |
| 228 | +# This ensures that the latest version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production. |
| 229 | +version=">= 1.0.0" |
| 230 | + |
| 231 | +agent_id=coder_agent.main.id |
| 232 | +order=1 |
| 233 | +} |
| 234 | + |
| 235 | +# See https://registry.coder.com/modules/jetbrains-gateway |
| 236 | +module"jetbrains_gateway" { |
| 237 | +count=data.coder_workspace.me.start_count |
| 238 | +source="registry.coder.com/modules/jetbrains-gateway/coder" |
| 239 | + |
| 240 | +# JetBrains IDEs to make available for the user to select |
| 241 | +jetbrains_ides=["IU","PS","WS","PY","CL","GO","RM","RD","RR"] |
| 242 | +default="IU" |
| 243 | + |
| 244 | +# Default folder to open when starting a JetBrains IDE |
| 245 | +folder="/home/coder" |
| 246 | + |
| 247 | +# This ensures that the latest version of the module gets downloaded, you can also pin the module version to prevent breaking changes in production. |
| 248 | +version=">= 1.0.0" |
| 249 | + |
| 250 | +agent_id=coder_agent.main.id |
| 251 | +agent_name="main" |
| 252 | +order=2 |
| 253 | +} |
| 254 | + |
| 255 | +resource"docker_volume""home_volume" { |
| 256 | +name="coder-${data.coder_workspace.me.id}-home" |
| 257 | +# Protect the volume from being deleted due to changes in attributes. |
| 258 | +lifecycle { |
| 259 | +ignore_changes=all |
| 260 | + } |
| 261 | +# Add labels in Docker to keep track of orphan resources. |
| 262 | +labels { |
| 263 | +label="coder.owner" |
| 264 | +value=data.coder_workspace_owner.me.name |
| 265 | + } |
| 266 | +labels { |
| 267 | +label="coder.owner_id" |
| 268 | +value=data.coder_workspace_owner.me.id |
| 269 | + } |
| 270 | +labels { |
| 271 | +label="coder.workspace_id" |
| 272 | +value=data.coder_workspace.me.id |
| 273 | + } |
| 274 | +# This field becomes outdated if the workspace is renamed but can |
| 275 | +# be useful for debugging or cleaning out dangling volumes. |
| 276 | +labels { |
| 277 | +label="coder.workspace_name_at_creation" |
| 278 | +value=data.coder_workspace.me.name |
| 279 | + } |
| 280 | +} |
| 281 | + |
| 282 | +resource"docker_container""workspace" { |
| 283 | +count=data.coder_workspace.me.start_count |
| 284 | +image="codercom/enterprise-base:ubuntu" |
| 285 | +# Uses lower() to avoid Docker restriction on container names. |
| 286 | +name="coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}" |
| 287 | +# Hostname makes the shell more user friendly: coder@my-workspace:~$ |
| 288 | +hostname=data.coder_workspace.me.name |
| 289 | +# Use the docker gateway if the access URL is 127.0.0.1 |
| 290 | +entrypoint=["sh","-c",replace(coder_agent.main.init_script,"/localhost|127\\.0\\.0\\.1/","host.docker.internal")] |
| 291 | +env=["CODER_AGENT_TOKEN=${coder_agent.main.token}"] |
| 292 | +host { |
| 293 | +host="host.docker.internal" |
| 294 | +ip="host-gateway" |
| 295 | + } |
| 296 | +volumes { |
| 297 | +container_path="/home/coder" |
| 298 | +volume_name=docker_volume.home_volume.name |
| 299 | +read_only=false |
| 300 | + } |
| 301 | + |
| 302 | +# Add labels in Docker to keep track of orphan resources. |
| 303 | +labels { |
| 304 | +label="coder.owner" |
| 305 | +value=data.coder_workspace_owner.me.name |
| 306 | + } |
| 307 | +labels { |
| 308 | +label="coder.owner_id" |
| 309 | +value=data.coder_workspace_owner.me.id |
| 310 | + } |
| 311 | +labels { |
| 312 | +label="coder.workspace_id" |
| 313 | +value=data.coder_workspace.me.id |
| 314 | + } |
| 315 | +labels { |
| 316 | +label="coder.workspace_name" |
| 317 | +value=data.coder_workspace.me.name |
| 318 | + } |
| 319 | +} |
| 320 | + |