fix(deploy): prevent Docker ENV vars from overriding JSON config

The root cause: Go's env.Parse() in LoadConfig reads PICOCLAW_*
environment variables AFTER loading config.json, silently overwriting
user-provided values. Dockerfile.coolify had hardcoded Gemini defaults
(PICOCLAW_AGENTS_DEFAULTS_PROVIDER=gemini) baked into the image layer,
so even when config.json correctly said 'vllm', the env vars won.

Fix:
- entrypoint-coolify.sh: When using PICOCLAW_CONFIG_JSON (Method 1), or
  mounted config (Method 2), unset all PICOCLAW_* env vars before
  calling picoclaw so the JSON file is the single source of truth.
- docker-compose-coolify.yml: Remove hardcoded gemini defaults from
  agent and doctor services.
- Updated docs header to recommend PICOCLAW_CONFIG_JSON as primary.
This commit is contained in:
mrbeandev 2026-02-16 12:19:23 +05:30
parent 255ed66f0d
commit aaf6fdf748
2 changed files with 27 additions and 7 deletions

View file

@ -9,12 +9,15 @@
# 4. Add environment variables in Coolify's UI (see below) # 4. Add environment variables in Coolify's UI (see below)
# 5. Deploy! # 5. Deploy!
# #
# REQUIRED ENVIRONMENT VARIABLES (set in Coolify UI): # RECOMMENDED: Use PICOCLAW_CONFIG_JSON for full control:
# PICOCLAW_CONFIG_JSON — Full JSON config (overrides everything below)
#
# ALTERNATIVE: Individual environment variables:
# GEMINI_API_KEY — Your Gemini API key # GEMINI_API_KEY — Your Gemini API key
# #
# OPTIONAL ENVIRONMENT VARIABLES: # OPTIONAL ENVIRONMENT VARIABLES:
# LLM_PROVIDER — LLM provider (default: gemini) # LLM_PROVIDER — LLM provider (e.g. gemini, vllm, openrouter)
# LLM_MODEL — Model name (default: gemini-2.5-flash-lite) # LLM_MODEL — Model name (e.g. gemini-2.5-flash-lite)
# TELEGRAM_BOT_TOKEN — Telegram bot token # TELEGRAM_BOT_TOKEN — Telegram bot token
# DISCORD_BOT_TOKEN — Discord bot token # DISCORD_BOT_TOKEN — Discord bot token
# OPENROUTER_API_KEY — OpenRouter API key # OPENROUTER_API_KEY — OpenRouter API key
@ -124,8 +127,8 @@ services:
profiles: profiles:
- agent - agent
environment: environment:
- PICOCLAW_AGENTS_DEFAULTS_PROVIDER=${LLM_PROVIDER:-gemini} - PICOCLAW_AGENTS_DEFAULTS_PROVIDER=${LLM_PROVIDER:-}
- PICOCLAW_AGENTS_DEFAULTS_MODEL=${LLM_MODEL:-gemini-2.5-flash-lite} - PICOCLAW_AGENTS_DEFAULTS_MODEL=${LLM_MODEL:-}
- PICOCLAW_PROVIDERS_GEMINI_API_KEY=${GEMINI_API_KEY:-} - PICOCLAW_PROVIDERS_GEMINI_API_KEY=${GEMINI_API_KEY:-}
- PICOCLAW_PROVIDERS_OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-} - PICOCLAW_PROVIDERS_OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}
- PICOCLAW_PROVIDERS_OPENAI_API_KEY=${OPENAI_API_KEY:-} - PICOCLAW_PROVIDERS_OPENAI_API_KEY=${OPENAI_API_KEY:-}
@ -151,8 +154,8 @@ services:
profiles: profiles:
- doctor - doctor
environment: environment:
- PICOCLAW_AGENTS_DEFAULTS_PROVIDER=${LLM_PROVIDER:-gemini} - PICOCLAW_AGENTS_DEFAULTS_PROVIDER=${LLM_PROVIDER:-}
- PICOCLAW_AGENTS_DEFAULTS_MODEL=${LLM_MODEL:-gemini-2.5-flash-lite} - PICOCLAW_AGENTS_DEFAULTS_MODEL=${LLM_MODEL:-}
- PICOCLAW_PROVIDERS_GEMINI_API_KEY=${GEMINI_API_KEY:-} - PICOCLAW_PROVIDERS_GEMINI_API_KEY=${GEMINI_API_KEY:-}
- TZ=${TZ:-UTC} - TZ=${TZ:-UTC}
volumes: volumes:

View file

@ -23,6 +23,17 @@ mkdir -p "${CONFIG_DIR}"
if [ -n "${PICOCLAW_CONFIG_JSON}" ]; then if [ -n "${PICOCLAW_CONFIG_JSON}" ]; then
echo "📝 Using config from PICOCLAW_CONFIG_JSON env var" echo "📝 Using config from PICOCLAW_CONFIG_JSON env var"
echo "${PICOCLAW_CONFIG_JSON}" > "${CONFIG_FILE}" echo "${PICOCLAW_CONFIG_JSON}" > "${CONFIG_FILE}"
# CRITICAL: Unset all PICOCLAW_* env vars (except PICOCLAW_CONFIG_JSON)
# so that Go's env.Parse() does NOT override values from the JSON file.
# Without this, Dockerfile ENV defaults (e.g. PICOCLAW_AGENTS_DEFAULTS_PROVIDER=gemini)
# would silently overwrite the user's JSON config every time.
for var in $(env | grep '^PICOCLAW_' | cut -d= -f1); do
if [ "$var" != "PICOCLAW_CONFIG_JSON" ]; then
unset "$var"
fi
done
exec picoclaw "$@" exec picoclaw "$@"
fi fi
@ -36,6 +47,12 @@ fi
if [ -f "/config/config.json" ]; then if [ -f "/config/config.json" ]; then
echo "📝 Using mounted config from /config/config.json" echo "📝 Using mounted config from /config/config.json"
cp /config/config.json "${CONFIG_FILE}" cp /config/config.json "${CONFIG_FILE}"
# Same protection as Method 1: unset PICOCLAW_* env vars
for var in $(env | grep '^PICOCLAW_' | cut -d= -f1); do
unset "$var"
done
exec picoclaw "$@" exec picoclaw "$@"
fi fi