Skip to content

API Reference

Reference for the helm/agent-manager umbrella chart: structure, values conventions, subchart dependencies, and the migrator Job hook pattern.

helm/agent-manager/
Chart.yaml # apiVersion, name, version, appVersion, dependencies[]
Chart.lock # pinned dependency digests; committed; regenerated by helm dep update
values.yaml # canonical defaults — every key present here
values-dev.yaml # dev overlay (Kind cluster)
values-prod.yaml # production overlay
charts/ # vendored local subcharts (tarballs + extracted)
templates/ # umbrella-owned Kubernetes objects
_helpers.tpl
*-app-db-url-secret.yaml # one per service; cross-service Secret injection

Each key at the root of values.yaml corresponds to either a shared infrastructure component or a service subchart. The umbrella owns the global block; everything else is passed through to the matching subchart under its own scope.

global:
namespace: paper-board # Kubernetes namespace for all objects
domain: paperboard.app # external domain; used by Ingress (Phase 7+)
imageRegistry: ghcr.io/paper-board
imagePullPolicy: IfNotPresent

Every service subchart block follows this shape:

<svc>:
enabled: false # feature-flag; default false until the phase activates it
secrets:
create: true # umbrella creates Secrets in dev; false in prod (ESO owns them)
<key>: "" # placeholder; real values supplied via --set or ESO
server:
config:
env: dev # propagated as SERVER_ENV env var inside the container
networkPolicy:
enabled: true # NetworkPolicy default-deny per ADR-0005
KeyTypeDefaultNotes
postgres.enabledbooltrueDisable only on clusters with an external Postgres
pgbouncerobjectalways onNo enabled toggle — mandatory Phases 1-4 (see Chart.yaml)
cert-manager.enabledboolfalsePhase 5+ (mTLS via cert-manager)
redis.enabledboolfalsePhase 1.5+ (event bus)

postgres.appUsers lists one entry per service. Each entry creates a Postgres role with USAGE on its own schema and ALL PRIVILEGES on its own tables. Passwords are injected at init time from environment variables; they are never committed.

postgres:
appUsers:
- name: identity_app
schema: identity
- name: agents_app
schema: agents
- name: billing_app
schema: billing
- name: platform_app
schema: platform

Vendored directly in this repo. Managed by the infra team.

ChartVersionConditionNotes
postgres0.2.0postgres.enabledSingle-cluster Postgres with init-db
pgbouncer0.1.0noneAlways rendered; transaction pool mode
cert-manager0.1.0cert-manager.enabledPhase 5+ only
redis0.1.0redis.enabledPhase 1.5+

OCI subcharts (oci://ghcr.io/paper-board/helm)

Section titled “OCI subcharts (oci://ghcr.io/paper-board/helm)”

Each service repo owns and publishes its chart. The umbrella declares the pinned version; helm dep update pulls the OCI artifact and writes the digest to Chart.lock.

ChartCurrent versionCondition
identity0.2.1identity.enabled
agents0.2.3agents.enabled

Future services (runtime, compute, billing, platform) follow the same pattern: the service repo tags a new OCI chart version, the umbrella bumps the pinned version in Chart.yaml, and helm dep update regenerates Chart.lock.

Every service with a schema ships a cmd/migrator binary (a ~30-line shim over paper-board/sdk/migrator). The service’s Helm chart includes a Kubernetes Job annotated as a Helm pre-install / pre-upgrade hook. The umbrella triggers this Job automatically on every helm upgrade --install.

# Inside the service subchart templates/migrator-job.yaml
metadata:
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded

hook-delete-policy: before-hook-creation,hook-succeeded ensures the Job is cleaned up after a successful run and does not block the next deploy.

The migrator Job must connect to Postgres directly (port 5432), not through PgBouncer (port 6432). PgBouncer’s transaction pool mode breaks the advisory-lock session required by golang-migrate.

env:
- name: MIGRATION_DB_URL # port 5432 — direct Postgres
valueFrom:
secretKeyRef:
name: <svc>-migration-db-url
key: url

The application Deployment uses a separate Secret:

env:
- name: DATABASE_URL # port 6432 — PgBouncer
valueFrom:
secretKeyRef:
name: <svc>-app-db-url
key: url

Never mount MIGRATION_DB_URL into the application container, and never use DATABASE_URL in the migrator Job.

Each service uses a distinct advisory lock ID, allowing parallel migrations across services without contention:

ServiceLock ID
identity1
billing2
agents3
platform4

The migrator binary (cobra CLI) supports:

SubcommandEffect
upApply all pending migrations
up --dry-runPrint pending SQL without executing
down NRoll back N migrations
force VERSIONForce-set the migration version (recovery only)
versionPrint current applied version
dropDrop all tables — requires MIGRATOR_ENV=dev