OpenCode Slack Integration - K8s Deployment Guide
Date: 2026-01-31
Project: opencode-slack-integration
Environment: k8s lab (lab.ctoaas.co)
Overview
This guide covers deploying the steel thread OpenCode Slack integration to the k8s lab environment.
🚀 Quick Start
TL;DR - Deploy in 5 commands:
# 1. Build and push gateway image
cd repos/ai-dev/services/gateway && task build
# 2. Deploy LGTM observability stack
kubectl apply -k repos/k8s-lab/components/lgtm
# 3. Deploy gateway via ArgoCD
kubectl apply -k repos/k8s-lab/other-seeds/ && argocd app sync ai-dev
# 4. Build and deploy updated codev with bridge plugin (auto-fetches plugin!)
cd repos/k8s-lab/components/codev && task build && kubectl apply -k .
# 5. Initialize state repo (one-time)
kubectl exec -it -n ai-dev deployment/opencode-slack-gateway -- \
git clone https://github.com/craigedmunds/ai-dev-state.git /workspace/ai-dev-stateThen test: DM your Slack bot to verify the steel thread works!
Architecture Summary
Three Components:
- LGTM Stack (
k8s-lab/components/lgtm) - Observability - OpenCode Slack Gateway (
ai-dev/infrastructure/kustomize/components/opencode-slack-gateway) - Slack Socket Mode service - Codev Pod (
k8s-lab/components/codev) - Updated with bridge plugin
Shared Storage:
- PVC:
code-server-storage(ReadWriteMany) - Mounted by: codev + gateway
- Contains: workspaces + ai-dev-state repo
Networking:
- Gateway service:
opencode-slack-gateway.ai-dev.svc.cluster.local:8000 - Bridge plugin → Gateway via internal k8s DNS
- Gateway → Slack via Socket Mode (outbound WebSocket, no ingress needed)
Prerequisites
1. Secrets in Central Store
Add the following secrets to your central secret store:
Secret name: slack-opencode-integration
Properties:
bot_token: Your Slack bot token (starts withxoxb-)app_token: Your Slack app token (starts withxapp-)
The ExternalSecret in ai-dev/infrastructure/kustomize/components/opencode-slack-gateway/external-secret.yaml will sync these to the ai-dev namespace.
2. GitHub Container Registry Authentication
Ensure gh-docker-registry-creds secret exists in:
ai-devnamespace (for gateway)code-servernamespace (for codev)
3. Slack App Configuration
Your Slack app must be configured with:
- Socket Mode enabled
- Event subscriptions:
message.im,app_mention - Bot token scopes:
chat:write,im:history,app_mentions:read - App-level token created
Component 1: LGTM Stack
Location: repos/k8s-lab/components/lgtm/
Namespace: lgtm
Deploy:
cd repos/k8s-lab/components/lgtm
kubectl apply -k .Verify:
kubectl get pods -n lgtm
kubectl get ingress -n lgtmAccess:
- Grafana UI: https://lgtm.lab.ctoaas.co (admin/admin)
- Loki API:
lgtm.lgtm.svc.cluster.local:3100
Component 2: OpenCode Slack Gateway
Location: repos/ai-dev/infrastructure/kustomize/components/opencode-slack-gateway/
Namespace: ai-dev
Build and Push Image
The gateway build process uses the workspace-shared Taskfile pattern for consistency with other components.
cd repos/ai-dev/services/gateway
# Build and push multi-arch image (uses VERSION file)
task build
# Or specify custom tag
task build TAG=0.1.0-devThis will:
- Build multi-arch image (amd64/arm64)
- Push to
ghcr.io/craigedmunds/opencode-slack-gateway:{{TAG}} - Auto-increment VERSION file on success
Deploy via ArgoCD
The ArgoCD application is defined in repos/k8s-lab/other-seeds/ai-dev.yaml.
Apply ArgoCD app:
cd repos/k8s-lab
kubectl apply -k other-seeds/Sync in ArgoCD UI:
- Navigate to ArgoCD dashboard
- Find
ai-devapplication - Click “Sync”
Or sync via CLI:
argocd app sync ai-devVerify:
kubectl get pods -n ai-dev
kubectl get svc -n ai-dev
kubectl get externalsecret -n ai-dev
kubectl logs -n ai-dev deployment/opencode-slack-gatewayComponent 3: Codev Pod Updates
Location: repos/k8s-lab/components/codev/
Namespace: code-server
Build Image with Bridge Plugin
✨ AUTOMATED: The bridge plugin is automatically fetched from the ai-dev repo during build!
The codev build process now handles fetching the OpenCode bridge plugin automatically:
Build command:
cd repos/k8s-lab/components/codev
# Build with auto-fetch of bridge plugin
task build TAG=1.0.28-devWhat happens during build:
fetch-bridge-plugintask runs automatically (as a dependency)- Clones ai-dev repo (shallow, depth 1)
- Copies
plugins/opencode-bridgeto build context - Builds Docker image with plugin installed
- Cleans up plugin from build context after build
Manual cleanup (if needed):
task clean-bridge-pluginSkip fetch if plugin already present:
The fetch-bridge-plugin task has a status check - if opencode-bridge/ already exists in the build context, it skips the fetch.
Deploy
Update the image tag in repos/k8s-lab/components/codev/kustomization.yaml:
images:
- name: ghcr.io/craigedmunds/codev
newTag: 1.0.28-devApply:
cd repos/k8s-lab/components/codev
kubectl apply -k .Or restart existing deployment:
kubectl rollout restart deployment/codev -n code-serverVerify:
kubectl get pods -n code-server
kubectl logs -n code-server deployment/codev
# Check if plugin is loaded
kubectl exec -it -n code-server deployment/codev -- opencode plugins listPost-Deployment: Initialize State Repo
The gateway needs to clone the ai-dev-state repo to the shared PVC.
Option 1: Manual initialization (first time)
# Shell into gateway pod
kubectl exec -it -n ai-dev deployment/opencode-slack-gateway -- /bin/bash
# Clone state repo to workspace
cd /workspace
git clone https://github.com/craigedmunds/ai-dev-state.gitOption 2: Add init container to gateway deployment
Add to deployment.yaml:
initContainers:
- name: init-state-repo
image: alpine/git
command:
- sh
- -c
- |
if [ ! -d /workspace/ai-dev-state ]; then
git clone https://github.com/craigedmunds/ai-dev-state.git /workspace/ai-dev-state
fi
volumeMounts:
- name: shared-workspace
mountPath: /workspaceTesting the Steel Thread
1. Send test question from Slack
In Slack, DM your bot:
@your-bot-name test permission request
2. Check logs
Gateway logs:
kubectl logs -n ai-dev deployment/opencode-slack-gateway -fCodev logs:
kubectl logs -n code-server deployment/codev -f3. Verify in Grafana
Navigate to https://lgtm.lab.ctoaas.co and check:
- Gateway logs in Loki
- Codev logs in Loki
- Filter by
namespace="ai-dev"ornamespace="code-server"
Troubleshooting
Gateway pod not starting
Check secrets:
kubectl get externalsecret -n ai-dev
kubectl get secret slack-tokens -n ai-dev -o yamlCheck image pull:
kubectl describe pod -n ai-dev -l app=opencode-slack-gatewayBridge plugin not loaded in codev
Verify plugin exists in image:
kubectl exec -it -n code-server deployment/codev -- ls -la /tmp/
kubectl exec -it -n code-server deployment/codev -- npm list -gCheck OpenCode config:
kubectl exec -it -n code-server deployment/codev -- opencode configSlack not receiving messages
Check Socket Mode connection:
kubectl logs -n ai-dev deployment/opencode-slack-gateway | grep "Socket Mode"Verify Slack tokens:
- Bot token starts with
xoxb- - App token starts with
xapp- - Both should be valid and not expired
PVC access issues
Check PVC:
kubectl get pvc -n code-server code-server-storage
kubectl describe pvc -n code-server code-server-storageVerify both pods can write:
# From gateway
kubectl exec -it -n ai-dev deployment/opencode-slack-gateway -- touch /workspace/test-gateway
# From codev
kubectl exec -it -n code-server deployment/codev -- ls /home/coder/src/test-gatewayRollback
Gateway
# Via ArgoCD
argocd app rollback ai-dev
# Or manually
kubectl rollout undo deployment/opencode-slack-gateway -n ai-devCodev
kubectl rollout undo deployment/codev -n code-serverNext Steps
- ✅ Deploy LGTM stack
- ✅ Build and push gateway image
- ✅ Deploy gateway via ArgoCD
- ✅ Build and deploy updated codev image
- ✅ Initialize ai-dev-state repo on PVC
- 🔲 Test end-to-end: Slack → Gateway → Bridge → OpenCode
- 🔲 Configure Grafana dashboards for monitoring
- 🔲 Set up alerts for gateway/bridge failures
References
- Architecture:
.ai/projects/ai-dev/opencode-slack-integration/architecture.md - PR #1: https://github.com/craigedmunds/ai-dev/pull/1
- Steering docs:
.ai/steering/