Configure Environment Variables#
This guide explains the different environment configuration files used in the SmartEM Decisions project and their specific purposes.
Overview#
The project uses multiple environment configuration patterns for different deployment scenarios:
File Pattern  | 
Purpose  | 
Gitignored  | 
Created From  | 
|---|---|---|---|
  | 
Template for local development  | 
No (committed)  | 
N/A  | 
  | 
Local development on host OS  | 
Yes  | 
Copy from   | 
  | 
Template for K8s development  | 
No (committed)  | 
N/A  | 
  | 
K8s development cluster config  | 
Yes  | 
Copy from   | 
  | 
Template for K8s staging  | 
No (committed)  | 
N/A  | 
  | 
K8s staging cluster config  | 
Yes  | 
Copy from   | 
  | 
Template for K8s production  | 
No (committed)  | 
N/A  | 
  | 
K8s production cluster config  | 
Yes  | 
Copy from   | 
  | 
Template for MCP configuration  | 
No (committed)  | 
N/A  | 
  | 
MCP server configuration  | 
Yes  | 
Copy from   | 
Environment File Types#
1. Local Development: .env#
Use Case: Running backend services directly on your host OS (outside containers) while connecting to K8s infrastructure.
When to Use:
Day-to-day development with
python -m smartem_backend.consumerRunning API server locally with
python -m smartem_backend.api_serverE2E testing with
./tools/run-e2e-test.shManual debugging and development workflows
Setup:
cp .env.example .env
# Edit .env with your local credentials
Key Configuration:
# Connect to K8s infrastructure via NodePorts
POSTGRES_HOST=localhost
POSTGRES_PORT=30432          # K8s NodePort for PostgreSQL
RABBITMQ_HOST=localhost
RABBITMQ_PORT=30672          # K8s NodePort for RabbitMQ
# Run services on host OS
HTTP_API_PORT=8000
Used By:
Python code via
load_dotenv()insmartem_backend/consumer.py,smartem_backend/utils.pyDocker
entrypoint.shwhen running containers outside KubernetesE2E test scripts (
./tools/run-e2e-test.sh)
2. Kubernetes Development: .env.k8s.development#
Use Case: Deploying SmartEM to local K8s cluster (k3s) for development.
When to Use:
Running
./tools/dev-k8s.sh upSetting up local development cluster with all services
Setup:
cp .env.example.k8s.development .env.k8s.development
# Add your DOCKER_USERNAME, DOCKER_EMAIL, DOCKER_PASSWORD (GitHub token)
Key Configuration:
# Docker/GHCR credentials for pulling container images
DOCKER_USERNAME=your-github-username
DOCKER_EMAIL=your-email@example.com
DOCKER_PASSWORD=ghp_your_github_token
# K8s internal service names (not localhost)
POSTGRES_HOST=postgres-service
POSTGRES_PORT=5432
RABBITMQ_HOST=rabbitmq-service
RABBITMQ_PORT=5672
# Credentials (can be simple for local dev)
POSTGRES_USER=username
POSTGRES_PASSWORD=password
RABBITMQ_USER=username
RABBITMQ_PASSWORD=password
Used By:
./tools/dev-k8s.shscript to create K8s Secrets and ConfigMaps
3. Kubernetes Staging: .env.k8s.staging#
Use Case: Deploying to staging Kubernetes cluster.
Setup:
cp .env.example.k8s.staging .env.k8s.staging
# Add production-like credentials and configuration
Key Differences from Development:
Real credentials (not test values)
Production-like service names and ports
Staging-specific CORS origins
May use sealed secrets instead of plain credentials
Used By:
CI/CD pipelines for staging deployments
DEPLOY_ENV=staging ./tools/dev-k8s.sh up(if adapted for remote clusters)
4. Kubernetes Production: .env.k8s.production#
Use Case: Deploying to production Kubernetes cluster.
Setup:
cp .env.example.k8s.production .env.k8s.production
# Add production credentials (should use Sealed Secrets in practice)
Security Considerations:
Should use Sealed Secrets (encrypted) instead of plain
.envfilesCredentials should be rotated regularly
Access to this file should be strictly controlled
See Manage Kubernetes Secrets for best practices
Used By:
Production CI/CD pipelines
Production deployment automation
5. MCP Configuration: .env.mcp#
Use Case: Configuring Model Context Protocol (MCP) server for Claude Code integration.
Setup:
cp .env.example.mcp .env.mcp
# Configure paths and adapter settings
Key Configuration:
SMARTEM_MCP_DATA_PATH=/path/to/epu/sessions    # Filesystem adapter
SMARTEM_MCP_API_URL=http://backend:8000        # API adapter
SMARTEM_MCP_ADAPTER=filesystem                 # Adapter selection
SMARTEM_MCP_LOG_LEVEL=INFO
Used By:
MCP server when run via Claude Code
See Use MCP Interface for details
Quick Start: First-Time Setup#
For local development on a new machine:
# 1. Copy environment templates
cp .env.example .env
cp .env.example.k8s.development .env.k8s.development
# 2. Edit .env.k8s.development with your GitHub credentials
# Required: DOCKER_USERNAME, DOCKER_EMAIL, DOCKER_PASSWORD
nano .env.k8s.development
# 3. Start K8s cluster (creates infrastructure)
./tools/dev-k8s.sh up
# 4. .env is already configured to connect to K8s NodePorts
# No changes needed unless you want custom ports
# 5. Test local development
source .venv/bin/activate
python -m smartem_backend.api_server
How Environment Variables Are Loaded#
Python Services#
All Python services use load_dotenv(override=False):
from dotenv import load_dotenv
load_dotenv(override=False)  # Loads .env but doesn't override existing env vars
Loading Priority (first wins):
Already exported environment variables (from
exportorsource .env)Variables in
.envfile (loaded byload_dotenv())Hardcoded defaults in code (if any)
Important for Testing: When running E2E tests or manual services, you must export variables BEFORE starting services:
# Export all variables from .env
set -a && source .env && set +a
# Now start services
python -m smartem_backend.api_server
python -m smartem_backend.consumer
Docker Containers#
Container behaviour depends on runtime environment:
# entrypoint.sh checks for Kubernetes
if [ -z "$KUBERNETES_SERVICE_HOST" ]; then
    # Running locally - source .env file
    source .env
else
    # Running in K8s - use ConfigMap/Secrets
    # Variables already injected by K8s
fi
Kubernetes Deployments#
When running in Kubernetes:
ConfigMaps provide non-sensitive configuration (hosts, ports, URLs)
Secrets provide sensitive data (passwords, tokens)
.envfiles are NOT used inside containersAll configuration comes from K8s resources created by
dev-k8s.sh
Common Scenarios#
Scenario 1: Local Development with K8s Infrastructure#
Goal: Run backend/agent on host OS, connect to K8s database/RabbitMQ.
# 1. Start K8s cluster
./tools/dev-k8s.sh up
# 2. Use .env (already configured for NodePorts)
cat .env
# POSTGRES_HOST=localhost
# POSTGRES_PORT=30432
# RABBITMQ_HOST=localhost
# RABBITMQ_PORT=30672
# 3. Run services on host
source .venv/bin/activate
python -m smartem_backend.api_server    # Uses .env via load_dotenv()
python -m smartem_backend.consumer -vv  # Uses .env via load_dotenv()
Scenario 2: Full K8s Deployment#
Goal: Everything runs in K8s (no host OS services).
# 1. Configure K8s environment
cp .env.example.k8s.development .env.k8s.development
# Edit with your credentials
# 2. Deploy
./tools/dev-k8s.sh up
# 3. All services run in pods
kubectl get pods -n smartem-decisions
# Access via NodePorts:
# - API: http://localhost:30080
# - Adminer: http://localhost:30808
# - RabbitMQ UI: http://localhost:30673
Scenario 3: E2E Testing#
Goal: Run automated E2E tests with recorded microscope data.
# 1. Ensure .env exists and is configured
test -f .env || cp .env.example .env
# 2. Start K8s cluster
./tools/dev-k8s.sh up
# 3. Run E2E test (script loads .env automatically)
./tools/run-e2e-test.sh
# The script does:
# - source .env (loads variables)
# - Starts services on host OS
# - Runs recorded data playback
# - Collects results
Troubleshooting#
Issue: Services can’t connect to database#
Symptom: psycopg2.OperationalError: could not connect to server
Check:
Is K8s cluster running?
kubectl get pods -n smartem-decisionsAre NodePorts accessible?
curl http://localhost:30432(should refuse connection but not timeout)Is
.envconfigured correctly?grep POSTGRES .env # Should show localhost:30432 for K8s NodePort
Issue: Docker password invalid in dev-k8s.sh#
Symptom: DOCKER_PASSWORD does not appear to be a valid GitHub token
Solution:
# Generate token: https://github.com/settings/tokens
# Or use GitHub CLI
gh auth token
# Add to .env.k8s.development
DOCKER_PASSWORD=ghp_your_token_here
Issue: Services using wrong database#
Symptom: Services connect to different database than expected.
Check loading priority:
# Unset ALL environment variables first
unset POSTGRES_HOST POSTGRES_PORT POSTGRES_DB POSTGRES_USER POSTGRES_PASSWORD
# Then load .env
set -a && source .env && set +a
# Verify variables
env | grep POSTGRES