Environment Variable Reference
Applies to: ChengOS v0.2.0+ | Last verified: 2026-09-25 | Source:
deploy/.env.example,deploy/generate-env.sh,crates/cheng-api/src/services/env_settings/registry.rs,config/decision_providers.toml
Every ChengOS deployment mode — native, Docker, and distributed — reads the same
deploy/.env file. This page is the parameter dictionary. For how to actually deploy, see
Install ChengOS and Docker deployment.
Start from the template rather than an empty file:
cp deploy/.env.example deploy/.env
chengos.sh install and generate-env.sh fill in generated secrets and derive ports and
paths, so in most cases you edit only what you want to differ from the defaults.
.env is instance-owned: an upgrade never overwrites it. Defaults introduced by a newer
release — such as the loopback API binding in v0.2.0 — apply to new installs only, so compare
your file against the new .env.example after each upgrade.
Required secrets
These have placeholder values in the template. An installation that leaves them unchanged is not secure. Generate each one before exposing the system.
| Variable | Generate with | Notes |
|---|---|---|
CREDENTIAL_MASTER_KEY_1 | openssl rand -hex 32 | Encrypts every stored credential. Losing it makes stored credentials unrecoverable; changing it strands the existing ones. |
JWT_SECRET | openssl rand -hex 32 | Signs API access tokens. Changing it invalidates every issued session. |
POSTGRES_PASSWORD | openssl rand -hex 16 | Must match the password inside DATABASE_URL. |
REDIS_PASSWORD | openssl rand -hex 16 | Must match the password inside REDIS_URL. |
Datastore connections
DATABASE_URL=postgres://tianai_db:<password>@127.0.0.1:5432/master_router
REDIS_URL=redis://:<password>@127.0.0.1:6379
QDRANT_URL=http://127.0.0.1:6334
The hostname depends on the deployment mode: 127.0.0.1 for native and managed-process
installs, the Compose service names postgres / redis / qdrant for Docker, and your
own host for distributed installs.
Agent memory nodes read the connection as discrete values rather than a URL, so these must
stay consistent with DATABASE_URL and REDIS_URL:
| Variable | Default |
|---|---|
DB_HOST / DB_PORT | 127.0.0.1 / 5432 |
DB_NAME / DB_USER / DB_PASSWORD | master_router / tianai_db / — |
REDIS_HOST / REDIS_PORT / REDIS_DB | 127.0.0.1 / 6379 / 0 |
Pool tuning is available for both: DATABASE_MAX_CONNECTIONS (10),
DATABASE_MIN_CONNECTIONS (1), DATABASE_CONNECTION_TIMEOUT (30), and the matching
REDIS_MAX_CONNECTIONS, REDIS_MIN_CONNECTIONS, REDIS_CONNECTION_TIMEOUT.
Ports and server binding
| Variable | Default | Service |
|---|---|---|
PORT / API_PORT | 19225 | API backend and WebSocket |
UI_PORT | 8080 | Visual editor and admin console |
APP_PORT | 5055 | Chat app and mobile H5 |
BIND_ADDRESS | 127.0.0.1 | API bind address |
UI_BIND / APP_BIND | 0.0.0.0 | Interface the native UI / app servers listen on |
The API stays on loopback in every supported layout: the UI and app servers proxy /api and
/ws to it, and the CLI and health checks dial 127.0.0.1. 0.0.0.0 would put the API on the
network beside the hardened frontends rather than behind them. A remote CLI or desktop client
should go through your reverse proxy on 443 instead.
UI_BIND / APP_BIND select an interface; they are not access control. Use 127.0.0.1 when
the proxy is on the same host, or a private/VPN address of this host when it is elsewhere.
Docker ignores all three: docker-compose.yml publishes host ports to 127.0.0.1 only and pins
BIND_ADDRESS=0.0.0.0 inside the API container, because the UI container must reach it over
the Compose network.
Edge and proxy trust
| Variable | Default | Notes |
|---|---|---|
TRUSTED_PROXY_IPS | empty | Comma-separated addresses or CIDRs of proxies allowed to report a visitor's real IP. Loopback and RFC 1918 peers are trusted without being listed; a proxy on a public or CGNAT (100.64.0.0/10) address must be listed, or every visitor shares one rate-limit bucket. |
TRUST_CLOUDFLARE | false | Also trust Cloudflare's ranges and read CF-Connecting-IP. Toggle with ./chengos.sh cloudflare on|off. |
CSP_CONNECT_SRC_EXTRA | empty | Extra origins, space-separated, for the frontends' CSP connect-src. |
See Hardening a Public Deployment for how these fit together.
Release pinning
| Variable | Default | Notes |
|---|---|---|
CHENGOS_VERSION | latest | The single release pin for all four Docker images. Set an exact version in production. |
CHENGOS_<SERVICE>_IMAGE | unset | Per-image override for private registries. Any override disables coordinated release updates. |
CHENGOS_IMAGE | chengos/chengos:latest | Legacy alias for older Compose overlays. Prefer CHENGOS_VERSION. |
Runtime behaviour
| Variable | Default | Notes |
|---|---|---|
RUN_MIGRATIONS | true | Apply database migrations on startup. Ignored while demo mode is on. |
CHENG_DEMO_MODE | false | Fail-closed public demo allowlist. Initialize the demo user before enabling. See demo mode. |
CHENG_DEMO_USER_EMAIL | unset | The ordinary, non-admin account demo visitors are signed in as. |
RUST_LOG | info | Log level. |
RUST_BACKTRACE | 1 | Include backtraces in error logs. |
DB_INSTALL_MODE | managed-process | managed-process (user sandbox, no root) or system-service (apt + systemd, needs sudo). |
ENABLE_REDIS | false | Turn on when using agent memory. |
ENABLE_QDRANT | false | Turn on when using RAG retrieval. |
Scheduler
Governs timed and triggered workflow runs.
| Variable | Default | Notes |
|---|---|---|
SCHEDULER_ENABLED | true | Master switch. |
SCHEDULER_NODE_ID | node-1 | Must be unique per instance in a multi-instance deployment. |
SCHEDULER_MAX_CONCURRENCY | 8 | Simultaneous scheduled executions. |
SCHEDULER_HOT_WINDOW_SECS | 60 | Look-ahead for imminent jobs. |
SCHEDULER_WARM_WINDOW_SECS | 300 | Look-ahead for upcoming jobs. |
SCHEDULER_SWEEPER_INTERVAL_SECS | 30 | Sweep interval for due jobs. |
SCHEDULER_LOCK_TIMEOUT_SECS | 60 | Lock lease before another instance may claim a job. |
CORS
CORS_PERMISSIVE=false
CORS_ALLOWED_ORIGINS=
CORS is deny-by-default, because every supported deployment is same-origin: the UI and app
servers proxy /api and /ws themselves. Fill CORS_ALLOWED_ORIGINS (comma-separated) only
when a browser on a different origin must call the API. CORS_PERMISSIVE=true allows any
origin, logs a warning on every start, and is for local experiments only.
Workspaces and sandboxes
| Variable | Notes |
|---|---|
CHENG_CLI_ALLOWED_ROOTS | Colon-separated absolute directories usable as CLI sandboxes. CLI sessions are disabled entirely if this is unset. The CLI and API must see these paths in the same filesystem namespace. |
CHENG_WORKSPACE_ROOT | Base directory for code_shell / code_python when no CLI sandbox is present. Defaults to {repo_root}/workspaces or ./workspaces. |
SKILLS_DIR | Skill library location. Default ./skills. |
NODE_SKILLS_DIR | Per-node skill definitions. Docker default /app/node_skills. |
CHENG_GLOBAL_CONFIG_DIR | Shared shortcuts.yaml and presets.yaml. Docker /app/config; native auto-detects. Per-workspace configs override these. |
TEMPLATE_WORKFLOWS_DIR | Read-only built-in workflow templates installed into new workspaces on bootstrap. Docker /app/workflow-templates; native auto-detects. |
Agent tool approval — see Tool-call Approval Policy:
| Variable | Notes |
|---|---|
CHENG_FILE_OPS_PROTECTED_PATTERNS | Comma-separated gitignore-style patterns added to the built-in protected paths. It can only add. |
CHENG_TRUSTED_AUTOMATION_POLICY_FILE | JSON file of scoped entries that let named workflows run deletes, moves, and rollbacks unattended. |
CHENG_WORKSPACE_PROCESS_APPROVAL_DISABLED | true removes the approval gate on workspace shell and test runs for the whole deployment. Trusted automation servers only. |
Decision models
Settings for the typed decision providers behind ai/decision_branch. They are read once at
startup. Details: Decision Providers & TypeSafe Jev.
| Variable | Default | Notes |
|---|---|---|
JEV_API_KEY | unset | Deployment-managed TypeSafe Jev key, used by nodes that select no credential. Routed request text is sent to TypeSafe. |
JEV_DEFAULT_MODEL | jev-1.13.0 | Jev model when neither the node nor its credential pins one. Use an exact version with a calibration profile. |
CHENG_DECISION_PROVIDERS_TOML | unset | Replacement for the shipped decision_providers.toml. An invalid file is ignored. |
CHENG_DECISION_CALIBRATION_TOML | unset | Replacement for the shipped calibration profiles. An invalid file is ignored. |
LAYA_ENABLED | false | Enable the local Laya decision model (laya serve). |
LAYA_PORT | 1215 | Laya on the API host's loopback. Never 8080, which UI_PORT uses. |
LAYA_ENDPOINT | unset | Full Laya address instead, e.g. http://host.docker.internal:1215 from Docker. |
LAYA_TRUSTED_NETWORK | false | Allow a non-loopback plain-http LAYA_ENDPOINT. |
LAYA_DEFAULT_MODEL | multilingual | Laya family when a node names none. |
LAYA_API_KEY | unset | Bearer token shared with laya serve. |
LAYA_ARTIFACT_SHA256, LAYA_ARTIFACT_SHA256_<FAMILY> | unset | SHA-256 pin of the served GGUF; calibration applies only to a pinned file. |
LAYA_BIN, LAYA_MODEL_PATH, LAYA_MODELS_DIR, LAYA_DEVICE, LAYA_LD_LIBRARY_PATH | unset | Native mode only: let hybrid/start.sh launch and verify laya serve. Leave empty to run it yourself. |
Jev endpoints and decision timeouts are TOML settings in decision_providers.toml, not
environment variables.
Code execution and model endpoints
| Variable | Default | Notes |
|---|---|---|
CHENG_ENABLE_CODE_PYTHON | true | Enables the tools/code_python node. |
CHENG_ENABLE_CODE_JS | true | Enables the tools/code_js node. |
ALLOW_PRIVATE_LLM_ENDPOINTS | true | Permits model endpoints on private network addresses, such as a local Ollama. Set false to block requests to private ranges. |
Optional integrations
MCP — MCP_ENABLED (false) mounts the app-level MCP server at /mcp.
MCP_SERVER_TOKEN sets a static bearer token; leave it unset to use database-backed MCP
tokens, which is the preferred mode. MCP_GATEWAY_PORT_START (9100) is the base port for
per-workflow dynamic servers.
OAuth2 — client IDs and secrets come from each provider's app console:
OAUTH2_OPENAI_*, OAUTH2_ANTHROPIC_*, OAUTH2_GOOGLE_*, OAUTH2_GITHUB_*,
OAUTH2_MICROSOFT_*. PKCE providers need no client secret; GitHub OAuth apps generally do.
OAUTH2_REDIRECT_URI must match the redirect URI registered with the provider exactly.
Email — EMAIL_ENABLED (false), then SMTP_HOST, SMTP_PORT, SMTP_USERNAME,
SMTP_PASSWORD, SMTP_FROM, and PASSWORD_RESET_BASE_URL. Required for password reset
mail.
Public URLs — used by Docker deployments to tell the frontends where to reach the
backend: UI_API_BASE_URL (/api/v1), UI_WS_URL (/ws), APP_API_BASE_URL,
APP_WS_URL (/ws/executions), APP_CHANNEL_ID, APP_BOUND_WORKFLOW_ID, and the
externally visible PUBLIC_UI_URL, PUBLIC_APP_URL, PUBLIC_API_URL.
CLI — CHENG_SERVER_URL is the server the cheng client connects to. Docker
deployments default it to http://api:3000.
Next steps
- REST API overview — what those endpoints and headers are.
- Docker deployment — the mode-specific hostname rules.
- Hardening a Public Deployment — the binding and trust settings in context.