Guides

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_image again — it returns a fresh image_ref with an auto-incrementing -N suffix — then nyx_deploy_manifests with just the updated Deployment document, app_manifest left 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_manifests with the changed document, app_manifest omitted again.
  • Rotate a secret. nyx_set_secret writes the new value, then nyx_shell runs kubectl 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_shell with kubectl scale deployment/<app> --replicas=N -n <namespace> for a one-shot change, or nyx_deploy_manifests with an updated Deployment YAML to make it persist.
  • Inspect. nyx_app_list / nyx_app_get for the app-level overview, nyx_app_deployments for the ReplicaSet rollout history, and nyx_shell with read-only kubectl get ... -o ... for anything else.
  • Delete. A single resource goes through nyx_shell (kubectl delete <kind>/<name> -n <namespace>); a whole app goes through kubectl 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_manifest is omitted, nyx_deploy_manifests reads the app.kubernetes.io/instance label 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 with app-not-found and app_manifest becomes 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/0
  • mongodb://mongo:27017/appdb
  • amqp://mq:5672
  • http://api:8080 for 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

Ask any AI about nyxory