zorath-env
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
AI-native .env validation in any language. Single-binary Rust CLI: typed schema validation, 22-pattern secret detection, SHA-pinned remote schemas, and a built-in stdio MCP server + Claude Code skill so AI agents drive it directly. No runtime, no hosting, no telemetry.
zorath-env
Package: zorath-env | Binary: zenv
Built by Zorath -- infrastructure for builders.
AI-native .env validation in any language. A fast, single-binary CLI that validates .env files against typed schemas, detects secrets, scans your code, generates docs, exports to 7 deployment formats, and auto-fixes issues -- with a Claude Code skill AND a stdio MCP server built into the binary so AI coding agents can drive it directly. No runtime, no hosting, no telemetry.
14 types -- 7 export formats -- 9 language scan -- 22 secret patterns -- 6 framework presets -- regression tests -- stdio MCP -- Claude Code skill
zenv combines typed
.envvalidation, a local stdio MCP server, pinned schema inheritance, and secret detection in one Rust binary.
Why zenv
.env files drift. Teams copy/paste secrets. CI fails at 3am. Docs go stale. Nobody catches the typo until production. AI coding agents need a tool they can drive without a Node runtime.
zenv catches config bugs at build time, not runtime. Your schema is the single source of truth -- docs, examples, and validation are all generated from it. And every AI coding agent in your workflow can drive it through MCP without any hosted infrastructure.
What makes zenv different:
- AI-native -- ships a Claude Code skill AND an
mcpsubcommand that speaks JSON-RPC 2.0 over stdio per MCP spec 2025-11-25. 5 tools, 3 resources, 3 prompts. No hosting, no telemetry, no vendor URL -- the agent drives the local binary as a subprocess - Validate with real types -- 14 validators (url, email, port, semver, uuid, ipv4, ipv6, date, hostname, and more), not just "is it a string?"
- Detect secrets in the validation pass -- 22 patterns (AWS, OpenAI, Anthropic, Stripe, GitHub, GitLab, Discord/Slack webhooks, JWT, private keys, more) PLUS value-aware URL-password detection that catches
postgres://user:pass@hosteven under innocuous keys likeFOO - Cryptographically-pinned remote schemas -- fetch over HTTPS with
--verify-hash <sha256>, custom CA, and connection-time address checks that reject internal destinations, including mapped IPv4. Share schemas across repos without trusting the host - Scan your code -- find env vars used in source code across 9 languages that aren't in your schema yet
- Export anywhere -- shell, Docker, Kubernetes, systemd, GitHub Secrets, JSON, dotenv
- Auto-fix -- add missing vars, remove unknown keys, preview changes safely with
--dry-run. Atomic write with Unix mode preservation - One binary, any stack -- Rust binary with no runtime deps. Node, Python, Go, Ruby, Java, PHP, Kotlin -- doesn't matter
- Verified supply chain -- SLSA build provenance attestations + OIDC trusted publishing to crates.io
See how zenv compares to dotenv-linter, envalid, dotenvx, and others: docs/comparison.md
Privacy
Local validation runs offline and never uploads your .env values. Remote schema URLs and version --check-update make explicit HTTPS requests. There is no telemetry.
Install
Via cargo (recommended)
Requires Rust 1.85 or newer with the locked dependencies.
cargo install --locked zorath-env
From source
cargo install --path .
Run locally
cargo run -- check
Library usage
zenv can be embedded in other Rust tools:
use zorath_env::commands::{check, docs, example, export};
use zorath_env::schema::{load_schema_with_options, LoadOptions};
// Load schema
let opts = LoadOptions::default();
let schema = load_schema_with_options("env.schema.json", &opts)?;
// Validate files directly
let errors = check::validate_files(".env", "env.schema.json", &opts)?;
// Generate documentation
let markdown = docs::generate(&schema, "markdown")?;
let json_docs = docs::generate(&schema, "json")?;
// Generate .env.example content
let example_content = example::generate(&schema, true); // include defaults
// Export to deployment formats
use zorath_env::commands::export::ExportFormat;
let docker_env = export::export_to_string(&env_map, ExportFormat::Docker)?;
let k8s_config = export::export_to_string(&env_map, ExportFormat::K8s)?;
Add to your Cargo.toml:
[dependencies]
zorath-env = "0.3"
Quick start
1. Create a schema from your existing .env:
zenv init # Infers types from .env.example
zenv init --preset nextjs # Or start from a framework preset
2. Validate your .env against the schema:
zenv check # Text output for humans
zenv check --format json # JSON output for CI/CD
zenv check --detect-secrets # Also scan for leaked credentials
zenv check --watch # Re-validate on every file save
3. Find env vars in your code that aren't in your schema:
zenv scan --show-unused # JS, Python, Go, Rust, PHP, Ruby, Java, C#, Kotlin
4. Export to deployment formats:
zenv export --env .env --format k8s # Kubernetes ConfigMap
zenv export --env .env --format docker # Dockerfile ENV directives
zenv export --env .env --format github-secrets # GitHub CLI gh secret set
5. Generate docs and examples:
zenv docs > ENVIRONMENT.md # Markdown documentation from schema
zenv example -o .env.example # Generate .env.example from schema
Commands
zenv check
Validates .env against env.schema.json.
Exit codes (CI-friendly):
0- Valid1- Validation failed (invalid values, missing required)2- Input/file error (file not found, failed to read)3- Schema error (invalid JSON, parse failure)
When fixable issues are found, check suggests running zenv fix.
zenv check # Basic validation
zenv check --detect-secrets # Also scan for potential secrets
zenv check --format json # JSON output for CI/CD
JSON Output (--format json):
Machine-readable output for CI/CD pipelines:
{
"valid": true,
"errors": [],
"warnings": [],
"secret_warnings": [],
"stats": { "total_variables": 10, "schema_variables": 10 }
}
Secret Detection (--detect-secrets):
Scans for potential secrets that shouldn't be committed:
- AWS Access Keys and Secret Keys
- Stripe, GitHub, GitLab, Slack tokens
- Google, Heroku, SendGrid, Twilio, Mailchimp API keys
- npm tokens
- Private key headers (RSA, SSH, PGP)
- JWT tokens
- URLs with embedded passwords
- High-entropy strings
Watch Mode (--watch):
Watches for file changes and re-validates automatically:
zenv check --watch # Watch .env and schema
zenv check --watch --detect-secrets # Watch with secret detection
Features:
- Delta detection: shows exactly which variable changed
- Shows changed keys and reports the complete current validation status
- Content-hash skip: ignores saves without changes
- Local timestamps
- Terminal bell on errors
- Tracks inherited local schemas, editor file replacements, and recovery after read errors
- Applies the same warning/error severity rules as a normal check
zenv docs
Generates documentation for all env vars in the schema.
zenv docs # Markdown (default)
zenv docs --format json # JSON output
zenv docs --format json > schema.json
zenv init
Creates env.schema.json from .env.example (best-effort inference, you refine types after).
zenv version
Shows installed version and optionally checks for updates.
zenv version # Show installed version
zenv version --check-update # Check crates.io for newer version
zenv completions
Generates shell completions for bash, zsh, fish, and PowerShell.
zenv completions bash > /etc/bash_completion.d/zenv
zenv completions zsh > ~/.zfunc/_zenv
zenv completions fish > ~/.config/fish/completions/zenv.fish
zenv completions powershell > zenv.ps1
# Or evaluate directly
eval "$(zenv completions bash)"
zenv example
Generates .env.example from schema (reverse of init).
zenv example # Output to stdout
zenv example --include-defaults # Include default values
zenv example --output .env.example # Write to file
Placeholders respect declared types, enum choices, and basic length/numeric bounds. All six bundled presets generate examples that pass their schema checks. Secret placeholders must still be replaced with real application values; passing a format check does not make them usable credentials or encryption keys. Arbitrary regex constraints that cannot be generated are marked for manual completion. Default values are masked in comments; --include-defaults explicitly writes them into assignments.
zenv diff
Compares two .env files and shows differences.
zenv diff .env.development .env.production
zenv diff .env.dev .env.prod --schema env.schema.json
zenv diff .env.dev .env.prod --format json # Machine-readable output
Shows:
- Variables only in first file
- Variables only in second file
- Variables with different values
- Possible typos ("Did you mean?" suggestions)
- Optional schema compliance check for both files
zenv fix
Auto-fix common .env issues with backup.
zenv fix # Fix issues, create backup
zenv fix --dry-run # Preview fixes without applying
zenv fix --remove-unknown # Also remove keys not in schema
What it fixes:
- Missing required variables (adds schema defaults, or empty placeholders for manual completion)
- Unknown keys (with
--remove-unknown)
Security: --dry-run masks sensitive values (passwords, keys, tokens) as ***MASKED***.
What it reports but doesn't fix:
- Invalid types (needs human input)
- Required values without a schema default (review and fill the added placeholders)
zenv scan
Scan source code for environment variable usage.
zenv scan # Scan current directory
zenv scan --path ./src # Scan specific directory
zenv scan --show-unused # Show vars in schema but not in code
zenv scan --show-paths # Show file:line for all found vars
zenv scan --format json # JSON output for CI
Supported languages: JavaScript/TypeScript, Python, Go, Rust, PHP, Ruby, Java, C#, Kotlin
zenv cache
Manage remote schema cache.
zenv cache list # Show cached schemas
zenv cache stats # Show cache statistics
zenv cache clear # Clear all cached schemas
zenv cache clear https://... # Clear specific cached schema
zenv cache path # Show cache directory location
Clearing removes the schema and its rate-limit metadata, so a fresh request can follow immediately. Listing, statistics, and doctor count schema files only; unrelated files and in-progress temporary writes are preserved.
zenv export
Export .env to various formats for deployment.
zenv export --env .env --format shell # Shell script (export FOO="bar")
zenv export --env .env --format docker # Dockerfile (ENV FOO=bar)
zenv export --env .env --format k8s # Kubernetes ConfigMap YAML
zenv export --env .env --format json # JSON object
zenv export --env .env --format systemd # systemd Environment directives
zenv export --env .env --format dotenv # Standard .env format
zenv export --env .env --format github-secrets # GitHub CLI (gh secret set)
zenv export --env .env --schema s.json # Only export vars in schema
zenv export --env .env -f shell -o setup.sh # Write to file
Exports preserve literal quotes, backslashes, and newlines where the target format supports them. Dockerfile export rejects multiline values; use JSON or dotenv for those values. Shell, Docker, systemd, and GitHub Secrets exports require valid environment variable names.
zenv doctor
Run health check and diagnostics.
zenv doctor
Checks:
- Schema file exists and is valid
- .env file exists and parses correctly
- Config file (.zenvrc) is valid JSON
- Remote schema cache is accessible
- Validation passes (if schema and env exist)
Output shows [OK], [WARN], or [ERROR] with actionable suggestions.
Doctor reports the selected custom or discovered config and validates the files it finds, including YAML schemas and .env.local. Explicit missing paths report an error. Warning-severity validation issues remain warnings.
zenv template
Generate CI/CD configuration templates for popular platforms.
zenv template github # Output GitHub Actions workflow
zenv template gitlab -o .gitlab-ci.yml # Write GitLab CI config
zenv template circleci # Output CircleCI config
zenv template --list # List available templates
Available templates:
github(aliases:gh,github-actions) - GitHub Actions workflowgitlab(aliases:gl,gitlab-ci) - GitLab CI configurationcircleci(aliases:circle) - CircleCI configuration
Files
By default, zenv looks for:
.env(optional).env.example(optional)env.schema.json(preferred)
Env file fallback
If .env doesn't exist, zenv check will automatically try:
.env.local.env.development.env.development.local
This is useful for Next.js and other frameworks that use .env.local for secrets.
You can override paths:
zenv check --env .env --schema env.schema.json
zenv docs --schema env.schema.json
zenv init --example .env.example --schema env.schema.json
Schema format (v0.3)
Schemas can be written in JSON or YAML (auto-detected by file extension).
JSON schema
env.schema.json is a JSON object where each key is an env var name.
{
"DATABASE_URL": {
"type": "url",
"required": true,
"description": "Primary database connection string"
},
"NODE_ENV": {
"type": "enum",
"values": ["development", "staging", "production"],
"default": "development",
"required": true,
"description": "Runtime environment"
},
"PORT": {
"type": "port",
"default": 3000,
"required": false,
"description": "HTTP port"
}
}
YAML schema
Use .yaml or .yml extension for YAML schemas:
# env.schema.yaml - more readable, supports comments
DATABASE_URL:
type: url
required: true
description: Primary database connection string
NODE_ENV:
type: enum
values:
- development
- staging
- production
default: development
description: Runtime environment
SERVER_PORT:
type: port
default: 3000
description: HTTP port
Supported types
| Type | Description | Example |
|---|---|---|
string |
Any string value | "hello" |
int |
Integer number | 42 |
float |
Floating point number | 3.14 |
bool |
Boolean (true/false/1/0/yes/no) | true |
url |
Valid URL | https://example.com |
enum |
One of specified values | "development" |
uuid |
UUID format | 550e8400-e29b-41d4-a716-446655440000 |
email |
Email address | [email protected] |
ipv4 |
IPv4 address | 192.168.1.1 |
ipv6 |
IPv6 address | 2001:0db8:85a3::8a2e:0370:7334 |
semver |
Semantic version | 1.2.3-beta.1 |
port |
Port number (1-65535) | 8080 |
date |
ISO 8601 date | 2024-06-15 |
hostname |
RFC 1123 hostname | api.example.com |
Validation rules
Add constraints with the validate field:
{
"PORT": { "type": "int", "validate": { "min": 1024, "max": 65535 } },
"RATE": { "type": "float", "validate": { "min_value": 0.0, "max_value": 1.0 } },
"API_KEY": { "type": "string", "validate": { "min_length": 32, "pattern": "^sk_" } }
}
Severity levels
Mark non-critical validations as warnings (don't cause exit code 1):
{
"DEBUG": {
"type": "bool",
"severity": "warning",
"description": "Enable debug mode (optional, won't fail CI)"
},
"DATABASE_URL": {
"type": "url",
"required": true,
"severity": "error"
}
}
Default severity is "error". Warnings are reported but don't fail validation.
Schema inheritance
Schemas can extend other schemas:
{
"extends": "base.schema.json",
"EXTRA_VAR": { "type": "string" }
}
Inheritance supports up to 10 levels of depth. Circular references are detected and will cause an error. Local parent schemas must exist within the referring schema's directory or its subdirectories; paths and symlinks that escape that directory are rejected.
A local schema can also extend an HTTPS URL. Pin each parent with extends_hash, using its SHA-256 digest (or at least 32 hexadecimal characters):
{
"extends": "https://example.com/base.schema.json",
"extends_hash": "<replace with the parent's actual SHA-256 digest>",
"EXTRA_VAR": { "type": "string" }
}
When --verify-hash pins the root, every inherited schema must have its own parent pin. A single digest cannot verify different files. Missing parent pins and hash mismatches fail before the untrusted dependency is used.
Schemas are validated when loaded: unknown variable/rule fields, inapplicable or contradictory constraints, missing enum choices, invalid patterns, and invalid defaults are errors even when no .env values exist. Defaults describe accepted fallback values and are used by fix and example --include-defaults; check does not inject them into your application or rewrite your .env.
Remote schemas
Fetch schemas from HTTPS URLs for shared team configurations:
# Validate against remote schema
zenv check --schema https://example.com/schemas/env.schema.json
# Generate docs from remote schema
zenv docs --schema https://raw.githubusercontent.com/org/repo/main/env.schema.json
# Force fresh fetch (skip cache)
zenv check --schema https://example.com/schema.json --no-cache
Features:
- HTTPS only (HTTP rejected for security)
- Automatic caching with 1-hour TTL
--no-cacheflag to bypass cache- Remote schemas can extend other schemas (URLs resolved relative to parent)
- Cached schemas remain available during the network rate-limit window
- YAML URL detection ignores query parameters and fragments
Remote requests connect directly: proxy environment variables are ignored so a proxy cannot bypass destination address checks. DNS resolution is covered by the 30-second request timeout, and the checked addresses are passed directly to the connection. Networks that require an outbound proxy must provide schemas locally.
Remote schema security
Hash verification - Verify schema integrity with SHA-256:
# Use the schema's actual SHA-256 digest (64 hexadecimal characters),
# or a prefix containing at least 32 hexadecimal characters.
zenv check --schema https://example.com/schema.json --verify-hash "$SCHEMA_SHA256"
Custom CA certificates - For enterprise internal servers:
zenv check --schema https://internal.corp/schema.json --ca-cert /path/to/ca.pem
Rate limiting - Prevents excessive fetching:
- Default: 60 seconds between fetches per URL
- Bypassed by
--no-cache - Configure in
.zenvrc:"rate_limit_seconds": 120
Configuration File (.zenvrc)
Create a .zenvrc file in your project root to set default options. CLI arguments always override .zenvrc settings.
{
"schema": "env.schema.json",
"env": ".env.local",
"detect_secrets": true
}
All Configuration Keys
| Key | Type | Description |
|---|---|---|
schema |
string | Path to schema file (default: env.schema.json) |
env |
string | Path to .env file (default: .env) |
allow_missing_env |
boolean | Allow validation when .env file is missing |
detect_secrets |
boolean | Enable secret detection during validation |
no_cache |
boolean | Skip cache when fetching remote schemas |
no_color |
boolean | Disable colored terminal output |
verify_hash |
string | SHA-256 hash (full or >=32-char prefix) to verify remote schema integrity |
ca_cert |
string | Path to custom CA certificate (PEM format) |
rate_limit_seconds |
number | Seconds between remote schema fetches (default: 60) |
format |
string | Default output format for check/docs/diff/scan/export (per-command default if omitted) |
Example: Full Configuration
Invalid or unreadable configuration is an input error; it no longer silently disables configured checks. Relative env, schema, and ca_cert paths are resolved from the config file directory. Explicit command-line paths are resolved from the current working directory.
{
"schema": "config/env.schema.json",
"env": ".env.local",
"allow_missing_env": false,
"detect_secrets": true,
"no_cache": false,
"no_color": false,
"verify_hash": "a1b2c3d4e5f6...",
"ca_cert": "/etc/ssl/certs/internal-ca.pem",
"rate_limit_seconds": 120,
"format": "json"
}
Note: Unknown keys in .zenvrc will trigger a warning but won't cause failures.
.env features
Comments and Blank Lines
Full-line comments, inline comments, and blank lines are supported:
# This is a full-line comment
DATABASE_URL=postgres://localhost/db # inline comment
# Blank lines are ignored
PORT=3000
Export prefix
Shell-style export prefix is supported for compatibility:
export DATABASE_URL=postgres://localhost/db
export NODE_ENV=development
Variable interpolation
Reference other variables with ${VAR} or $VAR:
BASE_URL=https://api.example.com
API_ENDPOINT=${BASE_URL}/v2
Multiline values
Use quoted strings for multiline:
SSH_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END RSA PRIVATE KEY-----"
Escape sequences
Double-quoted strings support \n, \t, \r, \\, \"
Example output
Success
$ zenv check
zenv: OK
Validation errors
$ zenv check
zenv check failed:
- DATABASE_URL: expected url, got 'not-a-url'
- NODE_ENV: expected one of ["development", "staging", "production"], got 'dev'
- API_KEY: missing (required)
When unknown variables are found in your .env that are not in the schema, zenv will show a helpful tip suggesting you update your schema.
Pre-commit hook
# .git/hooks/pre-commit (make executable)
#!/usr/bin/env bash
set -e
if [ -f "env.schema.json" ]; then
if command -v zenv >/dev/null 2>&1; then
zenv check || exit 1
else
cargo run --quiet -- check || exit 1
fi
fi
AI agent integration
For developers using Claude Code or any other AI coding agent: there is
a ready-made skill in integrations/claude-code/
that teaches the agent how to drive zenv against any .env file in any
project. The skill covers every subcommand, the right flags for
programmatic use, the structured exit codes, and the anti-patterns the
agent must not commit (e.g. never run zenv fix without --dry-run first).
Install (one-liner):
# Linux / macOS
mkdir -p ~/.claude/skills/zenv && \
curl -fsSL https://raw.githubusercontent.com/zorl-engine/zorath-env/main/integrations/claude-code/SKILL.md \
-o ~/.claude/skills/zenv/SKILL.md
The skill is plain markdown, runs entirely on your machine, makes no
network calls, and has no hosted dependency. Seeintegrations/claude-code/README.md
for the Windows install, prompts that demonstrate the integration, and
the privacy notes.
For clients that prefer the standard MCP protocol (Cursor, Cline,
Windsurf, or any future MCP-compatible client), the zenv mcp stdio
subcommand is built into the binary. Add to your client config:
{
"mcpServers": {
"zenv": { "command": "zenv", "args": ["mcp"] }
}
}
Exposes 5 tools, 3 resources (schema, masked .env, generated docs),
3 prompts (audit_env, new_var_workflow, diagnose_missing), and the
standard lifecycle surface (initialize, ping, logging/setLevel,
completion). Zero new dependencies in the binary, zero hosting, zero
telemetry -- runs entirely as a subprocess of your AI client.
zenv --config path/to/config.json mcp applies that configuration to both tool calls and resources. The masked env resource respects schema secret: true declarations and masks complete multiline assignments, including duplicates. Tool arguments are checked against their advertised input schemas before execution.
GitHub Action
Validate .env files in your CI/CD pipeline:
- name: Validate .env
uses: zorl-engine/zorath-env/.github/actions/zenv-action@main
with:
schema: env.schema.json
env-file: .env.example
Inputs:
schema- Path to schema file (default:env.schema.json)env-file- Path to .env file (default:.env)allow-missing-env- Allow missing .env (default:false)version- zenv version to use (default:latest)
Outputs:
valid-trueif validation passederrors- JSON array of error messages
Connect
- Official site: zorl.cloud
- Documentation: zorl.cloud/zenv/docs
- GitHub: github.com/zorl-engine/zorath-env
- crates.io: crates.io/crates/zorath-env
- All links: edgeurl.io/p/zorl-engine
License
MIT
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found