dify/cli/docs/specs/config.md

213 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: config
---
# config
> Implementation: see [`cli/src/`](../../src/). Build & test: see [`cli/README.md`](../../README.md).
Owns `config.yml`, `difyctl config` commands, env-var registry, `--env` / `X-Dify-Env` plumbing.
Identity (`hosts.yml`) lives in `auth.md §Credential storage`.
## Commands
| Command | Purpose |
|---|---|
| `difyctl config view [--json]` | Print full `config.yml` |
| `difyctl config get <key> [--json]` | Print one value; dotted path |
| `difyctl config set <key> <value>` | Set known key to validated value; atomic write |
| `difyctl config unset <key>` | Remove key → revert to built-in default; idempotent |
| `difyctl config path` | Print absolute path of `config.yml` |
| `difyctl env list [--json]` | Enumerate all env vars |
| `difyctl help environment` | Topic page — narrative over the env registry |
## File layout
```
~/.config/difyctl/
├── hosts.yml identity + tokens (owned by auth.md)
└── config.yml preferences + state (this doc)
```
Path resolution (matches `gh`):
1. `DIFY_CONFIG_DIR` env — verbatim override.
2. Per-OS default:
| OS | Default |
|---|---|
| Linux | `$XDG_CONFIG_HOME/difyctl` else `~/.config/difyctl` |
| macOS | `~/.config/difyctl` (not `~/Library/…`) |
| Windows | `%AppData%\difyctl` |
Single resolver lives in `cli/src/config/dir.ts`; `auth.md` reads `hosts.yml` from the same dir. Dir `0700`, files `0600`.
## `config.yml` schema (v1)
```yaml
version: 1
defaults:
format: table # table | json | yaml
limit: 50 # pagination default
state:
current_app: null # reserved; not yet written by any command
```
### Field ownership
| Field | Owner | Notes |
|---|---|---|
| `version` | config | Schema migration |
| `defaults.format` | config writes, output layer reads | `table` / `json` / `yaml` |
| `defaults.limit` | config writes, list commands read | Int 1200 |
| `state.current_app` | reserved; not yet written by any command | |
**No `default_host` / `default_workspace` in config.yml.** Both live in `hosts.yml` (identity state). Workspace switching via `difyctl auth use` — see `workspaces.md`.
### First run
Missing `config.yml` → treat as empty, return built-in defaults. File materializes only on first `config set` / `app use`. Zero-install still works.
## Precedence
Every setting resolves through the same chain. Higher wins.
1. Command-line flag (`--format json`, `--limit 50`, `--host …`)
2. Env var (`DIFY_FORMAT`, `DIFY_LIMIT`, `DIFY_HOST`, …)
3. `config.yml` defaults
4. `hosts.yml` session identity (read-only from this module)
5. Built-in default
**No duplication rule.** Anything in `hosts.yml` (host, workspace, account) invalid in `config.yml`. `config set default_host …` rejected.
**Per-call, not global.** Flags don't mutate files. File writes = explicit `config set` / `unset` / `app use`.
## Command details
### `config view`
```
$ difyctl config view
version: 1
defaults:
format: table
limit: 50
state:
current_app: null
```
`--json` → same structure as JSON. File absent → built-in defaults + stderr note.
### `config get <key>`
```
$ difyctl config get defaults.format
table
```
Dotted path, single scalar. Unknown key → exit 2 `config_invalid_key`. Null/unset → blank line + exit 0 (scripts branch on exit). `--json``{"key": "...", "value": ...}`.
### `config set <key> <value>`
Flow: resolve key → validate value → atomic temp-file+rename → one-line confirm. Unknown key → `config_invalid_key`. Invalid value → `config_invalid_value`. Both exit 2.
### `config unset <key>`
Remove key → revert on next resolution. Unknown → exit 2. Not set → exit 0 (idempotent).
### `config path`
Bare absolute path. Honors `DIFY_CONFIG_DIR`. Prints even if file missing. Useful: `$EDITOR "$(difyctl config path)"`.
### Known-keys registry
| Key | Type | Allowed | Default |
|---|---|---|---|
| `defaults.format` | string | `table` \| `json` \| `yaml` | `table` |
| `defaults.limit` | int | 1200 | `50` |
| `state.current_app` | string | app id (written only by R1) | `null` |
**Limit out-of-range = error, not silent clamp.** `defaults.limit` and `--limit` outside `[1, 200]` → exit 2 with `config_invalid_value` (`config set`) or `usage_invalid_flag` (`--limit` flag). Same rule for `DIFY_LIMIT` env at command resolution. CLI never silently truncates user intent.
Registry compiled into the bundle.
## Env-var registry
Compiled into the bundle. Runtime export via `difyctl env list`; narrative via `difyctl help environment`.
| Variable | Owner | Overrides | Meaning |
|---|---|---|---|
| `DIFY_CONFIG_DIR` | auth | Per-OS default | Config dir override for both files |
| `DIFY_HOST` | auth | `--host` / `hosts.yml.current_host` | Single-invocation host |
| `DIFY_WORKSPACE_ID` | auth | `--workspace` / `hosts.yml.workspace.id` | Single-invocation workspace |
| `DIFY_CREDENTIAL_STORAGE` | auth | Auto-detected backend | `file` forces file-mode |
| `DIFY_TOKEN` | auth | Stored bearer | Env escape hatch (see `auth.md §Env escape hatch`) — undocumented in `--help`. Accepts `dfoa_` / `dfoe_` only |
| `DIFY_FORMAT` | config | `defaults.format` | `table` \| `json` \| `yaml` |
| `DIFY_LIMIT` | config | `defaults.limit` | Pagination default |
| `NO_COLOR` | output | Auto color | Standard — disables all color |
| `CLICOLOR_FORCE` | output | Auto color | Force color in non-TTY |
| `DIFY_NO_PROGRESS` | output | Auto progress | Suppress spinners |
| `DIFY_PLAIN` | output | Display mode | Force plain mode |
| `DIFY_NO_VERSION_CHECK` | version | Version probe | `1` skips version check |
No `DIFY_NO_REFRESH`, `DIFY_ACCESS_TOKEN`, `DIFY_REFRESH_TOKEN`, `DIFY_CSRF_TOKEN` — refresh doesn't exist (bearer auth).
### `difyctl env list`
Human → table matching the registry above. `--json`:
```json
[{"name":"DIFY_HOST","owner":"auth","default":"...","description":"..."}]
```
### `difyctl help environment`
Topic page grouped by owner + narrative, reusing the registry data.
## Validation + schema versioning
### Strict keys
`config set` fails on:
- Unknown key → `config_invalid_key`, exit 2
- Wrong type → `config_invalid_value`, exit 2
- Known key owned by `hosts.yml` (e.g. `default_host`) → `config_invalid_key`
### Strict values
Enums checked. Ints parsed + range-checked. Unrecognized YAML fields (hand-edit path) → ignored with stderr warning:
```
warning: unknown config field 'defaults.color'; ignored
```
### Schema versioning
Every `config.yml` carries `version: <int>` at root.
| Stored | CLI supports | Behavior |
|---|---|---|
| equal | v1 = v1 | Read as-is |
| older | v1 → v2 | Step-by-step migrator on read, write back on next mutation, log `info: migrated config.yml from v1 to v2` once |
| newer | v2 > v1 | Refuse. Exit 6, `config_schema_unsupported`, stderr: `error: config.yml was written by a newer difyctl (version 2); upgrade this CLI or edit the file manually` |
Migrator framework ships as no-op until a v2 schema lands. Silent truncation = worse than a clear error.
## Concurrent writes
No file lock on `config.yml`. Mutations are user-interactive (`config set` / `app use`); the race window is tiny. Accept: two simultaneous `config set` can lose one write; later `config view` makes it obvious.
`hosts.yml` keeps `flock` as cheap insurance for any future write contention; this doesn't apply to `config.yml`.
## Error model
Exit codes follow `auth.md §Error model`. This module adds:
| Code | Exit | Trigger |
|---|---|---|
| `config_invalid_key` | 2 | `config set/get/unset` on unknown key |
| `config_invalid_value` | 2 | `config set` value outside enum/range |
| `config_schema_unsupported` | 6 | `config.yml version` > CLI supports |