Skip to main content

Local environment control plane for contract-driven development workflows

Project description

envctl

Your .env.local files drift between machines, hide missing variables, and break when you least expect it. envctl fixes that.

CI Python 3.10+ License: MIT


Why this exists

Most projects handle environment variables in a messy way:

  • .env.local files are undocumented
  • values get copied between machines
  • something works locally until it suddenly does not
  • CI and local setups behave differently
  • nobody is fully sure which variables are required

It works — until it breaks.

envctl brings structure to this without turning environment setup into a second project.


What is envctl?

envctl is a local-first environment control plane built around a contract-first model.

It separates three things that usually get mixed together:

  • what the project needs → defined in .envctl.schema.yaml and committed to the repository
  • what you have locally → stored in a private local vault, outside git
  • what actually runs → a validated environment resolved when needed

That gives you:

  • clear, documented variables
  • no secrets in git
  • fewer setup mistakes
  • more predictable local and team workflows
  • explicit validation before execution

Install

pip install envctl

Or from source:

git clone https://github.com/labrynx/envctl
cd envctl
pip install -e .

Quickstart

envctl config init
envctl init
envctl fill
envctl check
envctl run -- python app.py

What this does:

  • config init creates your local envctl config
  • init connects the current repository to envctl
  • fill asks only for missing values
  • check validates the environment before you run anything
  • run injects a clean resolved environment into the child process

Why not just .env.local?

Because it does not scale cleanly.

.env.local direnv Doppler / Infisical envctl
Documents variables Partial
Validates values
Keeps secrets out of git ⚠️ ✅ cloud ✅ local
Supports multiple environments manual files manual files ✅ profiles
Works without cloud

envctl is not a cloud secrets manager.

It is a way to make environment handling explicit, predictable, and local-first.

your repository defines what is needed, your machine provides the values, and envctl resolves the final environment.


A typical workflow

# one developer adds a new requirement
envctl add API_KEY sk-example
git add .envctl.schema.yaml
git commit -m "require API_KEY"

# another developer pulls the change
envctl check
envctl fill
envctl run -- python app.py

The contract is shared in git. The values stay local. The runtime environment is rebuilt consistently when needed.


How it works

At a high level:

  • contract → defines which variables exist and how they should look
  • vault → stores the real local values
  • profile → selects which local value set to use (local, dev, staging, ...)
  • resolution → builds the final validated environment
  • projection → applies it through run, sync, or export

Think of it like this:

the repository defines the rules, your machine provides the values, and envctl builds the environment you actually run.


Profiles

Instead of juggling multiple .env files:

envctl --profile dev fill
envctl --profile staging check
envctl --profile staging run -- python app.py

Each profile is explicit and independent. No hidden inheritance, no magic fallback between profiles.


Docker note

envctl run -- docker run ...

envctl injects variables into the Docker client process.

To pass them into the container, you still need one of these:

  • -e
  • --env
  • --env-file

A common pattern is:

docker run --env-file <(envctl export --format dotenv) ...

CI mode

ENVCTL_RUNTIME_MODE=ci envctl check

In CI:

  • validation still works
  • mutating commands are blocked

That keeps automation predictable and avoids accidental local-style writes in CI environments.


Common commands

envctl check
envctl inspect
envctl explain DATABASE_URL
envctl status
envctl doctor

envctl add DATABASE_URL <value>
envctl set PORT 4000
envctl unset PORT

envctl run -- <command>
envctl sync
envctl export

envctl profile list
envctl profile create staging

envctl vault check
envctl vault show
envctl vault encrypt
envctl vault decrypt

When envctl is a good fit

envctl is a strong fit if:

  • .env.local files drift between machines
  • onboarding is fragile
  • CI and local environments do not behave the same way
  • you work with multiple environments
  • you want a local-first workflow without depending on a hosted service

When envctl is not the right tool

envctl may be unnecessary if:

  • you only have one static .env file
  • the project is very small and has no real setup complexity
  • you already rely fully on a centralized secrets platform and do not want local-first handling

Security model

  • the contract contains no secrets
  • secrets stay on your machine
  • sensitive values are masked in normal output
  • vault files use restrictive permissions
  • optional encryption at rest is available for vault files

Vault encryption at rest

If you enable encryption, envctl stores vault files in an encrypted, self-identifying format instead of plaintext.

Enable it in your config:

{
  "encryption": {
    "enabled": true
  }
}

Then migrate existing vault files once:

envctl vault encrypt

This creates a local key file at:

~/.envctl/vault/master.key

That key is stored with restrictive permissions.

After encryption is enabled:

  • vault edit works transparently
  • vault check reports whether the file is plaintext, encrypted, using the wrong key, or corrupted
  • decrypt failures are explicit instead of looking like generic parse errors

To migrate back to plaintext:

envctl vault decrypt

Then disable encryption in config.

Important limitation

Encryption at rest helps protect vault files on disk.

It does not protect against a fully compromised machine or a compromised user session.

envctl assumes a trusted machine. If your machine is compromised, your secrets are compromised too.

Back up your master.key carefully. If you lose it, encrypted vault data cannot be recovered.


Documentation

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

envctl-2.4.1.tar.gz (82.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

envctl-2.4.1-py3-none-any.whl (132.2 kB view details)

Uploaded Python 3

File details

Details for the file envctl-2.4.1.tar.gz.

File metadata

  • Download URL: envctl-2.4.1.tar.gz
  • Upload date:
  • Size: 82.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for envctl-2.4.1.tar.gz
Algorithm Hash digest
SHA256 f083e5b46e73a8f496afc501fbdf7e0b5a1008895368765b7c685beec83412f6
MD5 408baf747c2e2b12a153eec74ff4f71b
BLAKE2b-256 1d2fbf6de3ff7998b2c487184ba98a4c34d3aff5d6e5b1e1e702e5283f354017

See more details on using hashes here.

File details

Details for the file envctl-2.4.1-py3-none-any.whl.

File metadata

  • Download URL: envctl-2.4.1-py3-none-any.whl
  • Upload date:
  • Size: 132.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for envctl-2.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e7f8a5991bb82b2194529323492f0787c696fb38b3f0c17bab3970b1370a1d66
MD5 5081c6d937c61c2842cc3659adf5a4ce
BLAKE2b-256 9d75994c06ef7ef8989fbffbbd5db46bf6eecf1d4f588499dc6c4338375c98c4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page