Deploy once, control from anywhere -- an AI-powered DevOps agent running inside your Kubernetes cluster, accessible from your phone via Remote Control.
flowchart TD
subgraph User["User Access"]
Phone["Claude Mobile App"]
Web["claude.ai/code"]
end
subgraph Cloud["Anthropic Cloud"]
API["Anthropic API"]
RC["Remote Control"]
end
subgraph Cluster["Kubernetes Cluster"]
subgraph Pod["claude-agent-0"]
CC["Claude Code"]
MCP["MCP Server\n(kubernetes-mcp-server)"]
Skills["DevOps Skills"]
Tools["32+ CLI Tools"]
end
SA["ServiceAccount\n(claude-agent)"]
NP["NetworkPolicy\n(egress-only)"]
PVC["PersistentVolumeClaim\n(1Gi)"]
end
Phone --> RC
Web --> RC
RC <--> CC
CC <--> API
CC --> MCP
MCP --> SA
SA --> Cluster
NP -.->|restricts| Pod
PVC -.->|mounts| Pod
The agent runs as a StatefulSet with a single replica. Claude Code communicates with the Anthropic API over HTTPS (port 443) and queries the Kubernetes API (port 6443) through an in-cluster MCP server. A NetworkPolicy restricts all ingress and limits egress to DNS, HTTPS, and the Kubernetes API. Persistent storage survives pod restarts.
Note: Remote Control is currently available on macOS only — it is server-gated on Linux even with a Max subscription. The entrypoint code is in place for when Linux support ships.
- Remote Control access -- manage your cluster from your phone or claude.ai/code
- MCP Kubernetes integration -- in-cluster read-only access to 14 resource types via kubernetes-mcp-server
- Three startup modes -- interactive, remote-control, or headless (single prompt execution)
- Tiered RBAC -- readonly (default), operator (mutations), or airgapped (restricted egress)
- NetworkPolicy isolation -- egress-only policy restricts traffic to DNS, HTTPS, and K8s API
- PVC persistence -- conversation history and skills survive pod restarts
- Non-root execution -- runs as UID 10000 with tini as PID 1 for proper signal handling
- Three deployment methods -- KIND local dev, Docker Compose standalone, or Helm for production
View all 32+ installed tools
| Category | Tools |
|---|---|
| Network | curl, dig, nmap, tcpdump, wget, netcat, ip, ss, ping |
| Process/System | htop, strace, ps, top, perf, bpftrace |
| Kubernetes | kubectl, helm, k9s, stern, kubectx, kubens |
| Data/Log | jq, yq, less |
| Database Clients | psql, mysql, redis-cli |
| Security | trivy, grype |
| Utilities | git, vim, nano, unzip, file, tree, ripgrep, bash |
| Claude Code | claude |
| Tool | Required For | Install Guide |
|---|---|---|
| Docker | All methods | docs.docker.com/get-docker |
| KIND | Local dev (quickstart) | kind.sigs.k8s.io |
| kubectl | KIND and Helm | kubernetes.io/docs/tasks/tools |
| Docker Compose v2 | Standalone method | Included with Docker Desktop |
| Helm 3+ | Production method | helm.sh/docs/intro/install |
Authentication: An Anthropic Pro or Max subscription is required for Remote Control mode. Run /login inside Claude Code to authenticate via browser OAuth on first use — credentials persist in the PVC at /app/.claude/.credentials.json.
The fastest path from zero to a running agent. Requires Docker, KIND, and kubectl.
git clone https://github.com/PatrykQuantumNomad/claude-in-a-box.git
cd claude-in-a-box
make bootstrapmake bootstrap creates a KIND cluster, builds the Docker image, loads it into the cluster, applies all Kubernetes manifests (ServiceAccount, RBAC, NetworkPolicy, StatefulSet), and waits for the pod to be Ready.
Verify the pod is running:
kubectl get pods -l app=claude-agentExpected output:
NAME READY STATUS RESTARTS AGE
claude-agent-0 1/1 Running 0 30s
Attach to the interactive session:
kubectl attach claude-agent-0 -c claude-agent -itThe default startup mode is interactive, which prompts for authentication on first launch if no credentials are provided. To pre-configure authentication, see the Authentication section.
Teardown:
make teardownWhen to use: Local development and testing without an existing Kubernetes cluster.
Prerequisites: Docker, KIND, kubectl.
| Command | Description |
|---|---|
make bootstrap |
Create KIND cluster, build image, load, and deploy |
make redeploy |
Rebuild image, reload into KIND, restart pod (no cluster recreation) |
make status |
Show cluster and pod status |
make teardown |
Destroy the KIND cluster |
# Full lifecycle
make bootstrap # Create cluster + build + deploy
make status # Check pod status
make redeploy # After code changes, rebuild and restart
make teardown # Clean upVerification:
kubectl get pods -l app=claude-agent
kubectl logs claude-agent-0 -c claude-agentWhen to use: Running the agent without Kubernetes. Suitable for single-machine deployments or local testing without KIND.
Prerequisites: Docker, Docker Compose v2.
Authentication: Start the agent, attach, and run /login inside Claude Code to authenticate via browser OAuth. Credentials are saved to the claude-data volume and persist across restarts.
# Start the agent
docker compose up -d
# Attach to the interactive session
docker attach claude-agent
# Stop the agent
docker compose downThe Compose file mounts a named volume (claude-data) at /app/.claude for persistence. The CLAUDE_MODE environment variable is passed through from the host.
To start in remote-control mode:
CLAUDE_MODE=remote-control docker compose up -dWhen to use: Production Kubernetes clusters with an existing cluster and Helm installed.
Prerequisites: kubectl (configured for your target cluster), Helm 3+.
Default readonly profile:
helm install claude-agent ./helm/claude-in-a-box \
--set image.repository=ghcr.io/PatrykQuantumNomad/claude-in-a-box \
--set image.tag=latestOperator profile (elevated permissions for pod delete, exec, rollout restart):
helm install claude-agent ./helm/claude-in-a-box \
-f helm/claude-in-a-box/values-operator.yaml \
--set image.repository=ghcr.io/PatrykQuantumNomad/claude-in-a-box \
--set image.tag=latestAirgapped profile (internal registry, restricted egress -- no external HTTPS):
helm install claude-agent ./helm/claude-in-a-box \
-f helm/claude-in-a-box/values-airgapped.yamlThe airgapped profile sets image.repository to internal-registry.corp/claude-in-a-box and disables external HTTPS egress. Update the repository to match your internal registry.
Security profiles comparison:
| Profile | File | RBAC | Egress |
|---|---|---|---|
| Readonly (default) | values.yaml |
get/list/watch on 14 resource types | DNS + HTTPS + K8s API |
| Operator | values-operator.yaml |
+ pod delete, pod/exec create, deployment/statefulset update/patch | DNS + HTTPS + K8s API |
| Airgapped | values-airgapped.yaml |
get/list/watch (readonly) | DNS + K8s API only (no external HTTPS) |
Set authentication via Helm values:
helm install claude-agent ./helm/claude-in-a-box \
--set claudeMode=remote-control \
--set image.repository=ghcr.io/PatrykQuantumNomad/claude-in-a-box \
--set image.tag=latestAuthenticate after deployment by attaching to the interactive session and running /login:
kubectl attach claude-agent-0 -c claude-agent -it
# Inside Claude Code: run /loginCredentials are saved to the PVC and persist across pod restarts.
Verification:
kubectl get pods -l app=claude-in-a-box
kubectl logs claude-agent-0 -c claude-agentTeardown:
helm uninstall claude-agent| Variable | Default | Description |
|---|---|---|
CLAUDE_MODE |
interactive |
Startup mode: interactive, remote-control, or headless |
CLAUDE_PROMPT |
(none) | Prompt for headless mode (required when CLAUDE_MODE=headless) |
| Mode | Command Executed | Use Case |
|---|---|---|
interactive |
claude --dangerously-skip-permissions |
TTY session for interactive debugging (default) |
remote-control |
claude remote-control --verbose |
Accessible via Claude Remote Control -- control from your phone or claude.ai/code |
headless |
claude -p "$CLAUDE_PROMPT" --output-format json --dangerously-skip-permissions |
Single prompt execution, outputs JSON |
Remote Control mode requires an Anthropic Pro or Max subscription and credentials saved in the PVC from a prior /login session. Note: Remote Control is currently server-gated on Linux and may not be available.
The entrypoint validates authentication before starting Claude Code. Two methods are supported:
| Priority | Method | Path | Notes |
|---|---|---|---|
| 1 | Credential file in PVC | /app/.claude/.credentials.json |
Created by running /login in interactive mode. Persists across restarts. |
| 2 | Interactive login | (none) | Attach to interactive mode and run /login on first launch |
Non-interactive modes (remote-control, headless) require method 1. If no credentials are found, the entrypoint exits with an actionable error message explaining the /login flow.
The agent uses a dedicated ServiceAccount (claude-agent) with the principle of least privilege. Three RBAC tiers are available.
Applied automatically. Provides get, list, watch on 14 resource types across 4 API groups:
| API Group | Resources |
|---|---|
Core ("") |
pods, services, events, nodes, namespaces, configmaps, persistentvolumeclaims |
Apps (apps) |
deployments, statefulsets, daemonsets, replicasets |
Batch (batch) |
jobs, cronjobs |
Networking (networking.k8s.io) |
ingresses |
No secrets access. No mutation verbs. No aggregation labels.
Adds mutation permissions on top of the readonly tier. RBAC is additive -- applying the operator tier does not remove readonly permissions.
| Resource | Additional Verbs |
|---|---|
| pods | delete (trigger pod restart) |
| pods/exec | create (interactive debugging) |
| deployments, statefulsets | update, patch (rollout restart) |
Apply via KIND/kubectl:
make deploy-operator
# or
kubectl apply -f k8s/overlays/rbac-operator.yamlApply via Helm:
helm install claude-agent ./helm/claude-in-a-box \
-f helm/claude-in-a-box/values-operator.yamlRevoke operator permissions:
make undeploy-operator
# or
kubectl delete -f k8s/overlays/rbac-operator.yamlUses the readonly RBAC tier with restricted egress. External HTTPS is disabled -- only DNS and Kubernetes API (restricted to 10.96.0.1/32) are allowed. Requires an internal container registry.
helm install claude-agent ./helm/claude-in-a-box \
-f helm/claude-in-a-box/values-airgapped.yaml \
--set image.repository=your-registry.internal/claude-in-a-boxSymptom: Pod logs show the AUTHENTICATION REQUIRED banner and the container exits.
Cause: No credential file (/app/.claude/.credentials.json) is present in the PVC, and the mode is not interactive.
Fix:
# Check pod logs for the auth error
kubectl logs claude-agent-0 -c claude-agent
# Switch to interactive mode and log in
kubectl set env statefulset/claude-agent CLAUDE_MODE=interactive
kubectl attach claude-agent-0 -c claude-agent -it
# Inside Claude Code: run /login to complete OAuth flow
# Credentials are saved to the PVC for subsequent startsSymptom: Claude Code cannot reach the Anthropic API. Logs show "connection timed out" or "connection refused" errors.
Cause: The CNI plugin does not enforce NetworkPolicy (KIND's default kindnet does not), or a cluster-level policy is blocking egress to port 443 or 6443.
Fix:
# For KIND: install Calico to enforce NetworkPolicy
scripts/install-calico.sh
# For production: verify your CNI supports NetworkPolicy and allows
# egress to TCP 443 (Anthropic API) and TCP 6443 (K8s API)
kubectl get networkpolicy -n default
kubectl describe networkpolicy claude-agent-netpol -n defaultSymptom: Changes to Dockerfile or scripts are not reflected in the running pod after rebuilding.
Cause: KIND cached the previous image. imagePullPolicy: IfNotPresent does not re-pull locally loaded images.
Fix:
# Rebuild, reload into KIND, and restart the pod in one command
make redeploymake redeploy rebuilds the Docker image, loads it into the KIND cluster (replacing the cached version), deletes the existing pod, re-applies manifests, and waits for the new pod to be Ready.
Symptom: Pod takes the full 60-second termination grace period before being killed (SIGKILL).
Cause: Claude Code is not receiving SIGTERM because the shell entrypoint script is PID 1 instead of tini, or the entrypoint is not using exec to hand off the process.
Fix:
# Verify tini is PID 1
kubectl exec claude-agent-0 -c claude-agent -- cat /proc/1/cmdline | tr '\0' ' '
# Expected: /usr/local/bin/tini -- /usr/local/bin/entrypoint.sh
# Verify entrypoint uses exec (check that claude is a direct child of tini)
kubectl exec claude-agent-0 -c claude-agent -- ps auxThe Dockerfile sets ENTRYPOINT ["/usr/local/bin/tini", "--"] and the entrypoint script uses exec to replace itself with the Claude Code process, ensuring signals are delivered directly.
Symptom: Claude Code or MCP tools return "forbidden" errors when querying Kubernetes resources.
Cause: The ServiceAccount only has reader permissions by default. Mutation operations (delete, exec, patch) require the operator tier.
Fix:
# Check current permissions
kubectl auth can-i --as=system:serviceaccount:default:claude-agent --list
# Apply operator tier for mutation permissions
kubectl apply -f k8s/overlays/rbac-operator.yaml
# Or with Helm
helm upgrade claude-agent ./helm/claude-in-a-box \
-f helm/claude-in-a-box/values-operator.yaml| Target | Description |
|---|---|
make bootstrap |
Create KIND cluster, build image, load, and deploy |
make teardown |
Destroy the KIND cluster |
make redeploy |
Rebuild image, load into KIND, restart pod |
make build |
Build the Docker image |
make deploy |
Apply k8s manifests and wait for Ready |
make deploy-operator |
Apply operator-tier RBAC |
make undeploy-operator |
Remove operator-tier RBAC |
make status |
Show cluster and pod status |
make test-setup |
Create test cluster with Calico CNI and deploy |
make test |
Run integration test suite (BATS) |
make test-teardown |
Destroy test cluster |
make help |
Show all available targets |
The integration test suite uses BATS and requires a KIND cluster with Calico CNI for NetworkPolicy enforcement.
make test-setup # Create cluster with Calico, build, and deploy
make test # Run integration tests
make test-teardown # Destroy test clusterThe GitHub Actions CI pipeline (.github/workflows/ci.yaml) runs on every push and pull request:
- Build and push -- Docker Buildx multi-stage build, pushes to
ghcr.io/PatrykQuantumNomad/claude-in-a-box - Trivy vulnerability scan -- Scans for CRITICAL and HIGH severity CVEs, uploads SARIF to GitHub Security tab
- SBOM generation -- Produces SPDX JSON software bill of materials
- Helm lint -- Strict lint of the Helm chart plus golden file tests
MIT -- Copyright (c) 2026 Patryk Golabek