# OpenClaw Config & Secrets Contract (v1)
> **Status**: normative
> **Version**: 1.0.6
> **Date**: 2026-06-04
This document defines the authoritative configuration contract for OpenClaw. It enumerates all supported environment variables, their precedence rules, and security classifications.
---
## 1. Configuration Principles
1. **Environment First**: Environment variables (`OPENCLAW_*`) always take precedence over runtime/file-based config layers.
2. **Secure by Default**: Missing optional secrets result in disabled features (fail-closed), not insecure open access.
3. **No Plaintext Storage**: Secrets MUST NOT be stored in plaintext config files committed to version control. They should be injected via environment variables or a secure secrets manager.
4. **Legacy Compatibility**: `MOLTBOT_*` keys are supported for backward compatibility but are deprecated. `OPENCLAW_*` keys are preferred.
---
## 2. Key Catalog
### 2.1 Backend LLM & AI Service
Controls the core LLM client used by nodes (Planner, Refiner, etc.).
| Variable | Required | Default | Description |
| :--- | :--- | :--- | :--- |
| `OPENCLAW_LLM_PROVIDER` | No | `openai` | Logic provider ID (e.g., `openai`, `anthropic`, `ollama`). |
| `OPENCLAW_LLM_MODEL` | No | Provider default | Specific model ID (e.g., `gpt-4o`, `claude-3-5-sonnet`). |
| `OPENCLAW_LLM_API_KEY` | **Yes*** | - | API Key for the configured provider.
*(Required unless using local provider or provider-specific key)* |
| `OPENCLAW_LLM_BASE_URL` | No | Provider default | Override base URL (crucial for local/compatible providers). |
| `OPENCLAW_LLM_TIMEOUT`| No | `120` | Request timeout in seconds. |
Optional local secret-manager path (disabled by default):
| Variable | Required | Default | Description |
| :--- | :--- | :--- | :--- |
| `OPENCLAW_1PASSWORD_ENABLED` | No | `0` | Enables optional 1Password CLI provider for API key resolution. |
| `OPENCLAW_1PASSWORD_ALLOWED_COMMANDS` | **Yes (when enabled)** | - | Comma-separated executable allowlist. Empty allowlist with enabled provider is fail-closed. |
| `OPENCLAW_1PASSWORD_CMD` | No | `op` | 1Password CLI executable name/path. Must match allowlist entry. |
| `OPENCLAW_1PASSWORD_VAULT` | **Yes (when enabled)** | - | Vault name used to resolve secret references. |
| `OPENCLAW_1PASSWORD_ITEM_TEMPLATE` | No | `openclaw/{provider}` | Item path template. In multi-tenant mode it must include both `{tenant}` and `{provider}` (default becomes `openclaw/{tenant}/{provider}`). |
| `OPENCLAW_1PASSWORD_FIELD` | No | `api_key` | Item field name containing the key value. |
| `OPENCLAW_1PASSWORD_TIMEOUT_SEC` | No | `5` | CLI lookup timeout (bounded, fail-closed on timeout). |
Lookup precedence for provider keys:
1. Provider-specific env key (`OPENCLAW_*`, legacy `MOLTBOT_*`)
2. Generic env key (`OPENCLAW_LLM_API_KEY`, legacy aliases)
3. Optional 1Password provider (if enabled and allowlist-valid)
4. Encrypted server-side secret store (`secrets.enc.json`)
Multi-tenant note:
- when `OPENCLAW_MULTI_TENANT_ENABLED=1`, 1Password lookup references become tenant-scoped and the item template must include `{tenant}` or lookup fails closed.
**SSRF Protection:**
| Variable | Default | Description |
| :--- | :--- | :--- |
| `OPENCLAW_LLM_ALLOWED_HOSTS` | - | Comma-separated list of additional exact public hosts for custom base URLs. |
| `OPENCLAW_ALLOW_ANY_PUBLIC_LLM_HOST` | `0` | Set `1` to bypass host allowlist and allow any public IP. |
| `OPENCLAW_LLM_ALLOW_PRIVATE_NETWORK` | `0` | Set `1` to allow the configured LLM `base_url` host to resolve to private/reserved IPs while keeping exact-host scope and DNS pinning. |
| `OPENCLAW_ALLOW_INSECURE_BASE_URL` | `0` | Set `1` to allow HTTP or private IP targets (Dangerous!). |
Notes:
- Local providers (`ollama`, `lmstudio`) are loopback-only by design and should use `localhost` / `127.0.0.1` / `::1`.
- Built-in local-provider defaults are OpenAI-compatible URLs:
- `ollama` -> `http://127.0.0.1:11434/v1`
- `lmstudio` -> `http://localhost:1234/v1`
- Local loopback provider targets do not require enabling insecure SSRF flags.
- `OPENCLAW_LLM_ALLOWED_HOSTS` does not allow private/reserved IPs; those require scoped `allow_private_network` for the configured LLM target or `OPENCLAW_ALLOW_INSECURE_BASE_URL=1`.
- The same scoped private-network setting and insecure override apply to config-save validation, `/openclaw/llm/models`, and outbound provider requests.
- Wildcard entries such as `*` are not supported in `OPENCLAW_LLM_ALLOWED_HOSTS`.
### 2.2 Security & Authentication
Controls access to APIs and administrative features.
| Variable | Sensitivity | Description |
| :--- | :--- | :--- |
| `OPENCLAW_ADMIN_TOKEN` | **Critical** | Bearer token for Admin Write actions (Config, Presets, Schedules).
*If unset, admin writes are loopback-only with strict checks.* |
| `OPENCLAW_OBSERVABILITY_TOKEN` | **High** | Token for Read-Only observability (Logs, Traces, Health).
*If unset, Remote observability is denied.* |
| `OPENCLAW_PUBLIC_SHARED_SURFACE_BOUNDARY_ACK` | **High** | Public-profile explicit ack that reverse-proxy path allowlist + network ACL controls are in place for shared ComfyUI/OpenClaw surface. Required by deployment-profile gate in `public` mode. |
| `OPENCLAW_WEBHOOK_AUTH_MODE` | **High** | Webhook auth mode (`bearer`, `hmac`, `bearer_or_hmac`). |
| `OPENCLAW_WEBHOOK_BEARER_TOKEN` | **High** | Bearer secret for inbound webhook auth when bearer mode is enabled. |
| `OPENCLAW_WEBHOOK_HMAC_SECRET` | **High** | HMAC secret for inbound webhook auth when hmac mode is enabled. |
| `OPENCLAW_WEBHOOK_REQUIRE_REPLAY_PROTECTION` | **High** | Set `1` to enforce replay protection for webhook requests. |
| `OPENCLAW_REQUIRE_APPROVAL_FOR_TRIGGERS` | Low | Set `1` to require admin approval for all external triggers (default: `0`). |
| `OPENCLAW_PRESETS_PUBLIC_READ` | Low | Set `0` to require Admin Token for listing presets (default: `1`). |
| `OPENCLAW_STRICT_LOCALHOST_AUTH` | Low | Legacy compatibility toggle used by preset read paths; prefer explicit `OPENCLAW_PRESETS_PUBLIC_READ` + `OPENCLAW_ADMIN_TOKEN`. |
### 2.3 Multi-tenant Boundary Contract
Controls tenant-boundary behavior for multi-tenant deployments.
| Variable | Default | Description |
| :--- | :--- | :--- |
| `OPENCLAW_MULTI_TENANT_ENABLED` | `0` | Enables fail-closed multi-tenant mode across config/secrets/connector resolution/API contexts. |
| `OPENCLAW_TENANT_HEADER` | `X-OpenClaw-Tenant-Id` | Request header used for tenant context extraction (legacy header alias still accepted). |
| `OPENCLAW_MULTI_TENANT_ALLOW_DEFAULT_FALLBACK` | `0` | If `1`, allows default tenant fallback when tenant context is missing (reduces strictness). |
| `OPENCLAW_MULTI_TENANT_ALLOW_CONFIG_FALLBACK` | `0` | If `1`, tenant config may fall back to global `llm` branch when `tenants..llm` is absent. |
| `OPENCLAW_MULTI_TENANT_ALLOW_LEGACY_SECRET_FALLBACK` | `0` | If `1`, tenant secret lookup may fall back to legacy unscoped secret keys. |
Boundary behavior:
- tenant mismatch between token context and tenant header is rejected (`tenant_mismatch`).
- connector installation resolution rejects cross-tenant matches fail-closed (`tenant_mismatch` diagnostics path).
- current admin/API handlers preserve compatibility by defaulting missing tenant context to `default`; stricter caller paths can enforce explicit-tenant requirements.
### 2.4 Connector & Delivery (Chat Apps)
Controls the `connector` sidecar process and outbound delivery.
| Variable | Platform | Description |
| :--- | :--- | :--- |
| `OPENCLAW_CONNECTOR_URL` | Core | URL of the OpenClaw backend (default: `http://127.0.0.1:8188`). |
| `OPENCLAW_CONNECTOR_ADMIN_TOKEN` | Core | Token to authenticate Connector calls to Backend. |
| `OPENCLAW_CONNECTOR_TELEGRAM_TOKEN` | Telegram | Bot API Token. |
| `OPENCLAW_CONNECTOR_TELEGRAM_ALLOWED_USERS` | Telegram | Comma-separated trusted user IDs. |
| `OPENCLAW_CONNECTOR_TELEGRAM_ALLOWED_CHATS`| Telegram | Comma-separated allowlist of logic IDs (User IDs or Chat IDs). |
| `OPENCLAW_CONNECTOR_DISCORD_TOKEN` | Discord | Bot User Token. |
| `OPENCLAW_CONNECTOR_DISCORD_ALLOWED_USERS` | Discord | Comma-separated trusted user IDs. |
| `OPENCLAW_CONNECTOR_DISCORD_ALLOWED_CHANNELS`| Discord | Comma-separated list of Channel IDs. |
| `OPENCLAW_CONNECTOR_LINE_CHANNEL_SECRET` | LINE | Channel Secret. |
| `OPENCLAW_CONNECTOR_LINE_CHANNEL_ACCESS_TOKEN`| LINE | Channel Access Token. |
| `OPENCLAW_CONNECTOR_LINE_ALLOWED_USERS` | LINE | Comma-separated trusted user IDs. |
| `OPENCLAW_CONNECTOR_LINE_ALLOWED_GROUPS` | LINE | Comma-separated trusted group IDs. |
| `OPENCLAW_CONNECTOR_WHATSAPP_ACCESS_TOKEN` | WhatsApp | Cloud API access token. |
| `OPENCLAW_CONNECTOR_WHATSAPP_APP_SECRET` | WhatsApp | App secret for webhook signature validation. |
| `OPENCLAW_CONNECTOR_WHATSAPP_ALLOWED_USERS` | WhatsApp | Comma-separated trusted `wa_id` values. |
| `OPENCLAW_CONNECTOR_WECHAT_TOKEN` | WeChat | Webhook verification token. |
| `OPENCLAW_CONNECTOR_WECHAT_APP_ID` | WeChat | Official Account AppID. |
| `OPENCLAW_CONNECTOR_WECHAT_APP_SECRET` | WeChat | Official Account AppSecret. |
| `OPENCLAW_CONNECTOR_WECHAT_ALLOWED_USERS` | WeChat | Comma-separated trusted OpenID values. |
| `OPENCLAW_CONNECTOR_KAKAO_ENABLED` | KakaoTalk | Enables Kakao adapter when truthy. |
| `OPENCLAW_CONNECTOR_KAKAO_ALLOWED_USERS` | KakaoTalk | Comma-separated trusted user IDs. |
| `OPENCLAW_CONNECTOR_SLACK_BOT_TOKEN` | Slack | Bot OAuth token (`xoxb-*`). |
| `OPENCLAW_CONNECTOR_SLACK_SIGNING_SECRET` | Slack | Ingress signature secret. |
| `OPENCLAW_CONNECTOR_SLACK_APP_TOKEN` | Slack | Optional Socket Mode app token (`xapp-*`). |
| `OPENCLAW_CONNECTOR_SLACK_CLIENT_ID` | Slack | OAuth client ID for multi-workspace installation flow. |
| `OPENCLAW_CONNECTOR_SLACK_CLIENT_SECRET` | Slack | OAuth client secret for multi-workspace installation flow. |
| `OPENCLAW_CONNECTOR_SLACK_OAUTH_REDIRECT_URI` | Slack | Explicit OAuth callback URL. Falls back to `OPENCLAW_CONNECTOR_PUBLIC_BASE_URL + OPENCLAW_CONNECTOR_SLACK_OAUTH_CALLBACK_PATH` when omitted. |
| `OPENCLAW_CONNECTOR_SLACK_OAUTH_INSTALL_PATH` | Slack | Local install route path (default `/slack/install`). |
| `OPENCLAW_CONNECTOR_SLACK_OAUTH_CALLBACK_PATH` | Slack | Local OAuth callback route path (default `/slack/oauth/callback`). |
| `OPENCLAW_CONNECTOR_SLACK_OAUTH_SCOPES` | Slack | Comma-separated bot scopes for install URL generation. |
| `OPENCLAW_CONNECTOR_SLACK_OAUTH_STATE_TTL_SEC` | Slack | TTL for single-use OAuth state tokens (default `600`, clamped to `60..3600`). |
| `OPENCLAW_CONNECTOR_SLACK_ALLOWED_USERS` | Slack | Comma-separated trusted user IDs. |
| `OPENCLAW_CONNECTOR_SLACK_ALLOWED_CHANNELS` | Slack | Comma-separated trusted channel IDs. |
| `OPENCLAW_CONNECTOR_FEISHU_APP_ID` | Feishu/Lark | App ID for the default binding. |
| `OPENCLAW_CONNECTOR_FEISHU_APP_SECRET` | Feishu/Lark | App secret for the default binding. |
| `OPENCLAW_CONNECTOR_FEISHU_VERIFICATION_TOKEN` | Feishu/Lark | Verification token for webhook event ingress. |
| `OPENCLAW_CONNECTOR_FEISHU_ENCRYPT_KEY` | Feishu/Lark | Optional encrypt key for encrypted webhook payloads. |
| `OPENCLAW_CONNECTOR_FEISHU_ACCOUNT_ID` | Feishu/Lark | Explicit account ID for the default binding. |
| `OPENCLAW_CONNECTOR_FEISHU_DEFAULT_ACCOUNT_ID` | Feishu/Lark | Fallback account ID for multi-binding setups. |
| `OPENCLAW_CONNECTOR_FEISHU_WORKSPACE_ID` | Feishu/Lark | Workspace or tenant identifier associated with the binding. |
| `OPENCLAW_CONNECTOR_FEISHU_WORKSPACE_NAME` | Feishu/Lark | Human-readable workspace name surfaced in diagnostics. |
| `OPENCLAW_CONNECTOR_FEISHU_BINDINGS_JSON` | Feishu/Lark | JSON list of account/workspace binding records for multi-account setups. |
| `OPENCLAW_CONNECTOR_FEISHU_ALLOWED_USERS` | Feishu/Lark | Comma-separated trusted user IDs. |
| `OPENCLAW_CONNECTOR_FEISHU_ALLOWED_CHATS` | Feishu/Lark | Comma-separated trusted chat IDs. |
| `OPENCLAW_CONNECTOR_FEISHU_DOMAIN` | Feishu/Lark | API domain selector (`feishu` or `lark`). |
| `OPENCLAW_CONNECTOR_FEISHU_MODE` | Feishu/Lark | Transport mode (`websocket` or `webhook`). |
| `OPENCLAW_CONNECTOR_FEISHU_CALLBACK_PATH` | Feishu/Lark | Local interactive callback route path (default `/feishu/callback`). |
| `OPENCLAW_CONNECTOR_RATE_LIMIT_USER_RPM` | Core | Per-user connector rate limit (default `10`, clamped to `1..600`). |
| `OPENCLAW_CONNECTOR_RATE_LIMIT_CHANNEL_RPM` | Core | Per-channel connector rate limit (default `30`, clamped to `1..600`). |
| `OPENCLAW_CONNECTOR_MAX_COMMAND_LENGTH` | Core | Max accepted connector command text length (default `4096`, clamped to `128..32768`). |
Connector posture rules:
- In strict posture (`OPENCLAW_DEPLOYMENT_PROFILE=public` or `OPENCLAW_RUNTIME_PROFILE=hardened`), active connector platforms without allowlist coverage are fail-closed.
- Public deployment profile check surfaces this as `DP-PUBLIC-009`.
- Connector reply visibility is policy-driven and does not introduce new secret/config knobs: text-only silent/internal/tool-only/no-mention replies can be suppressed by context, while approval cards and action buttons remain deliverable.
- Connector replay handling treats duplicate committed events as successful no-ops and allows retry only for failures before action/delivery commit.
- Slack multi-workspace installs persist only encrypted token refs in `connector_installations.json`; raw bot/app tokens remain in encrypted secret storage and must not appear in diagnostics or exported config surfaces.
- Feishu/Lark bindings persist normalized installation identity plus secret references only; app secrets and callback signing material must stay in encrypted/local secret storage and must not appear in diagnostics or exported config surfaces.
- Connector service-env propagation preserves only structured env-backed SecretRef metadata for supported connector credential variables. It reports secret-blind status/reason fields and rejects raw secrets, legacy marker strings, unsupported env names, missing envs, and runtime-only auth tokens such as admin, worker, and bridge tokens. Raw token values must not be written into diagnostics or service metadata.
- Connector bind-port envs (`OPENCLAW_CONNECTOR_LINE_PORT`, `...WHATSAPP_PORT`, `...WECHAT_PORT`, `...KAKAO_PORT`, `...SLACK_PORT`, `...FEISHU_PORT`) must stay within `1..65535`; invalid or out-of-range values fall back to the documented platform defaults instead of crashing startup.
**Delivery & Media:**
| Variable | Description |
| :--- | :--- |
| `OPENCLAW_CONNECTOR_DELIVERY_TIMEOUT_SEC` | Timeout (sec) for delivering results to chat (default `600`, clamped to `30..3600`). |
| `OPENCLAW_CONNECTOR_PUBLIC_BASE_URL` | Public base URL for serving images to LINE/Webhooks. |
| `OPENCLAW_CONNECTOR_MEDIA_PATH` | Local directory for staging media files. |
| `OPENCLAW_CONNECTOR_DELIVERY_MAX_IMAGES` | Max completed images delivered per job (default `4`, clamped to `1..16`). |
| `OPENCLAW_CONNECTOR_DELIVERY_MAX_BYTES` | Per-image delivery cap in bytes (default `10485760`, clamped to `65536..52428800`). |
| `OPENCLAW_CONNECTOR_MEDIA_TTL_SEC` | Media expiry in seconds (default `300`, clamped to `60..86400`). |
| `OPENCLAW_CONNECTOR_MEDIA_MAX_MB` | Max staged media size in MB (default `8`, clamped to `1..64`). |
### 2.5 External Tools and Runtime Hygiene
External tool execution is opt-in and admin-gated. Package-owned defaults, runtime state, and local validation artifacts are separate ownership classes.
| Variable | Default | Description |
| :--- | :--- | :--- |
| `OPENCLAW_ENABLE_EXTERNAL_TOOLS` | `false` | Enables `/openclaw/tools` and `/openclaw/tools/{name}/run`. Keep disabled unless a reviewed deployment needs allowlisted external CLI execution. |
| `OPENCLAW_TOOLS_CONFIG_PATH` | package `data/tools_allowlist.json` | Explicit path to a custom tools allowlist. If unset, OpenClaw uses the package-owned shipped allowlist rather than a state-dir shadow file. |
| `OPENCLAW_TOOL_SANDBOX_RUNTIME_AVAILABLE` | `1` | Runtime availability marker used by hardened tool execution diagnostics. In hardened mode, `0` fails closed before tool execution. |
| `OPENCLAW_TOOL_SANDBOX_DIR` | `{state_dir}/tool_sandbox` | Optional override for external-tool scratch/temp workspace. Legacy alias: `MOLTBOT_TOOL_SANDBOX_DIR`. |
Ownership rules:
- package resources such as the default tool allowlist are read from the installed custom-node pack
- state-owned runtime cache/sandbox paths live under `OPENCLAW_STATE_DIR` unless explicitly overridden
- repo-local generated folders such as `.tmp/`, `.venv/`, and `node_modules/` are local tooling artifacts, not runtime state
- OpenClaw does not automatically repair, migrate, or delete runtime dependency caches
- tool execution results classify common local failures with deterministic diagnostics such as `sandbox_runtime_unavailable`, `interpreter_missing`, `timeout`, and `workspace_violation`
### 2.6 Execution Budgets & Limits
Contractual limits to prevent resource exhaustion.
| Variable | Default | Description |
| :--- | :--- | :--- |
| `OPENCLAW_MAX_INFLIGHT_SUBMITS_TOTAL` | `2` | Max concurrent jobs submitted to ComfyUI. |
| `OPENCLAW_MAX_INFLIGHT_SUBMITS_WEBHOOK`| `1` | Max concurrent jobs from Webhooks. |
| `OPENCLAW_MAX_INFLIGHT_SUBMITS_TRIGGER`| `1` | Max concurrent jobs from trigger/manual fire paths. |
| `OPENCLAW_MAX_INFLIGHT_SUBMITS_SCHEDULER`| `1` | Max concurrent jobs from scheduler paths. |
| `OPENCLAW_MAX_INFLIGHT_SUBMITS_BRIDGE` | `1` | Max concurrent jobs from Bridge/Sidecar. |
| `OPENCLAW_MAX_INFLIGHT_SUBMITS_PER_TENANT` | `1` | Per-tenant concurrent submit cap (applies when multi-tenant mode is enabled). |
| `OPENCLAW_MAX_RENDERED_WORKFLOW_BYTES` | `524288` | Max size (bytes) of a rendered workflow JSON (512KB). |
### 2.7 Runtime & Diagnostics
| Variable | Description |
| :--- | :--- |
| `OPENCLAW_STATE_DIR` | Directory for persistent state (DBs, history, logs, runtime cache). Defaults to the platform user-data directory, such as `%LOCALAPPDATA%\comfyui-openclaw\`, `~/Library/Application Support/comfyui-openclaw/`, or `~/.local/share/comfyui-openclaw/`. |
| `OPENCLAW_LOG_TRUNCATE_ON_START` | Set `1` to truncate active log file (`openclaw.log`) once at process startup before new handlers write records. |
| `OPENCLAW_STARTUP_WARMUP_TIMEOUT_SEC` | Optional timeout for non-blocking startup warmups. Warmup timeout degrades health diagnostics but does not block required route startup. |
| `OPENCLAW_DIAGNOSTICS` | Comma-separated list of subsystems to enable debug logging for (e.g. `webhook.*,templates`). Safe-redacted. |
| `OPENCLAW_CONNECTOR_DEBUG` | Set `1` to enable verbose debug logging in Connector. |
Runtime guardrails contract (ENV-driven, runtime-only):
- `GET /openclaw/config` may include a `runtime_guardrails` diagnostics object describing effective runtime caps, sources, and degraded status.
- Runtime guardrails are evaluated at runtime (deployment/runtime profile aware) and are not part of the persisted user config contract.
- `PUT /openclaw/config` rejects attempts to persist `runtime_guardrails` / legacy guardrail payloads; callers must change the underlying environment variables instead.
---
## 3. Secret Rotation & Migration
### 3.1 Rotation Procedure
To rotate a secret (e.g., `OPENCLAW_ADMIN_TOKEN` or `OPENCLAW_LLM_API_KEY`):
1. **Update Environment**: Change the value in your `.env` file or environment configuration.
2. **Restart**: Restart ComfyUI (and the Connector process if running).
3. **Verify**: Check `/openclaw/health` to ensure services initialized correctly.
*Note: There is no zero-downtime rotation support in v1. Restart is required.*
### 3.2 Key Precedence
If multiple layers are configured for the same purpose, the following order applies:
1. Environment variable layer (`OPENCLAW_*` preferred, `MOLTBOT_*` fallback only when preferred key is absent)
2. Runtime override (process-local, non-persisted)
3. File-based config (`OPENCLAW_STATE_DIR/config.json`)
4. Defaults (Lowest priority)
### 3.3 Persistence
Non-secret configuration (such as enabled/disabled flags, feature toggles) may be persisted in the `OPENCLAW_STATE_DIR/config.json` via the Settings API. Runtime overrides (if enabled by internal callers) are process-local and non-persisted. **Environment variables always override runtime and persisted settings**.
Multi-tenant persistence note:
- global LLM settings are stored under `llm`
- tenant-specific settings are stored under `tenants..llm`
- tenant fallback to global config is disabled by default and requires `OPENCLAW_MULTI_TENANT_ALLOW_CONFIG_FALLBACK=1`
Persistence guardrails:
- Runtime-only guardrail fields (for example `runtime_guardrails` and legacy guardrail aliases) are stripped/ignored when loading persisted config and rejected on `/config` write requests.
- This prevents runtime safety caps (timeouts/retries/provider safety clamps) from being silently converted into mutable persisted settings.