{% extends "main.html" %} {% block tabs %} {{ super() }} {% endblock %} {% block content %}
Environment Coherence

Your .env.local works…
until it doesn't.

A local-first CLI that makes environment configuration deterministic. No cloud dependency. No guessing which value won.

terminal
1 # install
2 $ pip install envctl
3
4 # initialize
5 $ envctl config init
6 $ envctl init
7
8 # fill missing values, validate and...
9 $ envctl fill
10 $ envctl check
11
12 # run your app
13 $ envctl run -- python app.py
Python CLI · MIT License · Local-first · Open source

It works on your machine.

It fails in CI.

Your teammate asks: “what's DATABASE_URL?”

Onboarding depends on tribal knowledge.

.env.local gets copied around until nobody trusts it.

That is not a secret-storage problem.
It is an environment-consistency problem.

envctl fixes this.

Mental model

From contract to projection

Every step has a clear responsibility. No hidden source of truth.

01

Contract

What the project requires

02

Vault

What each machine stores locally

03

Profiles

Which local value set is active

04

Resolution

What is actually true at runtime

05

Projection

How the resolved environment reaches your tools

The repo defines shared requirements
Each machine keeps real values local
The runtime environment is explicit and checkable
Usage

A deterministic CLI flow

From install to runtime — every command has a clear purpose.

Get running in 60 seconds

  • config init — creates your user-level config
  • init — prepares the repo and installs Git hooks
  • fill — asks only for missing required values
  • check — validates the resolved environment
  • run — executes with resolved env injected
quickstart
1 $ pip install envctl
2 $ envctl config init
3 $ envctl init
4 $ envctl fill
5 $ envctl check
6 ✓ all variables resolved
7 $ envctl run -- python app.py

Share requirements, not secrets

  • add — adds a variable to the shared contract
  • Commit the contract to Git — teammates pull it
  • Each dev runs fill to provide their own local values
  • Real values never leave the machine
team workflow
1 # developer A adds a requirement
2 $ envctl add API_KEY sk-example
3 $ git add .envctl.yaml
4 $ git commit -m "require API_KEY"
5
6 # developer B pulls and fills
7 $ git pull
8 $ envctl check
9 ✗ API_KEY: missing
10 $ envctl fill
11 $ envctl run -- python app.py

Guard secrets automatically

  • Managed Git hooks run guard secrets before commit and push
  • No secrets in the contract — ever
  • Local values stay on the machine
  • Sensitive output is masked
  • Optional encryption at rest
security
1 $ envctl hooks install
2 ✓ pre-commit hook installed
3 ✓ pre-push hook installed
4
5 $ envctl hooks status
6 pre-commit: active (guard secrets)
7 pre-push: active (guard secrets)
8
9 $ envctl guard secrets
10 ✓ no secrets detected in staged files
{% endblock %} {% block footer %}{% endblock %}