> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usesink.co/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI configuration

> Where the CLI keeps its state, and every environment variable it reads.

The CLI keeps two separate things on disk, deliberately in different places: the **credential**, which belongs to a machine, and the **link**, which belongs to a repository.

## The credential

`sink login` stores your API key in the OS keychain — Keychain on macOS, Secret Service on Linux, Credential Manager on Windows. Nothing about it goes into the config file.

Where no keychain backend is available, the key falls back into the config file itself, which is written mode `0600`. `sink login` says which of the two happened, and `sink whoami` reports it under **Credential**.

```json ~/.config/sink/config.json theme={null}
{
  "api_url": "https://usesink.co",
  "email": "you@example.com",
  "name": "Your Name",
  "key_storage": "keyring"
}
```

The directory follows `XDG_CONFIG_HOME` when set, so the default is `~/.config/sink/` on Linux and macOS.

## The link file

`sink init` writes `.sink.json` into the current directory:

```json .sink.json theme={null}
{
  "workspace": { "id": "86da4d20-…", "name": "Acme" },
  "team":      { "id": "975b6812-…", "name": "Platform" },
  "project":   { "id": "8017614d-…", "name": "checkout-api" },
  "environment": "prod"
}
```

Ids and display names, no values — safe to commit, and meant to be. `pull`, `push` and `diff` find it by walking up from the working directory, so it can live at the repository root and still serve a command run three folders down.

If the file is missing an id, the CLI says which section and tells you to re-run `sink init` rather than guessing.

## Environment variables

| Variable             | Effect                                                                                   |
| -------------------- | ---------------------------------------------------------------------------------------- |
| `SINK_API_KEY`       | API key to use. **Beats** the keychain and the config file, which is what makes CI work. |
| `SINK_API_URL`       | API base URL. Overrides the stored `api_url`.                                            |
| `SINK_CONFIG_HOME`   | Directory for the config file, instead of `~/.config/sink`.                              |
| `XDG_CONFIG_HOME`    | Standard base directory, used when `SINK_CONFIG_HOME` is unset.                          |
| `SINK_RAILWAY_TOKEN` | Railway token for `sink import`.                                                         |
| `SINK_VERCEL_TOKEN`  | Vercel token for `sink import`.                                                          |
| `SINK_RENDER_TOKEN`  | Render token for `sink import`.                                                          |

Provider tokens are read for the one request that needs them and are never written to the config file or the keychain.

## Resolution order

<Steps>
  <Step title="API key">
    `SINK_API_KEY` → config file (when the key lives there) → OS keychain. Nothing found means "not logged in", and the command stops.
  </Step>

  <Step title="API URL">
    `SINK_API_URL` → `--api-url` as stored by `sink login` → the built-in default.
  </Step>

  <Step title="Scope">
    Command flags → `.sink.json` from this directory or a parent — and, for the environment, the argument you passed → the linked default.
  </Step>
</Steps>

## Files the CLI writes

| Path                         | Mode    | Contents                                                            |
| ---------------------------- | ------- | ------------------------------------------------------------------- |
| `~/.config/sink/config.json` | `0600`  | API URL, account label, and the key only when there is no keychain. |
| `.sink.json`                 | default | Workspace, team, project and environment ids. No values.            |
| `.env` (from `sink pull`)    | `0600`  | Decrypted secret values.                                            |

<Warning>
  `0600` keeps a pulled `.env` away from other users on the machine. It does nothing about version control or Docker build contexts — add `.env` to `.gitignore` and `.dockerignore` yourself.
</Warning>

## Installing without the installer

The one-line installer verifies the wheel against the deployment's manifest and links `sink` into `~/.local/bin`. To manage it yourself instead, install the published wheel with your own Python tooling:

```bash theme={null}
pipx install https://usesink.co/cli/<wheel-name>.whl
```

`GET /cli/manifest.json` names the current version and its checksum.
