Claude Code Plugins

Community-maintained marketplace

Feedback

|

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name env-config
description Use when setting up environment configuration, loading .env files, or managing application settings across environments. Triggers for: .env setup, loading environment variables, Pydantic BaseSettings, configuration validation, or secret management. NOT for: code-specific logic, feature flags, or runtime feature toggles.

Environment Configuration Skill

Expert environment configuration management for Python/FastAPI projects with secure secrets handling and multi-environment support.

Quick Reference

Pattern Usage
Load .env load_dotenv() at application start
Access var settings.DB_URL, settings.JWT_SECRET
Required var Field(..., description="Database URL")
Optional var DB_HOST: str = "localhost"
Secret type SecretStr for sensitive values

Project Structure

project/
├── .env                  # Local development (NOT committed)
├── .env.example          # Template with all required vars (committed)
├── .env.staging          # Staging environment
├── .env.production       # Production environment (managed by infra)
└── config/
    ├── __init__.py
    └── settings.py       # Pydantic BaseSettings

settings.py - Base Configuration

# config/settings.py
from functools import lru_cache
from pydantic import Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    # Application
    APP_NAME: str = "ERP System"
    DEBUG: bool = False
    API_V1_PREFIX: str = "/v1"

    # Database
    DB_URL: str = Field(
        ...,
        description="PostgreSQL connection URL",
        examples=["postgresql://user:pass@localhost:5432/dbname"],
    )
    DB_POOL_SIZE: int = Field(default=5, ge=1, le=100)

    # JWT Authentication
    JWT_SECRET_KEY: SecretStr = Field(
        ...,
        description="Secret key for JWT signing",
    )
    JWT_ALGORITHM: str = "HS256"
    JWT_EXPIRATION_MINUTES: int = Field(default=15, ge=1)

    # Redis (Optional)
    REDIS_URL: str | None = None

    # Logging
    LOG_LEVEL: str = Field(default="INFO", pattern="^(DEBUG|INFO|WARNING|ERROR)$")

    # CORS
    CORS_ORIGINS: list[str] = ["http://localhost:3000"]

    @property
    def is_production(self) -> bool:
        return not self.DEBUG


@lru_cache
def get_settings() -> Settings:
    """Cached settings instance for application lifecycle."""
    return Settings()

.env.example - Template File

# .env.example - Copy to .env and fill in values
# DO NOT commit actual secrets!

# Application
APP_NAME="ERP System"
DEBUG=false
API_V1_PREFIX="/v1"

# Database (required)
DB_URL="postgresql://user:password@localhost:5432/erp_db"

# JWT Authentication (required - generate with: openssl rand -hex 32)
JWT_SECRET_KEY="your-secret-key-here-generate-with-openssl-rand-hex-32"
JWT_ALGORITHM="HS256"
JWT_EXPIRATION_MINUTES=15

# Redis (optional)
# REDIS_URL="redis://localhost:6379/0"

# Logging
LOG_LEVEL="INFO"

# CORS
CORS_ORIGINS="http://localhost:3000"

.env - Local Development

# .env - Local development only
# NEVER commit this file to version control

APP_NAME="ERP System"
DEBUG=true
API_V1_PREFIX="/v1"

# Local PostgreSQL
DB_URL="postgresql://postgres:postgres@localhost:5432/erp_dev"

# Generate with: openssl rand -hex 32
JWT_SECRET_KEY="local-dev-secret-key-change-in-production"
JWT_ALGORITHM="HS256"
JWT_EXPIRATION_MINUTES=15

# Local Redis (if using)
REDIS_URL="redis://localhost:6379/0"

LOG_LEVEL="DEBUG"

CORS_ORIGINS="http://localhost:3000,http://localhost:5173"

Usage in Application

FastAPI Application

# main.py
from contextlib import asynccontextmanager
from dotenv import load_dotenv

load_dotenv()  # Load .env file

from config.settings import get_settings


@asynccontextmanager
async def lifespan(app):
    settings = get_settings()
    print(f"Starting {settings.APP_NAME} in {'DEBUG' if settings.DEBUG else 'PROD'} mode")
    yield
    print("Shutting down...")


app = FastAPI(
    title=get_settings().APP_NAME,
    lifespan=lifespan,
)


# Include routers
from app.routers import fees, students
app.include_router(fees.router, prefix=get_settings().API_V1_PREFIX)
app.include_router(students.router, prefix=get_settings().API_V1_PREFIX)

Database Connection

# database.py
from sqlmodel import create_engine, Session
from config.settings import get_settings

settings = get_settings()

engine = create_engine(
    settings.DB_URL.get_secret_value() if hasattr(settings.DB_URL, 'get_secret_value') else settings.DB_URL,
    pool_size=settings.DB_POOL_SIZE,
    max_overflow=10,
)


def get_session():
    with Session(engine) as session:
        yield session

JWT Configuration

# auth/jwt.py
from datetime import timedelta
from config.settings import get_settings

settings = get_settings()

JWT_SECRET = settings.JWT_SECRET_KEY.get_secret_value()
JWT_ALGORITHM = settings.JWT_ALGORITHM
ACCESS_TOKEN_EXPIRE_MINUTES = settings.JWT_EXPIRATION_MINUTES


def create_access_token(data: dict, expires_delta: timedelta | None = None) -> str:
    # ... token creation logic
    pass

Multi-Environment Support

Environment-Specific Configs

# config/settings.py

class Settings(BaseSettings):
    # ... shared settings

    @classmethod
    def from_env(cls, env: str = "development") -> "Settings":
        """Load settings for specific environment."""
        env_file = {
            "development": ".env",
            "staging": ".env.staging",
            "production": ".env.production",
        }.get(env, ".env")

        return cls(_env_file=env_file)

Production Override

# Production should use environment variables, not .env files
# Set these in your deployment platform (Docker, K8s, Cloud Run, etc.)

export DB_URL="postgresql://prod_user:prod_pass@prod-db.example.com:5432/erp_prod"
export JWT_SECRET_KEY="production-secret-key-from-secrets-manager"
export DEBUG=false
export LOG_LEVEL="WARNING"

Secret Management

Generate Secrets

# Generate secure random secret
openssl rand -hex 32  # For JWT_SECRET_KEY

# Generate database password
openssl rand -base64 32

Secret Rotation Script

# scripts/rotate_secret.py
"""Rotate a secret in all environments."""
import os
import re

def rotate_secret(env_file: str, key: str, new_value: str):
    """Replace secret value in .env file."""
    with open(env_file, "r") as f:
        content = f.read()

    # Pattern to match KEY=value
    pattern = f"^{key}=.*$"
    replacement = f"{key}={new_value}"

    new_content = re.sub(pattern, replacement, content, flags=re.MULTILINE)

    with open(env_file, "w") as f:
        f.write(new_content)

    print(f"Rotated {key} in {env_file}")


if __name__ == "__main__":
    import sys
    if len(sys.argv) != 4:
        print("Usage: rotate_secret.py <env_file> <key> <new_value>")
        sys.exit(1)

    rotate_secret(sys.argv[1], sys.argv[2], sys.argv[3])

Quality Checklist

  • Validation on load: All required fields have Field(..., ...) validation
  • No leaks in logs: Use SecretStr for sensitive values, never print settings
  • .env.example committed: Template shows all required variables
  • .env.gitignored: Local development file excluded from version control
  • Secrets generated: JWT secrets use openssl rand -hex 32
  • Environment isolation: Different configs for dev/staging/production
  • Type safety: All settings have proper type annotations

Integration with Other Skills

Skill Integration Point
@jwt-auth JWT_SECRET_KEY from settings
@sqlmodel-crud DB_URL from settings
@fastapi-app All app settings from settings
@db-migration Database URL for migrations
@api-route-design API prefix, CORS origins

Security Best Practices

DO

  • Use SecretStr for passwords, API keys, tokens
  • Rotate secrets regularly
  • Use different secrets per environment
  • Store production secrets in secrets manager
  • Validate all required settings at startup

DON'T

  • Never commit .env files to version control
  • Never hardcode secrets in source code
  • Never log settings or environment variables
  • Never use default/placeholder secrets in production
  • Never expose configuration details in error messages

Startup Validation

# config/validate.py
"""Validate required configuration at startup."""
from pydantic import ValidationError
from config.settings import Settings


def validate_settings() -> bool:
    """Ensure all required settings are configured."""
    try:
        settings = Settings()
        return True
    except ValidationError as e:
        print("Configuration validation failed:")
        for error in e.errors():
            print(f"  - {error['loc'][0]}: {error['msg']}")
        return False


if __name__ == "__main__":
    if not validate_settings():
        exit(1)