A FastAPI + HTMX dashboard for managing opencode agent workloads on Kubernetes.
- Workspaces — each workspace maps 1:1 to a Kubernetes namespace; create, rename, and delete workspaces from the UI
- Secrets — Fernet-encrypted storage for OpenCode credentials (GCP/Vertex AI, Gemini), GitHub PATs for HTTPS git auth, and OCI registry pull secrets; all auto-synced to Kubernetes Secret objects; optional unmanaged Secret
swarmer-agent-extra-envper workspace injects extra agent env vars - Session lifecycle — create → launch → monitor → stop → delete sessions backed by Kubernetes Pods and PVCs
- Three session modes:
- Prompt — one-shot: run a prompt, stream output, pod exits when done
- Server — persistent opencode web API with in-dashboard chat link
- TUI — full xterm.js browser terminal connected via WebSocket +
kubectl execPTY
- Git cloning — init containers clone configured repos into the PVC-backed workspace before the agent starts
- Live UI — HTMX polling for session status and output; no page reloads needed
- Python 3.11+ and
pip kubectlkind(for local cluster modes)- Docker or Podman (
CONTAINER_CMD=podmanto use Podman) opencode-golang:latestcontainer image available locally
Best for active Python development. FastAPI runs locally with auto-reload; session pods run inside kind.
make setup-auth # set dashboard password
make install # pip install -r requirements.txt
make kind-create # create kind cluster (localhost:8080 → NodePort 30080)
make kind-load-opencode # load opencode agent image into kind
make dev # uvicorn at http://localhost:8090, K8S_IN_CLUSTER=falseDashboard: http://localhost:8090
Best for end-to-end local testing. One command builds the image, creates the cluster, and deploys everything.
make setup-auth # set dashboard password
make kind-deploy # create cluster + build image + load + deploy (idempotent)Dashboard: http://localhost:8080 (via NodePort — no port-forward needed)
Teardown:
make kind-delete # deletes the kind cluster and all data inside itPush the image to a registry and deploy to your current kubectl context.
make setup-secret
make image-build image-push REGISTRY=your.registry.example.com
make k8s-deploy # applies namespace, RBAC, PVC, service, deployment
make k8s-connect # port-forward → http://localhost:8080Teardown:
make k8s-delete # removes all swarmer resources from the namespaceDeclarative deployment using Kustomize overlays instead of make. Two flavors:
- cluster-admin — full multi-namespace deployment (Namespace, ClusterRole, OAuthClient). Equivalent to
make openshift-deploy. - namespace-scoped — deploys into an existing namespace with no cluster-admin required. All workspaces share the target namespace.
# Build and push the image
podman build -f Containerfile -t <registry>/<namespace>/swarmer:latest .
podman push <registry>/<namespace>/swarmer:latest
# Create the secret key
oc create secret generic swarmer-secret \
--from-literal=SWARMER_SECRET_KEY=$(python3 -c "import os,base64; print(base64.urlsafe_b64encode(os.urandom(32)).decode())") \
-n <namespace>
# Copy and configure an overlay
cp -r kustomize/overlays/ephemeral kustomize/overlays/my-env
# Edit kustomize/overlays/my-env/kustomization.yaml — set NAMESPACE and image
# Deploy
oc apply -k kustomize/overlays/my-envSee kustomize/README.md for full documentation, flavor comparison, and teardown instructions.
Copy .env.example to .env and adjust as needed:
cp .env.example .envKey variables:
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite+aiosqlite:///data/swarmer.db |
SQLite database path |
AUTH_HASH_FILE |
auth/password.hash |
Argon2 password hash (written by make setup-auth) |
K8S_IN_CLUSTER |
false |
Set to true when running inside a pod |
AGENT_IMAGE |
opencode-golang:latest |
Image used for session pods |
AGENT_IMAGE_PULL_SECRET |
(empty) | Pull secret name in the workspace namespace |
These two commands are the primary way to onboard users and control workspace access.
Creates a Kubernetes ServiceAccount for the user (if it doesn't exist) and prints a bearer token they paste into the Swarmer login page:
make user-token SA_USER=alice
make user-token SA_USER=alice TOKEN_DURATION=24h # default: 8hShare the printed token with the user — it expires after TOKEN_DURATION.
Binds a user to a specific workspace namespace so they can see and manage sessions in it:
make grant-workspace SA_USER=alice WORKSPACE_NS=my-projectRun this once per user per namespace. A user with no workspace grants can log in but will see no workspaces.
make user-token SA_USER=alice # 1. create user + print token
make grant-workspace SA_USER=alice WORKSPACE_NS=team-a # 2. give access to a workspace
make grant-workspace SA_USER=alice WORKSPACE_NS=team-b # 3. repeat for additional workspacesmake help # list all Makefile targets
make lint # run ruff linter
make db-reset # delete the SQLite database (fresh schema on next start)