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.0.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.0-py3-none-any.whl (132.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: envctl-2.4.0.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.0.tar.gz
Algorithm Hash digest
SHA256 4cd6c2f3b0bc092fbc2a678910bd9cea2bee12757ccb27c379e681481d5a8484
MD5 b51bb96baa50338b52411403bca7ff9f
BLAKE2b-256 80ca0fe45a5d1743717ee042c08de5c133b0ecaea7d5e0caa7971c19b5494d27

See more details on using hashes here.

File details

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

File metadata

  • Download URL: envctl-2.4.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5160c973edbe49219a16e2669475bd7ee9416a112f0e855b5ae360585c62398a
MD5 9a3260a36a34138713bc7ee4c55c6622
BLAKE2b-256 3bc61e2d292853d524ae280f6ab9b7624b20791ed34475fc3ada15f0191f3ecb

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