Project Name: Agentic SDLC Runner
Version: 1.0.0
Date: 2026-02-14
Status: Draft
Enable local OpenCode CLI sessions to spawn and control remote AI agent pods running in Kubernetes, with full visibility from the main session.
- Spawn K8s pods for [ASYNC] tasks via OpenCode subagents
- Stream pod logs back to the main session
- Autonomous execution with git-based completion detection
- Integration with existing spec-kit workflow
- External controller (we use subagents)
- K-Agent framework
- Beads issue tracking
- Web dashboard
- Mayor pattern (Gastown)
┌─────────────────────────────────────────────────────────────────────────┐
│ MAIN OPENCODE SESSION │
│ │
│ Human: /implement │
│ │ │
│ ├──► Subagent 1: "Implement T001" │
│ │ ├── scripts/spawn-pod.sh T001 branch-async repo-url │
│ │ ├── scripts/tail-logs.sh pod-001 → streams to main │
│ │ └── git commit + push when done │
│ │ │
│ ├──► Subagent 2: "Implement T002" (parallel) │
│ │ ├── scripts/spawn-pod.sh T002 branch-async repo-url │
│ │ ├── scripts/tail-logs.sh pod-002 → streams to main │
│ │ └── git commit + push when done │
│ │ │
│ └──► Subagent N: "Implement T00N" (parallel) │
│ ├── scripts/spawn-pod.sh T00N branch-async repo-url │
│ ├── scripts/tail-logs.sh pod-00N → streams to main │
│ └── git commit + push when done │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ K8s CLUSTER │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Pod 1 │ │ Pod 2 │ │ Pod N │ │
│ │ opencode run │ │ opencode run │ │ opencode run │ │
│ │ + spec/plan │ │ + spec/plan │ │ + spec/plan │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ Each pod: git clone → implement → git push → done │
└─────────────────────────────────────────────────────────────────────────┘
| Step | Action |
|---|---|
| 1 | Developer creates branch: specs/feature-001/task-001-xxx-async |
| 2 | Orchestrator detects [ASYNC] task |
| 3 | Pod starts: git clone -b <branch> |
| 4 | Agent works autonomously |
| 5 | Agent: git add . && git commit && git push |
| 6 | Completion detected via log output |
| Component | Purpose | Location |
|---|---|---|
| Helm Chart | K8s resources templating | charts/agentic-sdlc-agent-runner/ |
| Release (Dev) | Dev environment values | releases/agentic-sdlc-agent-runner-dev/ |
| Release (Stg) | Staging environment values | releases/agentic-sdlc-agent-runner-stg/ |
| Release (Prod) | Production environment values | releases/agentic-sdlc-agent-runner-prod/ |
| Script | Purpose | Location |
|---|---|---|
spawn-pod.sh |
Creates K8s pod for a task using Helm templates | scripts/spawn-pod.sh |
tail-logs.sh |
Streams pod logs to stdout | scripts/tail-logs.sh |
| File | Purpose |
|---|---|
templates/namespace.yaml |
Create namespace for agents |
templates/rbac.yaml |
ServiceAccount and roles |
templates/configmap.yaml |
Shared configuration (non-sensitive) |
templates/external-secret.yaml |
External Secrets Operator integration |
templates/pod-template.yaml |
Agent pod template |
templates/_helpers.tpl |
Helm helper templates |
| File | Purpose |
|---|---|
docker/Dockerfile.opencode |
Container image with OpenCode + git |
Deploy the runner using Helm:
# Development
helm upgrade --install agentic-sdlc-agent-runner-dev \
releases/agentic-sdlc-agent-runner-dev \
-n agent-runner-dev --create-namespace
# Staging
helm upgrade --install agentic-sdlc-agent-runner-stg \
releases/agentic-sdlc-agent-runner-stg \
-n agent-runner-stg --create-namespace
# Production
helm upgrade --install agentic-sdlc-agent-runner-prod \
releases/agentic-sdlc-agent-runner-prod \
-n agent-runner-prod --create-namespaceSpawn a task pod using the helper script (after Helm deployment):
# Using the Helm-based spawn-pod.sh script
./scripts/spawn-pod.sh task-001 specs/feature/task-001-async https://github.com/user/repo
# With SSH authentication
SSH_SECRET_NAME=github-deploy-key ./scripts/spawn-pod.sh task-001 specs/feature/task-001-async git@github.com:user/repo.git
# Production environment
ENVIRONMENT=prod NAMESPACE=agent-runner-prod ./scripts/spawn-pod.sh task-001 specs/feature/task-001-async https://github.com/user/repoThe script uses helm template to generate the pod manifest from the release charts and applies it with kubectl apply.
Stream logs from a K8s pod using kubectl:
#!/bin/bash
# Tails logs from a K8s pod to stdout
NAMESPACE="${NAMESPACE:-agent-runner}"
POD_NAME="$1"
if [ -z "$POD_NAME" ]; then
echo "Usage: $0 <pod-name>"
exit 1
fi
kubectl logs -f -n "$NAMESPACE" "$POD_NAME"See templates/pod-template.yaml for the full pod spec template. Key features:
{{- define "agentic-sdlc-agent-runner.podTemplate" -}}
restartPolicy: Never
serviceAccountName: {{ include "agentic-sdlc-agent-runner.serviceAccountName" . }}
containers:
- name: agent
image: "{{ .Values.pod.image.repository }}:{{ include "agentic-sdlc-agent-runner.imageTag" . }}"
env:
- name: OPENCODE_SERVER_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "agentic-sdlc-agent-runner.externalSecretName" . }}
key: server-password
- name: GIT_REPO
value: "{{ .Values.task.defaultRepo }}"
- name: GIT_BRANCH
value: "{{ .Values.task.defaultBranch }}"
resources:
{{- toYaml .Values.pod.resources | nindent 6 }}
{{- end }}spec-kit Our Implementation
───────── ──────────────────
spec.md ──────► /plan ──────────► tasks.md
│ │
│ ├── [SYNC] tasks → Human does locally
│ │
│ └── [ASYNC] tasks → Spawns subagent
│ │
│ ├── scripts/spawn-pod.sh
│ ├── scripts/tail-logs.sh
│ └── completion detection
The integration happens at /implement command:
- Parse tasks.md for [ASYNC] markers
- For each [ASYNC] task, spawn an OpenCode subagent
- Subagent creates K8s pod via Helm or kubectl
Each pod receives:
- Git branch (from tasks.md)
- Repository URL (from git remote)
- Context files (spec.md, plan.md) via git clone
See templates/namespace.yaml:
{{- if .Values.namespace.create }}
apiVersion: v1
kind: Namespace
metadata:
name: {{ include "agentic-sdlc-agent-runner.namespace" . }}
labels:
{{- include "agentic-sdlc-agent-runner.labels" . | nindent 4 }}
{{- end }}See templates/rbac.yaml and templates/serviceaccount.yaml:
- ServiceAccount with optional Workload Identity annotations
- Role with pod management permissions
- RoleBinding
See templates/external-secret.yaml:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ include "agentic-sdlc-agent-runner.externalSecretName" . }}
spec:
refreshInterval: {{ .Values.externalSecret.refreshInterval }}
secretStoreRef:
name: {{ .Values.externalSecret.secretStore.name }}
kind: {{ .Values.externalSecret.secretStore.kind }}
target:
name: {{ include "agentic-sdlc-agent-runner.externalSecretName" . }}
data:
- secretKey: server-password
remoteRef:
key: {{ .Values.externalSecret.remoteRef.key }}Security Note: Secrets are managed via External Secrets Operator, not hardcoded in ConfigMap.
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
curl \
git \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://opencode.ai/install.sh | bash
RUN mkdir -p /workspace
WORKDIR /workspace
CMD ["/bin/bash"]agentic-sdlc-agent-runner/
├── SPEC.md # This file
├── PRD.md # Product requirements
├── docker/
│ └── Dockerfile.opencode # OpenCode container image
├── charts/
│ └── agentic-sdlc-agent-runner/ # Helm chart
│ ├── Chart.yaml
│ ├── values.yaml
│ ├── README.md
│ └── templates/
│ ├── _helpers.tpl # Template helpers
│ ├── namespace.yaml
│ ├── serviceaccount.yaml
│ ├── rbac.yaml
│ ├── configmap.yaml # Non-sensitive config only
│ ├── external-secret.yaml
│ └── pod-template.yaml
├── releases/
│ ├── agentic-sdlc-agent-runner-dev/
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ └── argocd.yaml # GitOps config
│ ├── agentic-sdlc-agent-runner-stg/
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ └── argocd.yaml
│ └── agentic-sdlc-agent-runner-prod/
│ ├── Chart.yaml
│ ├── values.yaml
│ └── argocd.yaml
└── scripts/
├── spawn-pod.sh # Create task pods via Helm
├── tail-logs.sh # Stream pod logs
└── README.md # Scripts documentation
- Git credentials: How does the pod authenticate to git? (SSH key, token, or workload identity?)
- Completion detection: Webhook or log parsing? (Log parsing preferred)
- Timeout: How long should a pod run before being killed?
- Cleanup: Auto-delete pods after completion?
| Dependency | Version | Purpose |
|---|---|---|
| Kubernetes | 1.25+ | Container orchestration |
| OpenCode | latest | AI coding agent |
| Git | any | Version control |
| kubectl | latest | K8s CLI |
- Helm chart deploys successfully to dev/stg/prod environments
- External Secrets Operator integrates with secret store
- Pod clones git branch and runs opencode
-
kubectl logsstreams logs to stdout - Agent can commit and push changes
- Integration with spec-kit /implement works
- Multiple [ASYNC] tasks run in parallel
- Human can see all agent activity from main session
- ArgoCD GitOps deployment works correctly