Skip to main content

envops

A single-file CLI to inspect and manipulate .env files, designed to be safe by default: values that look like secrets are masked in all output unless you explicitly ask otherwise.

Built with Python stdlib only — a plain python3 (≥3.10) runs it.

Though it works as a regular CLI, envops is first and foremost a skill for AI agents: the bundled skill (skills/envops/SKILL.md) makes the agent route every .env operation through envops — never cat or read env files directly, prefer masked output, treat --unsafe as a last resort — so credentials never leak into the conversation, logs, or context.

Install

Install the skill into your agent (Claude Code, etc.) with skills:

npx skills add reorx/envops

Or with skm:

skm install https://github.com/reorx/envops

That's all — the skill carries the CLI's own install steps, so the agent sets up the envops command by itself the first time it needs it.

Usage

show — print key-value pairs (secrets masked)

envops show ./test.env
FOO=hello
API_SECRET=sk******ij
DATABASE_URL=po******pp
DEBUG=true

Show only certain keys; add --unsafe to expose masked values — use with caution and compromise in mind:

envops show ./test.env -k FOO BAR
envops show ./test.env -k API_SECRET --unsafe

list-keys — list keys only

envops list-keys ./test.env

copy — copy pairs from source to dest

Specify keys with -k, or --full to copy every pair. Changes made to the dest file are printed (masked):

envops copy ./test.env /path/to/dest.env -k FOO BAR
envops copy ./test.env /path/to/dest.env --full
+ BAR="quoted value"
~ FOO=hello (was old_foo)
updated /path/to/dest.env: 2 change(s)

+ means the key was added, ~ means its value was updated. Keys already equal in dest are left untouched. Unrelated lines, comments, and formatting in dest are preserved; the dest file is created if it doesn't exist.

set — set a key's value from stdin

echo value | envops set ./test.env -k FOO
pbpaste | envops set ./test.env -k API_SECRET

One trailing newline is stripped from stdin. Existing keys are updated in place; new keys are appended.

read-value — print a key's raw value

Only use this when the other commands cannot solve the problem, as it exposes the value. --unsafe is required; without it the command fails:

envops read-value ./test.env -K FOO --unsafe

Remote files over SSH

Any file argument may be an scp-style remote path ([user@]host:/path, a colon before the first slash marks it remote). Hosts, keys, and options come from your regular ssh config:

envops show foo@bar:/app/.env
envops copy /tmp/test.env foo@bar:/app/.env --full
envops copy foo@bar:/app/.env ./local.env -k DATABASE_URL

Remote handling keeps the tool's safety guarantees:

  • remote content is only ever held in memory — no plaintext temp file lands on the local disk
  • writes are atomic: content goes to a mktemp file next to the target, then mv replaces it, so a dropped connection can't leave a half-written .env
  • the target's permissions are preserved (stat -c on Linux, stat -f on macOS/BSD remotes; 600 for newly created files)
  • output masking works exactly as for local files

Secret detection

A value is masked when any of these match — except pure-numeric values (timeouts, sizes, retry counts like AUTH_TOKEN_EXPIRE=604800), which are never treated as secrets:

  • Key name contains SECRET, TOKEN, PASSWORD, API_KEY, ACCESS_KEY, PRIVATE, CREDENTIAL, AUTH, SALT, SIGNING, DSN, ... (case-insensitive) — unless the key's last word marks plain config (URL, URI, ENDPOINT, HOST, PORT, DOMAIN, PATH, NAME, TELEMETRY, ...), so BETTER_AUTH_URL is not treated as a secret by its name alone
  • Value prefix matches known credential formats: sk-, ghp_, glpat-, xoxb-, AKIA..., JWT (eyJ...), etc.
  • Random-looking token run: the value contains an unbroken alphanumeric run of ≥20 chars that mixes letters and digits with Shannon entropy ≥3.5

The entropy check works on alphanumeric runs, so structured values — hostnames (oss-cn-beijing.aliyuncs.com), bucket names (myapp-demo-snapshot), db names — are cut into short segments by - . _ / and pass in the clear.

URL-shaped values (<scheme>://..., any scheme word) are masked per segment instead of as a whole, so the recognizable parts stay readable:

  • the userinfo password is always masked — weak passwords are still passwords
  • random-looking runs in the path/query are masked (webhook tokens, etc.)
  • scheme, username, host, and port stay in the clear
NEO4J_URL=neo4j://neo4j:12******cc@102.10.101.125:7687
SLACK_WEBHOOK=https://hooks.slack.com/services/T01ABCDEFGH/B02JKLMNOPQ/x9******ty

Masked form keeps the first and last 2 characters (sk******ij) so you can tell credentials apart without leaking them.

Env file handling

  • Supports export KEY=value, single/double quotes, inline # comments on unquoted values
  • Duplicate keys: last occurrence wins (dotenv semantics)
  • On write, values containing spaces or special characters are double-quoted with escaping
  • Writes preserve comments, blank lines, and unrelated lines byte-for-byte

Development

uv run pytest

Tests invoke the CLI as a subprocess and assert on real command behavior.

Download files

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

Source Distribution

envops-0.1.3.tar.gz (20.0 kB view details)

Uploaded Source

Built Distribution

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

envops-0.1.3-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file envops-0.1.3.tar.gz.

File metadata

  • Download URL: envops-0.1.3.tar.gz
  • Upload date:
  • Size: 20.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for envops-0.1.3.tar.gz
Algorithm Hash digest
SHA256 f845920a176e843f82bb841e1eef8d9e969085e42496acd11fc913340fb1bd85
MD5 20c75db5752c3a6c3a3bf68a6bd17b4d
BLAKE2b-256 4580c458dae4dbfa3a8adac957fe5a898a7d5d992bb5ce556f7b958090dcf280

See more details on using hashes here.

File details

Details for the file envops-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: envops-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 9.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.17 {"installer":{"name":"uv","version":"0.9.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for envops-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 51952c7d49c65819eb9785508eac975299f83d6c8a8383b0ab7bd6e7244dd908
MD5 00e52e25a49217654f00981884eb30a9
BLAKE2b-256 51e7b7af9fd62792672c6c0f29c851fd9433400c4add0d89a432bcd248d037af

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.3 This release

2 files

0.1.2

2 files

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