Skip to main content

Kelos Turns Autonomous Coding Agents Into Kubernetes CRDs

8 min readDora NodaDora Noda
Share
On this page

Run kubectl get tasks on a cluster running Kelos and you get back a live audit log of every AI coding agent that has ever touched the repo — who spawned it, what prompt it ran, which branch it pushed, and whether it's still running. Not a chat transcript buried in a vendor's dashboard. A Kubernetes resource, queryable with the same tool you already use to check pod status.

That's the pitch behind Kelos, a Kubernetes-native framework that landed on Hacker News twice in 2026 and now sits at v0.45.0 with 251 stars: define an autonomous coding agent's entire working context — prompt, model, instructions, MCP servers, git workspace, credentials, and pod resources — as four CRDs instead of a bespoke webhook-and-script pipeline. For a platform like bex, built on Cluster API and already committed to giving AI agents the same first-class operator status as human users, Kelos isn't just another agent-tooling launch to note and move past. It's a concrete answer to a question bex's own roadmap has to answer eventually: what does "spawn an agent to do work" look like as a resource type instead of a script?

The Four Primitives, Concretely

Kelos's whole bet is that "run an agent" decomposes cleanly into four separable concerns, each its own CRD:

CRDWhat it ownsKey fields
TaskOne agent executiontype (which agent), prompt, credentials, workspaceRef, dependsOn (chain to prior tasks), branch
WorkspaceGit repo contextrepo, ref, token/githubApp, setupCommand
AgentConfigReusable agent behavioragentsMD (instructions), plugins (skills), mcpServers (tool integrations)
TaskSpawnerEvent-to-Task wiringwhen (trigger source), taskTemplate, maxConcurrency, maxTotalTasks

A TaskSpawner polling GitHub Issues for the bug label looks like this in practice: it watches on a 5-minute interval, and for every matching issue it materializes a Task from a template, filling in the issue title and body as the prompt. That Task references a Workspace (which repo, which branch, how to bootstrap the checkout) and an AgentConfig (which agent binary — Claude Code, Codex, Gemini, OpenCode, Cursor, or a custom image — plus which MCP servers and skills it gets). The controller clones the repo, injects only the credentials that Workspace named, runs the agent in an isolated ephemeral pod with no host access, and captures the branch name and PR URL as outputs other Task resources can reference downstream via {{index .Deps "write-tests" "Results" "branch"}}.

Multi-step work is just dependsOn chains: a scaffold task, then a test-writing task gated on the scaffold's branch, then a review task gated on both. Each step is a Kubernetes resource with its own audit trail, not a shell script's stdout scrolling past in a CI log.

Where This Isn't kagent, and Why That Matters

It's worth being precise about category here, because "AI agents plus Kubernetes CRDs" now describes at least two different things. kagent — a CNCF Sandbox project — defines Agent, ModelConfig, and ToolServer CRDs for running general agentic AI applications (chatbots, ops assistants) as cluster-native workloads, with native MCP and A2A endpoints. That's infrastructure for agents that answer questions and call tools continuously.

Kelos's four CRDs are narrower and more specific: they model a coding task with a beginning and an end — clone a repo, do bounded work, produce a branch or PR, exit. Task is closer to a Kubernetes Job than to a long-running Agent custom resource. That distinction is exactly the shape of the thing bex's own MCP server needs for agent-triggered deploy, rollback, and logs calls: bounded, auditable, credential-scoped units of work, not a persistent chatbot.

The Alternative Kelos Is Replacing

The comparison that makes Kelos legible isn't to kagent — it's to what most teams already have instead: a webhook receiver, a script that shells out to claude or codex with a constructed prompt, and maybe a Slack notification when it's done. That pipeline works, but every piece of it is opaque to the rest of the platform. There's no kubectl get for "which prompts ran against which repos this week." Credential scope is whatever the script's service account happens to have, not something declared per-workspace. Retries, concurrency limits, and timeouts are whatever the script author remembered to add, not a schema-enforced field.

Turning that into CRDs doesn't make the underlying problem (an LLM writing code unsupervised) safer by itself. But it does make the governance surface reviewable the same way a Kubernetes platform already reviews everything else: TaskSpawner and AgentConfig changes go through a PR, get diffed, and get rolled back with git revert exactly like any other manifest. That's the concrete thing "GitOps-reviewable" buys over "bespoke webhook-and-script pipeline" — not a new capability, a governance model bex's platform-engineering audience already trusts.

The Governance Mechanics Worth Copying Directly

Three specific controls in Kelos are worth lifting regardless of whether bex adopts the CRDs wholesale:

  • Per-spawner RBAC scoping. Each TaskSpawner automatically creates its own ServiceAccount and RoleBinding, so a spawner watching one team's issue tracker can't touch another team's namespace. For a multi-tenant PaaS, that's the difference between "an agent can deploy the app it was invoked for" and "an agent has whatever permissions the platform's service account happens to carry."
  • Hard concurrency and lifetime caps. maxConcurrency, maxTotalTasks, and activeDeadlineSeconds exist specifically because an unattended agent loop is a cost and blast-radius risk, not just a UX one. A TaskSpawner that can't spawn more than three concurrent Tasks, each capped at a hard wall-clock deadline, bounds the damage of a misconfigured trigger before it bounds anything else.
  • Pod-level isolation with no host access. Agents run in ephemeral pods that can't read other pods or reach beyond the credentials explicitly injected into them. That's the same tenant-isolation posture a Cluster-API PaaS already has to enforce for ordinary tenant workloads — Kelos just applies it to the agent doing the deploying, not only the app being deployed.

The Verdict: Reference Architecture, Not a Dependency

Should bex import Kelos's four CRDs directly? No — and the reasons are less about Kelos's quality than about fit. At v0.45.0 with 251 stars, 262 open issues, and a stated non-goal of running outside Kubernetes, it's an early-stage project still dogfooding itself to build itself. Taking a direct dependency on a CRD schema that's still moving fast means inheriting its churn on top of bex's own.

But the shape is worth adopting as a reference architecture, mapped onto what bex already has:

  • Workspace and AgentConfig are close to solved. bex already manages git-repo checkout and build context for every deployed app; extending that same primitive to scope an agent's repo access and MCP-server allowlist is additive, not new infrastructure.
  • Task is the piece worth building custom, not importing. bex's version needs to be typed around its own domain from day one — a DeployTask, RollbackTask, LogQueryTask — rather than a generic "run an agent with this prompt" resource, because the MCP tool contract (what a deploy/rollback call is allowed to do) is stricter than an arbitrary coding task's.
  • TaskSpawner's trigger model is the one piece to copy almost verbatim. Watching GitHub issues, PRs, webhooks, and cron on a poll interval, with per-spawner RBAC and hard concurrency caps, is exactly the shape of "an agent notices something needs fixing and proposes a change" that bex's own self-healing GitOps story needs — and there's no reason to reinvent that trigger taxonomy from scratch.

Kelos proves the four-primitive decomposition works well enough that a small team could dogfood it into their own development loop within months — a strong signal the shape is right. It's not, on its own, a reason to hand bex's deploy/rollback authority to a dependency still finding its schema. What it is a reason for is borrowing the shape directly.

What the Reference Architecture Actually Looks Like

Concretely, borrowing Kelos's TaskSpawner shape for bex's own agent-ops layer means a resource that reads like this — watching for a specific, bounded failure mode instead of an open-ended coding prompt:

yaml
apiVersion: bex.co/v1alpha1
kind: DeployTaskSpawner
metadata:
  name: failed-health-check-rollback
  namespace: tenant-acme
spec:
  when:
    deployEvent:
      status: HealthCheckFailed
      pollInterval: 30s
  taskTemplate:
    kind: RollbackTask
    spec:
      appRef: acme-api
      strategy: previous-healthy-revision
      mcpServers:
        - name: bex-deploy
          allowedTools: [rollback, logs]
  maxConcurrency: 1
  activeDeadlineSeconds: 300

Everything that made Kelos's version legible is still here: the trigger is declarative and versioned, the spawner gets its own ServiceAccount scoped to tenant-acme, and allowedTools narrows the MCP surface to exactly rollback and logs — no deploy, no cross-tenant reach. The difference from Kelos's Task is that RollbackTask.spec is a typed, closed schema (an app reference and a rollback strategy) instead of a free-text prompt, because a rollback is a bounded operation with a small number of valid shapes, not an open-ended coding task an LLM has to interpret. That's the concrete form "reference architecture, not a dependency" takes: same trigger taxonomy and RBAC posture, a narrower and stricter Task equivalent underneath.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with the same API surface a human deploys through open to an agent as a first-class operator. Star the repo on GitHub or deploy your first app today.

Related articles

Give your agents a chain backend

Autonomous agents hit RPC endpoints very differently than people do. See what bex router handles on their behalf.

Read the agents guide