Zupp is a secure, runtime-agnostic agent execution platform for Kubernetes. It runs any AI agent runtime — Claude Code, OpenCode, or Goose — with any skill in an isolated sandbox on any K8s cluster, from a local kind cluster to production OpenShift.
zupp run skill code-review:v1.0.0 --runtime claude:v1.0.0 --model anthropic/claude-sonnet-4-6
Unlike platforms that provide their own agent runtime, Zupp runs the actual agent runtime as a process in a sandbox. The agent reasons, plans, and acts as it would on a developer's laptop, but with cluster-grade isolation, supply chain trust, and audit.
- Runtime-agnostic — bring Claude Code, OpenCode, or Goose (more coming)
- OCI all the way — skills, runtimes, and base images are OCI artifacts stored in Quay, signed with cosign
- Secure by default — read-only filesystem, non-root containers, NetworkPolicy isolation, RBAC scoping
- Warm pool support — pre-warmed sandboxes via agent-sandbox for sub-5s startup
┌──────────────────────────────────────────────────────┐
│ User / CI / Agent │
│ │ │
│ zupp CLI │
│ │ │
├─────────────────────────┼────────────────────────────┤
│ Zupp Controller (HA) │
│ │ │
│ ┌──────────┐ ┌───────┴────────┐ ┌──────────────┐ │
│ │ Resolver │ │ Sandbox │ │ Observability│ │
│ │ + Cosign │ │ Manager │ │ + Metrics │ │
│ └──────────┘ └───────┬────────┘ └──────────────┘ │
│ │ │
├────────────────────────┼───────────────────────────-─┤
│ agent-sandbox CRDs │
│ Sandbox · SandboxClaim · SandboxWarmPool │
│ │ │
├─────────────────────────┼────────────────────────────┤
│ Kubernetes Cluster │
│ Namespace │ Pod │ RBAC │ NetworkPolicy │ PSS │
└──────────────────────────────────────────────────────┘
External: Quay (OCI artifacts) · cosign (signatures) · cert-manager (webhook TLS)
| Runtime | Headless Mode | Tool Scoping | Skill Discovery | Image Variants |
|---|---|---|---|---|
| Claude Code | claude -p |
--disallowed-tools |
.claude/skills/ |
base, go |
| OpenCode | opencode run |
N/A (sandbox isolation) | .claude/skills/ |
base, go |
| Goose | goose run -i |
N/A (extension config) | .agents/skills/ |
base, go |
Image variants are selected automatically when a skill declares runtime dependencies in its zupp.yaml (e.g., requirements.runtimes: [go]). The controller resolves rt-opencode:1.17.9 → rt-opencode-go:1.17.9.
- Kubernetes 1.31+ (or OpenShift 4.20+)
- cert-manager
- agent-sandbox controller (>= v0.5.0)
# Create a kind cluster with Calico CNI
make kind-create
# Install Zupp
zupp install --kind
# Verify
zupp preflightCreate a llm-keys secret with credentials for your LLM provider:
# Anthropic
kubectl create secret generic llm-keys -n zupp-system \
--from-literal=anthropic-api-key=sk-ant-...
# Vertex AI (GCP)
kubectl create secret generic llm-keys -n zupp-system \
--from-literal=vertex-project-id=my-project \
--from-literal=vertex-region=global \
--from-file=vertex-credentials=$HOME/.config/gcloud/application_default_credentials.json
# OpenAI
kubectl create secret generic llm-keys -n zupp-system \
--from-literal=openai-api-key=sk-...
# Gemini
kubectl create secret generic llm-keys -n zupp-system \
--from-literal=gemini-api-key=...Supported providers: Anthropic, Vertex AI, OpenAI, Gemini, Azure OpenAI. The adapters detect which keys are present and inject the appropriate environment variables.
# Set defaults
zupp config model anthropic/claude-sonnet-4-6
zupp config namespace defaultzupp import runtime claude:v1.0.0 \
--source ghcr.io/anthropics/claude-code:latest \
--key cosign.key# Skill-scoped execution
zupp run skill code-review:v1.0.0 \
--runtime claude:v1.0.0 \
--repo https://github.com/org/repo \
--ref feature-branch
# Goal-directed agent
zupp run agent \
--goal "Review the PR for security issues and run the test suite" \
--runtime claude:v1.0.0 \
--skills code-review,testingzupp status <run-id> # Show phase, conditions, token usage
zupp logs <run-id> # Stream agent output
zupp list runs # List all runs
zupp diagnose <run-id> # Automated troubleshootingzupp
├── run skill/agent Run a skill or agent in a sandbox
├── status/logs Show status or stream logs
├── stop/delete Lifecycle management
├── list runs/runtimes/skills List resources
├── inspect run/runtime/skill Detailed views
├── import runtime/skill Import OCI artifacts
├── config Persistent settings (~/.zupp/config.yaml)
├── auth set Credential management
├── dev skill Local development mode
├── output/workspace Artifact retrieval
├── diagnose Automated troubleshooting
├── preflight Cluster readiness checks
├── install Install Zupp on a cluster
└── runtime rescan Trigger vulnerability rescan
| CRD | Scope | Purpose |
|---|---|---|
ZuppAgentRun |
Namespaced | Execution resource — drives a skill or agent run through its lifecycle |
ZuppRuntime |
Cluster | Tracks imported runtimes — version, digest, scan status |
ZuppPolicy |
Namespaced | Permission caps, resource limits, allowed runtimes per namespace |
- Isolation — each sandbox gets a dedicated ServiceAccount, Role, RoleBinding, and NetworkPolicy
- Least privilege — skills declare required permissions in
zupp.yaml, capped byZuppPolicy - Network — deny-all ingress, egress limited to DNS + HTTPS (LLM APIs)
- Supply chain — cosign-verified OCI artifacts, vulnerability scanning via Quay Clair
- Pod security —
runAsNonRoot,readOnlyRootFilesystem, drop all capabilities, seccomp RuntimeDefault - Admission — validating webhook enforces mode discriminator and required fields
Skills declare their requirements in a zupp.yaml file, which is included in the skill's ConfigMap alongside SKILL.md. The controller reads this manifest to select the right runtime image variant and validate permissions.
apiVersion: zupp.io/v1alpha1
type: standard
requirements:
runtimes: [go] # go, python, java, node
packages: [git]
tools: [go, git]
inputs:
- name: app
type: string
required: true
permissions:
- apiGroup: ""
resources: [pods]
verbs: [get, list]
egress:
- host: github.com
ports: [443]
limits:
timeout: 30m
cpu: "2"
memory: 4GiWhen requirements.runtimes is set, the controller selects a variant image with those runtimes pre-installed (e.g., rt-opencode-go:1.17.9 instead of rt-opencode:1.17.9). This is necessary because sandbox containers run with readOnlyRootFilesystem: true — packages cannot be installed at runtime.
If no zupp.yaml is present in the skill ConfigMap, the base image is used (backward compatible).
# Build
make build # CLI + controller binaries
make container-build # Controller container image (podman)
# Runtime images
make runtime-build-opencode # Base opencode image
make runtime-build-opencode-go # Go variant
make runtime-build-claude # Base claude image
make runtime-build-claude-go # Go variant
make runtime-build-all # All base + variant images
# Test
make test # Unit + integration tests
make e2e-test # E2E tests (requires kind cluster)
make contract-test # Agent-sandbox contract tests
# Generate
make generate # Deepcopy methods
make manifests # CRD YAMLApache 2.0