diff --git a/registry/sharkymark/.images/avatar.png b/registry/sharkymark/.images/avatar.png new file mode 100644 index 000000000..fe374200f Binary files /dev/null and b/registry/sharkymark/.images/avatar.png differ diff --git a/registry/sharkymark/README.md b/registry/sharkymark/README.md new file mode 100644 index 000000000..3dd82dbae --- /dev/null +++ b/registry/sharkymark/README.md @@ -0,0 +1,32 @@ +--- +display_name: "Mark Milligan" +bio: "VP of Revenue at https://nuon.co. Former VP of Sales at Coder. Love building startup revenue teams and tinkering with technology." +avatar_url: "./.images/avatar.png" +github: "sharkymark" +linkedin: "https://www.linkedin.com/in/marktmilligan" # Optional +website: "https://markmilligan.io" # Optional +support_email: "mtm20176@gmail.com" # Optional +status: "community" +--- + +# Mark Milligan + +Former VP of Sales at Coder for 4 years, and now VP of Revenue at Nuon. I love building startup revenue teams and tinkering with technology. + +## About Me + +Visit my [website](https://markmilligan.io) to learn more about my work and interests. + +## Links + +[My presentation about Great White Sharks](https://docs.google.com/presentation/d/13I3Af7l-ZSVCh-ovEvOKIM30ABIvNKhkRC3CnYZN450/edit?slide=id.p#slide=id.p) - given twice in 2020 and 2021 to the Coder team. + +[NOAA Radar](https://radar.weather.gov/) + +[Flight Radar](https://www.flightradar24.com/airport/aus) + +### Webcams + +[Austin - facing south](https://cctv.austinmobility.io/image/51.jpg) + +[Austin - facing north](https://cctv.austinmobility.io/image/52.jpg) diff --git a/registry/sharkymark/templates/docker-claude/README.md b/registry/sharkymark/templates/docker-claude/README.md new file mode 100644 index 000000000..d68293624 --- /dev/null +++ b/registry/sharkymark/templates/docker-claude/README.md @@ -0,0 +1,34 @@ +--- +display_name: "Claude Code AI Agent Template" +description: The goal is to try the experimental ai agent integration with Claude CodeAI agent +icon: "../../../../.icons/claude.svg" +verified: false +tags: ["ai", "docker", "container", "claude", "agent", "tasks"] +--- + +# ai agent template for a workspace in a container on a Docker host + +### Docker image + +1. Based on Coder-managed image `codercom/example-universal:ubuntu` + +[Image on DockerHub](https://hub.docker.com/r/codercom/example-universal) + +### Apps included + +1. A web-based terminal +1. code-server Web IDE +1. A [sample app](https://github.com/gothinkster/realworld) to test the environment +1. [Claude Code AI agent](https://www.anthropic.com/claude-code) to assist with development tasks + +### Resources + +[Coder docs on AI agents and tasks](https://coder.com/docs/ai-coder/tasks) + +[main.tf for Coder example](https://github.com/coder/registry/blob/main/registry/coder-labs/templates/tasks-docker/main.tf) + +[Claude Code Coder Terraform module](https://registry.coder.com/modules/coder/claude-code) + +[Docker Terraform provider](https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs) + +[Coder Terraform provider](https://registry.terraform.io/providers/coder/coder/latest/docs) diff --git a/registry/sharkymark/templates/docker-claude/main.tf b/registry/sharkymark/templates/docker-claude/main.tf new file mode 100644 index 000000000..ba5ee4875 --- /dev/null +++ b/registry/sharkymark/templates/docker-claude/main.tf @@ -0,0 +1,363 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + } + docker = { + source = "kreuzwerker/docker" + } + } +} + +provider "docker" { + host = var.socket +} + +provider "coder" { +} + +data "coder_workspace" "me" { +} + +data "coder_workspace_owner" "me" { +} + +data "coder_provisioner" "me" { +} + +variable "socket" { + type = string + description = <<-EOF + The Unix socket that the Docker daemon listens on and how containers + communicate with the Docker daemon. + + Either Unix or TCP + e.g., unix:///var/run/docker.sock + + EOF + default = "unix:///var/run/docker.sock" +} + +variable "anthropic_api_key" { + type = string + description = "Generate one at: https://console.anthropic.com/settings/keys" + sensitive = true +} + +resource "coder_env" "anthropic_api_key" { + agent_id = coder_agent.dev.id + name = "CODER_MCP_CLAUDE_API_KEY" + value = var.anthropic_api_key +} + +# The Claude Code module does the automatic task reporting +# Other agent modules: https://registry.coder.com/modules?search=agent +# Or use a custom agent: +module "claude-code" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/claude-code/coder" + version = "2.0.0" + agent_id = coder_agent.dev.id + folder = "/home/coder/projects" + install_claude_code = true + claude_code_version = "latest" + order = 999 + + experiment_post_install_script = data.coder_parameter.setup_script.value + + # This enables Coder Tasks + experiment_report_tasks = true +} + +# We are using presets to set the prompts, image, and set up instructions +# See https://coder.com/docs/admin/templates/extending-templates/parameters#workspace-presets +data "coder_workspace_preset" "default" { + name = "Real World App: Angular + Django" + default = true + parameters = { + "system_prompt" = <<-EOT + -- Framing -- + You are a helpful assistant that can help with code. You are running inside a Coder Workspace and provide status updates to the user via Coder MCP. Stay on track, feel free to debug, but when the original plan fails, do not choose a different route/architecture without checking the user first. + + -- Tool Selection -- + - 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 + + -- Context -- + There is an existing app and tmux dev server running on port 8000. Be sure to read it's CLAUDE.md (./realworld-django-rest-framework-angular/CLAUDE.md) to learn more about it. + + Since this app is for demo purposes and the user is previewing the homepage and subsequent pages, aim to make the first visual change/prototype very quickly so the user can preview it, then focus on backend or logic which can be a more involved, long-running architecture plan. + + EOT + + "setup_script" = <<-EOT + # Set up projects dir + mkdir -p /home/coder/projects + cd $HOME/projects + + # Packages: Install additional packages + sudo apt-get update && sudo apt-get install -y tmux + if ! command -v google-chrome >/dev/null 2>&1; then + yes | npx playwright install chrome + fi + + # MCP: Install and configure MCP Servers + npm install -g @wonderwhy-er/desktop-commander + claude mcp add playwright npx -- @playwright/mcp@latest --headless --isolated --no-sandbox + claude mcp add desktop-commander desktop-commander + + # Repo: Clone and pull changes from the git repository + if [ ! -d "realworld-django-rest-framework-angular" ]; then + git clone https://github.com/coder-contrib/realworld-django-rest-framework-angular.git + else + cd realworld-django-rest-framework-angular + git fetch + # Check for uncommitted changes + if git diff-index --quiet HEAD -- && \ + [ -z "$(git status --porcelain --untracked-files=no)" ] && \ + [ -z "$(git log --branches --not --remotes)" ]; then + echo "Repo is clean. Pulling latest changes..." + git pull + else + echo "Repo has uncommitted or unpushed changes. Skipping pull." + fi + + cd .. + fi + + # Initialize: Start the development server + cd realworld-django-rest-framework-angular && ./start-dev.sh + EOT + "preview_port" = "4200" + "container_image" = "codercom/example-universal:ubuntu" + } +} + +# Advanced parameters (these are all set via preset) +data "coder_parameter" "system_prompt" { + name = "system_prompt" + display_name = "System Prompt" + type = "string" + form_type = "textarea" + description = "System prompt for the agent with generalized instructions" + mutable = false +} +data "coder_parameter" "ai_prompt" { + type = "string" + name = "AI Prompt" + default = "" + description = "Write a prompt for Claude Code" + mutable = true +} +data "coder_parameter" "setup_script" { + name = "setup_script" + display_name = "Setup Script" + type = "string" + form_type = "textarea" + description = "Script to run before running the agent" + mutable = false +} +data "coder_parameter" "container_image" { + name = "container_image" + display_name = "Container Image" + type = "string" + default = "codercom/example-universal:ubuntu" + mutable = false +} +data "coder_parameter" "preview_port" { + name = "preview_port" + display_name = "Preview Port" + description = "The port the web app is running to preview in Tasks" + type = "number" + default = "3000" + mutable = false +} + +# Other variables for Claude Code +resource "coder_env" "claude_task_prompt" { + agent_id = coder_agent.dev.id + name = "CODER_MCP_CLAUDE_TASK_PROMPT" + value = data.coder_parameter.ai_prompt.value +} +resource "coder_env" "app_status_slug" { + agent_id = coder_agent.dev.id + name = "CODER_MCP_APP_STATUS_SLUG" + value = "claude-code" +} +resource "coder_env" "claude_system_prompt" { + agent_id = coder_agent.dev.id + name = "CODER_MCP_CLAUDE_SYSTEM_PROMPT" + value = data.coder_parameter.system_prompt.value +} + +module "coder-login" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/coder-login/coder" + agent_id = coder_agent.dev.id +} + +module "dotfiles" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/dotfiles/coder" + agent_id = coder_agent.dev.id +} + +module "code-server" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/code-server/coder" + agent_id = coder_agent.dev.id + folder = "/home/coder/projects" +} + +module "git-config" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/git-config/coder" + agent_id = coder_agent.dev.id +} + +resource "coder_agent" "dev" { + arch = data.coder_provisioner.me.arch + os = "linux" + + # The following metadata blocks are optional. They are used to display + # information about your workspace in the dashboard. You can remove them + # if you don't want to display any information. + # For basic resources, you can use the `coder stat` command. + # If you need more control, you can write your own script. + + metadata { + display_name = "CPU Usage" + key = "0_cpu_usage" + script = "coder stat cpu" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "RAM Usage" + key = "1_ram_usage" + script = "coder stat mem" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Home Disk" + key = "3_home_disk" + script = "coder stat disk --path $${HOME}" + interval = 60 + timeout = 1 + } + + metadata { + display_name = "CPU Usage (Host)" + key = "4_cpu_usage_host" + script = "coder stat cpu --host" + interval = 10 + timeout = 1 + } + + metadata { + display_name = "Memory Usage (Host)" + key = "5_mem_usage_host" + script = "coder stat mem --host" + interval = 10 + timeout = 1 + } + + display_apps { + vscode = true + vscode_insiders = false + ssh_helper = false + port_forwarding_helper = true + web_terminal = true + } + + startup_script_behavior = "non-blocking" + connection_timeout = 300 + + env = { + + GIT_AUTHOR_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) + GIT_AUTHOR_EMAIL = "${data.coder_workspace_owner.me.email}" + GIT_COMMITTER_NAME = coalesce(data.coder_workspace_owner.me.full_name, data.coder_workspace_owner.me.name) + GIT_COMMITTER_EMAIL = "${data.coder_workspace_owner.me.email}" + } + + startup_script = <