Skip to main content
  ███████╗███╗   ██╗██╗   ██╗██████╗  ██████╗  ██████╗████████╗ ██████╗ ██████╗ 
  ██╔════╝████╗  ██║██║   ██║██╔══██╗██╔═══██╗██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗
  █████╗  ██╔██╗ ██║██║   ██║██║  ██║██║   ██║██║        ██║   ██║   ██║██████╔╝
  ██╔══╝  ██║╚██╗██║╚██╗ ██╔╝██║  ██║██║   ██║██║        ██║   ██║   ██║██╔══██╗
  ███████╗██║ ╚████║ ╚████╔╝ ██████╔╝╚██████╔╝╚██████╗   ██║   ╚██████╔╝██║  ██║
  ╚══════╝╚═╝  ╚═══╝  ╚═══╝  ╚═════╝  ╚═════╝  ╚═════╝   ╚═╝    ╚═════╝ ╚═╝  ╚═╝
  ───────────────🩺 Environment Integrity, Drift & Code Auditor 🩺───────────────

End Silent Production Outages Caused by Missing Environment Variables.

A zero-dependency CLI & GitHub Action that validates .env contracts, automatically syncs .env.example templates with intelligent masked placeholders, and audits codebases for unconfigured environment variables.

CI Action CI GitHub Marketplace Version PyPI Python Version Zero Dependencies Tests Code style: ruff License: MIT


⚡ Instant Quickstart • 💥 Problem vs. Solution • 📊 Feature Comparison • 🤖 GitHub Actions CI • 📦 Installation • ⚙️ CLI Command Reference • 🔬 Pipeline Architecture • 🚀 Benchmarks • 🧪 Test Suite • 🤝 Contributing


⚡ Instant Quickstart

Run immediately anywhere without installing via uvx:

# Verify active .env against .env.example
uvx --from envdoctor-cli envdoctor check

# Enforce bidirectional strict match (zero extra or missing keys)
uvx --from envdoctor-cli envdoctor check --strict

# Safely sync missing keys into .env.example with dummy placeholders
uvx --from envdoctor-cli envdoctor sync

# Audit source code for environment variables you forgot to define
uvx --from envdoctor-cli envdoctor audit ./src

Or install globally via pip:

pip install envdoctor-cli

💥 Problem vs. Solution

The Pain with Traditional Workflows

  • Silent Production Crashes: A developer adds STRIPE_WEBHOOK_SECRET locally, merges the PR, but forgets .env.example. The app deploys and immediately crashes on boot with KeyError or undefined.
  • Secret Leaks: When developers try to update .env.example manually, real API tokens or database credentials accidentally get committed to Git.
  • Onboarding Friction: New team members clone the repo, copy .env.example to .env, and spend hours debugging missing variables that nobody documented.
  • Dead Config Debt: Variables deleted from code years ago remain in .env forever because nobody knows if they are still used.

The Character-Aligned Before & After

┌──────────────────────────────────────────────┬──────────────────────────────────────────────┐
│ BEFORE: Manual Drift & Production Outages    │ AFTER: Automated Contract Integrity Gate     │
├──────────────────────────────────────────────┼──────────────────────────────────────────────┤
│ $ git merge feature/billing-v2               │ $ envdoctor check --strict                   │
│ $ docker compose up -d                       │                                              │
│ [!] Container web crashed:                   │ 🩺 EnvDoctor v0.2.0 — Verifying contract...   │
│     KeyError: 'STRIPE_WEBHOOK_SECRET'        │                                              │
│                                              │ [!] MISSING IN .env (Required by template):  │
│ * Why was it missing?                        │     - STRIPE_WEBHOOK_SECRET                  │
│   Developer forgot to update .env.example.   │     - DATABASE_POOL_SIZE                     │
│ * Why didn't CI catch it?                    │                                              │
│   Test suites mock environment lookups.      │ [!] DISCREPANCY DETECTED:                    │
│ * Onboarding a new teammate:                 │     .env.example requires 12 variables,      │
│   "Hey, what should I put for REDIS_PORT?"   │     but active .env only defines 10.         │
│   "Oh, that was deprecated 6 months ago."    │                                              │
│                                              │ [✗] Contract check failed with exit code 1.  │
│ * Manual sync attempt:                       │     Run 'envdoctor sync' to auto-populate.   │
│   Developer accidentally commits live API    │                                              │
│   token into .env.example. Git leak incident!│ Result: CI blocks PR before deployment!     │
└──────────────────────────────────────────────┴──────────────────────────────────────────────┘

📊 Feature Comparison

Feature EnvDoctor dotenv-linter direnv python-dotenv trufflehog
Zero Runtime Dependencies ✅ Yes (Stdlib) ❌ Needs Rust/binary ❌ Needs Shell hook ❌ Python library only ❌ Heavy Go binary
.env vs .env.example Check ✅ Yes (Built-in) ⚠️ Syntax only ❌ No ❌ No ❌ No
Secret-Safe Auto Sync (sync) ✅ Yes (Masked) ❌ No ❌ No ❌ No ❌ No
Codebase Variable Audit (audit) ✅ Yes (Multi-lang) ❌ No ❌ No ❌ No ❌ No (Secrets only)
CI Quality Gate Exit Codes ✅ Yes (0/1/2) ✅ Yes ❌ No ❌ No ✅ Yes
Never Leaks Inline Comments ✅ Yes ❌ N/A ❌ N/A ❌ N/A ❌ N/A
Machine JSON Output (--format json) ✅ Yes ⚠️ Limited ❌ No ❌ No ✅ Yes
Cold Startup Time < 15ms < 10ms ~25ms ~40ms ~250ms
GitHub Marketplace Action ✅ Yes (@v1) ⚠️ Third-party ❌ No ❌ No ⚠️ Heavy action

🤖 GitHub Actions CI/CD Quality Gate

Enforce environment contract integrity on every Pull Request. Drop EnvDoctor into .github/workflows/env-check.yml:

name: Environment Contract Verification

on:
  pull_request:
    branches: [main]

jobs:
  env-check:
    runs-on: ubuntu-latest
    steps:
      - name: Check out code
        uses: actions/checkout@v4

      - name: Verify .env contract with EnvDoctor
        uses: umutgungorr/envdoctor@v1
        with:
          command: 'check'
          env-file: '.env.example'
          example-file: '.env.example'
          args: '--strict'

📦 Installation

Option 1: Run instantly with uvx (No installation needed)

uvx --from envdoctor-cli envdoctor check

Option 2: Install via pip

pip install envdoctor-cli

Option 3: Pre-commit Hook Integration

Add to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/umutgungorr/envdoctor
    rev: v0.2.1
    hooks:
      - id: envdoctor-check
        args: ["--strict"]

⚙️ CLI Command Reference

EnvDoctor provides three focused, high-speed diagnostic commands:

usage: envdoctor [-h] [-v] [--format {text,json}] [-o OUTPUT]
                 {check,sync,audit} ...

Zero-dependency .env linter, template synchronizer, and codebase auditor.

positional arguments:
  {check,sync,audit}
    check               Validate active .env against template (.env.example)
    sync                Append missing keys to .env.example with safe placeholders
    audit               Scan codebase files for unconfigured environment variables

options:
  -h, --help            Show this help message and exit
  -v, --version         Show program version number and exit
  --format {text,json}  Output format (default: text)
  -o, --output PATH     Write output report to file

1. envdoctor check

Validates that all required variables declared in .env.example exist in .env.

# Standard check: fail if .env is missing variables required by .env.example
envdoctor check --env .env --example .env.example

# Strict mode: fail if .env has missing OR undocumented extra variables
envdoctor check --strict

# Allow declared variables to be empty strings
envdoctor check --allow-empty

Exit Codes:

  • 0: All variables present and valid.
  • 1: Contract discrepancy detected (missing or empty variables).
  • 2: File not found or read/write I/O error.

2. envdoctor sync

Safely synchronizes .env.example by reading all keys from your local .env and generating intelligent, masked placeholder values.

# Preview changes without modifying file
envdoctor sync --dry-run

# Automatically update .env.example
envdoctor sync

Masking Intelligence Rules:

  • Secret / API keys (*_KEY, *_SECRET, *_TOKEN) $\rightarrow$ your_api_key_here
  • Port numbers (*_PORT, PORT) $\rightarrow$ 8080
  • URLs (*_URL, DATABASE_URL) $\rightarrow$ postgres://user:password@localhost:5432/dbname
  • Hostnames (*_HOST) $\rightarrow$ localhost
  • Private inline comments (# my private note) are never exported into .env.example.

3. envdoctor audit

Scans your application source code for direct environment lookups across Python, JavaScript, TypeScript, Go, Rust, and PHP:

# Audit entire source directory
envdoctor audit ./src

# Audit against a specific environment file
envdoctor audit ./src --env .env.production

Recognized Patterns:

  • Python: os.environ["KEY"], os.environ.get("KEY"), os.getenv("KEY")
  • JavaScript / TypeScript: process.env.KEY, process.env["KEY"]
  • Go: os.Getenv("KEY")
  • Rust: env::var("KEY")

🔬 Pipeline Architecture

┌────────────────┐     ┌────────────────┐     ┌──────────────────────────────────┐
│   Active .env  │     │  .env.example  │     │       Application Source Code    │
│  (Real Values) │     │   (Template)   │     │ (Python / JS / TS / Go / Rust)   │
└───────┬────────┘     └───────┬────────┘     └────────────────┬─────────────────┘
        │                      │                               │
        ▼                      ▼                               ▼
┌───────────────────────────────────────┐             ┌──────────────────────────┐
│       Enterprise .env Parser          │             │  Multi-Language Scanner  │
│  * Quoted & multiline strings         │             │  * Regex pattern cache   │
│  * Escaped characters & exports       │             │  * Ignores node_modules  │
└──────────────────┬────────────────────┘             └────────────┬─────────────┘
                   │                                               │
                   ▼                                               ▼
┌───────────────────────────────────────┐             ┌──────────────────────────┐
│             Differ Engine             │             │      Auditor Engine      │
│  * Missing keys detection             │             │  * Unconfigured env vars │
│  * Bidirectional strict symmetry      │             │  * Stale / dead vars     │
└───────┬───────────────────────────────┘             └────────────┬─────────────┘
        │
        ├──► check  ──► [ Exit 0: Clean | Exit 1: Discrepancy ]
        │
        └──► sync   ──► [ Secret-Safe Placeholder Generator ] ──► Updates .env.example

🚀 Verified Benchmarks

Measured on standard developer hardware (AMD Ryzen 9 / Apple M-series):

Metric Result Industry Alternative
Cold Startup Time < 15ms 250ms+ (Node/Go CLI tools)
Parsing 1,000 .env lines < 4ms ~20ms
Auditing 50,000 LOC < 110ms 1,500ms+ (AST-based linters)
Memory Footprint < 6 MB 50MB+ (V8 / Electron wrappers)
External Dependencies 0 12+ transitive packages

🧪 Test Suite

EnvDoctor maintains a 100% test pass rate across all major operating systems and Python versions:

# Run pytest with coverage report
uv run --with pytest pytest contract_tests tests -v
============================= test session starts =============================
platform win32 / linux / darwin -- Python 3.9 - 3.14
collected 32 items

contract_tests/test_contract.py ..                                       [  6%]
tests/test_auditor.py ...                                                [ 15%]
tests/test_cli.py .........                                              [ 43%]
tests/test_differ.py .....                                               [ 59%]
tests/test_parser.py .......                                             [ 81%]
tests/test_syncer.py ......                                              [100%]

============================= 32 passed in 0.31s ==============================

🤝 Contributing

Contributions are warmly welcomed! Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md for local development setup and guidelines.

# Clone the repository
git clone https://github.com/umutgungorr/envdoctor.git
cd envdoctor

# Run tests
uv run --with pytest pytest contract_tests tests -v

# Run linter
uv run --with ruff ruff check .

⚡ Part of the Developer Diagnostics Suite

EnvDoctor is a core pillar of the zero-dependency Developer Diagnostics Suite by @umutgungorr:

  • 🌲 PortTree: Dev socket tree scanner, Docker proxy unmasker, and process-tree killer.
  • ⚡ LogShrink: Zero-config CLI stream filter that collapses noisy polling logs and auto-boxes stack traces.
  • 🩺 RepoPulse: Git forensic health, architectural hotspot churn, and bus-factor risk engine.
  • 💊 EnvDoctor: Zero-dependency .env drift synchronizer, secret-safe generator, and codebase config auditor.

📖 Project Case Study

EnvDoctor is an open-source project by Umut Güngör. Read the EnvDoctor case study for its design philosophy, benchmarks, and real-world impact.


📄 License

This project is licensed under the terms of the MIT License.
Copyright (c) 2026 Umut Güngör.

Metadata

Release files for envdoctor-cli 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for envdoctor-cli 0.2.1
File Size Uploaded Provenance Actions
envdoctor_cli-0.2.1.tar.gz 655.9 kB Without provenance Details for envdoctor_cli-0.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for envdoctor-cli 0.2.1
File Interpreter ABI Platform Actions
envdoctor_cli-0.2.1-py3-none-any.whl Python 3 none any Details for envdoctor_cli-0.2.1-py3-none-any.whl

Total release size: 674.9 kB

Release files / envdoctor_cli-0.2.1.tar.gz

Download URL envdoctor_cli-0.2.1.tar.gz
Size 655.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2bb0c5da0a6ee4c86c8c9ec985776b01f227b01e4ffac72e681eab09ae3347fa
BLAKE2b-256 checksum
How to use checksums
4c209b2a12e0c1dceb905a50b32a08f1b2fad04e3e9157a1a604816ac8836045
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / envdoctor_cli-0.2.1-py3-none-any.whl

Download URL envdoctor_cli-0.2.1-py3-none-any.whl
Size 19.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
46c4f2340dcadc3b028f125f5f7223dd0e20e32b6cd76471bc5d87a62c77694f
BLAKE2b-256 checksum
How to use checksums
bd286024c6def7e3b54fc20c03b2de37fdf7d835a8fc1404d52cb72073e52f85
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for envdoctor-cli 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page