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)
This commit is contained in:
Hermes Agent service account
2026-08-24 19:03:07 -05:00
parent e301770adc
commit 7cdcc984a5
7 changed files with 398 additions and 0 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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