Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ§™ env-wizard

Never guess what goes in a .env again.

env-wizard walks you through .env.example one variable at a time β€” inline hints as you go, and your AI (cloud or local) on standby for anything unclear. Then it writes .env for you, safely.

Config in TOML/YAML/JSON? Same walkthrough, real file written, every comment kept.

No example file? It scans your code (JS/TS, Python, Rust, Go, Ruby, PHP) instead.

License: MIT Built with Rust AI: cloud or local Code scan: 8 languages Formats: env Β· toml Β· yaml Β· json Telemetry: none Platform: macOS Β· Linux Β· Windows (via Cargo)


⚑ Install

Hand it to a coding agent, or pick the method for your OS β€” then run env-wizard inside any repo that has a .env.example.

πŸ€– Installing via a coding agent

Working with Claude Code, Codex, or another coding agent? Just hand it this prompt:

Install env-wizard from https://github.com/alphonse-terrier/env-wizard
Manual install instructions (macOS / Linux / Windows / Cargo)

🍎 macOS

Homebrew (recommended):

brew tap alphonse-terrier/env-wizard
brew install env-wizard
Or download a prebuilt binary
# Apple Silicon (M1/M2/M3…). For an Intel Mac, swap aarch64 β†’ x86_64.
curl -L https://github.com/alphonse-terrier/env-wizard/releases/download/v0.6.0/env-wizard-v0.6.0-aarch64-apple-darwin.tar.gz | tar xz
sudo mv env-wizard-v0.6.0-aarch64-apple-darwin/env-wizard /usr/local/bin/

🐧 Linux

Homebrew (if you use it):

brew tap alphonse-terrier/env-wizard
brew install env-wizard

Prebuilt static binary (x86_64, no dependencies):

curl -L https://github.com/alphonse-terrier/env-wizard/releases/download/v0.6.0/env-wizard-v0.6.0-x86_64-unknown-linux-musl.tar.gz | tar xz
sudo mv env-wizard-v0.6.0-x86_64-unknown-linux-musl/env-wizard /usr/local/bin/

πŸͺŸ Windows

Install with Cargo (needs the Rust toolchain):

cargo install --git https://github.com/alphonse-terrier/env-wizard

πŸ“¦ Any OS β€” with Cargo

Works everywhere Rust runs:

cargo install --git https://github.com/alphonse-terrier/env-wizard
Build from a local clone
git clone https://github.com/alphonse-terrier/env-wizard
cd env-wizard
cargo install --path .

Verify a download against SHA256SUMS on the release page.

First run

cd my-freshly-cloned-project
env-wizard

That's it. πŸŽ‰

The first time you press ? for a hint, env-wizard asks which AI to use β€” pick one from a short list (Claude, OpenAI, local Ollama, LM Studio, OpenRouter, Groq, or your own) and it's remembered from then on. No config file to write by hand, no API to wire up. See Choose your AI.


Jump to: Demo Β· Features Β· Scan your code Β· Config templates Β· Choose your AI Β· Usage Β· How it works Β· FAQ

🎬 See it in action

Here's what a real run looks like:

env-wizard walking through a SECRET_KEY prompt, asking the AI for a hint, then writing .env

The πŸ’‘ Hint is your AI's answer, rendered cleanly in the terminal β€” headings, bullets, and commands, with the raw Markdown stripped away. Need something specific? Type your question after the ? (e.g. ? what format is expected?) and the AI answers it directly.

Prefer plain text? Here's the same run as a transcript
$ env-wizard
env-wizard
At each prompt, type:
  ┃  Enter   ┃  accept the suggested default
  ┃    ?     ┃  ask the AI for a hint
  ┃   ? …    ┃  ask the AI a specific question about this variable
  ┃ (nothing)┃  leave this variable empty
  ┃    q     ┃  quit without saving
Change the AI provider anytime with `env-wizard config`.

  # Secret used to sign session cookies (32+ chars)
? SECRET_KEY β€Ί ?

πŸ’‘ Hint
SECRET_KEY
This signs your session cookies. Generate one with:

    openssl rand -hex 32

 β€’ Must be at least 32 characters
 β€’ Keep it secret β€” put it in .env, never commit it

? SECRET_KEY β€Ί 9f2c8a…                ← you paste the real value
βœ” SECRET_KEY Β· 9f2c8a…
βœ“ Wrote .env

πŸ’› Why you'll like it

  • 🧭 Guided, not guesswork β€” every variable's .env.example comment shows inline as a hint, before you ever call the AI.
  • πŸ€– Your AI, your rules β€” hints come from whatever provider you pick: Claude, OpenAI, a local Ollama model, or any OpenAI-compatible endpoint. Nothing is hardcoded, and env-wizard stores no API keys.
  • πŸ”’ Private by design β€” your .env values are never sent to any AI, cloud or local. And with a local provider (Ollama, LM Studio at http://localhost:11434) the whole prompt stays on your machine β€” nothing leaves at all.
  • 🧠 Repo-aware hints β€” the AI is fed your README, common config files, and every place the variable appears in the code, so its advice is specific β€” not generic.
  • πŸ”Ž Catches drift β€” env-wizard scan audits your .env.example against what's actually used in the code (8 languages), and can even work with no example at all.
  • πŸ“„ Not just .env β€” TOML, YAML, and JSON config templates get the same guided walkthrough, and only the values you change are ever touched.
  • πŸ’Ύ Safe, tidy writes β€” confirms before overwriting an existing .env, keeps a .env.bak, carries your .env.example comments over each variable, and writes the file 0600 (owner-only) on Unix.
  • πŸͺΆ One small binary β€” written in Rust. No runtime, no daemon, starts instantly.

πŸ”Ž Scan your code for env vars

.env.example files drift: someone adds process.env.STRIPE_SECRET_KEY to the code and forgets the example. env-wizard reads the source itself β€” JS/TS, Python, Rust, Go, Ruby, PHP β€” to catch that before it costs you twenty minutes of debugging.

Show details
$ env-wizard scan
Used in code but missing from .env.example (2):
  β€’ REDIS_URL src/cache.py:1
  β€’ STRIPE_SECRET_KEY src/server.js:2

Declared in .env.example but not found in code (1):
  β€’ OLD_FEATURE_FLAG

Three ways to use it:

Command What it does
env-wizard scan Audit, read-only: what's used in code but missing from the example (with file:line), and what's declared but unused.
env-wizard scan --check Same audit, but exits with status 1 if any drift is found β€” drop it in CI to catch a .env.example that's fallen out of sync.
env-wizard (no .env.example present) Fallback: derives the variable list straight from the code and runs the wizard anyway.
env-wizard --from-code Augment: prompts for the example's variables plus any extras found in the code.

Before falling back to code detection, env-wizard also tries common example filename aliases when --input is omitted: .env.sample, .env.dist, .env.template, and env.example (no leading dot).

Detected patterns:

Language Detected
JS / TS process.env.FOO, process.env["FOO"], import.meta.env.FOO
NestJS (@nestjs/config) configService.get("FOO"), .get<Type>("FOO"), .getOrThrow("FOO")
Zod env schemas (zod / t3-env / znv) FOO: z.string() β€” any SCREAMING_SNAKE_CASE key mapped to a zod validator
Python os.environ["FOO"], os.environ.get("FOO"), os.getenv("FOO")
Rust env::var("FOO"), env!("FOO"), option_env!("FOO")
Go os.Getenv("FOO"), os.LookupEnv("FOO")
Ruby ENV["FOO"], ENV.fetch("FOO")
PHP getenv("FOO"), $_ENV["FOO"]
C# Environment.GetEnvironmentVariable("FOO")
Java / Kotlin System.getenv("FOO")

Heuristic (regex, v1): computed keys like process.env[someVar] can't be detected reliably. The NestJS and Zod patterns lean on conventions rather than a fixed API β€” a configService receiver name, a z import alias, SCREAMING_SNAKE_CASE keys β€” so a differently-named config service or a non-conventional schema won't be picked up. As everywhere else, real .env files are never read β€” only source code. (src/scan.rs)

πŸ“„ TOML / YAML / JSON config templates

Not every project configures itself through the environment. If yours ships a structured example instead β€” config.example.toml, settings.sample.yaml, appsettings.example.json β€” env-wizard walks that the same way it walks .env.example: one field at a time, dotted path shown as the prompt (database.host), the example's value as the default, and its comment (or JSONC ////* */ comment) as the hint.

Show details
$ env-wizard
Using config.example.toml (no .env.example found).

  # Hostname to connect to
? database.host (localhost) β€Ί db.prod
βœ” database.port Β· 5432
βœ” database.enabled Β· true
βœ“ Wrote config.toml

Only the values you actually change are touched β€” everything else (comments, key order, indentation, untouched siblings) comes out byte-for-byte identical to the example. Only scalar fields (string/number/bool) are prompted; arrays and nested tables you don't edit are carried over as-is.

Detection is automatic: env-wizard reads the file and detects the format from its actual content (TOML/YAML/JSON), falling back to the file extension only when the content itself isn't decisive (e.g. empty). That means a misnamed template (config.example.json that's actually TOML) or one with no extension at all (config.example) still works. A template is still recognized by its filename (example/sample/dist/template) the same way it is for .env.example aliases β€” dotenv examples still take priority if both exist, and dotenv-shaped filenames (.env, .env.example, …) are never reinterpreted as a structured format no matter what their content looks like. You can always be explicit with --input/-o. --from-code and env-wizard scan are dotenv-only, since a code scanner has nothing to say about config keys.

🧩 Choose your AI

The first time you press ?, env-wizard asks which AI to use and remembers your choice. Two kinds are supported:

Kind What it is Presets
CLI command Pipes the prompt to a local/cloud CLI. Manages its own auth β€” no keys stored. Claude (claude -p), Ollama (ollama run <model>), or any custom command
OpenAI-compatible HTTP base_url + model + an env var for the API key. OpenAI, local Ollama (http://localhost:11434/v1), LM Studio, OpenRouter, Groq…
Show details β€” changing your provider

Changing your provider

Two equivalent ways β€” pick whichever you like:

env-wizard config          # re-run the interactive picker

…or edit the config file by hand. Its location is, in order: $ENV_WIZARD_CONFIG if set, else $XDG_CONFIG_HOME/env-wizard/config.toml, else your OS config dir β€” ~/.config/env-wizard/config.toml on Linux, ~/Library/Application Support/env-wizard/config.toml on macOS, %APPDATA%\env-wizard\config.toml on Windows:

kind  = "command"          # "command" | "openai"
label = "Claude (CLI)"     # shown while fetching a hint

[command]                  # when kind = "command"
program    = "claude"
args       = ["-p"]
prompt_via = "arg"         # "arg" (append prompt) | "stdin" (pipe prompt)

# [openai]                 # when kind = "openai"
# base_url    = "https://api.openai.com/v1"
# model       = "gpt-4o-mini"
# api_key_env = "OPENAI_API_KEY"   # empty = no auth (e.g. local Ollama)

πŸ“– Usage reference

Run it at the root of a repo that has a .env.example:

env-wizard
Show details

At each prompt:

Input Effect
Enter Accept the shown default
? / /hint Ask the AI for a hint, then re-prompt
? <question> / /ask <question> Ask the AI a specific question about this variable
(empty) Leave the variable empty
q Quit without writing

Options:

Flag Description
-i, --input <PATH> Example file to read. Omit it to auto-detect: dotenv aliases (.env.example, .env.sample, .env.dist, .env.template, env.example) first, then a .toml/.yaml/.json config template
-o, --output <PATH> File to write. Defaults to .env for a dotenv example, or the template's name with the marker stripped for a config template (config.example.toml β†’ config.toml)
-y, --yes Accept all defaults and overwrite without confirming
--no-ai Disable the AI hint feature (no calls to a provider)
--from-code Also prompt for variables discovered in the code (dotenv only)

Commands:

Command Description
env-wizard Run the interactive .env filler
env-wizard config Choose or change the AI provider
env-wizard scan Audit code usage vs .env.example (add --check to exit 1 on drift, for CI)
env-wizard completions <shell> Print a shell completion script (bash, zsh, fish, elvish, powershell)

πŸ›  How it works

A quick look at the request β†’ hint pipeline:

Show details
.env.example ──▢ parse ──▢ prompt loop ──▢ .env
                              β”‚
                   type "?" ───
                              β–Ό
              gather repo context (README + configs + grep)
                              β–Ό
                 your AI provider (CLI or HTTP)
                              β–Ό
                render the hint cleanly in the terminal

❓ FAQ

Common questions about privacy, AI providers, and platform support:

Show details

What exactly is sent to the AI, and does it leave my machine? Only what's needed for a hint: the variable name, its .env.example comment, and repo context (your README, common config files, and code lines that mention the variable). The values you type and your existing .env are never sent. With a local provider (Ollama, LM Studio) even that context stays on your machine β€” only a cloud provider receives it over the network. env-wizard has no telemetry and stores no API keys; providers use their own configured credentials.

Could my existing .env secrets be sent to the AI? No. When building context, env-wizard deliberately skips real dotenv files (.env, .env.local, .env.production, …) β€” only template files like .env.example are ever read. So values already in your .env are never included in a prompt. (See is_secret_env_file in src/repo.rs.)

I don't have an AI CLI installed β€” is env-wizard still useful? Yes. The whole guided flow (inline comment hints, defaults, safe writing) works without any AI. If you press ? and the chosen provider isn't reachable, you get a clear error and the wizard simply continues. You can also run with --no-ai.

Which platforms are supported? Prebuilt binaries and Homebrew cover macOS and Linux. Windows works via cargo install (the code is cross-platform) but isn't part of the release binaries yet β€” feedback welcome.

πŸ“¦ Requirements

  • Nothing extra for the Homebrew or prebuilt-binary installs. A Rust toolchain (cargo) is only needed for the Cargo / from-source methods.
  • For the ? hint only: the provider you pick must be reachable β€” the chosen CLI on your PATH, or the HTTP endpoint up with its API key set. If not, everything else still works and the hint reports a clear error.

🀝 Contributing

If env-wizard saved you the twenty minutes of .env archaeology, a ⭐ on the repo helps other people find it too.

Issues and PRs are welcome! Before opening a PR, please run:

cargo test
cargo clippy --all-targets

πŸ“„ License

MIT Β© Alphonse Terrier

About

Interactive .env filler: walks a repo's .env.example, shows inline hints, and asks your AI (cloud or local) when you're stuck.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages