Commands
This is the complete Pyahu CLI reference. Every command accepts the global flags from the
next section. Most support --output json for use in scripts.
pyahu [command] [flags]Global flags
Section titled “Global flags”Available on any command:
| Flag | Default | Description |
|---|---|---|
-f, --file | automatic discovery | Path to the project’s pyahu.yaml. The global config is still applied. |
-o, --output | human | Output format: human or json. |
--no-color | false | Disable colors in the output. |
-q, --quiet | false | Suppress non-essential output. |
-v, --verbose | false | Show tool output (k3d, etc.). |
--no-input | false | Never prompt interactively. |
--version | — | Show version, commit, and build date. |
-h, --help | — | Command help. |
The CLI searches for the stack file from the current directory upward, in this order: pyahu.yaml,
pyahu.yml, .pyahu/stack.yaml, .pyahu/stack.yml. Use --file only to point at another
path.
Lifecycle
Section titled “Lifecycle”pyahu init
Section titled “pyahu init”Creates a pyahu.yaml from a preset.
| Flag | Default | Description |
|---|---|---|
--preset | minimal | Starting preset: minimal (PostgreSQL only) or platform (full stack). |
--force | false | Overwrite an existing stack file. |
pyahu init --preset platformpyahu init --preset minimal --forcepyahu init --preset platform -f infra/pyahu.yamlpyahu up
Section titled “pyahu up”Creates the k3d cluster when needed and reconciles the Kubernetes resources. It is idempotent:
a second pyahu up converges or does nothing. Resources managed by Pyahu that are no longer in
the stack are removed; persistent volume claims are retained to protect local data.
| Flag | Default | Description |
|---|---|---|
--skip-wait | false | Apply the resources without waiting for the services to become ready. |
Flow: preflight (doctor) → create/reuse the cluster → wait for the Kubernetes API → apply the services → wait for readiness → print the summary.
pyahu uppyahu up --skip-waitpyahu up --output jsonHuman output at the end:
Pyahu local stack is readycluster: pyahu-localnamespace: pyahu-local-devkubeconfig: /home/user/.config/k3d/kubeconfig-pyahu-local.yaml
POSTGRES_URL postgresql://pyahu:hidden@localhost:5432/app?sslmode=disablePOSTGRES_PASSWORD <hidden>ZITADEL_ISSUER https://zitadel.localhost...
next: eval "$(pyahu env)"The up summary redacts passwords, tokens, private keys, and credentials inside
URLs in both human and JSON output. Use the explicit pyahu env command when an
application needs the real connection values.
pyahu down
Section titled “pyahu down”Removes the local Pyahu resources.
| Flag | Default | Description |
|---|---|---|
--keep-cluster | false | Remove only the stack namespace and keep the k3d cluster. |
--purge-data | false | Permanently delete retained local storage after removing the cluster. |
--yes | false | Confirm --purge-data without an interactive prompt. |
pyahu down # deletes the entire k3d clusterpyahu down --keep-cluster # keeps the cluster, removes the namespacepyahu down --purge-data --yes # also permanently deletes retained local dataBy default, cluster data remains under ~/.pyahu/clusters/<cluster>/storage so
teardown never silently deletes host files. Pyahu prints the retained path.
--purge-data is irreversible, cannot be combined with --keep-cluster, and
requires confirmation; scripts and --no-input runs must pass --yes.
pyahu doctor
Section titled “pyahu doctor”Checks dependencies and local ports before bringing up the stack. Works even without a stack file (it uses defaults for the check).
pyahu doctorpyahu doctor --output jsonIt checks:
k3dinstalled on thePATH- Docker or Podman running
- Other local clusters (k3d/Kind): warning only, does not fail
- Availability of the host ports for the enabled services (when the cluster does not exist yet)
k3d ok k3d is installedcontainer-runtime ok docker is availablelocal-clusters ok no other local Kubernetes clusters detectedport:postgres ok 127.0.0.1:5432 is availablehost ok linux/amd64Inspection
Section titled “Inspection”pyahu status
Section titled “pyahu status”Shows the state of the cluster and of each service, including the pods.
pyahu statuspyahu status --output jsoncluster: pyahu-localnamespace: pyahu-local-devpostgres ready 1/1 readyzitadel ready 1/1 readykafka waiting startingpyahu services
Section titled “pyahu services”Lists the enabled services, their state, and local endpoints. Aliases: svc, ls.
pyahu servicespyahu svcpyahu services --output jsoncluster: pyahu-localnamespace: pyahu-local-devstate: running
SERVICE STATUS VERSION ENDPOINTSpostgres ready 18.4 localhost:5432zitadel ready v4.15.2 https://zitadel.localhostrabbitmq ready 4.3.2 localhost:5672, https://rabbitmq.localhostredis ready 8.1-alpine localhost:6379kafka ready 4.3.0 localhost:9092kafka-connect ready 3.5.2 http://localhost:8083kafka-ui ready v1.5.0 https://kafka-ui.localhostpyahu describe <service>
Section titled “pyahu describe <service>”Details for a service: status, endpoints (host + in-cluster), environment variables, config details, and pods.
Valid services: postgres, zitadel, rabbitmq, redis, kafka, kafka-connect, kafka-ui.
| Flag | Default | Description |
|---|---|---|
--show-secrets | false | Show secret values in the human output (masked by default). |
pyahu describe postgrespyahu describe zitadel --show-secretspyahu describe kafka-connect --output jsonpyahu logs <service>
Section titled “pyahu logs <service>”Streams a service’s logs.
| Flag | Default | Description |
|---|---|---|
--follow | false | Follow the logs in real time. |
--tail | 100 | Number of initial lines to show. |
pyahu logs postgres --tail 50pyahu logs zitadel --followpyahu logs kafka-connect --tail 200Connection and data
Section titled “Connection and data”pyahu env
Section titled “pyahu env”Prints the connection variables for local apps.
| Flag | Default | Description |
|---|---|---|
--format | shell | shell (with export), dotenv, or json. |
pyahu env # export VAR='value'pyahu env --format dotenv # VAR=valuepyahu env --format jsoneval "$(pyahu env)" # loads into the current shellThe variables cover each enabled service, for example POSTGRES_URL,
RABBITMQ_URL, REDIS_URL, KAFKA_BOOTSTRAP_SERVERS, KAFKA_CONNECT_URL,
ZITADEL_ISSUER.
pyahu kubeconfig
Section titled “pyahu kubeconfig”Prints the path of the local cluster’s kubeconfig.
| Flag | Default | Description |
|---|---|---|
--raw | false | Write the kubeconfig content to stdout instead of the path. |
pyahu kubeconfigpyahu kubeconfig --raw > kubeconfig.yamlexport KUBECONFIG="$(pyahu kubeconfig)"pyahu backup postgres [database]
Section titled “pyahu backup postgres [database]”Runs a real PostgreSQL dump on the primary pod straight into a file on the host
(pg_dump --format=custom). Without [database], it uses the first configured database.
| Flag | Default | Description |
|---|---|---|
--dir | .pyahu/backups | Host directory for the .dump file. |
pyahu backup postgres app --dir ./backupspyahu backup postgres # uses the first configured databaseThe file is named <stack>-<database>-<YYYYMMDD-HHMMSS>.dump (UTC).
pyahu restore postgres [database]
Section titled “pyahu restore postgres [database]”Restores a custom PostgreSQL dump from a local file or from s3://.
| Flag | Default | Description |
|---|---|---|
--source | — (required) | Path to the .dump file or s3:// URI. |
--s3-endpoint-url | — | S3-compatible endpoint for s3:// sources. |
--clean | true | Remove matching objects before restoring. |
--yes | false | Confirm the destructive restore without a prompt. |
pyahu restore postgres app --source ./backups/pyahu-local-app-20260622-131500.dumppyahu restore postgres app --source s3://my-bucket/dev/app.dump --yespyahu restore postgres app \ --source s3://bucket/app.dump \ --s3-endpoint-url http://localhost:9000 \ --yesConnectors
Section titled “Connectors”pyahu connectors apply
Section titled “pyahu connectors apply”Registers the connectors declared under services.kafkaConnect.connectors and
waits for their tasks to reach RUNNING.
Run it after the application that owns a connector’s source has booted at least once: an outbox connector reads a table, publication, or stream that does not exist on a fresh cluster. The command is idempotent — it re-applies the Secret and recreates the registration Job.
| Flag | Default | Description |
|---|---|---|
--name | (all) | Apply only the connector with this name. |
pyahu connectors applypyahu connectors apply --name checkout-outboxA successful, waiting pyahu up also reconciles connector ownership. It records
the connector names managed by this stack and deletes a previously managed
registration after its name is removed from pyahu.yaml. Connectors created
manually against the same worker are not in that inventory and are left alone.
The inventory is kept if Kafka Connect is temporarily disabled, so it can be
used safely when the service is enabled again.
pyahu connectors status
Section titled “pyahu connectors status”Shows the state of each connector and of each task.
| Flag | Default | Description |
|---|---|---|
--format | human | human or json. |
pyahu connectors statuspyahu connectors status --format jsonCONNECTOR TASK STATE DETAILallpick-core-outbox - RUNNING source 0 RUNNING -checkout-outbox - RUNNING source 0 FAILED ERR no such keyThe command exits non-zero when any task is not RUNNING, or when a
connector has no tasks at all.
connectors[].optional
Section titled “connectors[].optional”A connector whose source only exists after the application boots carries
optional: true:
services: kafkaConnect: connectors: - name: checkout-outbox kind: custom optional: true config: connector.class: com.redis.kafka.connect.RedisStreamSourceConnectorWith optional: true, a registration that does not become healthy during
pyahu up is reported as a warning in the summary instead of an error — up
stays green and you run pyahu connectors apply after the first boot. Without
optional, the failure fails up, which is the right behavior for a connector
whose source should already exist.
Local TLS
Section titled “Local TLS”pyahu certs status
Section titled “pyahu certs status”Shows the state of the local CA, the wildcard certificate, and the host trust.
pyahu certs statuspyahu certs status --output jsonlocal CA: ~/.config/pyahu/certs/ca.crtCA status: valid until 2036-06-19host trust: trustedcertificate: .pyahu/local/certs/localhost.crtcert status: valid until 2027-07-24domains: *.localhost, localhost, zitadel.localhostpyahu certs trust
Section titled “pyahu certs trust”Installs the local Pyahu CA into the host’s trust store. On macOS it may prompt for a password. After that,
curl and browsers accept https://zitadel.localhost (and the other *.localhost UIs) without warnings.
pyahu certs trustpyahu certs rotate
Section titled “pyahu certs rotate”Regenerates the local CA and the wildcard certificate. Run pyahu certs trust and pyahu up afterward
to re-trust the CA and update the TLS Secret in the cluster.
pyahu certs rotatepyahu certs trustpyahu upMore context in Local certificates.
pyahu completion [shell]
Section titled “pyahu completion [shell]”Generates the autocomplete script. Supported shells: bash, zsh, fish, powershell.
pyahu completion zsh > "${fpath[1]}/_pyahu"pyahu completion bash | sudo tee /etc/bash_completion.d/pyahu > /dev/nullpyahu completion fish > ~/.config/fish/completions/pyahu.fishJSON output for scripts
Section titled “JSON output for scripts”Almost all read commands support --output json:
pyahu doctor --output jsonpyahu status --output jsonpyahu services --output jsonpyahu describe postgres --output jsonpyahu env --format jsonpyahu certs status --output jsonOut-of-date notice
Section titled “Out-of-date notice”When a newer release exists, the CLI prints a notice at the end of any command:
⚠ pyahu x.y.z is out of date — a.b.c is available pyahu upgrade curl -fsSL https://cli.pyahu.io/install.sh | sh https://github.com/pyahu/cli/releases/tag/va.b.c silence this with PYAHU_NO_UPDATE_CHECK=1The suggested command follows how you installed it — the CLI reads its own binary path: under
the mise install tree it becomes mise use github:pyahu/cli@<version>, under GOBIN/GOPATH it
becomes go install, and otherwise the install script.
The notice goes to stderr, never stdout: eval "$(pyahu env)" and --output json consume
stdout, and a banner there would be evaluated as shell or break the JSON.
It stays silent when:
| Situation | Why |
|---|---|
--output json or --quiet | the output is read by a script |
Locally built binary (version dev) | there is no version to compare |
PYAHU_NO_UPDATE_CHECK is set | explicit opt-out; it does not even reach the network |
| Offline, behind a proxy, or GitHub API rate limited | the check fails silently |
The lookup runs alongside the command and the answer is cached for 24h in
<config dir>/pyahu/version-check.json, so it costs no wall-clock time: the command never waits
more than 700ms for it, and the next day the answer is already on disk.
pyahu check-update
Section titled “pyahu check-update”Asks the releases endpoint directly — it does not go through the 24h cache behind the passive notice.
| Flag | Default | Description |
|---|---|---|
--exit-code | false | Exit 1 when a newer release is available (for scripts/CI). |
pyahu check-updatepyahu check-update --output json # {"current":"x.y.z","latest":"a.b.c","outdated":true}pyahu check-update --exit-code # 0 = up to date, 1 = a newer release existsIt exits 0 by default even when behind: being out of date is not a command failure. Anyone who
wants to fail a pipeline over it asks for --exit-code, in the spirit of git diff --exit-code.
pyahu upgrade
Section titled “pyahu upgrade”Downloads the release, verifies its SHA-256 against the published checksums.txt, and swaps
this binary for the one inside the archive.
| Flag | Default | Description |
|---|---|---|
--yes | false | Replace without prompting. |
--version | (latest) | Install a specific version — this is also how you roll back. |
pyahu upgradepyahu upgrade --yespyahu upgrade --yes --version v0.10.0 # install or roll back to a specific releaseThe new binary is written next to the current one and renamed over it: the swap is atomic on the
same filesystem, and an interrupted download never leaves a half-written binary. On Unix the running
process stays on the old inode, so upgrade itself finishes normally.
The other refusals, all before downloading anything: a locally built binary (version dev), Windows
(a running executable cannot be replaced under it), and an install directory that is not writable —
there the message already carries both ways out (sudo, or reinstall into ~/.local/bin).
Recommended flow
Section titled “Recommended flow”pyahu init --preset platformpyahu doctorpyahu uppyahu certs trustpyahu serviceseval "$(pyahu env)"Pyahu Cloud
Section titled “Pyahu Cloud”| Command | Behavior |
|---|---|
pyahu login | Browser device authorization; saves the local session. |
pyahu logout | Deletes the saved session. |
pyahu kube list | Lists environments with enabled kubectl access. |
pyahu kube config --env <name> | Backs up kubeconfig, adds the Cloud context and selects it. |
pyahu kube doctor | Reports session and environment access configuration. |
See Pyahu Cloud access for the complete workflow.