Claude Control Configuration Management Module
As the project grew, configuration values started spreading everywhere. I built a configuration management module to bring Redis URLs, timeout values, session limits, and MCP server paths under a single, organized system.
Configuration Structure Design
I used Pydantic's BaseSettings to unify environment variables and YAML config files.
from pydantic_settings import BaseSettings
from pydantic import Field
from typing import Optional, List
import yaml
class RedisConfig(BaseSettings):
url: str = Field(default="redis://localhost:6379", env="REDIS_URL")
max_connections: int = Field(default=20, env="REDIS_MAX_CONN")
db: int = Field(default=0, env="REDIS_DB")
password: Optional[str] = Field(default=None, env="REDIS_PASSWORD")
class SessionConfig(BaseSettings):
max_sessions: int = Field(default=10, env="MAX_SESSIONS")
timeout_seconds: int = Field(default=3600, env="SESSION_TIMEOUT")
auto_continue: bool = Field(default=True, env="AUTO_CONTINUE")
max_iterations: int = Field(default=50, env="MAX_ITERATIONS")
class MCPConfig(BaseSettings):
mcp_dir: str = Field(default="./mcp", env="MCP_DIR")
tools_dir: str = Field(default="./tools", env="TOOLS_DIR")
auto_load: bool = Field(default=True, env="MCP_AUTO_LOAD")
class AppConfig(BaseSettings):
redis: RedisConfig = RedisConfig()
session: SessionConfig = SessionConfig()
mcp: MCPConfig = MCPConfig()
debug: bool = Field(default=False, env="DEBUG")
log_level: str = Field(default="INFO", env="LOG_LEVEL")
@classmethod
def from_yaml(cls, path: str) -> "AppConfig":
with open(path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f)
return cls(**data)
YAML Configuration File
# config.yaml
redis:
url: "redis://redis:6379"
max_connections: 50
db: 0
session:
max_sessions: 20
timeout_seconds: 7200
auto_continue: true
max_iterations: 100
mcp:
mcp_dir: "./mcp"
tools_dir: "./tools"
auto_load: true
debug: false
log_level: "INFO"
Per-Environment Configuration Overrides
Different settings can be applied for development, staging, and production environments.
class ConfigLoader:
@staticmethod
def load(env: str = None) -> AppConfig:
env = env or os.getenv("APP_ENV", "development")
base_config = AppConfig.from_yaml("config.yaml")
env_file = f"config.{env}.yaml"
if os.path.exists(env_file):
env_config = AppConfig.from_yaml(env_file)
# Override with environment-specific settings
return ConfigLoader._merge(base_config, env_config)
return base_config
@staticmethod
def _merge(base: AppConfig, override: AppConfig) -> AppConfig:
base_dict = base.model_dump()
override_dict = override.model_dump(exclude_unset=True)
merged = {**base_dict, **override_dict}
return AppConfig(**merged)
Runtime Configuration Updates
I also added the ability to update configuration at runtime via Redis, so timeouts and maximum session counts can be adjusted without restarting the server.
async def update_config(self, key: str, value: any):
await self.redis.hset("claude:config", key, json.dumps(value))
await self.redis.publish("claude:config_changed", key)
Takeaways
Modularizing configuration management made per-environment deployments much smoother. Thanks to Pydantic's validation, invalid config values are caught at startup and raise an error immediately, which cuts down debugging time significantly.