Documents
Home>Documents>AI>Agent>Geny

Building a Config Management Module for Claude Control

5 min readFeb 12, 2026Feb 22, 2026

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.

Tags
config managementConfigYAMLenvironment variablesAgent