---
title: "CLI overview"
description: "How the monedula-gitops CLI reads manifests and cluster config, its output formats and exit codes, with links to every command."
url: https://monedula.dev/flock/docs/gitops/reference/cli/
---
The `monedula-gitops` binary validates, diffs and applies manifests against a live cluster, and also runs the Kubernetes operator. Every command has the form `monedula-gitops <command> [flags]`; each command page lists its flags.

## Commands

| Command | Purpose |
| --- | --- |
| [`validate`](/flock/docs/gitops/reference/cli/validate/) | Parse and validate manifests, and their cluster references when a cluster config is given. |
| [`diff`](/flock/docs/gitops/reference/cli/diff/) | Show the operations needed to bring live state in line with the manifests. Exits 0 with or without drift, 2 on error. |
| [`verify`](/flock/docs/gitops/reference/cli/verify/) | Run the same comparison as `diff` and exit 1 on drift, for CI gating. |
| [`apply`](/flock/docs/gitops/reference/cli/apply/) | Apply the manifests to Kafka. `--dry-run` previews the planned operations. |
| [`doctor`](/flock/docs/gitops/reference/cli/doctor/) | Check connectivity and operational readiness for one cluster, without manifests. Never mutates Kafka. |
| [`import cluster`](/flock/docs/gitops/reference/cli/import-cluster/) | Read live cluster state and generate manifests from it. Never mutates Kafka. |
| [`operator`](/flock/docs/gitops/reference/cli/operator/) | Run the monedula-gitops Kubernetes operator. |
| [`version`](/flock/docs/gitops/reference/cli/version/) | Print the version, commit and build date. |
| [`completion bash`](/flock/docs/gitops/reference/cli/completion-bash/), [`zsh`](/flock/docs/gitops/reference/cli/completion-zsh/), [`fish`](/flock/docs/gitops/reference/cli/completion-fish/), [`powershell`](/flock/docs/gitops/reference/cli/completion-powershell/) | Generate the autocompletion script for that shell. |

## Global flags

- `--log-level`: works on every command. Sets the verbosity of the diagnostic logs on stderr: `error`, `warn` (default), `info` or `debug`. At `warn`, role-name typos and RBAC-coarsening warnings are visible; `debug` also enables the Kafka client's own logs.
- `-v`, `--version`: root command only. Prints the version and exits, as in `monedula-gitops --version`.

## Manifest input

`validate`, `diff`, `verify` and `apply` read manifests:

- `-f`, `--filename`: a manifest file or directory. Repeatable. `-` reads manifests from stdin. At least one is required.
- `-R`, `--recursive`: recurse into directories given to `-f`.

Add `-R` when manifests sit in subdirectories, for example the tree that `import cluster --output-dir` writes:

```bash
monedula-gitops verify -f ./imported -R --cluster-config-file ./clusters/prod.yaml   # exits 0: no drift
```

Reading from stdin lets any renderer that prints manifests, such as Kustomize or `helm template`, feed the CLI without a temporary file:

```bash
kubectl kustomize overlays/prod | monedula-gitops apply -f - --cluster-config-file env/prod/cluster.yaml
```

The CLI rejects duplicate identities when it loads manifests, and exits 2: two `KafkaTopic` resources with the same cluster and `topicName`, two `KafkaQuota` resources for the same cluster and entity, two `KafkaUser` resources with the same cluster and `username`, or two `KafkaRoleBinding` resources that compile to the same role binding. Each error names both resources, for example `KafkaTopic dup-orders-b collides with dup-orders-a: both resolve to topicName "dup.orders" on cluster "shared"`. Role bindings are compared only when a cluster config is loaded, because their identity needs the cluster's MDS cluster IDs. The operator handles duplicates as [Enforce tenancy with admission webhooks](/flock/docs/gitops/how-to/enforce-tenancy/) describes.

## Cluster config

Commands that talk to a cluster read `KafkaCluster` documents from a cluster config:

- `-c`, `--cluster-config-file`: a `KafkaCluster` config file or directory. Repeatable.
- `--cluster`: select a single cluster by name.

How each command uses it:

- `validate` works without a cluster config and needs no running Kafka. With one, it also checks that every `clusterRef` names a loaded cluster.
- `diff`, `verify` and `apply` require a cluster config, because they compare with live state. They work against one cluster; when the config holds more than one, select it with `--cluster`.
- `doctor` and `import cluster` require a cluster config and take no manifests. When more than one cluster is loaded, `--cluster` is required.

Credentials in a cluster config resolve from environment variables (`valueFrom.env`) or files (`valueFrom.file`, relative to the cluster-config directory). Kubernetes `secretKeyRef` references are resolved only by the operator. Resolved secret values are never logged.

`diff`, `verify` and `apply` read live state only for the kinds the loaded manifests declare: a set of topic manifests issues no ACL, quota, SCRAM, Schema Registry or MDS reads, so the connecting principal needs describe rights only for the kinds its pipeline manages ([Least-privilege connecting principal](/flock/docs/gitops/reference/connecting-principal-acls/)).

There is no built-in environment concept; [Promote changes across environments](/flock/docs/gitops/how-to/promote-across-environments/) shows how to lay out the files.

## Output

- `-o`, `--output`: the output format, `human` (default), `yaml` or `json`. `yaml` and `json` produce a deterministic document. Any other value exits 2.

Command output goes to stdout, and diagnostic logs go to stderr, so stdout stays clean at any log level and can be piped. For `import cluster`, `-o` selects the format of the import summary. Without `--output-dir`, it writes the manifests to stdout and the summary to stderr, so the manifest stream stays pipeable; with `--output-dir`, it writes files and prints the summary to stdout.

## Operation outcomes

`apply` lists the outcome of every planned operation:

| Outcome | Meaning |
| --- | --- |
| `Succeeded` | The operation ran. |
| `Failed` | The operation ran and returned an error. |
| `Skipped` | A prerequisite failed in the same run, for example the topic that an ACL belongs to could not be created. |
| `Blocked` | The operation needs `--allow-destructive`, which was not given. |
| `Rejected` | The operation is never allowed, for example a partition decrease. |
| `Unsupported` | The operation was approved but cannot be performed, for example a replication factor change. |
| `ReportOnly` | The operation belongs to a `DetectOnly` or `ObserveOnly` resource and is only reported. |
| `PruneDisabled` | An in-scope ACL or role binding that the manifests no longer list, kept because `--prune` was not given. |

Execution is best-effort and never rolls back: independent operations continue past failures, and running `apply` again converges the rest. [Safety gates](/flock/docs/gitops/concepts/safety-gates/) explains the approval and prune gates.

## Exit codes

| Code | Meaning |
| --- | --- |
| 0 | Success, no drift for `verify`, or all checks pass for `doctor`. |
| 1 | Drift detected. `verify` only; drift on `ObserveOnly` resources is ignored. |
| 2 | Validation, configuration or connectivity error, an `apply` with any failed, skipped or rejected operation, or a failed `doctor` check. |
| 3 | `apply` only: the only non-OK operations are `Blocked`. The plan is sound, and gated operations wait for `--allow-destructive`. |

Unconsented prune candidates (`PruneDisabled`) and report-only operations on `DetectOnly` or `ObserveOnly` resources count as OK for `apply`. `diff` exits 0 whether or not it finds drift, and 2 on errors.