apiVersion: apps/v1 kind: Deployment metadata: name: agent-pod namespace: agent-pod spec: replicas: 1 selector: matchLabels: app: agent-pod template: metadata: labels: app: agent-pod spec: # api.riotpiao.com has no in-cluster DNS record (only resolves from the # home network's own resolver) -- pin it to ingress-nginx-controller's # ClusterIP so pi's models.json baseUrl works unchanged. TLS still # terminates correctly since SNI/Host still say api.riotpiao.com. hostAliases: - ip: "10.101.128.185" hostnames: - "api.riotpiao.com" containers: # hub.js runs in the same container as pi (not a sidecar) so it can # spawn `pi -p --mode json` directly via child_process -- a separate # container can't exec into another container's filesystem/PATH. # It IS the container's long-running process now; no more `sleep # infinity` placeholder. # # Also builds the agent-manager fork (github.com/Riotpiaole/ # agent-manager, add-headless-spawn branch) from source and drops # coordinator.js in beside hub.js -- neither is the container's # foreground process. hub.js keeps that role unchanged; coordinator.js # itself now owns multi-repo concurrency (REPO_CONCURRENCY env, # default 3), so one invocation handles every repo: # `kubectl exec -- node /root/coordinator.js --repos # repoA,repoB,... --tasks ...`. Each repo gets its own clone and its # own persistent 4-agent pool (planner/investigator/implementer/ # judge, one agent-manager session per role, reused across every # task in that repo) on the container's local tmux server -- # `kubectl exec -it -- agent-manager` attaches its TUI live # against those same sessions, no cross-machine visibility problem # since spawner, tmux server, and viewer are all colocated here. # # No prebuilt Linux binary is shipped for agent-manager: the local # .bin/ build is macOS arm64 (wrong OS/arch for this container # anyway) and it's 27MB, well over a ConfigMap's ~1MiB cap. Debian's # `apt-get golang-go` is far too old for this fork's go 1.26.5 # requirement, so the real Go toolchain is fetched directly from # go.dev instead. - name: pi image: node:22-slim command: - sh - -c - | set -e apt-get update && apt-get install -y git curl jq openssh-client tmux python3 sqlite3 gcc build-essential ssh-keygen -y -f /root/.ssh/id_forgejo > /root/.ssh/id_forgejo.pub eval "$(ssh-agent -s)" ssh-add /root/.ssh/id_forgejo npm install -g @earendil-works/pi-coding-agent@0.84.2 npm install --prefix /root ws curl -fsSL "https://go.dev/dl/go1.26.5.linux-$(dpkg --print-architecture).tar.gz" | tar -C /usr/local -xz export PATH="$PATH:/usr/local/go/bin" git clone --branch add-headless-spawn --depth 1 \ https://github.com/Riotpiaole/agent-manager.git /root/agent-manager-src (cd /root/agent-manager-src && go build -o /usr/local/bin/agent-manager .) # Language toolchains for whatever repos the implementer/investigator/ # judge roles actually build and test -- go was already fetched above # only for building agent-manager itself, and its PATH export above is # local to this script, invisible to `kubectl exec` sessions into the # already-running container. Symlinking both into /usr/local/bin (on # PATH for every exec session, interactive or not) instead of relying # on shell rc sourcing, which pi's non-interactive tool calls don't do. ln -sf /usr/local/go/bin/go /usr/local/bin/go curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable ln -sf /root/.cargo/bin/cargo /usr/local/bin/cargo ln -sf /root/.cargo/bin/rustc /usr/local/bin/rustc ln -sf /root/.cargo/bin/rustup /usr/local/bin/rustup node /root/hub.js env: - name: PI_BIN value: pi - name: AGENT_MANAGER_BIN value: /usr/local/bin/agent-manager - name: HUB_WORK_DIR value: /root/agent-harness-work # planner/investigator/implementer stay on the default # (homelab-ornith/ornith:35b, pi's settings.json default). Judge # moves to the separate homelab-reasoning backend (DeepSeek-R1, # its own 2 GPU replicas) so judge calls stop contending with the # other 3 roles for the 2 ornith pods -- an entire role's worth # of traffic moves onto otherwise-idle capacity instead. - name: JUDGE_PROVIDER value: homelab-reasoning - name: JUDGE_MODEL value: reasoning ports: - containerPort: 9090 resources: requests: cpu: "4" memory: 8Gi limits: cpu: "8" memory: 16Gi volumeMounts: - name: pi-config mountPath: /root/.pi/agent/settings.json subPath: settings.json - name: pi-models mountPath: /root/.pi/agent/models.json subPath: models.json - name: pi-skills mountPath: /root/.pi/agent/skills - name: hub-src mountPath: /root/hub.js subPath: hub.js - name: coordinator-src mountPath: /root/coordinator.js subPath: coordinator.js - name: ssh-key mountPath: /root/.ssh/id_forgejo subPath: id_forgejo - name: ssh-config mountPath: /root/.ssh/config subPath: config volumes: - name: pi-config configMap: name: pi-config - name: pi-models secret: secretName: pi-models - name: pi-skills configMap: name: pi-skills items: - key: planner-SKILL.md path: planner/SKILL.md - key: investigator-SKILL.md path: investigator/SKILL.md - key: info-collector-SKILL.md path: info-collector/SKILL.md - key: implementer-SKILL.md path: implementer/SKILL.md - key: judge-SKILL.md path: judge/SKILL.md - key: resolver-SKILL.md path: resolver/SKILL.md - name: hub-src configMap: name: hub-src - name: coordinator-src configMap: name: coordinator-src - name: ssh-key secret: secretName: agent-pod-ssh-key defaultMode: 0600 - name: ssh-config configMap: name: agent-pod-ssh-config