A zhi workspace is defined by a zhi.yaml file in your project root. This file declares which providers to use, how components are organized, and what exports and apply commands are available.
version: "1"
config:
provider: structuredfile
options:
directory: ./config
transform: []
# - provider: my-transform
# options: {}
store:
provider: zhi-store-json
options:
directory: ./.zhi/store
components:
- name: database
description: "PostgreSQL database configuration"
paths:
- database/
mandatory: true
- name: redis
description: "Redis cache layer"
paths:
- redis/
dependencies:
- database
- name: monitoring
description: "Prometheus and Grafana monitoring stack"
paths:
- monitoring/
export:
templates:
- name: docker-compose
template: ./templates/docker-compose.yml.tmpl
output: ./docker-compose.override.yml
- name: env-file
format: dotenv
output: ./.env
prefix: app/env
apply:
command: "docker compose up -d"
workdir: "."
pre-export: true
env:
COMPOSE_PROJECT_NAME: "myapp"
timeout: 300
plugins:
directories:
- ~/.zhi/plugins
- ./plugins
configSpecifies the configuration provider that loads and manages config values.
| Field | Description |
|---|---|
provider |
Provider name (e.g., structuredfile). Must match a built-in or external plugin. |
options |
Provider-specific options passed to the factory function. |
The built-in structuredfile provider loads JSON and YAML files from a directory. See Structured File Provider for details.
transformA list of transform providers applied in order. Each entry has the same provider and options fields as config. Transform plugins mutate the configuration tree before display or after save.
storeSpecifies the storage backend for persisting configuration trees, component state, and optionally versioning and encryption.
| Field | Description |
|---|---|
provider |
Store provider name (e.g., zhi-store-json). |
options |
Provider-specific options. |
You can configure store authentication credentials directly in the workspace options as a fallback mechanism. This avoids having to use the interactive login tool or set environment variables for secrets.
store:
provider: vault
options:
addr: "http://127.0.0.1:8200"
mount: "kv"
auth:
method: token
credentials:
token: "hvs.xxxxx"
The auth section is consumed by the engine during initialization. If present, the engine attempts to auto-login after connecting to the store. The method must match one of the store’s supported auth methods, and credentials is a map of key-value pairs specific to that method.
Supported auth method examples for the Vault store:
| Method | Credentials |
|---|---|
token |
token |
userpass |
username, password |
approle |
role_id, secret_id |
ldap |
username, password |
kubernetes |
role, jwt |
If auto-login fails, a warning is logged and the session remains unauthenticated. Users can still log in interactively via the UI or MCP tools.
For workspaces that need automatic credential management for deployed applications, use the vault-manager store provider instead of vault. It wraps the standard vault store and adds AppRole/token generation driven by metadata labels. See Vault Credential Management for configuration details.
componentsDefines named groups of configuration paths. See Components for full details.
| Field | Required | Description |
|---|---|---|
name |
yes | Unique identifier matching [a-z][a-z0-9-]* |
description |
no | Human-readable description |
paths |
yes | List of config path prefixes this component owns |
mandatory |
no | If true, the component cannot be disabled |
dependencies |
no | Names of components this one depends on |
exportConfigures export templates. See Export and Templates.
applyConfigures the provisioning command. See Apply.
The apply section can also define multiple named targets:
apply:
default:
command: "docker compose up -d"
pre-export: true
destroy:
command: "docker compose down -v"
restart:
command: "docker compose restart"
uiConfigures which UI provider zhi edit uses by default and passes provider-specific options.
| Field | Description |
|---|---|
provider |
UI provider name (e.g., tui, webui, mcp-stdio). Overridden by zhi edit --ui. |
options |
Provider-specific options passed to the factory function. |
Available built-in UI providers:
| Provider | Description |
|---|---|
tui |
Terminal UI using Bubbletea (default, requires TTY) |
webui |
Browser-based UI served on localhost. See Web UI. |
mcp-stdio |
MCP server over stdin/stdout for LLM clients (Claude Desktop, Claude Code, Cursor) |
Example for the MCP stdio provider:
ui:
provider: mcp-stdio
options:
read_only: false
The mcp-stdio provider redirects os.Stdout to stderr internally so that stray log output does not corrupt the MCP JSON-RPC stream. LLM clients launch zhi edit --ui mcp-stdio as a child process and communicate over stdin/stdout.
An external MCP SSE plugin (zhi-ui-mcp-sse) is also available for network-based access:
ui:
provider: mcp-sse
options:
addr: "0.0.0.0:9090"
token: "my-secret-token"
| Option | Env Fallback | Default | Description |
|---|---|---|---|
addr |
ZHI_MCP_ADDR |
127.0.0.1:8091 |
HTTP listen address |
token |
ZHI_MCP_TOKEN |
(empty = no auth) | Bearer token for authentication |
Options from zhi.yaml take precedence over environment variables. See the examples directory.
Plugin options for external plugins: All provider options from zhi.yaml are propagated to external plugin processes via the ZHI_PLUGIN_OPTIONS environment variable (JSON-encoded). External plugins can read these using the pluginopts helper package from pkg/zhiplugin/pluginopts/.
pluginsOptional section to configure where zhi looks for external plugin binaries. Default: ~/.zhi/plugins/.
plugins:
directories:
- ~/.zhi/plugins
- /usr/local/lib/zhi/plugins
- ./plugins
sharing (global)Sharing configuration is set in ~/.zhi/config.yaml (not in the workspace zhi.yaml). It controls registry defaults, marketplace settings, verification policy, and update behavior:
# ~/.zhi/config.yaml
sharing:
defaultRegistry: ghcr.io
marketplace:
url: https://marketplace.zhi.dev
apiKey: zhk_abc123...
verification:
requireSignatures: false
trustedPublishers:
- zhi-project
updates:
checkInterval: 24h
autoCheck: true
autoInstall: false
See Sharing and Registries for details.
Workspaces can include a zhi-plugins.lock file that pins plugin dependencies to exact OCI digests for reproducible installations. Generate or update it with:
zhi workspace lock
See Sharing and Registries for details.
When you run any zhi command, it looks for zhi.yaml in the current directory, then walks up to parent directories until it finds one. You can override this with the --workspace flag:
zhi --workspace /path/to/project validate
Pass --verbose to any command to enable debug-level logging to stderr:
zhi validate --verbose
Logs go to stderr so that commands like zhi export --format json can still pipe cleanly to other tools.