--- title: Kubernetes Execution — Quickstart summary: First-time setup guide for operators connecting a Kubernetes cluster to Paperclip and provisioning a tenant namespace --- This guide walks an operator through connecting a Kubernetes cluster to a Paperclip M1 deployment and provisioning the first tenant namespace. By the end you will have a verified cluster connection and a namespace that passes `kubectl describe namespace` — ready for agent execution when M2 ships. **M1 scope:** This release delivers tenant namespace provisioning only. Agent execution (running adapter pods) is an M2 feature. See [What's not in M1](#whats-not-in-m1) for the full boundary. ## Prerequisites | Tool | Version | Notes | |------|---------|-------| | `kubectl` | 1.28+ | Must be on `$PATH` | | `kind` | 0.22+ | Only if using a local kind cluster | | Docker | 24+ | Required to run kind | | Paperclip server | M1 build | `PAPERCLIP_K8S_DRIVER=true` env var must be set | | `paperclipai` CLI | M1 build | `pnpm paperclipai --version` should print a version | A PostgreSQL database with the M1 migrations applied (`packages/db/src/migrations/0082_cluster_connections.sql`) is required before any cluster commands work. ## First-time cluster setup ### 1. Start a kind cluster (if you don't have one) ```bash kind create cluster --name paperclip-dev kubectl cluster-info --context kind-paperclip-dev ``` For a production cluster, ensure it has: - A default `StorageClass` (used for agent PVCs in M2) - `NetworkPolicy` enforcement (Calico, Cilium, or compatible CNI) ### 2. Apply the reference ClusterRole The Paperclip driver needs a `ClusterRole` that allows it to manage tenant namespaces and the objects inside them. ```bash kubectl apply -f packages/adapters/kubernetes-execution/manifests/paperclip-tenant-manager-clusterrole.yaml ``` Verify it was created: ```bash kubectl get clusterrole paperclip-tenant-manager ``` ### 3. Create the driver ServiceAccount and bind the ClusterRole For an **in-cluster** topology (Paperclip server running inside the same cluster), create the ServiceAccount in the `paperclip-system` namespace: ```yaml # paperclip-system-sa.yaml apiVersion: v1 kind: Namespace metadata: name: paperclip-system --- apiVersion: v1 kind: ServiceAccount metadata: name: paperclip-driver namespace: paperclip-system --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: paperclip-driver subjects: - kind: ServiceAccount name: paperclip-driver namespace: paperclip-system roleRef: kind: ClusterRole name: paperclip-tenant-manager apiGroup: rbac.authorization.k8s.io ``` ```bash kubectl apply -f paperclip-system-sa.yaml ``` For a **cross-cluster** topology (Paperclip server is elsewhere), the kubeconfig user must already be bound to the same `ClusterRole` on the workload cluster. See [cluster-rbac.md](./cluster-rbac.md) for details on both topologies. ### 4. Store the kubeconfig as a Paperclip secret Paperclip resolves cluster credentials through its secret provider abstraction. The `kubeconfig_secret_ref` field on a `cluster_connections` row holds a `{ provider, name }` pair. Supported providers in M1: | Provider string | Where the secret lives | |-----------------|----------------------| | `env` | Environment variable (e.g. `env:KUBECONFIG_KIND`) | | `aws_secrets` | AWS Secrets Manager secret ARN or name | | `gcp_secret` | GCP Secret Manager resource path | | `vault` | HashiCorp Vault path (`vault:secret/data/paperclip/kind-cfg`) | For a local kind cluster, the simplest path is the `env` provider. Export the kubeconfig and set an environment variable on the Paperclip server: ```bash kind get kubeconfig --name paperclip-dev > /tmp/kind-cfg.yaml export KUBECONFIG_KIND=$(cat /tmp/kind-cfg.yaml) ``` Then reference it as `env:KUBECONFIG_KIND` in the `--kubeconfig-secret` flag below. > **Note:** `local_encrypted` (a Paperclip-managed encrypted store) is planned for M2. Until then, use one of the providers listed above. ## Add a cluster connection ```bash paperclipai cluster add \ --label kind \ --kind kubeconfig \ --kubeconfig-secret env:KUBECONFIG_KIND ``` The command probes the cluster for capabilities (Cilium presence, default StorageClass, node architectures) and writes a row to `cluster_connections`. The printed `id` is the `` used in subsequent commands. Additional flags: | Flag | Purpose | |------|---------| | `--paperclip-public-url ` | Override the Paperclip server URL agents use to call back (cross-cluster only) | | `--image-registry ` | Override the image registry for agent runtime images | ## Verify the connection ```bash # Check reachability, RBAC, and cluster capabilities paperclipai cluster doctor # List all registered cluster connections paperclipai cluster list ``` `cluster doctor` checks: - API server reachability via the stored kubeconfig - `paperclip-tenant-manager` ClusterRole exists - Default StorageClass is present - Cilium CRD presence (informational) ## Provision a tenant for a company ```bash paperclipai cluster ensure-tenant ``` Expected output: ``` Provisioned namespace paperclip- (cilium=false) ``` Or, if Cilium is present on the cluster: ``` Provisioned namespace paperclip- (cilium=true) ``` `ensure-tenant` is **idempotent** — running it twice is safe and brings any drifted objects back to the desired state. The driver refuses to touch a namespace that lacks the `paperclip.ai/managed-by=paperclip` label. ## Verify the namespace with kubectl ```bash kubectl get ns,sa,resourcequota,limitrange,networkpolicy \ -l paperclip.ai/managed-by=paperclip ``` You should see: - `Namespace` named `paperclip-` - `ServiceAccount` named `paperclip-agent` - `ResourceQuota` named `paperclip-tenant-quota` - `LimitRange` named `paperclip-tenant-limits` - `NetworkPolicy` objects `default-deny-ingress`, `default-deny-egress`, `paperclip-agent-egress` ```bash kubectl describe namespace paperclip- ``` Check that the PSS labels are present: ``` Labels: pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/audit=restricted pod-security.kubernetes.io/warn=restricted paperclip.ai/managed-by=paperclip paperclip.ai/company-id= ``` ## What's not in M1 | Feature | Milestone | |---------|-----------| | Agent execution (running adapter pods as Kubernetes Jobs) | M2 | | Web UI for cluster management and health | M3 | | Per-company BYO cluster (one cluster connection per company) | V2 | | VolumeSnapshot-based agent workspace cloning | V2 | | `local_encrypted` secret provider | M2 | | `paperclipai cluster purge` (namespace teardown) | M2 | For the full V1/V2 scope split see the [design spec](../superpowers/specs/2026-05-08-paperclip-cloud-adapter-design.md#non-goals-v1). ## Next steps - [Security model](./security-model.md) — understand the isolation primitives applied to each namespace - [Multi-tenant onboarding](./multi-tenant-onboarding.md) — operator playbook for provisioning multiple companies - [Cluster RBAC](./cluster-rbac.md) — full ClusterRole reference and binding templates