diff --git a/.github/workflows/dogfood.yaml b/.github/workflows/dogfood.yaml index db3292392db19..6735f7d2ce8ae 100644 --- a/.github/workflows/dogfood.yaml +++ b/.github/workflows/dogfood.yaml @@ -169,6 +169,7 @@ jobs: CODER_URL: https://dev.coder.com CODER_SESSION_TOKEN: ${{ secrets.CODER_SESSION_TOKEN }} # Template source & details + TF_VAR_CODER_DOGFOOD_ANTHROPIC_API_KEY: ${{ secrets.CODER_DOGFOOD_ANTHROPIC_API_KEY }} TF_VAR_CODER_TEMPLATE_NAME: ${{ secrets.CODER_TEMPLATE_NAME }} TF_VAR_CODER_TEMPLATE_VERSION: ${{ steps.vars.outputs.sha_short }} TF_VAR_CODER_TEMPLATE_DIR: ./coder diff --git a/dogfood/coder/main.tf b/dogfood/coder/main.tf index ae4088ec40fe7..8ec22dfb56351 100644 --- a/dogfood/coder/main.tf +++ b/dogfood/coder/main.tf @@ -38,6 +38,7 @@ locals { repo_base_dir = data.coder_parameter.repo_base_dir.value == "~" ? "/home/coder" : replace(data.coder_parameter.repo_base_dir.value, "/^~\\//", "/home/coder/") repo_dir = replace(try(module.git-clone[0].repo_dir, ""), "/^~\\//", "/home/coder/") container_name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}" + has_ai_prompt = data.coder_parameter.ai_prompt.value != "" } data "coder_workspace_preset" "cpt" { @@ -150,6 +151,13 @@ data "coder_parameter" "image_type" { } } +variable "anthropic_api_key" { + type = string + description = "The API key used to authenticate with the Anthropic API." + default = "" + sensitive = true +} + locals { default_regions = { // keys should match group names @@ -242,6 +250,14 @@ data "coder_parameter" "devcontainer_autostart" { mutable = true } +data "coder_parameter" "ai_prompt" { + type = "string" + name = "AI Prompt" + default = "" + description = "Prompt for Claude Code" + mutable = false +} + provider "docker" { host = lookup(local.docker_host, data.coder_parameter.region.value) } @@ -380,6 +396,24 @@ module "devcontainers-cli" { agent_id = coder_agent.dev.id } +module "claude-code" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + source = "dev.registry.coder.com/coder/claude-code/coder" + version = "~>2.0" + agent_id = coder_agent.dev.id + folder = local.repo_dir + install_claude_code = true + claude_code_version = "latest" + order = 999 + + experiment_report_tasks = true + experiment_post_install_script = <<-EOT + claude mcp add playwright npx -- @playwright/mcp@latest --headless --isolated --no-sandbox + claude mcp add desktop-commander npx -- @wonderwhy-er/desktop-commander@latest + EOT +} + + resource "coder_agent" "dev" { arch = "amd64" os = "linux" @@ -710,4 +744,129 @@ resource "coder_metadata" "container_info" { key = "region" value = data.coder_parameter.region.option[index(data.coder_parameter.region.option.*.value, data.coder_parameter.region.value)].name } + item { + key = "ai_task" + value = local.has_ai_prompt ? "yes" : "no" + } +} + +resource "coder_env" "claude_system_prompt" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + agent_id = coder_agent.dev.id + name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT" + value = <<-EOT + + -- Framing -- + You are a helpful Coding assistant. Aim to autonomously investigate + and solve issues the user gives you and test your work, whenever possible. + + Avoid shortcuts like mocking tests. When you get stuck, you can ask the user + but opt for autonomy. + + -- Tool Selection -- + - coder_report_task: providing status updates or requesting user input. + - playwright: previewing your changes after you made them + to confirm it worked as expected + - desktop-commander - use only for commands that keep running + (servers, dev watchers, GUI apps). + - Built-in tools - use for everything else: + (file operations, git commands, builds & installs, one-off shell commands) + + Remember this decision rule: + - Stays running? → desktop-commander + - Finishes immediately? → built-in tools + + -- 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. IMMEDIATELY report status after receiving ANY user message + 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 + + In your summary: + - Be specific about what you're doing + - Clearly indicate what information you need from the user when in + "failure" state + - Keep it under 160 characters + - Make it actionable + + -- Context -- + There is an existing application in the current directory. + Be sure to read CLAUDE.md before making any changes. + + This is a real-world production application. As such, make sure to think carefully, use TODO lists, and plan carefully before making changes. + + EOT +} + +resource "coder_env" "claude_task_prompt" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + agent_id = coder_agent.dev.id + name = "CODER_MCP_CLAUDE_TASK_PROMPT" + value = data.coder_parameter.ai_prompt.value +} + +resource "coder_env" "anthropic_api_key" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + agent_id = coder_agent.dev.id + name = "ANTHROPIC_API_KEY" + value = var.anthropic_api_key +} + +resource "coder_app" "develop_sh" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + agent_id = coder_agent.dev.id + slug = "develop-sh" + display_name = "develop.sh" + icon = "${data.coder_workspace.me.access_url}/emojis/1f4bb.png" // 💻 + command = "screen -x develop_sh" + share = "authenticated" + subdomain = true + open_in = "tab" + order = 0 +} + +resource "coder_script" "develop_sh" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + display_name = "develop.sh" + agent_id = coder_agent.dev.id + run_on_start = true + start_blocks_login = false + icon = "${data.coder_workspace.me.access_url}/emojis/1f4bb.png" // 💻 + script = <<-EOT + #!/usr/bin/env bash + set -eux -o pipefail + + # Wait for the agent startup script to finish. + for attempt in {1..60}; do + if [[ -f /tmp/.coder-startup-script.done ]]; then + break + fi + echo "Waiting for agent startup script to finish... ($attempt/60)" + sleep 10 + done + cd "${local.repo_dir}" && screen -dmS develop_sh /bin/sh -c 'while true; do ./scripts/develop.sh --; echo "develop.sh exited with code $? restarting in 30s"; sleep 30; done' + EOT +} + +resource "coder_app" "preview" { + count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0 + agent_id = coder_agent.dev.id + slug = "preview" + display_name = "Preview" + icon = "${data.coder_workspace.me.access_url}/emojis/1f50e.png" // 🔎 + url = "http://localhost:8080" + share = "authenticated" + subdomain = true + open_in = "tab" + order = 1 + healthcheck { + url = "http://localhost:8080/healthz" + interval = 5 + threshold = 15 + } } diff --git a/dogfood/main.tf b/dogfood/main.tf index 72cd868f61645..c79e950efadf4 100644 --- a/dogfood/main.tf +++ b/dogfood/main.tf @@ -33,6 +33,13 @@ variable "CODER_TEMPLATE_MESSAGE" { type = string } +variable "CODER_DOGFOOD_ANTHROPIC_API_KEY" { + type = string + description = "The API key that workspaces will use to authenticate with the Anthropic API." + default = "" + sensitive = true +} + resource "coderd_template" "dogfood" { name = var.CODER_TEMPLATE_NAME display_name = "Write Coder on Coder" @@ -45,6 +52,12 @@ resource "coderd_template" "dogfood" { message = var.CODER_TEMPLATE_MESSAGE directory = var.CODER_TEMPLATE_DIR active = true + tf_vars = [ + { + name = "anthropic_api_key" + value = var.CODER_DOGFOOD_ANTHROPIC_API_KEY + } + ] } ] acl = { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy