cc
This commit is contained in:
148
WARP.md
Normal file
148
WARP.md
Normal 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.
|
||||
@@ -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
|
||||
@@ -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'"
|
||||
]))
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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..."
|
||||
Reference in New Issue
Block a user