Skip to content

Operate

This page covers the kindo-cli commands an operator will touch most often after the install completes. Before you pick up this page, the install should already be healthy (see Configure & Validate).

CommandPurpose
kindo statusInstall-state summary from the cluster ConfigMap
kindo config editEdit install-contract.yaml and re-sync the cluster secret
kindo config applyRegenerate per-app <app>-env Secrets and rollout-restart deployments
kindo config validate --preflightSchema check + infrastructure connectivity test
kindo config override list | set | unsetManage per-service env var overrides in the centralized config
kindo config override edit | diff | applyBulk-edit overrides, preview changes, and push them to the live Secrets
kindo config log-level set | show | unsetSet the global application log level across the seven Kindo-built apps
kindo db listEnumerate the six Postgres databases
kindo db tunnel <database>Open a port-forward tunnel to a database
kindo db prompt <database>Interactive psql session over a tunnel
kindo db reset [database]Drop all tables (destructive, requires two confirmations)
kindo model listList models registered in the Main DB (post-install verification)
kindo integrations listShow available and enabled MCP integrations
kindo integrations enable <name>Enable an integration in the contract
kindo integrations disable <name>Disable an integration in the contract
kindo integrations applyDeploy enabled integrations (Nango registration + MCP pods)
kindo integrations bootstrapRe-run integration registration against the cluster
kindo integrations statusLive integration status from the cluster
kindo uninstall all | applications | peripheriesTear down a group of releases

Check install state any time. The state lives in the kindo-install-state ConfigMap in kindo-system, so the answer is the same from any workstation with cluster access:

Terminal window
kindo status

Expect a table with one row per install step (generate-secrets, merge-bindings, setup-registry, db-bootstrap, peripheries, hatchet-token, migrations, applications, post-install). Anything other than completed for all rows on a fresh install is a signal to stop and investigate — kindo install --resume picks up from the failed step.

These two commands are the safe path for changing any non-infrastructure setting after the install. edit opens install-contract.yaml in $EDITOR, validates the result against the schema, and re-syncs the updated contract into the kindo-secrets-config Secret in kindo-system. apply reads that Secret, regenerates the per-app <app>-env Kubernetes Secret for every application whose inputs changed, and issues kubectl rollout restart deployment/<app> so each pod picks up the new values without downtime.

Terminal window
# Edit SMTP settings, admin email, a model, or an integration flag
kindo config edit
# Push the changes to the cluster: rebuilds <app>-env Secrets and restarts pods
kindo config apply

kindo config apply is also the recommended follow-up after any manual edit of the contract file. If you only changed one service, narrow the blast radius:

Terminal window
kindo config apply --app api

kindo config validate --preflight is the pre-flight check you can run before committing a change — it verifies schema validity and reruns the connectivity tests against Postgres, Redis, RabbitMQ, and object storage.

Use kindo config override when you want to change a single env var on a running service without editing the contract or running a full upgrade. Common cases: shortening SESSION_MAX_AGE_HOURS, pointing NEXT_PUBLIC_NANGO_CONNECT_URL at a different hostname, rotating a third-party API key. Overrides live under serviceOverrides.<service>.<ENV_KEY> in the centralized kindo-secrets-config Secret and are honored on every subsequent upgrade — precedence is overrides > live secret > generated defaults.

Terminal window
# Set one or more env vars on a service (scriptable)
kindo config override set next SESSION_MAX_AGE_HOURS=4
# Push the staged change into the live <service>-env Secret and rollout pods
kindo config override apply next
# Preview what `apply` would change against the live cluster (values redacted)
kindo config override diff next
# Bulk-edit the whole overrides subtree (or just one service) in $EDITOR
kindo config override edit
kindo config override edit next
# Remove an override; the next `apply` deletes the key from the live Secret
kindo config override unset next SESSION_MAX_AGE_HOURS
kindo config override apply next
# Inspect what is currently staged
kindo config override list
kindo config override list next --format=yaml

apply records the keys it writes in a kindo.ai/override-keys annotation on the live Secret, so unset followed by apply correctly removes the key — merge patches alone could not. Keys that already exist in the live Secret but are not in the override set (e.g. chart defaults, values applied manually via kubectl patch) are reported as “stray” and left untouched; pass --force to apply anyway. See Overrides runbook for the validation rules, troubleshooting table, and end-to-end examples.

kindo config log-level is one coarse knob for how verbosely the Kindo-built apps log. It accepts debug, info, warn, or error, and translates that into each of seven services’ own env var — api, task-worker-ts, next, credits, external-sync, and external-poller all read the value verbatim as LOG_LEVEL; litellm reads its native LITELLM_LOG (Python logging vocabulary — debug becomes DEBUG, warn becomes WARNING, and so on), never LOG_LEVEL. The other services (hatchet, nango, ssoready, mcp, mcp-unified, prisma-migrations) have their own logging config and are not touched.

There are two ways to set it. Day 0, put logLevel: in install-contract.yaml so a fresh install comes up at that level. Day 2, change it on a running cluster without a full upgrade:

Terminal window
# Set the level: patches each of the seven <app>-env Secrets on its own bound
# key (LOG_LEVEL=debug for six of them, LITELLM_LOG=DEBUG for litellm) and
# restarts the affected Deployments (external-poller is a CronJob — it picks
# up the change on its next scheduled run instead of restarting)
kindo config log-level set debug
# Show the global value plus any per-service overrides
kindo config log-level show
# Clear it: the six winston apps drop LOG_LEVEL, litellm is patched back to
# its LITELLM_LOG=INFO default (never removed), and the affected Deployments
# restart (external-poller picks it up on its next scheduled run)
kindo config log-level unset

set and unset take --no-restart to patch the Secrets without rolling pods; all three take --kube-context; unset also takes --no-apply to change only the stored config and leave the live cluster alone.

Precedence is per-service override > global log level > the app’s own default. A service pinned with kindo config override set api LOG_LEVEL=debug keeps debug even after kindo config log-level set warn, and keeps it through kindo config log-level unset. The per-service escape hatch for litellm is its own native key — kindo config override set litellm LITELLM_LOG=DEBUG — since litellm does not read LOG_LEVEL at all. See the Global log level section of the Overrides runbook for details.

set and unset continue past a failure on any individual service and exit non-zero if one occurred, so a partial reconcile is never mistaken for full success — re-run the command once the underlying issue is fixed.

The knob governs HTTP request logs too: api and credits emit their per-request access logs at info through the same gated logger, so a global warn or error suppresses access logging on those services along with application logs. To quiet an app while keeping its access logs, pin it with a per-service override (kindo config override set api LOG_LEVEL=info).

A day-2 kindo config log-level set persists across a normal kindo upgrade. Re-running kindo install --step merge-bindings with a contract that has no logLevel: field clears the global level, because the contract is the source of truth on that step — add logLevel: to install-contract.yaml to make a day-2 setting durable across a re-run of that step.

Six databases are deployed. The names are stable — use them with tunnel, prompt, and reset.

DatabaseBacks
mainapi, credits, external-sync, external-poller, task-worker-ts, cerbos
ssoreadySSO authentication service
litellmLiteLLM proxy and model catalog
hatchetHatchet workflow engine
nangoNango OAuth integration service
unleashUnleash feature flags

kindo db tunnel launches a disposable alpine/socat pod in the cluster, port-forwards from localhost:15432 (override with --port), and prints a ready-to-use psql URL. The tunnel stays up until you Ctrl+C:

Terminal window
kindo db tunnel main
# ✓ Tunnel active on localhost:15432
# Connect with:
# psql 'postgresql://admin:***@localhost:15432/kindo_apps?sslmode=require'

kindo db prompt wraps the tunnel + psql handoff in one command. Use it for quick inspections:

Terminal window
kindo db prompt litellm

kindo db reset drops every table, sequence, and enum type in the public schema of the named database. It is the right answer when a dev environment’s data is corrupt and the wrong answer for anything production-adjacent. Two confirmations are required for --all:

Terminal window
# Reset a single DB (one confirmation)
kindo db reset hatchet
# Reset every DB (two confirmations)
kindo db reset --all

After a reset, re-run kindo install --step migrations to recreate the schema and kindo install --step post-install to rebootstrap admin users, models, and feature flags.

MCP integrations (Slack, GitHub, Jira, …) are declared in install-contract.yaml under the integrations: block. The CLI is the source of truth for enabling and disabling them; edit the contract directly only if you know what you are doing.

Terminal window
# See what is available and which are enabled
kindo integrations list
# Enable two integrations (prompts for OAuth creds where needed)
kindo integrations enable github slack
# Deploy: registers integrations with Nango and deploys any legacy MCP pods
kindo integrations apply
# Re-run integration registration without deploying pods (e.g. after a Nango reset)
kindo integrations bootstrap
# Live status from the cluster: unified-MCP health + per-legacy-MCP Helm releases
kindo integrations status
# Turn one off
kindo integrations disable slack
kindo integrations apply

Disabling an integration and running apply stops deploying it, but its Nango configuration and any existing connections are retained. To fully remove an integration, also delete its auth instance in the Nango dashboard and re-run kindo integrations apply.

Most integrations run inside the shared mcp-unified pod in the mcp namespace. A small number of legacy TypeScript MCPs still ship as their own Helm release — kindo integrations status shows both.

Three scopes are available. Each is confirmed interactively unless you pass --force:

Terminal window
# Tear down applications only (keeps peripheries and databases running)
kindo uninstall applications
# Tear down peripheries only (Unleash, Qdrant, Presidio, Speaches, Hatchet, OTel Collector)
kindo uninstall peripheries
# Full teardown, preserving PVCs and the kindo-secrets-config Secret
kindo uninstall all --keep-data
# Full teardown including secrets config and all Kindo namespaces
kindo uninstall all --delete-namespaces

uninstall all reverses install order: post-installapplicationsperipheriesbootstrap. The kindo-secrets-config Secret and the kindo-install-state ConfigMap are preserved by default so you can reinstall against the same infrastructure without regenerating credentials. Pass --delete-namespaces for a fully clean slate.