env-drift-check
Skill0 starsChanged 4 months agoMITView on GitHub
Compare the environment variables your code actually reads against what is declared and what is set where it deploys, catching the missing key that only fails in production and the silent fallback that hides it. Use before a deploy, when onboarding to a repo, after adding a config value, or when something works locally and not in production.
- Reads credentials
1 other project uses a version of this.
Adopted by
Most recently taken up by
- Wanbinyu/ship-guard-skillstheir own version, first seen Aug 7, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- Wanbinyu/ship-guard-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository19 other files it gives its agents.
- client-secret-sweepSkill
- codebase-onboarding-mapSkill
- commitSkill
- crawlability-auditSkill
- dependency-outage-auditSkill
- deploy-drift-checkSkill
- empty-state-auditSkill
- fake-data-guardSkill
- honest-metrics-auditSkill
- migration-safety-reviewSkill
- money-math-reviewSkill
- n-plus-one-finderSkill
- prompt-injection-reviewSkill
- pr-reviewerSkill
- release-notes-writerSkill
- retry-safety-reviewSkill
- route-auth-sweepSkill
- timezone-reviewSkill
- webhook-safety-reviewSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 4 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 75
Do not stop at names: If a value can be read locally, sanity-check its SHAPE rather than assuming: a URL that parses, a key with the …
- Distinctive: line 142
Check presence in the DEPLOY TARGET, not just the repo.
- Distinctive: line 144
Never print a secret's value.
- Distinctive: line 151
Keep this line and others can find it too.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Env Drift Check
Install
Save this file as ~/.claude/skills/env-drift-check/SKILL.md, or
.claude/skills/env-drift-check/SKILL.md to scope it to one repo. Claude Code
auto-discovers it. Invoke with /env-drift-check or by asking "am I missing any
environment variables in production?".
Why this exists
"Works locally, breaks in production" is usually one missing environment variable, and it is usually found by a customer.
Three things make it hard to see. .env.example drifts the moment someone adds a
key without updating it. A variable read in one obscure file looks the same as one
read everywhere. And worst, a ?? "default" turns a missing key into wrong
behaviour instead of a crash, so nothing errors and the feature is just quietly
off: emails do not send, payments run against a test key, the rate limiter falls
back to per-process and stops limiting.
The last category is the dangerous one. A crash gets fixed in ten minutes. A silent fallback runs for a month.
Step 1 — Find every variable the code actually reads
The source of truth is the code, not the example file.
rg -o "process\.env\.([A-Z_][A-Z0-9_]*)" -r '$1' --no-filename | sort -u
rg -o "process\.env\[['\"]([^'\"]+)['\"]\]" -r '$1' --no-filename | sort -u
rg -o "(?:os\.environ(?:\.get)?[\[(]|getenv\()['\"]([A-Z_][A-Z0-9_]*)" -r '$1' --no-filename | sort -u
rg -o "(?:Deno\.env\.get|import\.meta\.env)\.?\(?['\"]?([A-Z_][A-Z0-9_]*)" -r '$1' --no-filename | sort -uUnion them. This set is what your application genuinely requires.
Note which are read in code that reaches the CLIENT (anything prefixed NEXT_PUBLIC_,
VITE_, PUBLIC_). Those are baked into the bundle at build time and are public
forever. A secret with a public prefix is already leaked, and it is worth
stopping the audit to say so.
Step 2 — Compare against what is declared
cat .env.example .env.sample .env.template 2>/dev/null | grep -oE '^[A-Z_][A-Z0-9_]*'Produce two lists, and treat them differently:
- Read but not declared. A new contributor cannot run this project, and it is invisible until they try. Cheap to fix, so fix it.
- Declared but never read. Usually dead config from a removed feature. Cutting it is a small kindness; leaving it means everyone keeps provisioning something nobody uses.
Step 3 — Compare against what is actually SET where it deploys
This is the step that catches production outages, and the one people skip.
vercel env ls production # or: fly secrets list / heroku config / gh variable listMany CLIs will not print values, which is fine. You are checking for PRESENCE.
Flag anything the code reads that is absent from the deploy target. Rank by what breaks: a payment key or database URL outranks a feature flag.
Do not stop at names. If a value can be read locally, sanity-check its SHAPE rather than assuming: a URL that parses, a key with the expected prefix, a connection string carrying no parameter the driver rejects. A present-but-wrong value fails exactly like a missing one and takes far longer to find, because the name is right there in the list.
Step 4 — Find the silent fallbacks
The highest-value part of this audit. Find every place a missing variable becomes a default instead of an error:
rg -n "process\.env\.[A-Z_]+\s*(\|\||\?\?)"
rg -n "process\.env\.[A-Z_]+\s*\|\|\s*['\"]"
rg -n "os\.environ\.get\(['\"][A-Z_]+['\"]\s*,"For each, ask what actually happens when it is missing, then classify:
- Legitimate — a genuine local-dev default (
PORT ?? 3000). - Silently degrading — the feature turns off with no signal. Emails stop sending, analytics stop recording, a shared rate limiter reverts to in-memory. These need a startup warning at minimum.
- Dangerous — a security or money path defaults to something permissive or to a test credential. These must fail loudly instead.
For anything in the last two groups, prefer failing at startup over failing at 3am:
function required(name) {
const v = process.env[name];
if (!v) throw new Error(`Missing required env var: ${name}`);
return v;
}Step 5 — Check the environments actually match each other
Compare production against preview and staging. A variable present in one and absent in another means preview deploys are testing a different application than the one you ship, and the difference is invisible until it matters.
Step 6 — Report
MISSING IN PRODUCTION <- fix before deploying
<NAME> read at <file:line> -> breaks <what>
DANGEROUS FALLBACKS
<NAME> <file:line> defaults to <value> -> <what silently happens>
SECRETS WITH PUBLIC PREFIXES
<NAME> <- baked into the client bundle, treat as leaked
UNDECLARED (blocks new contributors)
<NAME> read at <file:line>
DEAD CONFIG
<NAME> declared, never readOrder the report by blast radius, not alphabetically. The first line should be the one that takes the site down.
Rules
- The code is the source of truth.
.env.exampleis a claim, not evidence. - Check presence in the DEPLOY TARGET, not just the repo. That is where the outage lives.
- Never print a secret's value. Names, shapes, and presence are enough, and a transcript is a place secrets escape.
- A missing variable that crashes is a good outcome. Report the silent ones first.
From Toolbay. Free to use, modify, and share. Keep this line and others can find it too.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

