Agent pod fleet: SSH-able Claude / Codex / OpenAI runtimes on k3s #8
Labels
No labels
burndown-2026-06
coherence-core
consult
headless
interactive
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
coilyco-flight-deck/infrastructure#8
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally filed by @coilysiren on 2026-05-22T20:33:06Z - https://github.com/coilysiren/infrastructure/issues/283
Goal
Run Kai's Claude, Codex, and OpenAI agents as pods on the
kai-serverk3s cluster instead of natively on each host. Today each agent inherits its host's toolchain (brew on the Mac, linuxbrew on kai-server, Git Bash on Windows), socoily, paths, and tool versions drift per machine. A single pod image gives every agent an identical Linux userland no matter which node it lands on. Each pod sits on the tailnet, sossh kai@agent-claude-<node>drops Kai into the agent's shell the same wayssh kai@kai-serverdoes today.This started as a "just run them in Docker" idea. Kubernetes is the better fit because the cluster already has the hard parts: the Tailscale operator (393d), ExternalSecrets (401d), and cert-manager are all running.
Shape
agents.agent-claude,agent-codex,agent-openai. One per runtime, so each is restarted, version-pinned, and SSH'd into independently. Not one DaemonSet with three containers.nodeSelector: agent-host=true. A node opts into the fleet by carrying that label. This keeps the "one per node" model while decoupling rollout from node count. Label a node, pods appear.tailscaledruns inside the agent container, not as a separatetssidecar likedeploy/repo-recall.yml.tailscale up --sshthen puts the agent's own shell on the tailnet. A sidecar would land SSH in the sidecar container, not the agent. The sidecar pattern is for exposing an HTTP service. The goal here is a shell.hostPath. The nodes are durable physical machines, so work survives a pod restart by living on the node. DaemonSets have novolumeClaimTemplateanyway.Hard constraint: only kai-server can host the fleet today
A tailnet-attached pod needs kernel-mode tailscale, which needs
/dev/net/tun. The two WSL2-backed nodes (kai-macbook-pro-vm,kai-desktop-tower-wsl) don't expose that device to containerd.deploy/repo-recall.ymlpins tokai-serverfor exactly this reason. So at rollout onlykai-servercarriesagent-host=trueand the fleet is three pods. Expanding to the other nodes (and whether that is even wanted, since they back machines Kai uses interactively) is tracked in #285.Tailscale SSH and the UID question
tailscaledneeds root for the netlink and TUN ioctls. The agent must write/home/kai/projectson the host, owned bykai(UID 1000 on kai-server). So the agent image carries akaiuser at UID 1000, the entrypoint startstailscaledas root, then runs the agent runtime askai. Tailscale SSH execs the inbound session askaivia the tailnet ACLsshrule. Files stay owned by 1000,tailscaledstays happy. This is the reasontailscaledcan co-locate with the agent without the container-split thatrepo-recall.ymluses.Auth keys
Mint one reusable, ephemeral,
tag:agentauth key per runtime interraform/tailscale-devices/, sync to SSM at/coilysiren/agents/<runtime>/ts-authkey. Reusable so a DaemonSet spanning nodes shares one key. Ephemeral so a dead pod deregisters instead of littering the tailnet. Tagged so a tailnet ACL can scope who reaches the agent pods (only Kai's devices).Drafted manifest
agent-claudeshown.agent-codexandagent-openaiare identical bar the name and image. Land all three plus the namespace and RBAC indeploy/agents.yml.Sub-tasks
ghcr.io/coilysiren/agent-<runtime>): base userland,coily, the runtime CLI,tailscaled, akaiUID-1000 user, the drop-privileges entrypoint. Ship via adocker.ymlGHA workflow like the other repos.tag:agentauth keys interraform/tailscale-devices/, sync to SSM under/coilysiren/agents/<runtime>/ts-authkey.deploy/agents.yml: namespace, RBAC, three DaemonSets, three ExternalSecrets.tag:agentreachable over SSH only from Kai's own devices.kai-serveragent-host=true, apply, verifyssh kai@agent-claude-kai-server.docs/k3s-deploy-notes.mdonce it works.Open decisions
coilysiren/agent-imagesrepo, or a directory ininfrastructure. Leaning new repo to match the per-repodocker.ymlpattern./home/kai/projectsread-write. Could scope per-runtime or use read-only plus an overlay if blast radius matters.Out of scope
Backlog burndown 2026-06-17: closing low-priority (P3/P4) to bring the open count to a manageable level. Nothing lost — reopen if this resurfaces. Batch tag:
burndown-2026-06.