# services/hermes/suite-planner-deployment.yaml apiVersion: v1 kind: ServiceAccount metadata: name: hermes-suite-planner namespace: hermes automountServiceAccountToken: false --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: hermes-suite-metadata namespace: hermes annotations: # Preserve titan-22's original ledger until the offline node can be recovered. kustomize.toolkit.fluxcd.io/prune: disabled spec: accessModes: [ReadWriteOnce] storageClassName: local-path resources: requests: storage: 1Gi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: hermes-suite-metadata-recovery namespace: hermes spec: accessModes: [ReadWriteOnce] storageClassName: local-path resources: requests: storage: 1Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: hermes-suite-planner namespace: hermes spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: hermes-suite-planner template: metadata: labels: app: hermes-suite-planner annotations: fluentbit.io/exclude: "true" ai.bstein.dev/config-rev: suite-v6-adaptive-v11-node-recovery-20260930 ai.bstein.dev/metadata-store: titan24-recovery-20260930 vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/agent-pre-populate-only: "true" vault.hashicorp.com/agent-init-first: "true" vault.hashicorp.com/agent-run-as-user: "10000" vault.hashicorp.com/agent-run-as-group: "10000" vault.hashicorp.com/agent-service-account-token-volume-name: vault-auth vault.hashicorp.com/role: hermes-suite-planner vault.hashicorp.com/agent-inject-containers: planner vault.hashicorp.com/agent-inject-secret-token: kv/data/atlas/hermes/suite-planning-api vault.hashicorp.com/agent-inject-template-token: | {{- with secret "kv/data/atlas/hermes/suite-planning-api" -}} {{ .Data.data.token }} {{- end -}} vault.hashicorp.com/agent-inject-secret-synthetic-token: kv/data/atlas/hermes/suite-planning-api vault.hashicorp.com/agent-inject-template-synthetic-token: | {{- with secret "kv/data/atlas/hermes/suite-planning-api" -}} {{ .Data.data.synthetic_token }} {{- end -}} vault.hashicorp.com/agent-inject-secret-operational-token: kv/data/atlas/hermes/suite-planning-api vault.hashicorp.com/agent-inject-template-operational-token: | {{- with secret "kv/data/atlas/hermes/suite-planning-api" -}} {{ .Data.data.operational_token }} {{- end -}} vault.hashicorp.com/agent-inject-secret-local-token: kv/data/atlas/hermes/model-gate-lan-api vault.hashicorp.com/agent-inject-template-local-token: | {{- with secret "kv/data/atlas/hermes/model-gate-lan-api" -}} {{ .Data.data.token }} {{- end -}} vault.hashicorp.com/agent-inject-secret-claude-token: kv/data/atlas/hermes/agent-tokens vault.hashicorp.com/agent-inject-template-claude-token: | {{- with secret "kv/data/atlas/hermes/agent-tokens" -}} {{ .Data.data.claude_oauth_token }} {{- end -}} vault.hashicorp.com/agent-inject-perms-token: "0400" vault.hashicorp.com/agent-inject-perms-synthetic-token: "0400" vault.hashicorp.com/agent-inject-perms-operational-token: "0400" vault.hashicorp.com/agent-inject-perms-local-token: "0400" vault.hashicorp.com/agent-inject-perms-claude-token: "0400" spec: serviceAccountName: hermes-suite-planner automountServiceAccountToken: false enableServiceLinks: false terminationGracePeriodSeconds: 15 # The pinned CLI needs amd64. Titan-22 is offline; no GPU is requested here. nodeSelector: kubernetes.io/hostname: titan-24 securityContext: runAsNonRoot: true runAsUser: 10000 runAsGroup: 10000 fsGroup: 10000 fsGroupChangePolicy: OnRootMismatch seccompProfile: type: RuntimeDefault initContainers: - name: stage-cli image: python:3.13-slim@sha256:9662417aace5ae7b8e2609cce472b72a8958e134ba372808abe9cc1a0c0125e6 command: [python, -c] args: - | import hashlib,pathlib,urllib.request target=pathlib.Path('/opt/cli/claude') url='https://downloads.claude.ai/claude-code-releases/2.1.285/linux-x64/claude' digest=hashlib.sha256() size=0 with urllib.request.urlopen(url, timeout=120) as source, target.open('wb') as output: while data:=source.read(1048576): size+=len(data) if size > 240327864: raise RuntimeError('CLI artifact exceeds pinned size') digest.update(data) output.write(data) if size != 240327864 or digest.hexdigest() != '33dad1ec615a2e08cc78b494f05c110e49916de2c79d78ec8799ebf46b233d29': raise RuntimeError('CLI artifact verification failed') target.chmod(0o555) securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: [ALL] volumeMounts: - {name: cli, mountPath: /opt/cli} resources: requests: {cpu: 25m, memory: 256Mi} limits: {cpu: "1", memory: 1Gi} containers: - name: planner image: python:3.13-slim@sha256:9662417aace5ae7b8e2609cce472b72a8958e134ba372808abe9cc1a0c0125e6 command: [python, /opt/planner/suite_api.py] env: - {name: PYTHONDONTWRITEBYTECODE, value: "1"} - {name: PYTHONUNBUFFERED, value: "1"} # User approved generalized CASE records on this Claude account, 2026-09-29. - {name: PLANNING_GENERALIZED_CLAUDE_APPROVED, value: "true"} - {name: PLANNING_CLAUDE_SHA256, value: 33dad1ec615a2e08cc78b494f05c110e49916de2c79d78ec8799ebf46b233d29} - {name: PLANNING_CLAUDE_MODEL, value: claude-opus-5-5} ports: - {name: http, containerPort: 9000} - {name: decision, containerPort: 9001} readinessProbe: httpGet: {path: /healthz, port: decision} livenessProbe: httpGet: {path: /healthz, port: decision} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: [ALL] volumeMounts: - {name: scripts, mountPath: /opt/planner, readOnly: true} - {name: cli, mountPath: /opt/cli, readOnly: true} - {name: jobs, mountPath: /jobs} - {name: tmp, mountPath: /tmp} - {name: state, mountPath: /state} resources: requests: {cpu: 100m, memory: 512Mi} limits: {cpu: "2", memory: 2Gi} volumes: - name: scripts configMap: name: hermes-suite-planner - name: cli emptyDir: {medium: Memory, sizeLimit: 512Mi} - name: jobs emptyDir: {medium: Memory, sizeLimit: 512Mi} - name: tmp emptyDir: {medium: Memory, sizeLimit: 64Mi} - name: state persistentVolumeClaim: claimName: hermes-suite-metadata-recovery - name: vault-auth projected: sources: - serviceAccountToken: path: token expirationSeconds: 600 --- apiVersion: v1 kind: Service metadata: name: hermes-suite-planner namespace: hermes spec: selector: app: hermes-suite-planner ports: - {name: http, port: 9000, targetPort: http} - {name: decision, port: 9001, targetPort: decision}