ztnet 0.1.17

ZTNet CLI — manage ZeroTier networks via ZTNet
# Configuration

ztnet-cli uses a TOML configuration file with named profiles. This document covers the file format, environment variables, and how configuration values are resolved.

## Config file location

| Platform | Default path |
|----------|-------------|
| Linux | `~/.config/ztnet/config.toml` or `$XDG_CONFIG_HOME/ztnet/config.toml` |
| macOS | `~/Library/Application Support/ztnet/config.toml` |
| Windows | `%APPDATA%\ztnet\config.toml` |

Print the path on your system:

```bash
ztnet config path
```

The config file is created automatically when you first run `auth set-token` or `config set`.

## File format

```toml
active_profile = "default"

[host_defaults]
"http://localhost:3000" = "default"

[profiles.default]
host = "http://localhost:3000"
token = "your-api-token-here"
default_org = ""
default_network = ""
output = "table"
timeout = "30s"
retries = 3

[profiles.production]
host = "https://ztnet.example.com"
token = "prod-api-token"
output = "json"
timeout = "60s"
```

### Top-level keys

| Key | Type | Description |
|-----|------|-------------|
| `active_profile` | string | Name of the profile to use by default. Defaults to `"default"` if not set. |
| `host_defaults` | table | Map of canonical host keys (e.g. `"https://ztnet.example.com"`) to the default profile name for that host. Used when `--host` is set without `--profile`. |
| `profiles` | table | Map of profile names to their configuration. |

### Profile keys

| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `host` | string | `http://localhost:3000` | Base URL of the ZTNet instance |
| `token` | string | _(none)_ | API token (`x-ztnet-auth` header value) |
| `default_org` | string | _(none)_ | Default organization ID or name for `--org` |
| `default_network` | string | _(none)_ | Default network ID or name for `--network` |
| `output` | string | `table` | Output format: `table`, `json`, `yaml`, `raw` |
| `timeout` | string | `30s` | HTTP timeout in [humantime]https://docs.rs/humantime format (e.g., `30s`, `2m`, `1h`) |
| `retries` | integer | `3` | Number of retries for transient errors (5xx, timeouts, rate limits) |

## Environment variables

Environment variables override config file values but are overridden by CLI flags.

| Variable | Maps to | Description |
|----------|---------|-------------|
| `ZTNET_HOST` | `--host` | ZTNet base URL |
| `API_ADDRESS` | `--host` | Alternative (zt2hosts compat) |
| `ZTNET_TOKEN` | `--token` | API token |
| `ZTNET_API_TOKEN` | `--token` | Alternative (zt2hosts compat) |
| `ZTNET_PROFILE` | `--profile` | Profile name |
| `ZTNET_OUTPUT` | `--output` | Output format |

Example:

```bash
export ZTNET_HOST=https://ztnet.example.com
export ZTNET_TOKEN=sk_your_token
ztnet network list
```

## Precedence

Configuration values are resolved in this order (highest priority first):

1. **CLI flags** (`-H`, `-t`, `--org`, `--output`, etc.)
2. **Environment variables** (`ZTNET_HOST`, `ZTNET_TOKEN`, etc.)
3. **Config file** (active profile in `config.toml`)
4. **Hardcoded defaults** (`http://localhost:3000`, `table` output, `30s` timeout, 3 retries)

**Note:** When `--host` (or `ZTNET_HOST` / `API_ADDRESS`) is set and `--profile` is **not** set, ztnet-cli will select a profile for that host using `host_defaults` (or the first matching profile by name). Stored tokens/sessions are only used when the selected profile’s host matches the target host.

## Managing profiles

### Create / switch profiles

```bash
# Save a token to a specific profile
ztnet --profile staging config set host https://staging.example.com
ztnet --profile staging auth set-token STAGING_TOKEN

# Switch the active profile
ztnet auth profiles use staging

# List all profiles
ztnet auth profiles list
```

**Note:** `auth set-token` validates the token against the server by default. Use `--no-validate` to skip the check.

### Host defaults (host-bound auth)

Profiles can share the same host (multiple credential sets per ZTNet instance). To control which profile is used when you target a host without passing `--profile`, configure a per-host default:

```bash
ztnet auth hosts set-default https://ztnet.example.com production
ztnet auth hosts set-default https://staging.example.com staging
ztnet auth hosts list
```

This updates the top-level `[host_defaults]` mapping in `config.toml`.

### View current config

```bash
# Show the effective auth context (host, profile, token, org, network)
ztnet auth show

# Show the full merged configuration
ztnet config list
```

### Set context defaults

Set a default org and/or network so you don't need `--org` and `--network` on every command:

```bash
# Set defaults
ztnet config context set --org my-org --network my-network

# Show current context
ztnet config context show

# Clear defaults
ztnet config context clear
```

## Config commands

| Command | Description |
|---------|-------------|
| `config path` | Print the config file path |
| `config get <KEY>` | Get a config value (e.g., `profiles.default.host`) |
| `config set <KEY> <VALUE>` | Set a config value |
| `config unset <KEY>` | Remove a config value |
| `config list` | Print the full effective config (tokens redacted) |
| `config context show` | Show default org/network for the active profile |
| `config context set` | Set default org and/or network |
| `config context clear` | Clear default org and network |

### Host normalization and validation

When setting a host (`config set host <URL>` or `profiles.<name>.host`), ztnet-cli normalizes the URL (trims whitespace, infers a scheme, removes trailing slashes) and validates it against the server by default (including correcting a missing/extra `/api` if needed). Use `--no-validate` to skip the server check.

If a request fails because the host was configured with (or without) a trailing `/api` incorrectly, the CLI can auto-retry with the other variant and print a banner with a suggested fix (unless `--quiet`).

### Dotted key examples

```bash
ztnet config get active_profile
ztnet config set host https://ztnet.example.com
ztnet config set profiles.default.host https://ztnet.example.com   # equivalent
ztnet config set profiles.default.output json
ztnet config set profiles.default.timeout 60s
ztnet config set profiles.default.retries 5
ztnet config unset profiles.default.default_org

# Skip host validation (format is still normalized)
ztnet config set host https://ztnet.example.com --no-validate
```