This commit is contained in:
2025-09-29 00:47:39 +00:00
parent 508252e596
commit 1c3cf0a6d7
19 changed files with 284 additions and 49 deletions

BIN
._WARP.md Normal file

Binary file not shown.

BIN
._tf Normal file

Binary file not shown.

148
WARP.md Normal file
View File

@@ -0,0 +1,148 @@
# WARP.md
This file provides guidance to WARP (warp.dev) when working with code in this repository.
## Common Commands
### Python Development
```bash
# Run the main application
python main.py
# Install dependencies with uv (modern Python package manager)
uv pip install -r requirements.txt # If requirements file exists
uv add <package> # Add new dependency
uv remove <package> # Remove dependency
# Alternative with pip
pip install -e . # Install in development mode
```
### Container Development
```bash
# Build devcontainer (safe - no coolify disruption)
docker compose -f .devcontainer/docker-compose.yml build
# Build coder workspace container
docker compose -f coder-compose.yaml build
# Note: Avoid docker compose up/down/restart - services run in coolify
```
### Terraform Workspace Management
```bash
# Initialize and work with Coder workspace templates
cd tf-dockerfile
terraform init
terraform plan
terraform apply
# Check workspace status
terraform show
terraform output
```
### Development Tools
```bash
# Run development info script (if available in devcontainer)
devinfo
# Claude CLI helpers (if installed)
claude auth login
claude chat
claude edit <file>
claude-help
# Git with credential helper (configured as 'store')
git clone <repo>
git push # Uses stored credentials
```
## Architecture Overview
### Repository Structure
- **`main.py`**: Simple Python entry point application
- **`.devcontainer/`**: VS Code devcontainer configuration with comprehensive tooling
- **`tf-dockerfile/`**: Terraform module for provisioning Coder workspaces
- **`coder-compose.yaml`**: Docker Compose configuration for Coder service
- **`pyproject.toml`**: Python project configuration (requires Python >=3.12)
### Development Environment Layers
1. **Base Layer**: Universal devcontainer image (`mcr.microsoft.com/devcontainers/universal:2-linux`)
2. **Language Support**: Python 3.12, Node.js LTS, Go, Rust, Terraform
3. **Development Tools**: Git, GitHub CLI, Docker-in-Docker, various CLI utilities
4. **AI Integration**: Claude Code CLI, Cursor IDE, Windsurf IDE support
5. **Database Services**: Optional PostgreSQL, Redis, Qdrant with pgAdmin
### Coder Workspace Architecture
- **Workspace Container**: Runs development environment with mounted home directory
- **Service Network**: Isolated Docker network for workspace services
- **Data Persistence**: Separate volumes for workspace data and user home
- **Port Forwarding**: Automatic setup for development services (3000, 5000, 8000, 8080, etc.)
## Development Environment Setup
### Prerequisites
- Docker and Docker Compose
- VS Code with Dev Containers extension (for devcontainer)
- Terraform >= 1.3.0 (for workspace management)
- Python >= 3.12 (if running outside container)
### Environment Configuration
The devcontainer automatically configures:
- **Shell**: Zsh with Oh My Zsh and enhanced aliases
- **Git**: Credential helper set to 'store', configured for lab SSL certificates
- **CLI Tools**: bat, fd, ripgrep, eza, lazygit, htop, and others
- **AI Tools**: Claude Code CLI, IDE integrations for Cursor and Windsurf
### Key Environment Variables
- `POSTGRES_URL`: Database connection string (when services enabled)
- `REDIS_URL`: Redis connection string (when services enabled)
- `QDRANT_URL`: Vector database connection string (when services enabled)
- `CODER_WORKSPACE_ID`: Unique workspace identifier
- `ENABLE_SERVICES`: Toggle for database services
- `ENABLE_PGADMIN`/`ENABLE_MARIMO`: Toggle for admin interfaces
## Terraform Workspace Template
The `tf-dockerfile/` directory contains a complete Terraform module for provisioning Coder workspaces:
### Key Features
- **Customizable Base Image**: Defaults to universal devcontainer but configurable
- **Optional Services**: Toggle PostgreSQL, Redis, Qdrant with single parameter
- **AI Tool Integration**: Automated setup of Claude, Cursor, Windsurf tooling
- **Repository Cloning**: Automatic git clone of specified repositories
- **SSL Certificate Handling**: Automatic lab certificate installation and Git configuration
### Workspace Parameters
- `project_repository`: Git URL to clone into workspace
- `enable_services`: Boolean for database services
- `enable_ai_tools`: Boolean for AI helper installation
- `enable_pgadmin`: Boolean for database admin interface
- `enable_marimo`: Boolean for notebook interface
- `enable_jetbrains`: Boolean for JetBrains Gateway integration
### Important Files
- `main.tf`: Core infrastructure and Docker resources
- `workspace.tf`: Coder agent and workspace container configuration
- `services.tf`: Database and service definitions
- `apps.tf`: Coder application definitions and port forwarding
- `scripts.tf`: Startup script resources for development tools
## Development Workflow
### Starting Development
1. Use devcontainer in VS Code or deploy Terraform workspace in Coder
2. Workspace automatically installs development tools and configures environment
3. Git credentials and SSH keys are mounted from host system
4. Services (if enabled) start automatically with health checks
### Working with Services
- PostgreSQL: Available at `postgres-{workspace-id}:5432`
- Redis: Available at `redis-{workspace-id}:6379`
- Qdrant: Available at `qdrant-{workspace-id}:6333`
- pgAdmin: Accessible via port forwarding on localhost:5050
- Marimo: Accessible via port forwarding on localhost:6333
### Port Forwarding
The workspace automatically forwards common development ports and provides scripts for accessing database services on the local machine when services are enabled.

View File

@@ -14,14 +14,6 @@ resource "coder_app" "code_server" {
}
}
resource "coder_app" "terminal" {
agent_id = coder_agent.main.id
slug = "terminal"
display_name = "Terminal"
icon = "/icon/terminal.svg"
command = "bash -lc 'exec sudo -u coder -i bash -c \"export GEM_HOME=/home/coder/.gem; export GEM_PATH=/home/coder/.gem; cd /workspaces && exec bash\"'"
}
resource "coder_app" "pgadmin" {
count = local.services_enabled && data.coder_parameter.enable_pgadmin.value ? 1 : 0
agent_id = coder_agent.main.id
@@ -44,7 +36,7 @@ resource "coder_app" "qdrant" {
agent_id = coder_agent.main.id
slug = "qdrant"
display_name = "Qdrant"
url = "http://qdrant-${local.workspace_id}:6333"
url = "http://qdrant-${local.workspace_id}:6333/dashboard"
icon = "/icon/database.svg"
subdomain = false
share = "owner"
@@ -180,7 +172,7 @@ resource "coder_app" "btop" {
agent_id = coder_agent.main.id
slug = "btop"
display_name = "System Monitor"
icon = "/icon/monitor.svg"
icon = "/icon/chart.svg"
command = "bash -lc 'exec sudo -u coder -i bash -c \"export GEM_HOME=/home/coder/.gem; export GEM_PATH=/home/coder/.gem; btop\"'"
group = "Terminal Tools"
order = 40

View File

@@ -116,7 +116,8 @@ locals {
git_author_email = data.coder_workspace_owner.me.email
project_repo_url = trimspace(data.coder_parameter.project_repository.value)
repo_clone_command = local.project_repo_url != "" ? "git clone ${local.project_repo_url} /workspaces || (echo 'Git clone failed - authentication required. Configure external auth provider in Coder or clone manually.' && mkdir -p /workspaces && cd /workspaces && git init . && echo 'Initialized empty workspace directory.')" : "echo 'No repository requested'"
gitea_pat = trimspace(var.gitea_pat)
github_pat = trimspace(var.github_pat)
services_enabled = data.coder_parameter.enable_services.value
pgadmin_enabled = data.coder_parameter.enable_pgadmin.value
@@ -134,8 +135,18 @@ locals {
"export GEM_HOME=\"$HOME/.gem\"",
"export GEM_PATH=\"$HOME/.gem\"",
"# Ensure required directories exist",
"mkdir -p /home/coder/code-tools/tf/scripts",
"mkdir -p /home/coder/code-tools/tf/scripts/agentapi",
"mkdir -p /home/coder/code-tools/terraform/scripts",
"mkdir -p /home/coder/code-tools/terraform/scripts/agentapi",
"# Ensure Python 3.12 is available",
"if ! command -v python3 >/dev/null 2>&1 || ! python3 -c 'import sys; exit(0) if sys.version_info >= (3, 12) else exit(1)' ; then",
" echo 'Installing Python 3.12...'",
" apt-get update -qq",
" apt-get install -y software-properties-common",
" add-apt-repository ppa:deadsnakes/ppa -y",
" apt-get update -qq",
" apt-get install -y python3.12 python3.12-venv python3.12-dev python3-pip",
" update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1",
"fi",
"# SSL Certificate setup (running as root)",
"if [ -f /home/coder/lab-certs/lab.crt ]; then",
" echo 'Installing SSL certificate for lab.crt'",
@@ -151,12 +162,9 @@ locals {
" sudo -u coder git config --global http.\"https://git.lab\".sslVerify false || echo 'Cannot configure git ssl skip'",
"fi",
"# End SSL setup",
local.project_repo_url != "" ? "if [ ! -d /workspaces/.git ]; then ${local.repo_clone_command}; fi" : "",
"# Fix ownership of cloned repository",
local.project_repo_url != "" ? "chown -R coder:coder /workspaces || echo 'Cannot fix workspace ownership'" : "",
"export ENABLE_PGADMIN=${tostring(local.pgadmin_enabled)}",
"export ENABLE_MARIMO=${tostring(local.marimo_enabled)}",
local.port_forwarding ? "bash /home/coder/code-tools/tf/scripts/port-forward.sh || echo 'Port forwarding script not found or failed'" : "echo 'No service port forwarding requested'"
local.port_forwarding ? "if [ -x /home/coder/code-tools/terraform/scripts/port-forward.sh ]; then bash /home/coder/code-tools/terraform/scripts/port-forward.sh; else echo \"Port forwarding script not found\"; fi" : "echo 'No service port forwarding requested'"
]))
}

View File

@@ -215,11 +215,11 @@ resource "docker_container" "pgadmin" {
}
healthcheck {
test = ["CMD-SHELL", "nc -z localhost 5050 || exit 1"]
test = ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5050/misc/ping || exit 1"]
interval = "30s"
timeout = "10s"
retries = 3
start_period = "60s"
start_period = "90s"
}
restart = "unless-stopped"

View File

@@ -120,3 +120,19 @@ variable "install_gemini_support" {
type = bool
default = true
}
variable "gitea_pat" {
description = "Personal access token for Gitea (optional)."
type = string
default = ""
sensitive = true
}
variable "github_pat" {
description = "Personal access token for GitHub (optional)."
type = string
default = ""
sensitive = true
}

View File

@@ -3,15 +3,21 @@ resource "coder_agent" "main" {
os = "linux"
dir = "/workspaces"
env = {
"GIT_AUTHOR_NAME" = local.git_author_name
"GIT_AUTHOR_EMAIL" = local.git_author_email
"CODER_WORKSPACE_ID" = local.workspace_id
"CODER_WORKSPACE_REPO" = local.project_repo_url
"ENABLE_MARIMO" = tostring(local.marimo_enabled)
"ENABLE_SERVICES" = tostring(local.services_enabled)
"CODER_AGENT_BLOCK_FILE_TRANSFER" = var.block_file_transfer ? "1" : ""
}
env = merge(
{
"GIT_AUTHOR_NAME" = local.git_author_name
"GIT_AUTHOR_EMAIL" = local.git_author_email
"CODER_WORKSPACE_ID" = local.workspace_id
"CODER_WORKSPACE_REPO" = local.project_repo_url
"ENABLE_MARIMO" = tostring(local.marimo_enabled)
"ENABLE_SERVICES" = tostring(local.services_enabled)
"CODER_AGENT_BLOCK_FILE_TRANSFER" = var.block_file_transfer ? "1" : ""
"GEM_HOME" = "/home/coder/.gem"
"GEM_PATH" = "/home/coder/.gem"
},
local.gitea_pat != "" ? { "GITEA_PAT" = local.gitea_pat } : {},
local.github_pat != "" ? { "GITHUB_PAT" = local.github_pat } : {}
)
startup_script = <<-EOT
#!/bin/bash
@@ -20,38 +26,103 @@ resource "coder_agent" "main" {
# Basic setup
${local.agent_startup}
# Ensure coder user can access Docker socket
if getent group docker >/dev/null 2>&1; then
if id -nG coder | tr ' ' '\n' | grep -qx docker; then
:
else
echo "Adding coder user to docker group..."
usermod -aG docker coder
fi
else
echo "docker group not found; skipping docker socket setup"
fi
# Switch to coder user for service startup
sudo -u coder bash << 'CODER_SETUP'
set -euo pipefail
# Fix RVM environment variables to suppress warnings
# Consistent RubyGems environment for every shell
export GEM_HOME="$HOME/.gem"
export GEM_PATH="$HOME/.gem"
export GEM_PATH="$GEM_HOME"
mkdir -p "$GEM_HOME/bin"
# Ensure gem directory exists
mkdir -p "$HOME/.gem"
case ":$PATH:" in
*":$GEM_HOME/bin:"*) ;;
*) export PATH="$GEM_HOME/bin:$PATH" ;;
esac
# Add RVM environment to bashrc for persistence
if ! grep -q 'export GEM_HOME="$HOME/.gem"' ~/.bashrc; then
echo '# RVM environment fix' >> ~/.bashrc
echo 'export GEM_HOME="$HOME/.gem"' >> ~/.bashrc
echo 'export GEM_PATH="$HOME/.gem"' >> ~/.bashrc
echo 'export PATH="$GEM_HOME/bin:$PATH"' >> ~/.bashrc
ensure_shell_env_block() {
local target="$1"
local start_marker="# >>> coder gem environment >>>"
local end_marker="# <<< coder gem environment <<<"
mkdir -p "$(dirname "$target")"
touch "$target"
if grep -q "$start_marker" "$target"; then
tmp_file=$(mktemp)
sed "/$start_marker/,/$end_marker/d" "$target" > "$tmp_file"
mv "$tmp_file" "$target"
fi
sed -i '/# RVM environment fix/,+3d' "$target" 2>/dev/null || true
cat <<'EOF' >> "$target"
# >>> coder gem environment >>>
export GEM_HOME="$HOME/.gem"
export GEM_PATH="$GEM_HOME"
if [ -d "$HOME/.gem/bin" ]; then
case ":$PATH:" in
*":$HOME/.gem/bin:"*) ;;
*) export PATH="$HOME/.gem/bin:$PATH";;
esac
else
mkdir -p "$HOME/.gem/bin"
case ":$PATH:" in
*":$HOME/.gem/bin:"*) ;;
*) export PATH="$HOME/.gem/bin:$PATH";;
esac
fi
# <<< coder gem environment <<<
EOF
}
# Also add to profile for login shells
if ! grep -q 'export GEM_HOME="$HOME/.gem"' ~/.profile 2>/dev/null; then
echo '# RVM environment fix' >> ~/.profile
echo 'export GEM_HOME="$HOME/.gem"' >> ~/.profile
echo 'export GEM_PATH="$HOME/.gem"' >> ~/.profile
echo 'export PATH="$GEM_HOME/bin:$PATH"' >> ~/.profile
fi
for shell_rc in ~/.bashrc ~/.profile ~/.zprofile ~/.zshrc ~/.zshenv; do
ensure_shell_env_block "$shell_rc"
done
# Add coder user to docker group for LazyDocker access
if ! groups | grep -q docker; then
echo "Adding coder user to docker group..."
sudo usermod -aG docker coder
# Clone requested repository into /workspaces if not already present
mkdir -p /workspaces
if [ -n "$${CODER_WORKSPACE_REPO:-}" ]; then
if [ ! -d /workspaces/.git ]; then
if [ -z "$(ls -A /workspaces 2>/dev/null)" ]; then
echo "Cloning $${CODER_WORKSPACE_REPO} into /workspaces"
if (cd /workspaces && git clone "$${CODER_WORKSPACE_REPO}" .); then
echo "Repository clone completed"
else
echo "Git clone failed; initializing empty repository"
(cd /workspaces && git init . && echo "Initialized empty workspace directory")
fi
else
echo "/workspaces already contains files; skipping automatic clone"
fi
else
echo "Git repository already present in /workspaces"
fi
else
echo "No repository requested"
fi
cd "$HOME"
mkdir -p "$HOME/.config/fish/conf.d"
cat <<'EOF' > "$HOME/.config/fish/conf.d/gem_env.fish"
set -gx GEM_HOME $HOME/.gem
set -gx GEM_PATH $HOME/.gem
if not contains $HOME/.gem/bin $PATH
set -gx PATH $HOME/.gem/bin $PATH
end
EOF
# Install terminal tools if not already installed
echo "Installing terminal tools..."