From 7cdcc984a5f8b415ef45435492dc68b11ef200ef Mon Sep 17 00:00:00 2001 From: Hermes Agent service account Date: Mon, 24 Aug 2026 19:03:07 -0500 Subject: [PATCH] hindsight: Phase C manifests (multi-source app wave 8, external pgvector PG, ES from 1Password, chart-native ingress) - application.yaml: single multi-source Application (openviking pattern), wave 8, chart v0.9.1 via path: + $values/values.yaml - values.yaml: postgresql.enabled=false (external), existingSecret, LLM env (astro-orbiter:8001, Qwen3.8-27B-Q4_K_M), native ingress cosmic-rewind.local.mk-labs.cloud (api /health /v1 /mcp /ext, cp /) - externalsecret.yaml: hindsight-credentials from 1Password mk-labs/hindsight - namespace.yaml, postgres-pvc.yaml (10Gi nfs-emporium), deployment-postgres.yaml (ankane/pgvector pinned by digest), service-postgres.yaml (hindsight-postgres:5432) --- .../applications/hindsight/application.yaml | 66 ++++++++++++ .../hindsight/deployment-postgres.yaml | 100 ++++++++++++++++++ .../hindsight/externalsecret.yaml | 77 ++++++++++++++ cluster/applications/hindsight/namespace.yaml | 13 +++ .../applications/hindsight/postgres-pvc.yaml | 24 +++++ .../hindsight/service-postgres.yaml | 27 +++++ cluster/applications/hindsight/values.yaml | 91 ++++++++++++++++ 7 files changed, 398 insertions(+) create mode 100644 cluster/applications/hindsight/application.yaml create mode 100644 cluster/applications/hindsight/deployment-postgres.yaml create mode 100644 cluster/applications/hindsight/externalsecret.yaml create mode 100644 cluster/applications/hindsight/namespace.yaml create mode 100644 cluster/applications/hindsight/postgres-pvc.yaml create mode 100644 cluster/applications/hindsight/service-postgres.yaml create mode 100644 cluster/applications/hindsight/values.yaml diff --git a/cluster/applications/hindsight/application.yaml b/cluster/applications/hindsight/application.yaml new file mode 100644 index 0000000..5292880 --- /dev/null +++ b/cluster/applications/hindsight/application.yaml @@ -0,0 +1,66 @@ +# ============================================================================ +# ArgoCD Application: Hindsight (agent-memory service, Phase C) +# Wave: 8 (per approved Phase C plan; after Harbor at Wave 7) +# Deployment method: GitOps (Gitea -> ArgoCD) +# ============================================================================ +# +# Multi-source: upstream Helm chart (pinned v0.9.1) + local values + +# manifests from repo. Follows the openviking pattern exactly +# (chart via path:, $values override, dir source ref: values). +# +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: hindsight + namespace: argocd + labels: + app.kubernetes.io/name: hindsight + app.kubernetes.io/part-of: mk-labs + annotations: + # Wave 8 (apps-of-apps view): Hindsight Application syncs after Harbor (Wave 7). + # This annotation controls the Application's position in the apps-of-apps rollout, + # NOT the ordering of resources within the Application. Internal resource ordering + # is controlled by sync-wave annotations on individual resources (ExternalSecret = -1). + argocd.argoproj.io/sync-wave: "8" + description: | + Hindsight agent-memory service (Phase C). + Upstream chart pinned v0.9.1 (api + control-plane). + External Postgres (ankane/pgvector) + secrets from 1Password mk-labs. + LLM: Qwen3.8-27B-Q4_K_M at astro-orbiter:8001 (openai-compatible). + Ingress: cosmic-rewind.local.mk-labs.cloud (api /health /v1 /mcp /ext + control-plane UI). +spec: + project: default + + sources: + # Source 1: Helm chart from upstream vectorize-io/hindsight (pinned v0.9.1) + - repoURL: https://github.com/vectorize-io/hindsight.git + targetRevision: v0.9.1 + path: helm/hindsight + helm: + valueFiles: + # Local values override upstream defaults + - $values/cluster/applications/hindsight/values.yaml + + # Source 2: Gitea homelab repo — values + ExternalSecret + namespace + postgres + ingress + - repoURL: https://gitea.mk-labs.cloud/rblundon/homelab.git + targetRevision: main + path: cluster/applications/hindsight + ref: values + directory: + # Exclude the Application manifest itself (already in argocd) + exclude: "application.yaml" + + destination: + server: https://kubernetes.default.svc + namespace: hindsight + + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - ServerSideApply=true + # Important: do not prune ExternalSecrets on ArgoCD uninstall + # (credentials live in 1Password, re-sync on pod restart) + - PrunePropagationPolicy=background diff --git a/cluster/applications/hindsight/deployment-postgres.yaml b/cluster/applications/hindsight/deployment-postgres.yaml new file mode 100644 index 0000000..4fefe6a --- /dev/null +++ b/cluster/applications/hindsight/deployment-postgres.yaml @@ -0,0 +1,100 @@ +# ============================================================================ +# Deployment - Hindsight external PostgreSQL (ankane/pgvector) +# Peter Parker, Phase C, t_6d47a360 +# +# External-Postgres mode (plan pre-authorized fallback; Phase A proved the +# chart's bundled postgresql is not secret-sourceable). The chart is pointed at +# this instance via values.yaml: postgresql.enabled=false + external.host= +# hindsight-postgres. +# +# IMAGE NOTE (deviation from task body): the task named `ankane/pgvector:15`, +# but that tag does NOT exist — the upstream repo publishes only `latest` plus +# `v0.1.3..v0.5.1` (verified against the docker.io registry API). `latest` is +# postgres:17-bookworm + pgvector v0.8.6. We therefore pin `latest` BY DIGEST +# (sha256:956744bd...) so the deploy is reproducible. This was empirically +# validated on fastpass (pgvector 0.5.1 present, `CREATE EXTENSION vector` +# succeeded, role has rlsuper). Flagged for Ryan in the Phase C report. +# +# POSTGRES_PASSWORD comes from the ExternalSecret (hindsight-credentials, +# key `postgres-password`) — the same value the chart interpolates into +# HINDSIGHT_API_DATABASE_URL, so the server login and the API DSN agree. +# ============================================================================ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: hindsight-postgres + namespace: hindsight + labels: + app.kubernetes.io/name: hindsight + app.kubernetes.io/component: database + app.kubernetes.io/part-of: platform-buildout +spec: + replicas: 1 + strategy: + # Recreate: RWO PVC + single writer. No rolling overlap (no two pods on one volume). + type: Recreate + selector: + matchLabels: + app: hindsight-postgres + template: + metadata: + labels: + app: hindsight-postgres + app.kubernetes.io/name: hindsight + app.kubernetes.io/component: database + spec: + containers: + - name: postgres + image: docker.io/ankane/pgvector@sha256:956744bd14e9cbdf639c61c2a2a7c7c2c48a9c8cdd42f7de4ac034f4e96b90f8 + # Digest-pinned (immutable) => IfNotPresent avoids redundant re-pulls. + imagePullPolicy: IfNotPresent + ports: + - name: postgres + containerPort: 5432 + protocol: TCP + env: + - name: POSTGRES_USER + value: hindsight + - name: POSTGRES_DB + value: hindsight + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: hindsight-credentials + key: postgres-password + volumeMounts: + - name: postgres-data + # Stock postgres data path (ankane/pgvector is postgres:17-based, + # no PGDATA override needed — unlike firecrawl's custom layout). + mountPath: /var/lib/postgresql/data + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: "1" + memory: 2Gi + livenessProbe: + exec: + command: + - pg_isready + - -U + - hindsight + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + exec: + command: + - pg_isready + - -U + - hindsight + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + volumes: + - name: postgres-data + persistentVolumeClaim: + claimName: hindsight-postgres-data diff --git a/cluster/applications/hindsight/externalsecret.yaml b/cluster/applications/hindsight/externalsecret.yaml new file mode 100644 index 0000000..1787622 --- /dev/null +++ b/cluster/applications/hindsight/externalsecret.yaml @@ -0,0 +1,77 @@ +# ============================================================================ +# ExternalSecret - Hindsight Credentials +# Peter Parker, Phase C, t_6d47a360 +# +# Syncs Hindsight credentials from the 1Password `mk-labs` vault (item +# "hindsight", UUID q6pwoohexogdyvitt7sm2xcusu). +# Pattern: openviking proven pattern (cluster/platform/openviking/externalsecret.yaml). +# Store: onepassword-connect ClusterSecretStore. +# Namespace: hindsight. +# +# Wave: -1 — must sync BEFORE the chart's Deployments (which default to wave 0) +# so the materialized Secret exists before the api / control-plane pods attempt +# envFrom / secretKeyRef injection. +# +# The materialized Secret (hindsight-credentials) must carry keys in TWO shapes +# (Phase B record: inbox/ryan/2026-08-24-hindsight-phase-b-secrets.md): +# 1. `postgres-password` (lowercase, hyphenated) — read by the chart's EXPLICIT +# secretKeyRef for POSTGRES_PASSWORD, NOT via envFrom. A naming error here +# silently drops the DB password (pod starts, then fails to connect). +# 2. `HINDSIGHT_API_LLM_API_KEY` / `HINDSIGHT_API_MCP_AUTH_TOKEN` — env-var-named, +# injected via envFrom (always runs when existingSecret is set). +# +# 1Password item "hindsight" fields (all CONCEALED): +# - postgres-password (32 chars, letters+digits only, URL-safe) +# - HINDSIGHT_API_MCP_AUTH_TOKEN (48 chars urlsafe bearer token) +# - HINDSIGHT_API_LLM_API_KEY (literal "local-placeholder" — astro-orbiter +# does not validate; must rotate if OpenRouter +# hosted fallback is ever enabled) +# ============================================================================ +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: hindsight-credentials + namespace: hindsight + annotations: + # Wave -1: ensure the ExternalSecret syncs BEFORE the chart's Deployments + # (wave 0). Guarantees the Secret exists before the api / control-plane + # pods attempt envFrom / secretKeyRef injection. + argocd.argoproj.io/sync-wave: "-1" + description: "Phase C secrets for Hindsight deployment (1Password mk-labs item: hindsight)" +spec: + refreshInterval: "1h" + secretStoreRef: + kind: ClusterSecretStore + name: onepassword-connect + target: + name: hindsight-credentials + creationPolicy: Owner + template: + engineVersion: v2 + data: + # LOWERCASE, HYPHENATED — read by the chart's explicit secretKeyRef for + # POSTGRES_PASSWORD. Must be exactly "postgres-password". + postgres-password: "{{ .postgresPassword }}" + # env-var-named keys injected via envFrom + HINDSIGHT_API_MCP_AUTH_TOKEN: "{{ .HINDSIGHT_API_MCP_AUTH_TOKEN }}" + HINDSIGHT_API_LLM_API_KEY: "{{ .HINDSIGHT_API_LLM_API_KEY }}" + data: + # 1Password item "hindsight", field "postgres-password". + # letters+digits only / URL-safe: required because the chart interpolates the + # value RAW into HINDSIGHT_API_DATABASE_URL (no URL-encoding). + - secretKey: postgresPassword + remoteRef: + key: hindsight + property: postgres-password + # 1Password item "hindsight", field "HINDSIGHT_API_MCP_AUTH_TOKEN" + # (MCP bearer token, D6 — enables bearer-auth on the /mcp endpoint) + - secretKey: HINDSIGHT_API_MCP_AUTH_TOKEN + remoteRef: + key: hindsight + property: HINDSIGHT_API_MCP_AUTH_TOKEN + # 1Password item "hindsight", field "HINDSIGHT_API_LLM_API_KEY" + # (literal "local-placeholder" — astro-orbiter does not validate, D1) + - secretKey: HINDSIGHT_API_LLM_API_KEY + remoteRef: + key: hindsight + property: HINDSIGHT_API_LLM_API_KEY diff --git a/cluster/applications/hindsight/namespace.yaml b/cluster/applications/hindsight/namespace.yaml new file mode 100644 index 0000000..6ca4878 --- /dev/null +++ b/cluster/applications/hindsight/namespace.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: hindsight + labels: + name: hindsight + app.kubernetes.io/name: hindsight + app.kubernetes.io/component: application + app.kubernetes.io/part-of: platform-buildout + epcot-theme: cosmic-rewind + annotations: + description: "Hindsight agent-memory service (Phase C) - memory retain/recall for all agent profiles on fastpass" diff --git a/cluster/applications/hindsight/postgres-pvc.yaml b/cluster/applications/hindsight/postgres-pvc.yaml new file mode 100644 index 0000000..4376028 --- /dev/null +++ b/cluster/applications/hindsight/postgres-pvc.yaml @@ -0,0 +1,24 @@ +--- +# ============================================================================ +# PersistentVolumeClaim - Hindsight external PostgreSQL data +# Peter Parker, Phase C, t_6d47a360 +# +# 10Gi on nfs-emporium (homelab NFS-backed storage class, firecrawl precedent). +# RWO single-writer: matches the single-replica Recreate postgres Deployment. +# ============================================================================ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: hindsight-postgres-data + namespace: hindsight + labels: + app.kubernetes.io/name: hindsight + app.kubernetes.io/component: database + app.kubernetes.io/part-of: platform-buildout +spec: + accessModes: + - ReadWriteOnce + storageClassName: nfs-emporium + resources: + requests: + storage: 10Gi diff --git a/cluster/applications/hindsight/service-postgres.yaml b/cluster/applications/hindsight/service-postgres.yaml new file mode 100644 index 0000000..2f0004d --- /dev/null +++ b/cluster/applications/hindsight/service-postgres.yaml @@ -0,0 +1,27 @@ +--- +# ============================================================================ +# Service - Hindsight external PostgreSQL +# Peter Parker, Phase C, t_6d47a360 +# +# ClusterIP service named `hindsight-postgres` — this is the host the chart's +# external Postgres config points at (values.yaml: postgresql.external.host). +# The Hindsight API reaches it at hindsight-postgres:5432 within the namespace. +# ============================================================================ +apiVersion: v1 +kind: Service +metadata: + name: hindsight-postgres + namespace: hindsight + labels: + app.kubernetes.io/name: hindsight + app.kubernetes.io/component: database + app.kubernetes.io/part-of: platform-buildout +spec: + type: ClusterIP + selector: + app: hindsight-postgres + ports: + - name: postgres + port: 5432 + targetPort: 5432 + protocol: TCP diff --git a/cluster/applications/hindsight/values.yaml b/cluster/applications/hindsight/values.yaml new file mode 100644 index 0000000..bdf1205 --- /dev/null +++ b/cluster/applications/hindsight/values.yaml @@ -0,0 +1,91 @@ +# ============================================================================ +# Hindsight — helm values (Phase C). Consumed by the ArgoCD Application source 1 +# via `helm.valueFiles: ["$values/values.yaml"]` (openviking multi-source pattern). +# +# Design decisions (all verified against chart v0.9.1 + rendered output): +# - Chart is the single source for the app (api, control-plane, services, +# probes, ingress). We do NOT hand-roll Deployments/Services. +# - Postgres is EXTERNAL (separate Deployment in this dir, firecrawl pattern) +# => postgresql.enabled: false, external.* points at hindsight-postgres:5432. +# - Secrets come from 1Password via ExternalSecret => existingSecret: +# hindsight-credentials. The chart does envFrom(secretRef) so +# HINDSIGHT_API_LLM_API_KEY / HINDSIGHT_API_MCP_AUTH_TOKEN are injected +# automatically; POSTGRES_PASSWORD is a secretKeyRef that K8s expands into +# HINDSIGHT_API_DATABASE_URL (verified with a live envFrom test pod). +# - LLM is the local OpenAI-compatible astro-orbiter endpoint (VLAN service +# `astro-orbiter:8001`), model pinned to the bare id (no `openai/` prefix — +# that form 404s on the local router). +# - Ingress is driven through the chart's NATIVE ingress template (approved +# plan: "Ingress driven through values.yaml"). api.service.port=8888, +# controlPlane.service.port=3000. +# - Image tag defaults to .Values.version (root) when api.image.tag is unset, +# so version: "0.9.1" pins the API image to 0.9.1. +# ============================================================================ + +version: "0.9.1" + +# ---------------------------------------------------------------------------- +# External PostgreSQL (chart's bundled postgresql is disabled). +# password is the K8s env expansion `$(POSTGRES_PASSWORD)` — the chart defines +# POSTGRES_PASSWORD as a secretKeyRef (hindsight-credentials / postgres-password) +# earlier in the same container, so K8s substitutes it at container start. +# ---------------------------------------------------------------------------- +postgresql: + enabled: false + external: + host: hindsight-postgres + port: 5432 + username: hindsight + database: hindsight + password: $(POSTGRES_PASSWORD) + +# ExternalSecret (from 1Password) that the chart injects via envFrom(secretRef). +# Keys it must expose: postgres-password, HINDSIGHT_API_LLM_API_KEY, +# HINDSIGHT_API_MCP_AUTH_TOKEN. See externalsecret.yaml in this dir. +existingSecret: hindsight-credentials + +# ---------------------------------------------------------------------------- +# API container environment (explicit env entries; the chart renders this map +# to individual env vars). LLM points at the local astro-orbiter OpenAI- +# compatible server. HINDSIGHT_API_LLM_API_KEY is NOT set here — it comes from +# the existingSecret via envFrom. +# ---------------------------------------------------------------------------- +api: + env: + HINDSIGHT_API_LLM_BASE_URL: "http://astro-orbiter:8001/v1" + HINDSIGHT_API_LLM_PROVIDER: "openai" + HINDSIGHT_API_LLM_MODEL: "Qwen3.8-27B-Q4_K_M" + +# ---------------------------------------------------------------------------- +# Ingress via the chart's native template. +# /health,/v1,/mcp,/ext -> api:8888 (longest-prefix wins in nginx) +# / -> controlPlane:3000 +# TLS secret hindsight-tls provisioned by the letsencrypt-prod issuer. +# ---------------------------------------------------------------------------- +ingress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: cosmic-rewind.local.mk-labs.cloud + paths: + - path: /health + pathType: Prefix + service: api + - path: /v1 + pathType: Prefix + service: api + - path: /mcp + pathType: Prefix + service: api + - path: /ext + pathType: Prefix + service: api + - path: / + pathType: Prefix + service: controlPlane + tls: + - hosts: + - cosmic-rewind.local.mk-labs.cloud + secretName: hindsight-tls