## Why Publish chart 0.1.7 after the feature PR merged from a fork and therefore intentionally skipped the internal-branch auto-tag job. ## What - Trigger the `chart-release/0.1.7` release lane - Update the quickstart example to reference chart 0.1.7 ## Risk Assessment Low — the chart implementation is already merged and tested; this PR creates its immutable release tag and OCI artifact. ## References - Chart implementation: https://github.com/block/buzz/pull/3322 - `helm unittest` 0.8.2: 43/43 tests passed - Local pre-push checks passed Generated with Amp Signed-off-by: David Grochowski <dgrochowski@squareup.com> Co-authored-by: Amp <amp@ampcode.com>
Buzz Helm Chart
Buzz is a Nostr-based messaging platform for human–agent collaboration: a single relay binary serving WebSocket + REST + web UI, backed by PostgreSQL, Redis, and S3-compatible object storage.
This chart has two operating profiles selected by values:
| Profile | When | What you get |
|---|---|---|
| Production (default) | Self-hosted multi-tenant, regulated, or GitOps-managed | External managed Postgres/Redis/S3, secrets.existingSecret:, no chart-side autogen, HA-capable (replicaCount ≥ 2) |
| Quickstart (eval) | Eval, single-node, one-off demo | In-cluster Postgres + Redis + MinIO subcharts/Deployments, chart auto-generates relay + service secrets, single replica |
Quickstart (eval only)
helm install buzz oci://ghcr.io/block/buzz/charts/buzz --version 0.1.7 \
--create-namespace --namespace buzz \
--set quickstart=true \
--set postgresql.enabled=true \
--set redis.enabled=true \
--set minio.enabled=true \
--set relayUrl=wss://buzz.example.com \
--set ownerPubkey=<64-char-hex-pubkey>
This brings up everything in-cluster — Postgres, Redis, and MinIO (with
its bucket created by a post-install Job) — and composes the relay's
BUZZ_S3_ENDPOINT plus autogenerated credentials automatically. No external services required. The quickstart=true flag is an
intent marker surfaced in NOTES.txt; the bundled services are opted in via the
four *.enabled flags above (see ci/quickstart-values.yaml for the exact set
CI installs). Eval-only: every bundled service is a single replica with no HA.
Production (GitOps)
The chart is designed for ArgoCD and Flux. Both render charts with helm template, in which mode Helm's lookup function returns empty — any chart-side randAlphaNum call would regenerate secrets on every sync. The chart-managed Secret path is only safe for helm install / helm upgrade.
Production deploys MUST use secrets.existingSecret:. The Secret is consumed for any keys present and ignored for keys missing — extras are harmless.
See:
examples/argocd-app.yaml— ArgoCD Applicationexamples/flux-helmrelease.yaml— Flux HelmRelease v2examples/secret-sample.yaml— Secret schema
Required inputs
| Key | What | When required |
|---|---|---|
relayUrl |
Public wss:// URL clients connect to |
Always |
ownerPubkey |
64-char lowercase hex Nostr pubkey of the relay operator | When relay.requireRelayMembership=true (default) |
secrets.existingSecret |
Name of pre-created Secret | Production / GitOps |
externalPostgresql.url / externalRedis.url / s3.endpoint |
External service URLs | Production — when the matching bundled service is disabled (the default) |
The chart fails at helm install / helm template time with a clear message if any of these are missing or malformed (see templates/_validate.tpl).
Relay Pod extensions
The chart exposes narrow extension points for init containers, volumes, relay
volume mounts, and image command/argument overrides. extraManifests creates
independent Kubernetes resources but cannot modify the chart-managed relay
Deployment. These extension values insert fields into that Deployment, avoiding
duplication of its environment, probes, security context, secrets, and
chart-owned volumes.
For example, an init container can copy a wrapper binary into a shared volume and make that wrapper the relay entrypoint:
extraInitContainers:
- name: install-wrapper
image: example.com/wrapper-init:v1
args: [/opt/wrapper/wrapper]
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
resources:
requests:
cpu: 10m
memory: 16Mi
volumeMounts:
- name: wrapper
mountPath: /opt/wrapper
extraVolumes:
- name: wrapper
emptyDir: {}
relay:
command: [/opt/wrapper/wrapper]
args: [/usr/local/bin/buzz-relay]
extraVolumeMounts:
- name: wrapper
mountPath: /opt/wrapper
These values are raw Kubernetes fragments rendered with toYaml, not tpl.
The chart does not validate cross-field relationships: extension names must not
collide with chart-owned containers or volumes, mounts must reference existing
volumes, and each init container must define an appropriate security context
and resources. Empty relay.command and relay.args arrays preserve the image
defaults; non-empty values override its entrypoint and arguments respectively.
Device pairing relay
The chart can run Buzz's stateless pairing WebSocket relay as an independent Deployment and Service using the same image as the main relay:
pairingRelay:
enabled: true
url: wss://pairing.example.com
pairingRelay.url is advertised in the main relay's NIP-11 document so Buzz
clients connect directly to the dedicated endpoint. The chart does not create
an Ingress or HTTPRoute for the pairing Service; route the public hostname to
<release>-buzz-pairing:5000 with your platform's ingress configuration.
HA (production)
replicaCount > 1 hard-requires Redis:
- Redis (
redis.enabled=true,externalRedis.url, orREDIS_URLinexistingSecret) — forbuzz-pubsubfan-out
It does not require ReadWriteMany git storage. Git ref/object state is object-store-backed (each request hydrates an ephemeral repo from S3-compatible storage; writer serialization is the object-store pointer CAS — see docs/git-on-object-storage.md), and repo-name uniqueness lives in Postgres. Each replica can use its own ReadWriteOnce volume; no shared filesystem is needed.
The chart template-fails if the Redis invariant is broken at replicaCount > 1. No silent degradation.
Relay autoscaling
The optional HPA scales the relay on the larger recommendation from CPU or average active WebSockets per pod:
autoscaling:
enabled: true
minReplicas: 5
maxReplicas: 15
targetCPUUtilizationPercentage: 65
websocketMetricEnabled: true
websocketMetricName: buzz_ws_connections_active
targetWebsocketConnections: 5000
CPU scaling requires Kubernetes Metrics Server. Set websocketMetricEnabled: false
for a CPU-only HPA. WebSocket scaling additionally requires a custom-metrics
adapter (for example Prometheus Adapter) configured to expose the relay's
buzz_ws_connections_active gauge as a pod metric with the name in
websocketMetricName. The chart creates the HPA but deliberately does not
install or configure a cluster-wide metrics adapter. Scale-down is gradual by
default so long-lived WebSocket connections have time to drain.
Upgrades
Schema migrations are embedded in the relay binary via sqlx::migrate! and run at startup, gated by BUZZ_AUTO_MIGRATE (default true). Multiple replicas race-safely behind a Postgres advisory lock. helm upgrade is the entire upgrade procedure.
If you prefer decoupling migrations from serving, set migrate.autoMigrate=false. In that mode the chart does not run migrations for you — you own running buzz-admin migrate (separate Pod / one-shot Job) against the database before every helm install / helm upgrade. Readiness probes only verify DB connectivity, not schema freshness, so a pod will appear healthy against an unmigrated schema and fail under load. A pre-upgrade Helm Job for this is on the chart roadmap; the values knob migrate.preUpgradeJob.enabled is reserved.
Backups
Save these. Losing any of them is data loss. See NOTES.txt printed by helm install for the live list:
BUZZ_RELAY_PRIVATE_KEY— relay identity. Rotating it = new identity (federation peers will not recognize the relay).- PostgreSQL database — the canonical event store.
- S3 bucket — media blobs (chart default bucket:
buzz-media). - Git PVC — repo on-disk state served by the relay's git endpoint.
- Owner private key — held by the operator, not by this chart. Restore by re-installing with the same
ownerPubkey.
Honest limitations (v1)
- Bundled MinIO is eval-only. The quickstart profile runs an in-cluster
MinIO (single replica, no HA,
lookup-autogenerated credentials) so the relay starts with zero external object storage. Production leavesminio.enabledoff and pointss3.endpoint(orBUZZ_S3_*inexistingSecret) at managed S3-compatible storage. The bundled Deployment is not GitOps-safe and is not intended for production traffic. - Minimal-mode is not yet supported. The relay's
BUZZ_PUBSUB=local/ filesystem media paths are upstream work in progress — even quickstart currently stands up real Redis and S3 rather than the relay's single-node fallbacks. (Full-text search already runs in Postgres, so no separate search service is provisioned.) - Cosign signing of the published chart is a follow-up (the relay image is
attested via
actions/attest-build-provenance; the chart is not yet). The chart itself is published to GHCR — see Releasing.
Releasing
The chart is published to GHCR as an OCI artifact at
oci://ghcr.io/block/buzz/charts/buzz by the helm chart workflow
(.github/workflows/helm-chart.yml), versioned independently of the desktop app
and the relay image via its own chart-v* tags. Every PR/main push still
lints, unit-tests, and render-checks the chart; only a chart-v* tag publishes,
so an in-progress main can never overwrite a released version.
To cut a release, push a chart-release/<version> branch whose <version>
matches Chart.yaml's version; merging it auto-tags chart-v<version> and
dispatches the publish job (same lane machinery as the desktop and relay
releases — see .github/workflows/auto-tag-on-release-pr-merge.yml). The publish
job fails loudly if the tag version and Chart.yaml version disagree.
Development
# Render every fixture
for f in ci/*-values.yaml tests/fixtures/*-values.yaml; do
helm template buzz . -f "$f" >/dev/null && echo "ok: $f"
done
# Unit tests
helm plugin install https://github.com/helm-unittest/helm-unittest
helm unittest .
# Lint
helm dependency build .
ct lint --config ../../../ct.yaml --charts .