Agent skill

env-config

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.

Stars 232
Forks 15

Install this agent skill to your Project

npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/awais68/env-config

SKILL.md

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

python
# 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

bash
# .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

bash
# .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

python
# 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

python
# 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

python
# 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

python
# 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

bash
# 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

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

# Generate database password
openssl rand -base64 32

Secret Rotation Script

python
# 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

python
# 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)

Expand your agent's capabilities with these related and highly-rated skills.

aiskillstore/marketplace

perigon-backend

Perigon ASP.NET Core + EF Core + Aspire conventions

232 15
Explore
aiskillstore/marketplace

perigon-agent

Pointers for Copilot/agents to apply Perigon conventions

232 15
Explore
aiskillstore/marketplace

perigon-angular

Angular 21+ standalone/Material/signal conventions for Perigon WebApp

232 15
Explore
aiskillstore/marketplace

fastapi-mastery

Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.

232 15
Explore
aiskillstore/marketplace

context7-efficient

Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.

232 15
Explore
aiskillstore/marketplace

browser-use

Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.

232 15
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results