Compare commits

..

28 Commits

Author SHA1 Message Date
github-actions[bot] 3637a0a6fc chore: release version 1.0.2 2026-02-24 02:53:07 +00:00
DevContainer User f67066823b fix(docker): correct Crush installation tar extraction
Fixed the Crush AI assistant installation in Dockerfile by replacing the
single-line tar extraction with --strip-components (which was failing)
with a multi-step approach: download to temp, extract, move binary,
and cleanup. This ensures the binary is properly extracted from the
versioned directory structure in the tarball.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-24 02:42:44 +00:00
Chris Farhood 50560652cb feat(helm): rip out sequentialthinking MCP server sidecar 2026-02-23 21:05:40 -05:00
Chris Farhood 0fc4ff503b ci: fix chart version update failing when version already matches 2026-02-23 20:55:38 -05:00
Chris Farhood 04203e4efb feat(helm): rip out fetch MCP server as requested 2026-02-23 20:54:15 -05:00
Chris Farhood b710daac05 fix(helm): allow additionalProperties in values schema to prevent Flux dropping variables and change sidecar container configs 2026-02-23 20:54:15 -05:00
github-actions[bot] 52a29da38d chore: release version 0.4.11 2026-02-24 01:45:24 +00:00
github-actions[bot] ea71f71c74 chore: release version 0.4.9 2026-02-24 01:25:29 +00:00
Chris Farhood f6eceb4d94 fix(helm): shorten sequentialthinking port name (fixes #48) 2026-02-23 20:24:27 -05:00
github-actions[bot] 84bf7841c3 chore: release version 0.4.8 2026-02-23 23:59:03 +00:00
Chris Farhood c823a30c2a fix(chart): add missing MCP sidecars to values schema (#47)
PR #45 added fetch and sequentialthinking MCP sidecars to values.yaml
and the deployment template but missed updating values.schema.json.
The schema has additionalProperties: false on mcp.sidecars, causing
Helm upgrade to fail with validation errors.

Also adds resourceProfile to the schema as it was missing.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
2026-02-23 18:57:41 -05:00
github-actions[bot] 27af9dc9c4 chore: release version 0.4.7 2026-02-23 23:35:13 +00:00
github-actions[bot] 0944dcec1c chore: release version 0.4.6 2026-02-23 21:19:15 +00:00
Chris Farhood 60a2689658 Merge pull request #46 from cpfarhood/fix/ci-race-condition
fix(ci): resolve Docker build race condition
2026-02-23 16:18:04 -05:00
Chris Farhood 53bc4b68a6 fix(ci): resolve race condition between build and release workflows
Remove tag triggers and duplicate release job from build-and-push.yaml.
The release-unified.yaml workflow handles the full release flow (Docker
build, Helm chart, GitHub release) when triggered via workflow_dispatch.

Previously, release-unified.yaml pushing a commit to main AND a v* tag
would trigger build-and-push.yaml up to twice, causing multiple Docker
builds to race for the :latest tag. The stale GHA layer cache in the
racing build could overwrite :latest with an image missing new tools
(e.g., crush, opencode).

Changes:
- Remove tags: ['v*'] trigger (release-unified handles tag-based releases)
- Remove duplicate release job (Helm chart + GitHub release)
- Remove semver tag patterns from metadata (not needed without tag trigger)
- Skip builds from github-actions[bot] to avoid racing with release commits

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-23 16:05:53 -05:00
Chris Farhood d526a445fd Merge pull request #45 from cpfarhood/feature/add-fetch-sequential-thinking-mcp
feat: add Fetch and Sequential Thinking MCP sidecars
2026-02-23 13:41:46 -05:00
DevContainer User f56b3efb66 feat: add Fetch and Sequential Thinking MCP sidecars
Add two new MCP (Model Context Protocol) sidecars to enable web content fetching
and structured problem-solving capabilities:

- **Fetch MCP**: Web content fetching and HTML to markdown conversion on port 8082
- **Sequential Thinking MCP**: Structured thinking and problem-solving processes on port 8083

Both sidecars are enabled by default and use the official MCP Docker images
(mcp/fetch and mcp/sequentialthinking) with fastmcp SSE transport.

Changes:
- Add fetch and sequentialthinking sidecars to values.yaml
- Add sidecar containers to deployment.yaml template
- Update .mcp.json with new server endpoints
- Update CLAUDE.md documentation with new sidecar details

Closes #43, #44

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-23 18:37:12 +00:00
github-actions[bot] a778d32b3b chore: release version 0.4.5 2026-02-23 01:17:43 +00:00
DevContainer User b48fce97d5 fix: improve Antigravity IDE installation to resolve AI chat issues
- Force fresh APT repository data by clearing package cache before update
- Add debugging output to show available and installed versions
- Use --no-install-recommends to avoid unnecessary packages
- Add version validation during build process
- Disable auto-updates in Antigravity settings to prevent container conflicts

This should resolve the "agentSessions service not found" error that prevents
the AI chat window from responding.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-23 01:13:41 +00:00
github-actions[bot] 47af7acc5e chore: release version 0.4.4 2026-02-23 01:08:30 +00:00
DevContainer User da45415cfe fix: playwright MCP sidecar bind to 0.0.0.0 for probe access (#42)
The Playwright MCP server binds to 127.0.0.1 by default, which makes
it unreachable by Kubernetes liveness/readiness probes from the kubelet.
Add --host 0.0.0.0 to bind to all interfaces.

Fixes #42

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 20:43:28 +00:00
DevContainer User 897555b1dc chore: bump chart version to 0.4.2
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 20:27:12 +00:00
DevContainer User df1f4d9b50 fix: ensure Docker image is built before release creation
- Move release job into build-and-push workflow with dependency
- Remove separate release.yaml workflow to prevent race condition
- Ensures Docker image is available before GitHub release is published

Fixes the issue where clients see release with docker pull instructions
before the image is uploaded to GHCR.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 20:20:26 +00:00
DevContainer User 2f5a8d65d5 fix: playwright MCP sidecar startup args (#41)
The Playwright MCP image (mcr.microsoft.com/playwright/mcp) doesn't
support --transport flag. Use node cli.js entrypoint with --headless,
--browser chromium, --no-sandbox, and --port for SSE mode.

Fixes #41

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 20:04:16 +00:00
github-actions[bot] 0d8fe1ec64 chore: release version 0.4.0 2026-02-22 19:39:04 +00:00
DevContainer User 00638d372c docs: comprehensive update for new values format and template names
- Fix CLAUDE.md: update Docker build example from antigravity to devcontainer
- Fix README.md stale value references throughout:
  - ide → ide.type, ssh → ssh.enabled
  - happyServerUrl → happy.serverUrl (and all happy.* values)
  - secureConnection → display.secureConnection
  - userId/groupId → user.id/user.groupId
  - mcpSidecars.* → mcp.sidecars.*
- Remove GitHub MCP sidecar from custom config example (discontinued)
- Fix YAML indentation in MCP config examples
- Fix storage mount path from /home to /config
- Fix Happy state directory from /home/user/.happy to /config/userdata/.happy

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 19:38:11 +00:00
DevContainer User 31ec139a8a refactor: rename template helpers from antigravity to devcontainer
Rename all Helm template helper functions from antigravity.* to
devcontainer.* to match the actual chart name. Also update Chart.yaml
description to remove "Antigravity" branding.

Renamed helpers:
- antigravity.fullname → devcontainer.fullname
- antigravity.pvcName → devcontainer.pvcName
- antigravity.envSecretName → devcontainer.envSecretName
- antigravity.labels → devcontainer.labels
- antigravity.smartResources → devcontainer.smartResources
- antigravity.smartDefaults → devcontainer.smartDefaults
- antigravity.mcpDefaults → devcontainer.mcpDefaults

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 19:34:09 +00:00
DevContainer User 71c6ca70cc fix: resolve MCP sidecar image failures (issue #40)
Three fixes for broken MCP sidecars:

1. Remove GitHub MCP sidecar entirely - the upstream image
   (ghcr.io/modelcontextprotocol/servers/github) is discontinued.
   GitHub MCP is now accessed via Copilot API instead.

2. Fix Playwright MCP image - changed from non-existent
   microsoft/playwright-mcp to mcr.microsoft.com/playwright/mcp
   (the official Microsoft Container Registry image).

3. Fix pgtuner MCP startup command - changed --transport to --mode
   and added --host 0.0.0.0 to match the current pgtuner_mcp CLI.

Bumps chart version to 0.3.3.

Closes #40

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-22 19:31:08 +00:00
16 changed files with 181 additions and 287 deletions
+3 -1
View File
@@ -2,6 +2,8 @@
"enabledMcpjsonServers": [
"kubernetes",
"flux",
"playwright"
"playwright",
"github",
"pgtuner"
]
}
+3 -5
View File
@@ -4,8 +4,6 @@ on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
@@ -18,6 +16,9 @@ env:
jobs:
build-and-push:
runs-on: ubuntu-latest
# Skip builds triggered by release-unified.yaml commits (github-actions[bot])
# to prevent racing with the release workflow's own Docker build
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.actor != 'github-actions[bot]'
permissions:
contents: read
packages: write
@@ -46,9 +47,6 @@ jobs:
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix=sha-
type=raw,value=latest,enable={{is_default_branch}}
+1 -1
View File
@@ -79,7 +79,7 @@ jobs:
run: |
sed -i "s/^version: .*/version: ${{ steps.version.outputs.version }}/" chart/Chart.yaml
git add chart/Chart.yaml
git commit -m "chore: release version ${{ steps.version.outputs.version }}"
git diff --quiet --staged || git commit -m "chore: release version ${{ steps.version.outputs.version }}"
- name: Create and Push Tag
run: |
-86
View File
@@ -1,86 +0,0 @@
name: Release
on:
push:
tags:
- 'v*'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Helm
uses: azure/setup-helm@v4
- name: Extract version from tag
id: version
run: |
TAG=${GITHUB_REF#refs/tags/}
VERSION=${TAG#v}
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "🚀 Creating release for ${TAG}"
- name: Package and Push Helm Chart
run: |
helm registry login ghcr.io \
--username ${{ github.actor }} \
--password ${{ secrets.GITHUB_TOKEN }}
helm package chart/
helm push devcontainer-${{ steps.version.outputs.version }}.tgz oci://ghcr.io/cpfarhood/charts
- name: Generate Release Notes
id: notes
run: |
# Get commits since last tag
PREV_TAG=$(git describe --tags --abbrev=0 ${{ steps.version.outputs.tag }}^ 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
COMMITS=$(git log --pretty=format:"- %s (%h)" ${{ steps.version.outputs.tag }})
else
COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..${{ steps.version.outputs.tag }})
fi
cat << EOF > release-notes.md
## 🚀 Release ${{ steps.version.outputs.version }}
### Changes
${COMMITS}
### Docker Image
\`\`\`bash
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}
\`\`\`
### Helm Chart
\`\`\`bash
helm install devcontainer oci://ghcr.io/cpfarhood/charts/devcontainer --version ${{ steps.version.outputs.version }}
\`\`\`
EOF
echo "notes<<EOF" >> $GITHUB_OUTPUT
cat release-notes.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.version.outputs.tag }}
release_name: Release ${{ steps.version.outputs.tag }}
body: ${{ steps.notes.outputs.notes }}
draft: false
prerelease: false
+8
View File
@@ -22,6 +22,14 @@
"pgtuner": {
"type": "sse",
"url": "http://localhost:8085/sse"
},
"fetch": {
"type": "sse",
"url": "http://localhost:8082/sse"
},
"sequentialthinking": {
"type": "sse",
"url": "http://localhost:8083/sse"
}
}
}
+37 -31
View File
@@ -20,7 +20,7 @@ The stack is primarily **Bash scripts + YAML** — there is no Node.js package,
```bash
make build # Build Docker image
make build REGISTRY=ghcr.io/myuser IMAGE_TAG=v1.0 # Custom registry/tag
docker build -t ghcr.io/cpfarhood/antigravity:latest . # Direct build
docker build -t ghcr.io/cpfarhood/devcontainer:latest . # Direct build
```
### Running Locally
@@ -77,7 +77,7 @@ Container start
| `chart/templates/pvc.yaml` | PersistentVolumeClaim for user home |
| `chart/templates/service.yaml` | ClusterIP Service (VNC + optional SSH) |
| `chart/values.yaml` | Default Helm values |
| `.mcp.json` | MCP server connection config (Kubernetes, Flux, GitHub, Home Assistant, Playwright) |
| `.mcp.json` | MCP server connection config (GitHub Copilot, Kubernetes, Flux, Fetch, Sequential Thinking, Playwright, pgtuner) |
| `Makefile` | Build/deploy automation |
### MCP Sidecars
@@ -88,15 +88,18 @@ 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 |
| `github-mcp` | `ghcr.io/modelcontextprotocol/servers/github` | latest | 8088 | `http://localhost:8088/sse` | Disabled |
| `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 |
| `pgtuner-mcp` | `dog830228/pgtuner_mcp` | latest | 8085 | `http://localhost:8085/sse` | Disabled |
| `playwright-mcp` | `microsoft/playwright-mcp` | latest | 8086 | `http://localhost:8086/sse` | Enabled |
| `playwright-mcp` | `mcr.microsoft.com/playwright/mcp` | latest | 8086 | `http://localhost:8086/sse` | Enabled |
**Note:**
- GitHub MCP is accessed via the Copilot API (`https://api.githubcopilot.com/mcp/`), not as a sidecar
- Kubernetes and Flux sidecars require `clusterAccess` != `none` to be deployed (they need RBAC permissions)
- Kubernetes and Flux sidecars inherit the pod's ServiceAccount RBAC permissions
- GitHub sidecar uses `GITHUB_TOKEN` from the env secret (same token used for repo cloning)
- Fetch sidecar provides web content fetching capabilities and HTML to markdown conversion
- Sequential thinking sidecar enables structured thinking and problem-solving processes
- Home Assistant sidecar requires `HOMEASSISTANT_URL` and `HOMEASSISTANT_TOKEN` in the env secret
- PostgreSQL tuner sidecar requires `DATABASE_URI` in the env secret (PostgreSQL connection string)
- Playwright sidecar provides browser automation and web testing capabilities
@@ -109,34 +112,38 @@ To control MCP sidecars, set the `enabled` flag in your values override:
# Disable all MCP sidecars
mcp:
sidecars:
kubernetes:
enabled: false
flux:
enabled: false
github:
enabled: false
homeassistant:
enabled: false
pgtuner:
enabled: false
playwright:
enabled: false
kubernetes:
enabled: false
flux:
enabled: false
fetch:
enabled: false
sequentialthinking:
enabled: false
homeassistant:
enabled: false
pgtuner:
enabled: false
playwright:
enabled: false
# Or selectively enable/disable
mcp:
sidecars:
kubernetes:
enabled: true # Keep Kubernetes MCP enabled
flux:
enabled: false # Disable Flux MCP
github:
enabled: true # Keep GitHub MCP enabled (uses GITHUB_TOKEN)
homeassistant:
enabled: true # Enable Home Assistant MCP (requires secrets)
pgtuner:
enabled: true # Enable PostgreSQL tuner MCP (requires DATABASE_URI)
playwright:
enabled: true # Enable Playwright MCP for browser automation
kubernetes:
enabled: true # Keep Kubernetes MCP enabled
flux:
enabled: false # Disable Flux MCP
fetch:
enabled: true # Enable Fetch MCP for web content fetching
sequentialthinking:
enabled: true # Enable Sequential Thinking MCP for problem-solving
homeassistant:
enabled: true # Enable Home Assistant MCP (requires secrets)
pgtuner:
enabled: true # Enable PostgreSQL tuner MCP (requires DATABASE_URI)
playwright:
enabled: true # Enable Playwright MCP for browser automation
```
When deploying via Helm:
@@ -179,8 +186,7 @@ helm install my-devcontainer ./chart -f custom-values.yaml
### CI/CD
- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. Tags: `latest` (main), semver, branch name, commit SHA.
- **`release.yaml`** — Creates a GitHub Release with docker pull instructions when a version tag is pushed.
- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. For version tags, also creates GitHub Release with Helm chart after Docker build completes. Tags: `latest` (main), semver, branch name, commit SHA.
- **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image.
Image registry: `ghcr.io/cpfarhood/devcontainer`
+22 -4
View File
@@ -72,9 +72,11 @@ RUN OPENCODE_VERSION=$(curl -sL https://api.github.com/repos/opencode-ai/opencod
# Install Crush AI coding agent (OpenCode successor by Charm)
RUN CRUSH_VERSION=$(curl -sL https://api.github.com/repos/charmbracelet/crush/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \
curl -fsSL "https://github.com/charmbracelet/crush/releases/download/v${CRUSH_VERSION}/crush_${CRUSH_VERSION}_Linux_x86_64.tar.gz" | \
tar -xz --strip-components=1 -C /usr/local/bin "crush_${CRUSH_VERSION}_Linux_x86_64/crush" && \
chmod +x /usr/local/bin/crush
curl -fsSL "https://github.com/charmbracelet/crush/releases/download/v${CRUSH_VERSION}/crush_${CRUSH_VERSION}_Linux_x86_64.tar.gz" -o /tmp/crush.tar.gz && \
tar -xzf /tmp/crush.tar.gz -C /tmp && \
mv /tmp/crush_${CRUSH_VERSION}_Linux_x86_64/crush /usr/local/bin/crush && \
chmod +x /usr/local/bin/crush && \
rm -rf /tmp/crush*
# Install VSCode
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/packages.microsoft.gpg && \
@@ -89,10 +91,26 @@ RUN mkdir -p /etc/apt/keyrings && \
gpg --dearmor --yes -o /etc/apt/keyrings/antigravity-repo-key.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/antigravity-repo-key.gpg] https://us-central1-apt.pkg.dev/projects/antigravity-auto-updater-dev/ antigravity-debian main" \
> /etc/apt/sources.list.d/antigravity.list && \
# Clear package cache to force fresh repository data
rm -rf /var/lib/apt/lists/* && \
apt-get update && \
apt-get install -y antigravity && \
# Show available versions for debugging
apt-cache policy antigravity && \
# Install latest version
apt-get install -y --no-install-recommends antigravity && \
# Display installed version
dpkg -l | grep antigravity && \
rm -rf /var/lib/apt/lists/*
# Pre-configure Antigravity to skip onboarding/setup on first run
RUN mkdir -p /etc/skel/.config/antigravity/User/globalStorage && \
echo '{"antigravityUnifiedStateSync.seenNuxOneTimeMigration": true, "antigravityUnifiedStateSync.browserOnboarding.completed": true, "antigravityUnifiedStateSync.hasOnboardingCompleted": true, "browserOnboarding.hasSeenWelcome": true, "antigravityUnifiedStateSync.browserPreferences.hasAddedLocalhostToAllowlist": true, "antigravityUnifiedStateSync.oauthToken.hasLegacyMigrated": true, "antigravityUnifiedStateSync.auth.tokenSyncEnabled": true, "antigravityUnifiedStateSync.auth.cloudSyncEnabled": true, "theme": "vs-dark"}' \
> /etc/skel/.config/antigravity/User/globalStorage/storage.json && \
echo '{"workbench.startupEditor": "none", "workbench.welcomePage.walkthroughs.openOnInstall": false, "workbench.tips.enabled": false, "extensions.ignoreRecommendations": true, "telemetry.telemetryLevel": "off", "update.mode": "none", "extensions.autoUpdate": false, "extensions.autoCheckUpdates": false, "workbench.enableExperiments": true, "workbench.settings.enableNaturalLanguageSearch": true, "antigravity.onboarding.completed": true, "antigravity.browserOnboarding.completed": true, "antigravity.setup.completed": true, "antigravity.ai.enabled": true, "antigravity.ai.autoComplete.enabled": true, "antigravity.ai.chat.enabled": true, "antigravity.ai.codeActions.enabled": true, "antigravity.ai.explainCode.enabled": true, "antigravity.ai.generateCode.enabled": true, "antigravity.ai.optimizeCode.enabled": true, "antigravity.ai.autoSuggest.enabled": true, "antigravity.telemetry.crashReporter": "on", "antigravity.ai.acceptTerms": true, "antigravity.auth.syncState": true, "antigravity.auth.enableTokenSync": true, "antigravity.ai.enableCloudSync": true, "antigravity.settings.sync": true}' \
> /etc/skel/.config/antigravity/User/settings.json && \
# Validate Antigravity installation
/usr/share/antigravity/antigravity --version || echo "WARNING: Antigravity version check failed"
# Install OpenSSH server (for SSH IDE mode)
RUN apt-get update && \
apt-get install -y openssh-server && \
+61 -77
View File
@@ -48,9 +48,9 @@ The secret is picked up automatically via `envFrom`. Keys recognised:
| `VNC_PASSWORD` | Password for the VNC web UI |
| `ANTHROPIC_API_KEY` | API key — alternative to browser-based Claude login |
| `SSH_AUTHORIZED_KEYS` | Public key(s) for SSH access (required when `ssh: true`) |
| `HOMEASSISTANT_URL` | Home Assistant URL (required when `mcpSidecars.homeassistant.enabled: true`) |
| `HOMEASSISTANT_TOKEN` | Home Assistant long-lived access token (required when `mcpSidecars.homeassistant.enabled: true`) |
| `DATABASE_URI` | PostgreSQL connection string (required when `mcpSidecars.pgtuner.enabled: true`) |
| `HOMEASSISTANT_URL` | Home Assistant URL (required when `mcp.sidecars.homeassistant.enabled: true`) |
| `HOMEASSISTANT_TOKEN` | Home Assistant long-lived access token (required when `mcp.sidecars.homeassistant.enabled: true`) |
| `DATABASE_URI` | PostgreSQL connection string (required when `mcp.sidecars.pgtuner.enabled: true`) |
| `PGTUNER_EXCLUDE_USERIDS` | Comma-separated PostgreSQL user OIDs to exclude from monitoring (optional) |
```bash
@@ -119,14 +119,14 @@ The Helm chart uses a logical organization with these main sections:
|-------|---------|-------------|
| `name` | `""` | Instance name — used in all resource names (`devcontainer-{name}`) |
| `githubRepo` | `""` | Repository to clone into `/workspace` on startup |
| `ide` | `vscode` | IDE to launch — `vscode`, `antigravity`, or `none` (see below) |
| `ssh` | `false` | Also start an OpenSSH server on port 22 (additive, any `ide`) |
| `ide.type` | `vscode` | IDE to launch — `vscode`, `antigravity`, or `none` (see below) |
| `ssh.enabled` | `false` | Also start an OpenSSH server on port 22 (additive, any IDE) |
| `image.repository` | `ghcr.io/cpfarhood/devcontainer` | Container image |
| `image.tag` | `latest` | Image tag |
### IDE choice
`ide` controls what GUI is launched in the VNC session:
`ide.type` controls what GUI is launched in the VNC session:
| Value | Port | Description |
|-------|------|-------------|
@@ -136,14 +136,14 @@ The Helm chart uses a logical organization with these main sections:
### SSH access
`ssh: true` starts OpenSSH on port 22 **in addition to** the IDE. It works with any `ide` value:
`ssh.enabled: true` starts OpenSSH on port 22 **in addition to** the IDE. It works with any `ide.type` value:
```bash
# SSH-only (no VNC)
helm install mydev ./chart --set name=mydev --set ide=none --set ssh=true
helm install mydev ./chart --set name=mydev --set ide.type=none --set ssh.enabled=true
# VSCode in VNC + SSH access at the same time
helm install mydev ./chart --set name=mydev --set ssh=true
helm install mydev ./chart --set name=mydev --set ssh.enabled=true
```
Add your public key to the env secret:
@@ -165,10 +165,10 @@ ssh -p 2222 user@localhost
| Value | Default | Description |
|-------|---------|-------------|
| `happyServerUrl` | `https://happy.farh.net` | Happy Coder server endpoint |
| `happyWebappUrl` | `https://happy-coder.farh.net` | Happy Coder webapp URL |
| `happyHomeDir` | `/home/user/.happy` | Happy runtime state directory (persists on the home PVC) |
| `happyExperimental` | `true` | Enable experimental Happy features |
| `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
@@ -200,16 +200,16 @@ The devcontainer includes MCP (Model Context Protocol) servers as sidecar contai
|---------|---------|---------|
| `mcp.sidecars.kubernetes.enabled` | `true` | Kubernetes API access via MCP |
| `mcp.sidecars.flux.enabled` | `true` | Flux GitOps operations via MCP |
| `mcp.sidecars.github.enabled` | `false` | GitHub API access via MCP (DISABLED: archived image) |
| `mcp.sidecars.homeassistant.enabled` | `false` | Home Assistant smart home control via MCP |
| `mcp.sidecars.pgtuner.enabled` | `false` | PostgreSQL performance tuning and analysis via MCP |
| `mcp.sidecars.playwright.enabled` | `true` | Browser automation and web testing via MCP |
**Notes:**
- GitHub MCP is accessed via the Copilot API (`https://api.githubcopilot.com/mcp/`), not as a sidecar
- Kubernetes and Flux sidecars require `clusterAccess` != `none` to be deployed (automatically disabled when no cluster access)
- Kubernetes and Flux sidecars inherit the pod's ServiceAccount RBAC permissions (controlled by `clusterAccess`)
- Home Assistant sidecar requires `homeassistant-url` and `homeassistant-token` in the env secret
- PostgreSQL tuner sidecar requires `database-uri` in the env secret (PostgreSQL connection string)
- Home Assistant sidecar requires `HOMEASSISTANT_URL` and `HOMEASSISTANT_TOKEN` in the env secret
- PostgreSQL tuner sidecar requires `DATABASE_URI` in the env secret (PostgreSQL connection string)
- Playwright sidecar provides browser automation and web testing capabilities
**Disable MCP sidecars:**
@@ -263,62 +263,46 @@ helm install mydev ./chart \
# values.yaml override
mcp:
sidecars:
kubernetes:
enabled: true
image:
repository: quay.io/containers/kubernetes_mcp_server
tag: v0.0.57
port: 8080
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
flux:
enabled: false # Disabled in this example
github:
enabled: false # Disabled by default (archived image)
homeassistant:
enabled: true
image:
repository: ghcr.io/homeassistant-ai/ha-mcp
tag: stable
port: 8087
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
pgtuner:
enabled: true
image:
repository: dog830228/pgtuner_mcp
tag: latest
port: 8085
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
playwright:
enabled: true
image:
repository: microsoft/playwright-mcp
tag: latest
port: 8086
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "1000m"
kubernetes:
enabled: true
image:
repository: quay.io/containers/kubernetes_mcp_server
tag: v0.0.57
port: 8080
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
flux:
enabled: false # Disabled in this example
homeassistant:
enabled: true
image:
repository: ghcr.io/homeassistant-ai/ha-mcp
tag: stable
port: 8087
pgtuner:
enabled: true
image:
repository: dog830228/pgtuner_mcp
tag: latest
port: 8085
playwright:
enabled: true
image:
repository: mcr.microsoft.com/playwright/mcp
tag: latest
port: 8086
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "1000m"
```
### Display and resources
@@ -327,9 +311,9 @@ mcp:
|-------|---------|-------------|
| `display.width` | `1920` | VNC width (px) |
| `display.height` | `1080` | VNC height (px) |
| `secureConnection` | `0` | Set to `1` if TLS is not terminated upstream |
| `userId` | `1000` | UID for the app user |
| `groupId` | `1000` | GID for the app user |
| `display.secureConnection` | `0` | Set to `1` if TLS is not terminated upstream |
| `user.id` | `1000` | UID for the app user |
| `user.groupId` | `1000` | GID for the app user |
| `storage.size` | `32Gi` | Home PVC size |
| `storage.className` | `ceph-filesystem` | StorageClass (must be ReadWriteMany) |
| `shm.sizeLimit` | `2Gi` | `/dev/shm` size (memory-backed; used by Electron apps) |
@@ -362,10 +346,10 @@ Container start
| Mount | Source | Persistence |
|-------|--------|-------------|
| `/home` | ReadWriteMany PVC (`userhome-{name}`) | Survives pod restarts — stores Claude credentials, dotfiles, git config |
| `/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 `/home/user/.happy` on the persistent home PVC, so auth credentials and settings survive pod restarts when manually started.
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.
---
+2 -2
View File
@@ -1,6 +1,6 @@
apiVersion: v2
name: devcontainer
description: Antigravity Dev Container with Happy Coder AI assistant
description: Dev Container with AI coding agents and MCP sidecars
type: application
version: 0.3.2
version: 1.0.2
appVersion: "latest"
+7 -7
View File
@@ -1,28 +1,28 @@
{{/*
Resource name prefix: devcontainer-{name}
*/}}
{{- define "antigravity.fullname" -}}
{{- define "devcontainer.fullname" -}}
{{- printf "devcontainer-%s" .Values.name }}
{{- end }}
{{/*
PVC name: userhome-{name}
*/}}
{{- define "antigravity.pvcName" -}}
{{- define "devcontainer.pvcName" -}}
{{- printf "userhome-%s" .Values.name }}
{{- end }}
{{/*
Secret name for env vars, default to devcontainer-{name}-secrets-env
*/}}
{{- define "antigravity.envSecretName" -}}
{{- define "devcontainer.envSecretName" -}}
{{- .Values.envSecretName | default (printf "devcontainer-%s-secrets-env" .Values.name) }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "antigravity.labels" -}}
{{- define "devcontainer.labels" -}}
app: devcontainer
instance: {{ .Values.name }}
{{- end }}
@@ -30,7 +30,7 @@ instance: {{ .Values.name }}
{{/*
Smart resource sizing based on enabled features
*/}}
{{- define "antigravity.smartResources" -}}
{{- define "devcontainer.smartResources" -}}
{{- $baseMemory := "2Gi" }}
{{- $baseCpu := "1000m" }}
{{- $limitMemory := "8Gi" }}
@@ -59,7 +59,7 @@ limits:
{{/*
Auto-detect environment type and set smart defaults
*/}}
{{- define "antigravity.smartDefaults" -}}
{{- define "devcontainer.smartDefaults" -}}
{{- $isDev := or (contains "dev" .Values.name) (contains "test" .Values.name) (contains "local" .Values.name) }}
{{- $isProd := or (contains "prod" .Values.name) (contains "production" .Values.name) }}
{{- $isTeam := or (contains "team" .Values.name) (contains "shared" .Values.name) }}
@@ -79,7 +79,7 @@ team: true
{{/*
Smart MCP sidecar selection based on cluster access
*/}}
{{- define "antigravity.mcpDefaults" -}}
{{- define "devcontainer.mcpDefaults" -}}
{{- if eq .Values.clusterAccess "none" }}
{{/* No cluster access - disable k8s/flux sidecars */}}
kubernetes:
+20 -46
View File
@@ -1,21 +1,21 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "antigravity.fullname" . }}
name: {{ include "devcontainer.fullname" . }}
labels:
{{- include "antigravity.labels" . | nindent 4 }}
{{- include "devcontainer.labels" . | nindent 4 }}
spec:
replicas: 1
selector:
matchLabels:
{{- include "antigravity.labels" . | nindent 6 }}
{{- include "devcontainer.labels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "antigravity.labels" . | nindent 8 }}
{{- include "devcontainer.labels" . | nindent 8 }}
spec:
{{- if ne (.Values.clusterAccess | default "none") "none" }}
serviceAccountName: {{ include "antigravity.fullname" . }}
serviceAccountName: {{ include "devcontainer.fullname" . }}
{{- end }}
securityContext:
fsGroup: 1000
@@ -81,7 +81,7 @@ spec:
value: {{ .Values.githubRepo | quote }}
envFrom:
- secretRef:
name: {{ include "antigravity.envSecretName" . }}
name: {{ include "devcontainer.envSecretName" . }}
optional: true
resources:
{{- toYaml .Values.resources | nindent 12 }}
@@ -178,13 +178,13 @@ spec:
- name: HOMEASSISTANT_URL
valueFrom:
secretKeyRef:
name: {{ include "antigravity.envSecretName" . }}
name: {{ include "devcontainer.envSecretName" . }}
key: HOMEASSISTANT_URL
optional: true
- name: HOMEASSISTANT_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "antigravity.envSecretName" . }}
name: {{ include "devcontainer.envSecretName" . }}
key: HOMEASSISTANT_TOKEN
optional: true
livenessProbe:
@@ -200,43 +200,11 @@ spec:
resources:
{{- toYaml .Values.mcp.sidecars.homeassistant.resources | nindent 12 }}
{{- end }}
{{- if .Values.mcp.sidecars.github.enabled }}
- name: github-mcp
image: "{{ .Values.mcp.sidecars.github.image.repository }}:{{ .Values.mcp.sidecars.github.image.tag }}"
imagePullPolicy: Always
args:
- --sse
- --port={{ .Values.mcp.sidecars.github.port }}
ports:
- name: github
containerPort: {{ .Values.mcp.sidecars.github.port }}
env:
- name: GITHUB_PERSONAL_ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "antigravity.envSecretName" . }}
key: GITHUB_TOKEN
optional: true
livenessProbe:
httpGet:
path: /health
port: {{ .Values.mcp.sidecars.github.port }}
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: {{ .Values.mcp.sidecars.github.port }}
initialDelaySeconds: 5
periodSeconds: 5
resources:
{{- toYaml .Values.mcp.sidecars.github.resources | nindent 12 }}
{{- end }}
{{- if .Values.mcp.sidecars.pgtuner.enabled }}
- name: pgtuner-mcp
image: "{{ .Values.mcp.sidecars.pgtuner.image.repository }}:{{ .Values.mcp.sidecars.pgtuner.image.tag }}"
imagePullPolicy: Always
command: ["python", "-m", "pgtuner_mcp", "--transport", "sse", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"]
command: ["python", "-m", "pgtuner_mcp", "--mode", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"]
ports:
- name: pgtuner
containerPort: {{ .Values.mcp.sidecars.pgtuner.port }}
@@ -244,13 +212,13 @@ spec:
- name: DATABASE_URI
valueFrom:
secretKeyRef:
name: {{ include "antigravity.envSecretName" . }}
name: {{ include "devcontainer.envSecretName" . }}
key: DATABASE_URI
optional: true
- name: PGTUNER_EXCLUDE_USERIDS
valueFrom:
secretKeyRef:
name: {{ include "antigravity.envSecretName" . }}
name: {{ include "devcontainer.envSecretName" . }}
key: PGTUNER_EXCLUDE_USERIDS
optional: true
livenessProbe:
@@ -270,9 +238,15 @@ spec:
- name: playwright-mcp
image: "{{ .Values.mcp.sidecars.playwright.image.repository }}:{{ .Values.mcp.sidecars.playwright.image.tag }}"
imagePullPolicy: Always
command: ["node"]
args:
- --transport
- sse
- cli.js
- --headless
- --browser
- chromium
- --no-sandbox
- --host
- 0.0.0.0
- --port
- {{ .Values.mcp.sidecars.playwright.port | quote }}
ports:
@@ -303,4 +277,4 @@ spec:
sizeLimit: {{ .Values.shm.sizeLimit }}
- name: userhome
persistentVolumeClaim:
claimName: {{ include "antigravity.pvcName" . }}
claimName: {{ include "devcontainer.pvcName" . }}
+2 -2
View File
@@ -1,9 +1,9 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "antigravity.pvcName" . }}
name: {{ include "devcontainer.pvcName" . }}
labels:
{{- include "antigravity.labels" . | nindent 4 }}
{{- include "devcontainer.labels" . | nindent 4 }}
spec:
accessModes:
- ReadWriteMany
+2 -2
View File
@@ -1,7 +1,7 @@
{{- $access := .Values.clusterAccess | default "none" }}
{{- $name := include "antigravity.fullname" . }}
{{- $name := include "devcontainer.fullname" . }}
{{- $ns := .Release.Namespace }}
{{- $labels := include "antigravity.labels" . }}
{{- $labels := include "devcontainer.labels" . }}
{{- if ne $access "none" }}
---
+3 -3
View File
@@ -1,9 +1,9 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "antigravity.fullname" . }}
name: {{ include "devcontainer.fullname" . }}
labels:
{{- include "antigravity.labels" . | nindent 4 }}
{{- include "devcontainer.labels" . | nindent 4 }}
spec:
ports:
{{- if ne (.Values.ide.type | default "vscode") "none" }}
@@ -19,4 +19,4 @@ spec:
targetPort: ssh
{{- end }}
selector:
{{- include "antigravity.labels" . | nindent 4 }}
{{- include "devcontainer.labels" . | nindent 4 }}
+7 -4
View File
@@ -4,6 +4,7 @@
"title": "Dev Container Helm Chart Values Schema",
"description": "Schema for validating values.yaml in the Dev Container Helm chart",
"type": "object",
"additionalProperties": true,
"properties": {
"name": {
"type": "string",
@@ -177,9 +178,6 @@
"homeassistant": {
"$ref": "#/$defs/mcpSidecar"
},
"github": {
"$ref": "#/$defs/mcpSidecar"
},
"pgtuner": {
"$ref": "#/$defs/mcpSidecar"
},
@@ -195,6 +193,11 @@
"envSecretName": {
"type": "string",
"description": "Custom environment secret name"
},
"resourceProfile": {
"type": "string",
"enum": ["auto", "small", "medium", "large", "xlarge"],
"description": "Resource profile preset"
}
},
"required": ["name"],
@@ -256,4 +259,4 @@
"required": ["enabled", "image", "port", "resources"]
}
}
}
}
+3 -16
View File
@@ -108,6 +108,8 @@ mcp:
memory: "256Mi"
cpu: "500m"
# Home Assistant smart home control
homeassistant:
enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN
@@ -123,21 +125,6 @@ mcp:
memory: "256Mi"
cpu: "500m"
# GitHub API access (DISABLED: archived image)
github:
enabled: false
image:
repository: ghcr.io/modelcontextprotocol/servers/github
tag: latest
port: 8088
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
# PostgreSQL performance tuning
pgtuner:
enabled: false # Requires DATABASE_URI in secrets
@@ -157,7 +144,7 @@ mcp:
playwright:
enabled: true
image:
repository: microsoft/playwright-mcp
repository: mcr.microsoft.com/playwright/mcp
tag: latest
port: 8086
resources: