Compare commits

..

13 Commits

Author SHA1 Message Date
github-actions[bot] 02c4f864f7 chore(release): 2.2.5 [skip ci] 2026-02-28 19:35:54 +00:00
DevContainer User ea966fadab fix: restore Helm CLI in Dockerfile
Only the MCP sidecar was removed, not the CLI itself.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:35:22 +00:00
github-actions[bot] f0e70438db chore(release): 2.2.4 [skip ci] 2026-02-28 19:34:40 +00:00
DevContainer User 0fe568a7d6 fix: remove helm MCP sidecar and CLI, disable Docker layer cache
- Remove Helm CLI from Dockerfile (OOMKilled sidecar was the only consumer)
- Disable helm MCP sidecar in chart values (uses 194Mi+ idle, OOMKills at 256Mi)
- Remove helm from .mcp.json
- Disable Docker layer cache in build-and-push workflow (cache serves stale
  layers missing tool binaries - DO NOT RE-ENABLE)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:34:00 +00:00
DevContainer User 7235d2dc67 fix: disable Docker layer cache in release builds
Release workflow was using GHA cache which served stale layers,
causing tools like gh CLI to be missing from tagged images despite
being in the Dockerfile. Use no-cache for release builds to ensure
every layer is built fresh. Regular CI builds keep the cache for speed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:43:11 +00:00
DevContainer User 7940e80cf0 chore: bump chart version to 2.2.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:10:39 +00:00
DevContainer User f6cbec05f6 feat: disable Claude Code auto-updater by default
Auto-updater doesn't work inside Docker and produces annoying errors.
Seed ~/.claude/settings.json with DISABLE_AUTOUPDATER=1 via /etc/skel
(new PVCs) and init-repo.sh (existing PVCs).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 15:27:17 +00:00
Chris Farhood 9175d48844 fix: correct ha-mcp image tag from v6.7.1 to 6.7.1 (no v prefix) 2026-02-28 09:23:34 -05:00
DevContainer User cb60f2a428 chore: bump chart version to 2.2.0
Breaking change: removed Happy Coder and Node.js.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:22:09 +00:00
DevContainer User 1179897cba feat: remove Happy Coder and Node.js from devcontainer
Happy Coder is no longer used. Node.js was only installed as a
dependency for `npm install -g happy-coder`, so both are removed.
This shrinks the Docker image and simplifies the configuration.

Removed from: Dockerfile, Helm values/schema/templates, serverless
manifests, Makefile, and all documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:17:47 +00:00
DevContainer User 46dc486cb4 fix: use mcp-helm hardcoded port 8012 and remove invalid -port arg
mcp-helm does not support a -port flag — it always listens on 8012.
The invalid argument caused the container to crashloop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:41:31 +00:00
github-actions[bot] 41ec70c7da chore(release): 2.1.1 [skip ci] 2026-02-27 02:46:33 +00:00
DevContainer User e3f751240a fix: use expanding heredoc for release notes to avoid sed failure
The multi-line COMMITS variable broke sed substitution due to embedded
newlines. Switch to an expanding heredoc that interpolates variables
directly, removing the fragile sed placeholder replacement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 02:30:03 +00:00
19 changed files with 36 additions and 184 deletions
-1
View File
@@ -19,7 +19,6 @@
- [ ] Built Docker image locally
- [ ] Tested container startup
- [ ] Tested repository cloning
- [ ] Tested Happy Coder integration
- [ ] Tested VNC web interface
## Checklist
+1 -2
View File
@@ -56,6 +56,5 @@ jobs:
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
no-cache: true
platforms: linux/amd64
+15 -16
View File
@@ -96,11 +96,11 @@ jobs:
with:
context: .
push: true
no-cache: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
@@ -156,8 +156,10 @@ jobs:
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
TAG: ${{ steps.version.outputs.tag }}
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}
run: |
# Build release notes
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD)
@@ -165,29 +167,26 @@ jobs:
COMMITS=$(git log --pretty=format:"- %s (%h)" "${PREV_TAG}..HEAD")
fi
cat > release-notes.md <<'NOTESEOF'
## Release RELEASE_VERSION
cat > release-notes.md <<NOTESEOF
## Release ${VERSION}
### Changes
RELEASE_COMMITS
${COMMITS}
### Docker Image
```bash
docker pull RELEASE_IMAGE
```
\`\`\`bash
docker pull ${IMAGE}
\`\`\`
### Helm Chart
```bash
\`\`\`bash
helm repo add devcontainer https://cpfarhood.github.io/devcontainer
helm repo update
helm install mydev devcontainer/devcontainer --version RELEASE_VERSION --set name=mydev
```
helm install mydev devcontainer/devcontainer --version ${VERSION} --set name=mydev
\`\`\`
NOTESEOF
sed -i 's/^ //' release-notes.md
sed -i "s|RELEASE_VERSION|${{ steps.version.outputs.version }}|g" release-notes.md
sed -i "s|RELEASE_IMAGE|${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}|g" release-notes.md
sed -i "s|RELEASE_COMMITS|${COMMITS}|g" release-notes.md
gh release create "${{ steps.version.outputs.tag }}" \
--title "Release ${{ steps.version.outputs.tag }}" \
gh release create "${TAG}" \
--title "Release ${TAG}" \
--notes-file release-notes.md
-4
View File
@@ -18,10 +18,6 @@
"playwright": {
"type": "sse",
"url": "http://localhost:8086/sse"
},
"helm": {
"type": "sse",
"url": "http://localhost:8088/sse"
}
}
}
+3 -5
View File
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
The Dev Container is a Docker-based cloud development environment that provides:
- Web-based GUI IDE (VSCode/Antigravity) via VNC on port 5800
- Claude Code, Happy Coder, OpenCode, and Crush AI coding agents (terminal-based)
- Claude Code, OpenCode, and Crush AI coding agents (terminal-based)
- Built-in web file manager for uploading/downloading files (optional, via `fileManager.enabled`)
- Automatic GitHub repository cloning on startup
- Kubernetes-native deployment with persistent home storage
@@ -69,7 +69,7 @@ Container start
| File | Purpose |
|------|---------|
| `Dockerfile` | Image definition — installs Chrome, Node.js, VSCode, Helm, gh CLI, kubeseal, Claude Code, Happy Coder, OpenCode, Crush; creates non-root user (UID 1000) |
| `Dockerfile` | Image definition — installs Chrome, VSCode, Helm, gh CLI, kubeseal, Claude Code, OpenCode, Crush; creates non-root user (UID 1000) |
| `scripts/init-repo.sh` | Configures git credentials, clones GitHub repo |
| `scripts/startapp.sh` | Calls init-repo.sh then opens VSCode in the workspace |
| `chart/` | Helm chart for Kubernetes deployment |
@@ -89,7 +89,7 @@ MCP (Model Context Protocol) servers run as sidecar containers in the pod, enabl
|---------|-------|---------|------|----------|---------|
| `kubernetes-mcp` | `quay.io/containers/kubernetes_mcp_server` | v0.0.57 | 8080 | `http://localhost:8080/sse` | Enabled |
| `flux-mcp` | `ghcr.io/controlplaneio-fluxcd/flux-operator-mcp` | v0.41.1 | 8081 | `http://localhost:8081/sse` | Enabled |
| `helm-mcp` | `ghcr.io/zekker6/mcp-helm` | v1.3.1 | 8088 | `http://localhost:8088/sse` | Enabled |
| `helm-mcp` | `ghcr.io/zekker6/mcp-helm` | v1.3.1 | 8012 | `http://localhost:8012/sse` | Enabled |
| `fetch-mcp` | `mcp/fetch` | latest | 8082 | `http://localhost:8082/sse` | Enabled |
| `sequentialthinking-mcp` | `mcp/sequentialthinking` | latest | 8083 | `http://localhost:8083/sse` | Enabled |
| `homeassistant-mcp` | `ghcr.io/homeassistant-ai/ha-mcp` | stable | 8087 | `http://localhost:8087/sse` | Disabled |
@@ -188,8 +188,6 @@ helm install my-devcontainer ./chart -f custom-values.yaml
- `VNC_PASSWORD` — VNC web interface password
- `DISPLAY_WIDTH` / `DISPLAY_HEIGHT` — VNC resolution
- `USER_ID` / `GROUP_ID` — Override UID/GID (default 1000)
- `HAPPY_SERVER_URL` / `HAPPY_WEBAPP_URL` — Custom Happy Coder endpoints
- `HAPPY_HOME_DIR` / `HAPPY_EXPERIMENTAL`
- `WEB_FILE_MANAGER` — Set to `1` to enable the built-in web file manager (controlled via `fileManager.enabled` in Helm values)
- `WEB_FILE_MANAGER_ALLOWED_PATHS` — Paths accessible by the file manager (default: `/workspace,/config`)
- `WEB_FILE_MANAGER_DENIED_PATHS` — Paths to deny access to (takes precedence over allowed)
-12
View File
@@ -225,18 +225,6 @@ spec:
## Advanced Configurations
### Custom Happy Coder Endpoints
For self-hosted Happy instances:
```bash
helm install mydev ./chart \
--set name=mydev \
--set githubRepo=https://github.com/youruser/yourrepo \
--set happyServerUrl=https://your-happy-server.com \
--set happyWebappUrl=https://your-happy-webapp.com
```
### Custom Display Resolution
```bash
+4 -8
View File
@@ -56,20 +56,16 @@ exec /usr/bin/google-chrome-stable \\\n\
"$@"\n' > /usr/local/bin/google-chrome && \
chmod +x /usr/local/bin/google-chrome
# Install Node.js LTS (required by Happy Coder)
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
# Install Happy Coder globally via npm (stable, rarely changes)
RUN npm install -g happy-coder
# Install Claude Code native binary (npm wrapper breaks remote control)
RUN curl -fsSL https://claude.ai/install.sh | bash && \
cp /root/.local/bin/claude /usr/local/bin/claude && \
rm -rf /root/.local/bin/claude && \
claude --version
# Disable Claude Code auto-updater (doesn't work inside Docker)
RUN mkdir -p /etc/skel/.claude && \
echo '{"env":{"DISABLE_AUTOUPDATER":"1"}}' > /etc/skel/.claude/settings.json
# Install OpenCode AI coding agent
RUN OPENCODE_VERSION=$(curl -sL https://api.github.com/repos/opencode-ai/opencode/releases/latest | jq -r '.tag_name') && \
curl -fsSL "https://github.com/opencode-ai/opencode/releases/download/${OPENCODE_VERSION}/opencode-linux-x86_64.tar.gz" | \
-1
View File
@@ -26,7 +26,6 @@ run:
-e GITHUB_REPO="${GITHUB_REPO}" \
-e GITHUB_TOKEN="${GITHUB_TOKEN}" \
-e VNC_PASSWORD="${VNC_PASSWORD}" \
-e HAPPY_EXPERIMENTAL="true" \
-v $(PWD)/home:/home \
-v $(PWD)/workspace:/workspace \
--name devcontainer \
+3 -32
View File
@@ -5,7 +5,7 @@
A containerized cloud development environment with web-based GUI access, featuring:
- **VSCode or Google Antigravity** via browser-based VNC (port 5800)
- **SSH access** option (OpenSSH on port 22, additive with any IDE)
- **Claude Code**, **Happy Coder**, **OpenCode**, and **Crush** AI coding agents (terminal-based)
- **Claude Code**, **OpenCode**, and **Crush** AI coding agents (terminal-based)
- **Built-in web file manager** for uploading/downloading files via the VNC web interface
- **Helm CLI** included for Kubernetes chart development and deployment
- **Automatic GitHub repo cloning** on startup
@@ -114,7 +114,7 @@ The Helm chart uses a logical organization with these main sections:
- **Basic Configuration**: name, image, githubRepo
- **Access & Interface**: IDE, SSH, display, user settings
- **Infrastructure**: storage, resources, cluster access
- **Integrations**: Happy Coder, MCP sidecars
- **Integrations**: MCP sidecars
- **Smart Defaults**: auto-detection and profiles
📖 **Documentation**:
@@ -189,15 +189,6 @@ helm install mydev ./chart \
--set fileManager.enabled=true
```
### Happy Coder
| Value | Default | Description |
|-------|---------|-------------|
| `happy.serverUrl` | `https://happy.farh.net` | Happy Coder server endpoint |
| `happy.webappUrl` | `https://happy-coder.farh.net` | Happy Coder webapp URL |
| `happy.homeDir` | `/config/userdata/.happy` | Happy runtime state directory (persists on the home PVC) |
| `happy.experimental` | `true` | Enable experimental Happy features |
### Kubernetes cluster access
The `clusterAccess` value provisions a ServiceAccount, Role/ClusterRole, and binding so the devcontainer pod can interact with the Kubernetes API. The default is `none` — no RBAC resources are created.
@@ -377,30 +368,10 @@ Container start
| `/config` | ReadWriteMany PVC (`userhome-{name}`) | Survives pod restarts — stores Claude credentials, dotfiles, git config |
| `/workspace` | `emptyDir` | Ephemeral — repo is re-cloned on each pod start |
Happy Coder's runtime state (`HAPPY_HOME_DIR`) is kept in `/config/userdata/.happy` on the persistent home PVC, so auth credentials and settings survive pod restarts when manually started.
---
## Troubleshooting
### Happy Coder (manual startup)
Happy daemon is not started automatically. Launch it manually when needed:
```bash
# Start Happy Coder daemon manually
happy daemon start
# Check daemon status
happy daemon status
# View daemon logs
ls ~/.happy/logs/
# Stop daemon if needed
happy daemon stop
```
### Claude not authenticated
Browser-based OAuth login is the primary method (works inside VNC via the Chrome wrapper). If you prefer API key auth:
@@ -466,4 +437,4 @@ The image is also built and pushed automatically by CI on every push to `main` a
## Credits
- Base image: [jlesage/docker-baseimage-gui](https://github.com/jlesage/docker-baseimage-gui)
- AI assistant: [Happy Coder](https://happy.engineering) + [Claude](https://claude.ai)
- AI assistant: [Claude](https://claude.ai)
-30
View File
@@ -52,30 +52,6 @@ Complete reference for all configurable values in the Antigravity Dev Container
- **Options:** `Always`, `IfNotPresent`, `Never`
- **Description:** Image pull policy
## Happy Coder Configuration
### happyServerUrl
- **Type:** String
- **Default:** `https://happy.farh.net`
- **Description:** Happy Coder server endpoint
- **When to Change:** Self-hosted Happy instance
### happyWebappUrl
- **Type:** String
- **Default:** `https://happy-coder.farh.net`
- **Description:** Happy Coder webapp URL
- **When to Change:** Self-hosted Happy instance
### happyHomeDir
- **Type:** String
- **Default:** `/config/userdata/.happy`
- **Description:** Happy runtime state directory (persists on PVC)
### happyExperimental
- **Type:** String
- **Default:** `"true"`
- **Description:** Enable experimental Happy features
## Display Configuration
### display.width
@@ -339,8 +315,6 @@ storage:
clusterAccess: readonly
happyServerUrl: https://happy.internal.company.com
happyWebappUrl: https://happy-app.internal.company.com
```
### Smart Home Development Configuration
@@ -431,10 +405,6 @@ These environment variables are set in the container based on chart values:
| `VNC_PASSWORD` | Secret: `vnc-password` | VNC access password |
| `ANTHROPIC_API_KEY` | Secret: `anthropic-api-key` | Claude API key |
| `SSH_AUTHORIZED_KEYS` | Secret: `ssh-authorized-keys` | SSH public keys |
| `HAPPY_SERVER_URL` | `happyServerUrl` | Happy server endpoint |
| `HAPPY_WEBAPP_URL` | `happyWebappUrl` | Happy webapp URL |
| `HAPPY_HOME_DIR` | `happyHomeDir` | Happy data directory |
| `HAPPY_EXPERIMENTAL` | `happyExperimental` | Experimental features |
| `DISPLAY_WIDTH` | `display.width` | VNC width |
| `DISPLAY_HEIGHT` | `display.height` | VNC height |
| `SECURE_CONNECTION` | `secureConnection` | TLS termination |
+1 -1
View File
@@ -2,7 +2,7 @@ apiVersion: v2
name: devcontainer
description: Dev Container with AI coding agents and MCP sidecars - supports persistent and dynamic deployment modes
type: application
version: 2.1.0
version: 2.2.5
appVersion: "latest"
keywords:
- development
-9
View File
@@ -80,14 +80,6 @@ spec:
value: {{ .Values.fileManager.deniedPaths | quote }}
{{- end }}
{{- end }}
- name: HAPPY_HOME_DIR
value: {{ .Values.happy.homeDir | quote }}
- name: HAPPY_EXPERIMENTAL
value: {{ .Values.happy.experimental | quote }}
- name: HAPPY_SERVER_URL
value: {{ .Values.happy.serverUrl | quote }}
- name: HAPPY_WEBAPP_URL
value: {{ .Values.happy.webappUrl | quote }}
{{- if .Values.githubRepo }}
- name: GITHUB_REPO
value: {{ .Values.githubRepo | quote }}
@@ -184,7 +176,6 @@ spec:
image: "{{ .Values.mcp.sidecars.helm.image.repository }}:{{ .Values.mcp.sidecars.helm.image.tag }}"
args:
- -mode=sse
- -port={{ .Values.mcp.sidecars.helm.port }}
ports:
- containerPort: {{ .Values.mcp.sidecars.helm.port }}
name: helm-mcp
-13
View File
@@ -59,19 +59,6 @@ spec:
value: "1"
- name: WEB_FILE_MANAGER_ALLOWED_PATHS
value: "/workspace,/tmp" # No persistent /config in dynamic mode
# Happy Coder (ephemeral in dynamic mode)
- name: HAPPY_HOME_DIR
value: "/tmp/.happy"
- name: HAPPY_EXPERIMENTAL
value: {{ .Values.happy.experimental | quote }}
{{- if .Values.happy.serverUrl }}
- name: HAPPY_SERVER_URL
value: {{ .Values.happy.serverUrl | quote }}
{{- end }}
{{- if .Values.happy.webappUrl }}
- name: HAPPY_WEBAPP_URL
value: {{ .Values.happy.webappUrl | quote }}
{{- end }}
# Secret environment variables
envFrom:
- secretRef:
-7
View File
@@ -100,13 +100,6 @@ user:
shm:
sizeLimit: 2Gi
# Happy Coder (ephemeral in dynamic mode)
happy:
serverUrl: ""
webappUrl: ""
homeDir: "/tmp/.happy" # Ephemeral location in dynamic mode
experimental: "true"
# MCP sidecars are not supported in dynamic mode (Knative limitation)
mcp:
sidecars:
-23
View File
@@ -229,29 +229,6 @@
"enum": ["none", "readonlyns", "readwritens", "readonly", "readwrite"],
"description": "Kubernetes cluster access level"
},
"happy": {
"type": "object",
"properties": {
"serverUrl": {
"type": "string",
"description": "Happy Coder server URL"
},
"webappUrl": {
"type": "string",
"description": "Happy Coder webapp URL"
},
"homeDir": {
"type": "string",
"description": "Happy Coder home directory"
},
"experimental": {
"type": "string",
"enum": ["true", "false"],
"description": "Enable experimental Happy features"
}
},
"required": ["homeDir", "experimental"]
},
"mcp": {
"type": "object",
"properties": {
+3 -10
View File
@@ -83,13 +83,6 @@ clusterAccess: none
# INTEGRATIONS
# =============================================================================
# Happy Coder AI assistant configuration
happy:
serverUrl: ""
webappUrl: ""
homeDir: "/config/userdata/.happy"
experimental: "true"
# MCP (Model Context Protocol) server sidecars
mcp:
sidecars:
@@ -126,11 +119,11 @@ mcp:
# Helm chart browsing and management
helm:
enabled: true
enabled: false
image:
repository: ghcr.io/zekker6/mcp-helm
tag: v1.3.1
port: 8088
port: 8012
resources:
requests:
memory: "64Mi"
@@ -144,7 +137,7 @@ mcp:
enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN
image:
repository: ghcr.io/homeassistant-ai/ha-mcp
tag: v6.7.1
tag: "6.7.1"
port: 8087
resources:
requests:
+6
View File
@@ -104,6 +104,12 @@ chown -R "$RUN_UID:$RUN_GID" "$WORKSPACE_DIR"
mkdir -p "$HOME"
chown "$RUN_UID:$RUN_GID" "$HOME"
# Seed Claude Code settings if missing (disable auto-updater in Docker)
if [ ! -f "$HOME/.claude/settings.json" ]; then
mkdir -p "$HOME/.claude"
echo '{"env":{"DISABLE_AUTOUPDATER":"1"}}' > "$HOME/.claude/settings.json"
chown -R "$RUN_UID:$RUN_GID" "$HOME/.claude"
fi
# Export workspace directory for startapp.sh
echo "$WORKSPACE_DIR" > /tmp/workspace-dir
-5
View File
@@ -155,11 +155,6 @@ spec:
value: "1"
- name: WEB_FILE_MANAGER_ALLOWED_PATHS
value: "/workspace,/config"
# Happy Coder config (ephemeral in serverless mode)
- name: HAPPY_HOME_DIR
value: "/tmp/.happy"
- name: HAPPY_EXPERIMENTAL
value: "true"
# Use secrets for sensitive data
envFrom:
- secretRef:
-5
View File
@@ -49,11 +49,6 @@ spec:
value: "1"
- name: WEB_FILE_MANAGER_ALLOWED_PATHS
value: "/workspace,/config"
# Happy Coder config
- name: HAPPY_HOME_DIR
value: "/config/userdata/.happy"
- name: HAPPY_EXPERIMENTAL
value: "true"
# Use secrets for sensitive data
envFrom:
- secretRef: