Day-2 operations
How your agent ships changes, restarts, scales, rolls back, and runs multi-app projects after the first deploy.
There’s no separate “update” toolset. Every day-2 operation — a new image, a config change, a secret rotation, a scale-up — runs through the same nyx_* tools as the first deploy, just combined differently. (For watching an app rather than changing it — logs, resource usage, traffic — see Monitoring.)
Change, restart, scale, inspect
- Ship a new image build (same source, rebuilt). Your agent calls
nyx_build_and_push_imageagain — it returns a freshimage_refwith an auto-incrementing-Nsuffix — thennyx_deploy_manifestswith just the updated Deployment document,app_manifestleft out so the tool resolves the app’s UID from the cluster on its own. - Change a ConfigMap, Service, or Ingress. Same path:
nyx_deploy_manifestswith the changed document,app_manifestomitted again. - Rotate a secret.
nyx_set_secretwrites the new value, thennyx_shellrunskubectl rollout restart deployment/<app> -n <namespace>so the pod picks up the new ciphertext — the same command covers a plain restart with no spec change. - Scale. Either
nyx_shellwithkubectl scale deployment/<app> --replicas=N -n <namespace>for a one-shot change, ornyx_deploy_manifestswith an updated Deployment YAML to make it persist. - Inspect.
nyx_app_list/nyx_app_getfor the app-level overview,nyx_app_deploymentsfor the ReplicaSet rollout history, andnyx_shellwith read-onlykubectl get ... -o ...for anything else. - Delete. A single resource goes through
nyx_shell(kubectl delete <kind>/<name> -n <namespace>); a whole app goes throughkubectl delete app/<name> -n <namespace>— the ownerRef cascade removes everything it owns. PVCs are the exception; they survive app delete by design.
Note: When
app_manifestis omitted,nyx_deploy_manifestsreads theapp.kubernetes.io/instancelabel off each document, confirms they all belong to the same app, resolves that app’s UID in the cluster, substitutes<APP_UID>, validates ownerRefs, then applies. If the app doesn’t exist yet, this fails withapp-not-foundandapp_manifestbecomes required.
Multiple apps per project
A project can host any number of apps — a Compose monorepo with frontend, API, and DB, or a web/worker/queue split. Each app gets its own nyx_deploy_manifests call with its own app_manifest; the tool is atomic per app and doesn’t batch across calls.
Independent apps can deploy in any order. Dependent apps (an API that needs its DB up first) deploy the dependency, then wait on it before deploying the dependent app:
kubectl wait --for=condition=Ready pod -l app.kubernetes.io/instance=<dependency> -n <namespace> --timeout=25s
Keep each wait under roughly 25 seconds and re-poll on timeout — a single long timeout or sleep loop won’t survive the MCP client’s own timeout.
If the plan creates more than one workload pod, check RAM and CPU headroom before the first deploy call — the project’s quota is shared across every pod in the namespace.
For docker-compose.yml repos, each service becomes its own App CRD — never one app for the whole compose file. depends_on maps directly to deploy order. Compose environment blocks become either a project-scoped secret (shared values) or a per-service app secret.
For Helm charts: render with helm template, inject the standard labels and ownerRefs, then kubectl apply. Skip helm install directly — it bypasses the App CRD ownership model and leaks resources when the app is later deleted.
Service discovery
An app reaches a sibling app in the same namespace through that app’s Service name as host — the short name (db) or the FQDN (db.<namespace>.svc.cluster.local) — on the Service’s port, not its targetPort. This runs over standard cluster DNS; nothing extra needs provisioning.
Never address a sibling app by pod IP (it changes on every restart) or by its public {{ .AppDomainPattern }} URL — that would route out to the internet and back through ingress. Database wire protocols return a 502 over that path, and non-HTTP services don’t get a public domain at all.
Build the connection string from the Service name and Service port, write it with nyx_set_secret at project scope so every app in the namespace can read it, and consume it via envFrom:
DATABASE_URL=postgres://user:pass@db:5432/appdb
The same pattern applies to any backing service — only the scheme and port change:
redis://cache:6379/0mongodb://mongo:27017/appdbamqp://mq:5672http://api:8080for an internal HTTP API (keep the port unnamed / non-HTTP to stay off ingress)
For separate host/port env vars, use host = <service-name> and port = <service port>. Cross-namespace calls need the FQDN; same-namespace calls only need the short name.
Next steps
- Add a custom domain → — bind your own hostname
- Deploy a Next.js app → — first deploy walk-through