Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ¦… enview

Cross-project .env scanner, auditor, and drift detector.
Know what secrets live where β€” without exposing them.

Install β€’ Commands β€’ CI Integration β€’ Why?


Your .env files are scattered across dozens of projects. Some are encrypted, some aren't. Some are gitignored, some aren't. Some have keys that don't exist in production. You don't know which ones AI agents can read.

enview gives you a single terminal command to see all of it.

The Problem

If you're a developer shipping multiple projects, you probably have:

  • πŸ”“ Plaintext API keys sitting in .env files that any LLM, build script, or npm postinstall can read
  • πŸ•³οΈ Missing keys between dev and production that cause deploy failures
  • 🀷 No idea which projects use encryption (dotenvx, sops, etc.) and which don't
  • πŸ“‚ No inventory of what secrets exist across your entire workspace

enview is a zero-config CLI that scans your project directories and tells you the truth.

Install

npx @pickbitsai/enview scan ~/code        # try it instantly

npm install -g @pickbitsai/enview          # or install globally

The package is scoped, but the command it installs is plain enview β€” every example below works as written once it's on your PATH.

Commands

enview scan β€” Find everything

Recursively discover all .env files across your projects. See encryption status, gitignore coverage, and modification dates at a glance.

enview scan ~/code ~/projects ~/freelance
πŸ›‘οΈ  enview scan β€” 4 projects, 6 env files

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Project      β”‚ File            β”‚ Env        β”‚ Keys β”‚ Encrypted      β”‚ .gitignore β”‚ Modified β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ echoforge    β”‚ .env            β”‚ developmentβ”‚ 4    β”‚ 🟑 dotenvx 2/4 β”‚ βœ… yes     β”‚ 3d ago   β”‚
β”‚              β”‚ .env.production β”‚ production β”‚ 4    β”‚ πŸ”’ dotenvx     β”‚ βœ… yes     β”‚ 1w ago   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ my-saas      β”‚ .env            β”‚ developmentβ”‚ 12   β”‚ πŸ”“ none        β”‚ ❌ NO      β”‚ 2mo ago  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ side-project β”‚ .env            β”‚ developmentβ”‚ 3    β”‚ πŸ”“ none        β”‚ βœ… yes     β”‚ today    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

enview audit β€” Security check

Find plaintext secrets, missing .gitignore entries, partial encryption, and environment drift β€” all in one pass.

enview audit ~/code
enview audit --strict ~/code   # exit code 1 on critical findings (for CI)
πŸ›‘οΈ  enview audit β€” 6 findings

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Level    β”‚ Project    β”‚ File             β”‚ Finding                                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ CRITICAL β”‚ my-saas    β”‚ .env             β”‚ Plaintext .env file is NOT gitignored        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ CRITICAL β”‚ my-saas    β”‚ .env             β”‚ 3 sensitive keys in plaintext:               β”‚
β”‚          β”‚            β”‚                  β”‚ STRIPE_SECRET_KEY, DATABASE_PASSWORD…        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ WARN     β”‚ echoforge  β”‚ .env             β”‚ Partial encryption β€” 2/4 keys encrypted      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ WARN     β”‚ echoforge  β”‚ .env β†’ .env.prod β”‚ 1 key in .env missing from .env.production   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  ⚠️  2 critical issue(s) require immediate attention

enview keys β€” Key inventory

List every key name across every project. Values are never shown. Encrypted keys get πŸ”’, plaintext secrets get ⚠️.

enview keys ~/code
πŸ”‘  enview keys β€” key inventory (values never shown)

  πŸ“ echoforge
     .env (development)
       πŸ”’ ANTHROPIC_API_KEY
       πŸ”’ DATABASE_URL
       πŸ”“ OLLAMA_HOST
       πŸ”“ APP_NAME

     .env.production (production)
       πŸ”’ ANTHROPIC_API_KEY
       πŸ”’ DATABASE_URL
       πŸ”’ REDIS_URL
       πŸ”“ APP_NAME

enview drift β€” Compare environments

Find keys that exist in one environment but not another. Catches the "works on my machine" deploy failures.

enview drift ~/code
πŸ‘οΈ  enview drift β€” environment key comparison

  πŸ“ echoforge
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Key         β”‚ .env β”‚ .env.production β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ OLLAMA_HOST β”‚ βœ“    β”‚ βœ— missing       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ REDIS_URL   β”‚ βœ—    β”‚ βœ“               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

enview history β€” What you already committed

A working-tree scan answers "what is exposed right now". It cannot answer the expensive question: what did I commit last year and forget? Deleting a .env and gitignoring it changes nothing about the copy in every clone, fork and CI cache β€” the credential is published until it is rotated.

enview history ~/code
πŸ•°οΈ  enview history β€” 4 risky paths across 3 repos

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Repo          β”‚ Path in history                  β”‚ Kind                    β”‚ Keys        β”‚ Still tracked β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ CoachMark     β”‚ .env                             β”‚ environment file        β”‚ 4 sensitive β”‚ no            β”‚
β”‚ PantryPlanner β”‚ android/app/release-keystore.jks β”‚ private key or keystore β”‚ β€”           β”‚ no            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Walks --all, so a secret on an abandoned branch still counts. Scoped to risky paths β€” env files, private keys, keystores, .npmrc, service-account JSON β€” rather than grepping every blob, because a scan slow enough to be switched off protects nothing. Key names are recovered from historical blobs; values are never returned.

enview ui β€” Manage them

The one place enview handles values. Everything else β€” CLI, library, any dashboard reading them β€” sees names and status only.

enview ui ~/code

Masked values with reveal and copy, add/edit/delete/rename, and one-click remediation for what the scan found: generate a .env.example with values stripped, add a file to .gitignore. Every write makes a timestamped .bak first.

A revealed value re-masks itself after 30 seconds, with the countdown on the button β€” screen shares and recordings are a likelier way to lose a credential than an attacker is. The mask is a fixed width and no length is ever returned, so a short value and a long one look the same.

Security model β€” one user, one machine. Binds 127.0.0.1; validates Host and Origin on every request, which is what defeats DNS rebinding; requires a token printed once in your terminal; no CORS, restrictive CSP, no telemetry, no external requests. Only files found by the scan can be touched β€” an allowlist, not path sanitising. Do not put it behind a tunnel, port-forward or reverse proxy; it has no multi-user concept.

Values cross the wire one key at a time, only when you ask, and are never cached or logged.

enview protect β€” Keep it that way

Working-tree audit plus history scan, exiting non-zero on anything critical. Built for cron, Task Scheduler or CI β€” a guard that always exits 0 is decoration.

enview protect ~/code                 # exits 1 if anything critical
enview protect ~/code --quiet         # silent unless there is something to say
enview protect ~/code --no-history    # much faster; skips the history walk
enview protect ~/code --json          # for automation
πŸ›‘οΈ  enview protect β€” 4 critical findings
   2 on disk Β· 2 in git history

Findings deduplicate across the two scans: when history has the real answer, the working-tree inference is dropped rather than reported twice.

Run it on a schedule
# cron β€” 9am daily
0 9 * * * npx @pickbitsai/enview protect ~/code --quiet

# Windows Task Scheduler
schtasks /create /tn "enview protect" /tr "npx @pickbitsai/enview protect C:\code --quiet" /sc daily /st 09:00

CI Integration

Use --json for machine-readable output and --strict to fail builds:

# GitHub Actions
- name: Audit secrets
  run: npx @pickbitsai/enview audit --strict --json . > audit-results.json
# GitLab CI
audit:secrets:
  script:
    - npx @pickbitsai/enview audit --strict .
  allow_failure: false

What It Detects

Detection Description
Plaintext secrets API keys, tokens, passwords stored without encryption
Missing .gitignore .env files that could be committed to version control
Partial encryption Files where some keys are encrypted but others aren't
Environment drift Keys present in dev but missing in production (or vice versa)
Encryption type Identifies dotenvx, SOPS, age, and other encryption schemes
Sensitive key patterns Flags keys matching *_API_KEY, *_SECRET, *_PASSWORD, *_TOKEN, etc.

Why AI-Safety Matters

AI coding agents (Claude Code, Cursor, Copilot, Aider) run in your terminal with access to your filesystem. A plaintext .env file is trivially readable by any process β€” including AI agents, npm postinstall scripts, and supply chain attacks.

enview helps you answer: "Which of my projects have secrets that an AI agent could read right now?"

Pair it with dotenvx to encrypt everything it flags.

Options

Flag Description
--json Output as JSON (all commands)
--strict Exit code 1 on critical findings (audit only)
-d, --depth <n> Max directory depth (default: 6)

Encryption Detection

enview automatically identifies:

  • dotenvx β€” encrypted: prefix with DOTENV_PUBLIC_KEY header
  • SOPS β€” ENC[AES256_GCM,...] values or sops metadata
  • age β€” age-encryption.org markers

Ignores (by default)

  • node_modules, .git, vendor, dist, build, target, etc.
  • .env.example, .env.sample, .env.template
  • .env.keys (dotenvx private key files β€” never scanned)

Contributing

PRs welcome. Some ideas:

  • enview rotate β€” Track key rotation history via git log
  • enview init β€” Bootstrap dotenvx encryption for unprotected projects
  • enview watch β€” File watcher that alerts on new plaintext secrets
  • TUI dashboard mode (blessed/ink)
  • 1Password / Bitwarden vault cross-reference
  • Pre-commit hook integration
  • .enviewrc config file for custom scan roots

License

MIT

Releases

Packages

Used by

Contributors

Languages