Skip to content

Repository files navigation

License: MIT Helm Kubernetes CI Test Coverage Benchmark: 79.4%


kube-coder dashboard

kube-coder

One Helm chart turns a Kubernetes cluster into a fleet of AI-native cloud dev workspaces.

KubeCoder.com Β· Docs & public demo Β· Benchmark Β· r/kubecoder


The idea

Give every developer β€” or every AI agent β€” a real computer in the cloud, and make spinning one up a two-minute, self-service action.

Each kube-coder workspace is an isolated pod with a persistent home directory and everything a developer needs, reachable from any browser behind your own GitHub login:

  • VS Code in the browser (code-server)
  • a persistent tmux terminal that keeps running when you close the tab
  • an in-pod Chrome you can watch over VNC (for previewing web apps, or letting an agent drive a browser)
  • a dashboard that ties it together β€” plus Chat that operates the pod for you and an AI CTO that keeps track of your projects
  • pluggable coding agents β€” Claude Code, Codex, Gemini, Ante, OpenCode β€” that you can spawn, message, and fan out in parallel

Because it's just Kubernetes underneath, a single chart deploys as many of these as your cluster can hold β€” each with its own namespace, ingress, TLS certificate, persistent volume, and OAuth allowlist. Onboarding a new teammate is a form in the admin console; their workspace resolves and issues its own TLS on first request.

The short version: it's a self-hosted, multi-tenant, AI-first replacement for "here's a laptop, spend two days setting it up." The environment survives restarts, an in-flight agent keeps working after you disconnect, and you can drive the whole thing from your phone.

Your laptop is a thin client

The agent doesn't run on your machine. It runs on a pod in a cluster you operate β€” so the repo, the .env, the build cache and the model API calls all stay inside your perimeter. Close the lid mid-build and it keeps going.

How a kube-coder session actually runs


Proven on real tasks

kube-coder isn't a demo β€” the agents inside it solve real problems, and there's a public benchmark to show it.

kubecoder-bench runs coding agents against the Aider polyglot (Exercism) suite, scored against hidden tests β€” a pass means the agent genuinely solved the task, not that it memorized the answer. Every task runs in its own isolated kube-coder workspace, fanned out across parallel workers.

Backend Python split (34 tasks) Notes
Oracle (reference solutions) 34 / 34 validates the harness end-to-end
Claude Code 27 / 34 β€” 79.4% single attempt, no retries; ~5.3Γ— faster via parallel workspaces
Ante (DeepSeek/OpenRouter) runnable βœ“ agent-agnostic β€” swap one flag

The 79.4% is a conservative floor: public leaderboards allow multiple attempts, this run allows one. The point isn't a headline number β€” it's that the same infrastructure this repo ships parallelizes real agent work across isolated environments and validates it honestly.

git clone https://github.com/imran31415/kubecoder-bench && cd kubecoder-bench
./setup.sh
python3 harness/bench.py --lang python --backend claude --workers 6

See it

Three screenshots that capture the whole idea β€” a workspace home you drive from one composer, every agent in one queue, and a chat that operates the pod for you:

Desktop home β€” start-a-build composer with the Mission Control strip

Desktop home β€” ask anything or start a build in one line; the Mission Control strip keeps running, waiting, and finished agents one glance away

Mission Control β€” every agent across builds, chats and sub-agents in one board

Mission Control β€” every agent across builds, chats, and sub-agents in one queue: waiting on you, running, needs review, done

Hypervisor chat rendering a screenshot it captured inline

Hypervisor β€” chat with the workspace and it acts; here it captured a screenshot and rendered it right in the thread

More surfaces

Fullstack Python app in split-pane with terminal
Fullstack Python β€” split-pane editor with live terminal
Fullstack Go app in split-pane with Claude
Fullstack Go β€” split-pane editor with Claude Code
LibreFang agent running alongside its UI dashboard
Agent + app side by side β€” an agent working next to its live UI
Live build sessions list with inline output previews
Build sessions β€” every agent session, with live output inline

▢️ Videos: new-user provisioning Β· product demo Β· marketing


Chat β€” talk to your workspace, and it acts

Hypervisor chat calling get_metrics and list_tasks

Chat is the feature that makes a kube-coder pod feel alive β€” internally the Hypervisor, which is the name you'll see in the code and specs. You talk to the workspace in plain language and it does the thing:

"How many tasks are running and what's my CPU?" Β· "Spin up a build to run the tests." Β· "Remember that I deploy with make ship." Β· "Pin port 3000 to Apps."

Under the hood it's not a screen-scraped terminal β€” each thread is a structured agent session. Your chosen CLI (Claude, Codex, Ante, …) runs headless over pipes, and a canonical event stream renders clean prose plus expandable tool cards. It's wired to three MCP servers so it can genuinely operate the pod:

  • dashboard β€” read metrics/tasks/health, create & message builds, pin apps, manage memory
  • memory β€” persistent facts about you and your projects
  • agent-orchestrator β€” spawn and coordinate sub-agents

Destructive actions (kill_task, delete_memory) ask for confirmation right in the chat. It's fully mobile, works with whichever assistant you pick, and survives pod restarts (the Claude adapter --resumes its session). See docs/hypervisor-spec.md for the architecture.


AI CTO & Feed β€” someone minding the whole thing

Chat operates the pod. The AI CTO (/cto) works a level up: it holds a picture of your projects.

Projects are discovered automatically β€” no forms. Each carries its own north star, decision log, goals and memory namespace, and the CTO answers from a live brief (running builds, recent activity, open threads) rather than from whatever happens to be in context. Ask it what to work on next and it argues from the actual state of the repo.

The Feed (/feed) is the single stream of what changed and what needs you: build outcomes, decisions recorded, trigger fires, plus anything an agent judged worth surfacing. Anything in it can be handed straight to the CTO with "Discuss with CTO."

Both are on the phone app too.


Bring your own environment β€” devcontainer.json

If a repo already carries a .devcontainer/devcontainer.json β€” because it came from Codespaces, Coder, Ona or DevPod β€” kube-coder reads it. Forwarded ports land on the Apps page with their labels, VS Code extensions and settings reach code-server, containerEnv/remoteEnv reach the agents you dispatch, and the lifecycle commands are shown to you verbatim so you can run them with one click. Moving a project across stops being "rebuild your environment by hand" and becomes "point it at the repo."

It interprets the file inside the workspace pod rather than building a container, so features, image, build and dockerComposeFile cannot be honoured β€” the pod runs as UID 1000 with no privilege escalation and there is no Docker daemon. Those come back named, with the reason and a remedy, instead of being silently dropped: a workspace that looks configured and isn't is the worst outcome for something whose whole job is migration.

Nothing from a cloned repo ever runs on discovery. Consent is pinned to the file's hash, so if devcontainer.json changes between the dialog and your click the server refuses rather than running text you never read. See docs/devcontainer.md.


Build sessions & parallel agents

A build session is an interactive Claude / Codex / Ante / OpenCode tmux session inside the pod. Start one from the dashboard, the phone app, or the API; it survives restarts, and its output is mirrored to a log you can tail from anywhere.

The New build flow is deliberately minimal β€” pick an assistant + working directory, get a memorable name (funny-kitty-37), and land straight in a live terminal. No prompt box to fill out first; type your first prompt in the REPL, like you would locally.

Parallelism is the point. The built-in agent-orchestrator MCP lets any session spawn sub-agents β€” across different harnesses β€” to fan work out and collect results:

spawn_agent("Refactor module A", assistant="ante")     β†’ task_1
spawn_agent("Write tests for module C", assistant="claude") β†’ task_2
wait_for_agent(task_1); wait_for_agent(task_2)         β†’ synthesize

Guardrails (max spawn depth, max concurrent agents) keep a runaway loop from fork-bombing the pod.

API

# POST /api/claude/tasks  (oauth2 headers OR Authorization: Bearer <token>)
curl -s https://<user>.dev.example.com/oauth/api/claude/tasks \
  -H 'Content-Type: application/json' \
  -d '{"prompt": "review this PR", "assistant": "claude"}'
Endpoint Purpose
POST /api/claude/tasks Create a build (prompt optional)
GET /api/claude/tasks List sessions
GET /api/claude/tasks/{id} Detail
GET /api/claude/tasks/{id}/output Tail the tmux pane
GET /api/claude/tasks/{id}/stream SSE live stream
POST /api/claude/tasks/{id}/message Send a follow-up prompt
DELETE /api/claude/tasks/{id} Kill the tmux session

Full reference: docs/claude-task-api.md. There's also a /remote-task skill to dispatch a prompt from a lighter workspace to a stronger one and stream the result back.


What's in a workspace

Every workspace exposes the same set of surfaces, all behind a single GitHub OAuth login:

Surface What it is Access URL
Dashboard SPA Vite + Preact app: Desktop, Hypervisor, Build, Memory, Triggers, Apps, Skills, Files, Settings /
Hypervisor Chat that reports live state and acts on the pod / β†’ Hypervisor
Terminal ttyd-attached tmux, reachable from any browser /oauth/terminal/
VS Code code-server rooted at /home/dev /oauth/vscode/?folder=/home/dev
In-pod browser Chrome on a virtual X display, viewed via noVNC /oauth/vnc-direct/vnc.html
Metrics + health Live CPU / Mem / Disk + service health /oauth/metrics, /oauth/health
Assistants Claude Code, Codex, Gemini, Ante, OpenCode, LibreFang per-session

The dashboard

Desktop home tab (light theme) with the centered composer and Mission Control strip

The dashboard at / is a single Preact app:

  • Desktop β€” your workspace home: a centered ask-anything / start-a-build composer, a Mission Control strip of recent agents, and a dock of pinned shortcuts.
  • Mission Control β€” every agent across builds, chats, and sub-agents on one board: waiting on you, running, and done.
  • Build β€” live + past agent sessions on the left, a detail pane on the right with Terminal, Preview (split ttyd ┃ noVNC), Send message (chat mirror of the tmux pane, with image paste), Info, and Subagents tabs.
  • Memory β€” persistent, SQLite-backed memory with history + relations, mirrored over MCP.
  • Triggers β€” webhooks + cron jobs that spawn builds on a schedule or an inbound POST.
  • Apps β€” pin a running port (e.g. :3000) to preview your app inside the dashboard.
  • Skills β€” browse and sync SKILL.md files across every harness in the pod.
  • Files β€” read the PVC, upload files, make directories.
  • Settings β€” appearance, GitHub identity, subscription logins, browser/VNC controls, and real-time metrics with alerts.

A persistent top bar shows live CPU/mem/disk and one-click VS Code + New-terminal buttons. It's fully responsive β€” below 720px the rail collapses to a bottom nav, the detail pane becomes a swipeable sheet, and the layout re-flows for touch.


Persistent memory

Every workspace has a SQLite-backed memory store β€” facts about you, your projects, and your conventions β€” reachable three ways:

  • Dashboard β†’ Memory (CRUD with history + relations)
  • MCP server auto-spawned for every agent (read + write from inside the assistant)
  • REST at /api/memory

Agents read it on demand; optional pre-injection (KC_MEMORY_PREINJECT=1, off by default) prefixes a new build's prompt with the most relevant records. It's how the Hypervisor "remembers that I deploy with make ship" and how a fresh session already knows your setup. Deep dive: docs/persistent-memory.md.


Triggers β€” webhooks, crons, completion hooks

Three ways to start a build without clicking New build:

  1. Completion hooks β€” fire a webhook when an agent finishes (status, output URL, summary).
  2. Webhooks β€” accept inbound POSTs and turn the body into a build prompt via a template.
  3. Crons β€” UNIX cron expressions that POST to a webhook on a schedule.

All three live under Triggers, and what-fired-what is tracked in the memory store.


Chat over WhatsApp

Drive your workspace agent from WhatsApp. The gateway is opt-in and bring-your-own-credentials β€” connect your own Twilio (or Meta) app from Settings β†’ Messaging / WhatsApp, paste the webhook URL into the provider console, tap Link WhatsApp, and text the pairing code once. After that you just chat: messages drive a Hypervisor turn and replies come back to your phone, with keyword commands (new chat, stop, unlink, workspaces, @ws) and a fail-closed signature check on every inbound. The same card is in the mobile app.

Full guide: docs/whatsapp-gateway.md.


Pluggable AI assistants

Every session β€” and every orchestrator sub-agent β€” picks its assistant at create-time, so you can mix them freely in one workspace. Keys live in users-private/<name>/secrets/assistant.yaml (gitignored); the public defaults are empty, so it ships Claude-only out of the box, and users can add their own provider keys self-service from Settings.

Assistant, model and reasoning effort (low β†’ max, translated to each CLI's native knob) can be set per turn, or saved as a per-project default so the CTO dispatches work with the right one without being told.

Assistant Backend Configure with
Claude Code (default) Anthropic API key or subscription login claude.apiKey, or make shell USER=<name> β†’ claude to log in once
Codex OpenAI's terminal agent; ChatGPT OAuth (no API key) codex login once in the pod
Google Gemini Google's gemini CLI (default gemini-2.5-pro) assistant.gemini.apiKey
Ante Antigma's terminal agent; defaults to DeepSeek v3.2 via OpenRouter assistant.openrouter.apiKey (CLI pre-installed)
OpenCode β†’ OpenRouter any OpenRouter model assistant.openrouter.apiKey + model
OpenCode β†’ DeepSeek DeepSeek native API assistant.deepseek.apiKey
LibreFang open-source agent OS; reuses set provider keys assistant.librefang.agent

A "Claude-like" agent without an Anthropic key β€” Ante + DeepSeek

Pair the Ante CLI β€” pre-installed in every workspace β€” with DeepSeek and you get a Claude-Code-style experience: autonomous multi-step edits, shell/file tools, and the same MCP memory + orchestrator servers Claude uses, at a fraction of the cost. Set OPENROUTER_API_KEY and Ante defaults to deepseek/deepseek-v3.2 (~$0.23 / $0.34 per 1M in/out tokens) β€” cheap enough to be the default background sub-agent in the orchestrator.


Mobile app (iOS & Android)

kube-coder mobile app

Beyond the responsive web dashboard, kube-coder ships a native Expo / React Native app (mobile/) to drive your workspace from your phone: list / create / message / kill agent sessions, tail their color terminal output with a control-key bar (Shift-Tab, Esc, arrows, Ctrl-C, Paste), chat with the Hypervisor, attach photos to a follow-up, search memory, and watch live metrics β€” all over the workspace's Bearer-token API. It points at any kube-coder host: a cloud workspace, or a local minikube one via make mobile-forward.

cd mobile && npm install
npm run ios          # iOS Simulator   (or: npm run android / npm run web)

Enter your workspace host + API token (copy both from Settings β†’ Mobile app) on the first screen. Store builds use EAS β€” no Mac needed:

make mobile-build         # EAS cloud build (iOS .ipa + Android .aab)
make mobile-screenshots   # regenerate App Store / Play Store screenshots

Full walkthrough: mobile/README.md.


Quick start

kube-coder runs two ways β€” pick the one that fits:

Local (minikube) Cloud / multi-tenant
Best for trying it out, dev, offline real deployments, teams
Needs Docker + minikube a cluster, registry, DNS, GitHub OAuth
Auth http basic (admin/admin) GitHub OAuth2 (or basic)
TLS none (plain HTTP, localhost) cert-manager + Let's Encrypt
Guide Option A + docs/local-development.md Option B + docs/NEW_USER_PROVISIONING.md

πŸ“– Follow-along walkthroughs:

Option A β€” Local (minikube)

Run the whole stack on a local single-node cluster β€” no cloud account, registry, DNS, or TLS.

Prerequisites: Docker, minikube, kubectl, helm (brew install minikube kubectl helm on macOS).

make local          # start minikube, build the image, deploy, and print access info

Then reach the dashboard:

echo '127.0.0.1  kube-coder.local' | sudo tee -a /etc/hosts   # one time
make local-forward                                            # keep running in a terminal
# open http://kube-coder.local:8080/   β†’   basic auth: admin / admin

make local wraps steps that each run on their own (local-up, local-build, local-secret, local-deploy, local-info, local-down). Everything targets the minikube context explicitly, so it never touches a remote cluster. Full guide: docs/local-development.md.

Option B β€” Cloud / multi-tenant

Prerequisites: Kubernetes 1.19+, Helm 3.0+, an nginx-ingress controller, wildcard DNS (*.<your-domain> β†’ the ingress IP), a GitHub OAuth App for the controller console, a private GitHub repo as the GitOps config store, and a regcred image-pull secret.

DOMAIN=<your-domain> make doctor  # preflight: check ALL of the above at once (read-only)
make deploy-base                  # base infra: nginx-ingress, oauth2-proxy, cert-manager
make ship-controller-config       # the admin console (workspace-controller)

Run make doctor first. It's a read-only preflight that verifies every prerequisite above β€” kubectl/helm versions, the ingress controller and its external IP, cert-manager plus a ClusterIssuer, that *.<your-domain> actually resolves to your ingress IP (the failure that otherwise only surfaces as a dead workspace later), the regcred secret, and GitOps-repo reachability β€” reporting all failures at once with a fix for each. Pass DOMAIN=<your-domain> to include the wildcard-DNS check (skipped otherwise).

Two things make self-service onboarding work; you set them once:

  • Wildcard DNS β€” point *.<your-domain> at your ingress IP. Every workspace lives at <github-login>.<your-domain>, so a new user's host resolves the moment they're created, and cert-manager + Let's Encrypt issues its TLS cert on first request.
  • The console's GitHub OAuth App + admin allowlist β€” gates the dashboard at controller.<your-domain>; only allowlisted logins may administer workspaces. One-time config: docs/PROVISIONING.md.

Onboard a user β€” the 2-minute dashboard flow

Scenario. Dana (@dana-codes) joins Monday morning and needs a full cloud workspace before standup.

  1. Open the console at https://controller.<your-domain> β†’ New workspace.
  2. Look up the user β€” type dana-codes, hit Look up. The controller confirms it's a real GitHub account and shows the host: dana-codes.<your-domain>.
  3. Create a GitHub OAuth App β€” the one manual step (GitHub has no API for it). The form shows the exact Homepage + callback URLs.

    ⚠️ It must be an OAuth App (Client ID starts with Ov…), not a GitHub App (Iv…), which silently 404s the login.

  4. Paste & create β€” drop the Client ID + Secret into the form β†’ Create workspace. The controller commits Dana's config to your GitOps repo and launches a provisioner Job; the page streams the rollout: Starting β†’ Deploying β†’ Workspace ready.
  5. Hand it off β€” send Dana https://dana-codes.<your-domain>. She signs in with her own GitHub account (she, and only she, is on the allowlist) and lands in VS Code, a terminal, and Claude Code. Elapsed time: a couple minutes, most of it the image pull.

Manage a user β€” limits, updates, lifecycle

controller edit-limits panel controller mobile management

All per-workspace, in the same console:

  • Right-size resources β€” Edit limits β†’ set CPU / memory. Applying patches the live pod and commits the new limits to GitOps, so it's durable across redeploys. Live usage + estimated monthly cost sit right above the control.
  • Keep them current β€” each workspace shows its release and an update action; users can also self-update from their own dashboard.
  • Pause to save spend β€” Stop scales the pod to zero (PVC preserved); Start brings it back unchanged.

Automation / break-glass: the CLI

The same workspaces are fully operable from the Makefile β€” for scripting, CI, or when the console is down. Config lives in the GitOps repo; make users-sync checks it out locally so CLI and console share one source of truth:

make users-sync                   # pull the GitOps config store into .users/
make new-user      USER=<name>    # scaffold a workspace (prints the OAuth-App checklist)
make deploy        USER=<name>    # helm upgrade --install
make logs|shell|test USER=<name>  # operate a running workspace
make stop|start    USER=<name>    # scale to zero / back

Full CLI walkthrough: docs/NEW_USER_PROVISIONING.md.


Architecture

kube-coder workspace topology

A per-user PVC mounted at /home/dev survives pod restarts; the tmux sessions attached to it survive too, so an in-flight agent build keeps running even after you close the tab. oauth2-proxy injects X-Auth-Request-User on every /oauth/* route; each workspace's proxy is pinned to exactly one GitHub login.

Isolation & security posture

Each workspace is a tenant boundary, not a folder:

  • Its own namespace (ws-<user>) with a dedicated ServiceAccount, ResourceQuota and LimitRange β€” scoped so a workspace can read nothing outside itself.
  • NetworkPolicy both ways β€” ingress only from ingress-nginx; egress denied to the cloud metadata endpoint and to other tenants' pods, while normal internet (GitHub, npm, registries, model providers) stays open.
  • No signing keys in the agent's container β€” the GitHub App private key lives in its own sidecar, which hands the ide container only an hourly token.
  • Agent-readable instruction files are scanned for hidden-text prompt injection (zero-width and Unicode-tag characters in CLAUDE.md, .cursorrules, …) β€” the technique used by the 2026 TrapDoor supply-chain campaign.
  • Provisioning is opt-in and constrained β€” a ValidatingAdmissionPolicy pins the shape of the privileged Job, and chart refs must be immutable.

Full policy, reporting process and hardening defaults: SECURITY.md Β· docs/SUPPLY_CHAIN.md.

Repository layout

charts/
β”œβ”€β”€ base-infrastructure/   # ingress, oauth2-proxy, cert-manager
└── workspace/             # per-user workspace chart
    β”œβ”€β”€ server.py          # API + dashboard backend (tmux, memory, metrics, hypervisor)
    β”œβ”€β”€ hypervisor_session.py  # structured agent-session runner + per-CLI adapters
    β”œβ”€β”€ mcp_dashboard.py   # dashboard MCP server (read/act on the pod)
    └── web/               # Vite + Preact SPA (the dashboard at /)
        β”œβ”€β”€ src/routes/    # desktop, cto, feed, hypervisor, mission, tasks, memory, triggers, apps, files, docs, skills, walkie, settings
        β”œβ”€β”€ src/store/     # signals: tasks, ui, metrics, router
        └── scripts/shoot.mjs   # playwright screenshots
deployments/               # public sample per-user values.yaml + secrets
users-private/             # gitignored; controller bootstrap config
mobile/                    # native Expo / React Native app (iOS + Android, EAS builds)
devlaptop/Dockerfile       # the workspace image (SPA baked into /opt/dashboard-dist)
Makefile                   # all common commands (`make help`)

Pre-installed stack

Component Version
Node.js 20 LTS
code-server (VS Code) v4.x
Claude Code CLI 2.1.174
Codex CLI 0.144.3
OpenCode CLI 1.17.4
Ante CLI stable channel
LibreFang 2026.x beta
ttyd 1.7.7
tmux, yarn, gh, jq, ripgrep, fzf latest from Ubuntu

Bump versions in devlaptop/Dockerfile and run make push to rebuild.


Common commands

# Docker image
make build / make push / make clean

# Per-user lifecycle
make deploy   USER=<name>         # helm upgrade --install
make ship     USER=<name>         # build + push + roll the pod
make rollback USER=<name>         # helm rollback
make logs|shell|test USER=<name>  # operate a running workspace

# Dashboard SPA
make dashboard-web                # type-check + vite build β†’ web/dist
make dashboard-web-test           # vitest unit tests

# Tests across the repo
make test-all-units               # SPA (vitest) + server.py (unittest)
make coverage                     # HTML coverage reports

# Cluster status
make status                       # helm + pod status

make help (or just make) lists everything with one-line descriptions.


Testing & code quality

Component Coverage Framework
Frontend (Dashboard) 41.6% Vitest + @testing-library
Backend (Python API) 74% unittest + coverage.py
Overall 60% statement-weighted average
make test-all-units    # SPA + Python unit tests (run before every PR)
make coverage          # HTML reports β†’ web/coverage/ and htmlcov/

All tests run automatically on GitHub Actions.


Development

# Run the SPA locally against a built dist with auth bypassed
make dashboard-web
DASHBOARD_DIST_DIR=$(pwd)/charts/workspace/web/dist \
  python3 charts/workspace/web/dev_server.py
# β†’ http://127.0.0.1:7070

Pull requests welcome β€” please run make test-all-units and keep coverage healthy before opening a PR. Contribution guide: CONTRIBUTING.md.


Acknowledgments

kube-coder stands on excellent open source:


Videos

New-user provisioning https://github.com/user-attachments/assets/d9e6c19c-28ab-4f5e-963a-08b1d0a7085a
Marketing https://github.com/user-attachments/assets/1e4d1bd5-ec9c-4f4e-88ba-7c2b79593a4c
Demo https://github.com/user-attachments/assets/f5821e5c-a834-4db2-a34d-2d405c3daef2

Contact

Interested in a demo, an enterprise deployment, or a custom integration? scalebaseio@gmail.com Β· KubeCoder.com Β· r/kubecoder

License

MIT β€” see LICENSE.

About

helm chart for a isolated dev coding environment pod in kubernetes

Resources

Contributing

Security policy

Stars

340 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages