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-state

Then test: DM your Slack bot to verify the steel thread works!

Architecture Summary

Three Components:

  1. LGTM Stack (k8s-lab/components/lgtm) - Observability
  2. OpenCode Slack Gateway (ai-dev/infrastructure/kustomize/components/opencode-slack-gateway) - Slack Socket Mode service
  3. 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 with xoxb-)
  • app_token: Your Slack app token (starts with xapp-)

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-dev namespace (for gateway)
  • code-server namespace (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 lgtm

Access:


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-dev

This will:

  1. Build multi-arch image (amd64/arm64)
  2. Push to ghcr.io/craigedmunds/opencode-slack-gateway:{{TAG}}
  3. 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:

  1. Navigate to ArgoCD dashboard
  2. Find ai-dev application
  3. Click “Sync”

Or sync via CLI:

argocd app sync ai-dev

Verify:

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-gateway

Component 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-dev

What happens during build:

  1. fetch-bridge-plugin task runs automatically (as a dependency)
  2. Clones ai-dev repo (shallow, depth 1)
  3. Copies plugins/opencode-bridge to build context
  4. Builds Docker image with plugin installed
  5. Cleans up plugin from build context after build

Manual cleanup (if needed):

task clean-bridge-plugin

Skip 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-dev

Apply:

cd repos/k8s-lab/components/codev
kubectl apply -k .

Or restart existing deployment:

kubectl rollout restart deployment/codev -n code-server

Verify:

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 list

Post-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.git

Option 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: /workspace

Testing 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 -f

Codev logs:

kubectl logs -n code-server deployment/codev -f

3. 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" or namespace="code-server"

Troubleshooting

Gateway pod not starting

Check secrets:

kubectl get externalsecret -n ai-dev
kubectl get secret slack-tokens -n ai-dev -o yaml

Check image pull:

kubectl describe pod -n ai-dev -l app=opencode-slack-gateway

Bridge 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 -g

Check OpenCode config:

kubectl exec -it -n code-server deployment/codev -- opencode config

Slack 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-storage

Verify 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-gateway

Rollback

Gateway

# Via ArgoCD
argocd app rollback ai-dev
 
# Or manually
kubectl rollout undo deployment/opencode-slack-gateway -n ai-dev

Codev

kubectl rollout undo deployment/codev -n code-server

Next Steps

  1. ✅ Deploy LGTM stack
  2. ✅ Build and push gateway image
  3. ✅ Deploy gateway via ArgoCD
  4. ✅ Build and deploy updated codev image
  5. ✅ Initialize ai-dev-state repo on PVC
  6. 🔲 Test end-to-end: Slack → Gateway → Bridge → OpenCode
  7. 🔲 Configure Grafana dashboards for monitoring
  8. 🔲 Set up alerts for gateway/bridge failures

References