> ## Documentation index
> The full klickops handbook index is at https://klickops.io/llms.txt
> The HTML of this page is at https://klickops.io/en/docs/cli
> Language: en

# klops CLI

Everything the web interface does, from a terminal or a script.

## What it is

`klops` is the klickops command line. It talks to the same REST API the web interface uses, so anything you can click, you can script. There is no second feature set and nothing the UI can do that the CLI cannot.

It talks to klickops and to nothing else. No kubeconfig, no direct database connections, no `kubectl` on your machine. That is deliberate: access control, audit and TLS all stay in one place, and your laptop needs no cluster credentials.

## When you'd use it

- A deploy from a script, or from your own CI.
- Reading logs or running a query without opening a browser.
- Doing the same thing across ten projects without twenty clicks.

## Signing in

```bash
klops auth login --server https://klickops.example.com
```

That writes `~/.klickops/config.yaml` with permissions `0600`, and refuses to read the file if the permissions are looser. For CI, skip the login and set `KLICKOPS_SERVER` and `KLICKOPS_TOKEN` instead, using an [API token](/docs/tokens) rather than your own account.

## The shape of a command

Commands read as noun then verb.

```bash
klops apps list --project shop
klops apps logs web --project shop --follow
klops db query orders-db --project shop -c "select count(*) from orders"
klops apps deploy web --image nginx:1.27-alpine --port 80 --project shop
```

Every read command takes `-o`, which is what makes it scriptable:

| Format | For |
| --- | --- |
| `table` | Reading. The default. |
| `json` | Piping into `jq`. |
| `yaml` | Diffing, or feeding something else. |
| `name` | Just the names, for a shell loop. |
| `wide` | Reading, with more columns. |

Colour is dropped automatically when the output is not a terminal, so `klops apps list -o json \| jq` never sees escape codes.

## Where settings come from

Flag beats environment variable beats config file beats default. So a `--project` on the command line wins over `KLICKOPS_PROJECT`, which wins over the current context in `~/.klickops/config.yaml`.

| Variable | Sets |
| --- | --- |
| `KLICKOPS_SERVER` | Which klickops to talk to |
| `KLICKOPS_TOKEN` | The token to authenticate with |
| `KLICKOPS_ORG` | Default organization |
| `KLICKOPS_PROJECT` | Default project |

## Exit codes

Scripts depend on these, so they are stable.

| Code | Means |
| --- | --- |
| `0` | Success |
| `1` | Something went wrong |
| `2` | You used the command wrong |
| `3` | Not signed in, or the token expired |
| `4` | Signed in, but not allowed |
| `5` | Not found |
| `6` | Already exists |

The useful consequence: `3` and `4` are different questions. A `3` in CI means the token needs renewing; a `4` means it needs more rights.

## Limits and gotchas

- **There is no cache.** Every command asks the server, because stale state bites worse than a round trip.
- **The config file is refused if its permissions are loose.** It holds a token, so a world-readable file is treated as a mistake rather than a preference.
- **A token belongs to an organization, not to you.** Scripts should use one rather than your personal session, so a person leaving does not break the pipeline. See [API tokens](/docs/tokens).

## Related

- [API tokens](/docs/tokens) for authenticating a script.
- [MCP server](/docs/mcp) if the thing driving klickops is an AI assistant rather than a script.
