amagi-env-check
Compare .env, .env.example and the environment your app actually runs with on Vercel, Railway or Fly. It lists the keys that are missing, extra, empty or defined twice, and it never prints a value.
Install
pipx install amagi-env-check
Python 3.9 or newer. No dependencies.
Usage
Run it from your project folder. With no options it compares .env (or .env.local) against .env.example:
amagi-env-check
Add the live environment by letting it call the platform CLI you are already logged in to:
amagi-env-check --run vercel
Real output from the Next.js example that ships in this repo, using a saved vercel env ls production table:
cd examples/nextjs-app
amagi-env-check --live vercel-env-ls.txt
Compared 3 sources: .env.example (9 keys), .env.local (8 keys), vercel (7 keys, names only)
MISSING IN vercel listed in .env.example, not in vercel
RESEND_API_KEY
STRIPE_WEBHOOK_SECRET
MISSING IN .env.local listed in .env.example, not in .env.local
RESEND_API_KEY
EXTRA IN vercel in vercel, not listed in .env.example
LEGACY_API_TOKEN
EXTRA IN .env.local in .env.local, not listed in .env.example
DEBUG_SQL line 8
EMPTY IN .env.local present with an empty value
NEXT_PUBLIC_POSTHOG_KEY line 7
DUPLICATE IN .env.local defined more than once; the last one wins
DATABASE_URL lines 1, 9
7 problems (3 missing, 2 extra, 1 empty, 1 duplicate) across 11 keys. No values were printed.
The exit code is 1 because problems were found. Missing keys in the live source come first, because those are the ones that break a deploy.
Add --matrix to see every key against every source:
KEY .env.example .env.local vercel
DATABASE_URL listed set present
DEBUG_SQL - set -
LEGACY_API_TOKEN - - present
NEXTAUTH_SECRET listed set present
NEXTAUTH_URL listed set present
NEXT_PUBLIC_POSTHOG_KEY listed empty present
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY listed set present
RESEND_API_KEY listed - -
SENTRY_DSN optional - -
STRIPE_SECRET_KEY listed set present
STRIPE_WEBHOOK_SECRET listed set -
present means the platform lists the key but hides its value, so the tool can't tell whether it is empty. optional comes from a commented # SENTRY_DSN= line in the example file: the key is documented, and leaving it out is fine.
The live environment
There are two ways in. --run calls the platform CLI for you. --live reads output you saved or piped, so you can run the CLI however you like.
Vercel
amagi-env-check --run vercel # production
amagi-env-check --run vercel --target preview
vercel env ls production | amagi-env-check --live -
--run vercel uses vercel env ls <target> --format json and falls back to the plain table on older CLIs. Vercel only returns names here, never values.
Railway
amagi-env-check --run railway
amagi-env-check --run railway --run-args "--service api"
railway variable list --json > live.json && amagi-env-check --live live.json
--run railway uses railway variable list --json and falls back to railway variables --json. Railway does return values. The tool reads each one only to check whether it is empty, then drops it. Sealed variables count as present.
Fly
amagi-env-check --run fly --run-args "-a my-app"
fly secrets list -a my-app | amagi-env-check --live -
--run fly uses fly secrets list --json (or flyctl). Fly returns names and digests, never values.
Anything else
--live also takes a flat JSON object, a JSON list of {"name": ...} items, or a plain dotenv file such as the one vercel env pull writes. Use --live-format if auto-detection guesses wrong, and --live-name to change the label in the report.
The four categories
- missing: the example file lists the key, and this source doesn't have it. With no example file,
.envbecomes the reference, and keys that only the live source has show up as missing from.env. - extra: the source has a key that the example file never mentions. Either document it or delete it.
- empty: the key is there with nothing after the
=. A key that is optional in the example file is allowed to be empty. - duplicate: the key is defined twice in one file. Most loaders keep the last one, which is rarely what you meant.
Options
amagi-env-check path/to/project # compare another folder
amagi-env-check --env .env.production # pick the local file
amagi-env-check --example .env.sample # pick the example file
amagi-env-check --no-env --run vercel # example vs live only
amagi-env-check --matrix # add the key-by-source table
amagi-env-check --format json # findings as JSON
amagi-env-check --ignore 'DEBUG_*' # skip a key or glob (repeatable)
amagi-env-check --fail-on missing,empty # only these categories fail the run
amagi-env-check --fail-on none # report, always exit 0
Keys the platforms inject on their own (VERCEL, VERCEL_*, TURBO_*, NX_DAEMON, RAILWAY_*, FLY_*) are skipped in .env and the live source unless your example file lists them, so a file written by vercel env pull doesn't flag VERCEL_OIDC_TOKEN. --no-default-ignore keeps them. For keys you want to silence for good, put one name or glob per line in a .envcheckignore file in the project folder.
Exit codes: 0 means no problems, 1 means problems were found, 2 means a usage or input error.
What it never does
It never prints, logs or stores a value. Parsers read a value only to decide whether it is empty, and the result holds key names and line numbers, nothing else. A warning about a malformed line gives the line number, and the key when there is one. The test suite plants a sentinel value in every input format that carries values (dotenv, JSON, the Railway table) and fails if it shows up anywhere in text, matrix or JSON output, or on stderr.
It doesn't change anything either. --run only calls the read-only list command for each platform.
Use it from Claude Code
This repo ships a skill at .claude/skills/amagi-env-check/SKILL.md. Copy that folder into your own .claude/skills/ and Claude Code can run the diff before a deploy, read the JSON, and tell you which keys to add where.
Limits
- Vercel and Fly never return values, so
emptycan't be checked for those sources. Railway can, except for sealed variables. --runneeds the platform CLI on your PATH, logged in and linked to the project. When the CLI fails, the tool exits 2 and shows the last lines of its error.- Vercel
--targetmatches the environment column, so custom environments work only if the name appears there. - It compares one live environment per run. To check preview and production, run it twice.
- Dotenv parsing follows the common rules (quotes,
export, inline#comments, multi-line double quotes). Variable expansion such as${OTHER}is not resolved, which doesn't matter for an empty check.
If this saved you time
A star helps other people find it.
More from AmagiLabs
- amagilabs: other small open source dev tools from the same lab.
- amagi-site-diff: compare two versions of a website page by page.
- amagi-watch: turn a video URL into a Claude-readable transcript and frame index.
- amagi-legal-review-skills: Claude Code skills for contract and lease review.
License
MIT, see LICENSE. Copyright (c) 2026 Amagisolutionsgroup, Inc. (AmagiLabs)
Metadata
Release files for amagi-env-check 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| amagi_env_check-0.1.0.tar.gz | 24.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| amagi_env_check-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.8 kB
Release files / amagi_env_check-0.1.0.tar.gz
| Download URL | amagi_env_check-0.1.0.tar.gz |
|---|---|
| Size | 24.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9dafb95aed49156e015ddb3612793be27baa8fa0c4248a34f22b3f2187197f6a
|
|
BLAKE2b-256 checksum How to use checksums |
46150991ecc89409f60b96de5cc32118cbb09567cd7b180dedac5ff0da6bb1f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logRelease files / amagi_env_check-0.1.0-py3-none-any.whl
| Download URL | amagi_env_check-0.1.0-py3-none-any.whl |
|---|---|
| Size | 16.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ee98ce9eb9c053f4959a2f8711530c2efda701a7e44f61e61b5c65e65e861ce6
|
|
BLAKE2b-256 checksum How to use checksums |
de377e7b1427964aa05739975def31661f69e16192d41542537c507806b9097d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logSecurity for amagi-env-check 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for amagi_env_check-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.