Env Setup
Make a project's environment configuration explicit: find every variable the
code reads, keep .env.example truthful, verify the developer's real .env
satisfies it, and make sure no secret file can reach git.
Contract
Inputs:
- A repository; mode
setup (default, discover + scaffold + validate),
validate (check only), or scaffold (regenerate templates only).
Outputs:
- The discovered variable inventory grouped by service, gaps between code and
.env.example, missing/unset required variables, and any .gitignore holes.
Creates/Modifies:
setup/scaffold: creates or updates .env.example (and per-app templates
in a monorepo). May add missing .env* rules to .gitignore.
- Never creates, edits, or overwrites a real
.env/.env.local — it reports
what is missing there and leaves the values to the developer.
External Side Effects:
- None. Reads the codebase and env files locally; never transmits values.
Confirmation Required:
- Before overwriting an existing
.env.example that has hand-written comments
or values the scan did not produce.
When to Use
- Setting up environment variables for a new project or app
- Regenerating
.env.example after configuration drift
- Validating that a
.env satisfies what the code requires
- Auditing that
.gitignore keeps secret env files out of git
Phase 1: Discover Required Variables
Scan the codebase for environment reads:
grep -rEoh "(process\.env|import\.meta\.env)(\.[A-Z0-9_]+|\[['\"][A-Z0-9_]+['\"]\])" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
--include="*.mjs" --include="*.cjs" \
--exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build \
--exclude-dir=.next --exclude-dir=coverage . \
| grep -oE "[A-Z0-9_]{2,}" | sort -u
Treat that grep as a starting inventory, never as the answer. It knows one
language family (JS/TS) and two syntaxes (process.env.X and
process.env["X"], plus the import.meta.env equivalents). It cannot see a
variable read through a helper (getEnv("STRIPE_KEY")), a destructure
(const { DATABASE_URL } = process.env), a dynamic key, or a non-JS service in
the same repo — Python os.environ, Go os.Getenv, Dockerfiles, CI workflows.
Exclusions are directory-scoped (--exclude-dir) because filtering grep -oh
output by path is impossible: -o prints only the matched text and -h
suppresses the filename, so a downstream grep -v node_modules matches nothing
and silently filters nothing.
Widen the sweep by hand from there: framework config (next.config.*,
nest-cli.json, deploy config), schema-based env validation modules
(zod/valibot env files), container and CI definitions, and existing .env*
files. In a monorepo, inventory per app/package — apps often need different
variables. Report the inventory as "found by scan + found by hand", so a reader
can see what the automated pass could not cover.
Phase 2: Generate .env.example
Create or update .env.example from the inventory. Group by service with a
comment header per group, placeholder values only — never a real credential:
# Application
NODE_ENV=development
PORT=3001
# Database
DATABASE_URL=postgresql://user:password@host:5432/dbname
# Authentication
AUTH_SECRET=...
# Monitoring
SENTRY_DSN=https://...
For monorepos, write per-app templates when apps diverge. Preserve existing
hand-written comments; confirm before overwriting anything the scan did not
produce. Document any variable whose purpose is not obvious from its name.
Phase 3: Validate
- Every variable the code reads appears in
.env.example; every template
variable is actually read somewhere (flag dead entries).
- The local
.env (if present) sets every required variable; report gaps
without printing secret values.
- For TypeScript projects, recommend schema-based env validation (e.g. zod) at
app startup so missing variables fail fast — point at where to add it rather
than wiring it unasked.
Phase 4: Keep Secrets Out of Git
.gitignore must cover .env, .env.local, and every .env.* variant
except .env.example (which must be committed).
- Check nothing secret is already tracked:
git ls-files '.env*' should return
only templates. A tracked secret file is a finding to surface — removing it
from history belongs to git-safety, not this skill.
- For production, point at platform-native secret stores (AWS Secrets Manager,
Vercel/hosting env vars) — real values never live in the repo.
Final Report
State the mode that ran, variables discovered (per app where relevant),
template files created or updated, validation gaps, and any .gitignore or
tracked-secret findings.
Anti-Patterns
- Writing real values. This skill produces templates and reports; actual
secrets are entered by the developer or a secret manager.
- Printing secret values in output. Name the variable, never its value.
- Guessing variables the code never reads. The template mirrors the code,
not a generic stack checklist.
1---
2name: env-setup
3description: >-
4 Discover the environment variables a codebase actually reads, generate or
5 update a grouped .env.example template, validate that required variables are
6 set, and keep secrets out of git. Use when setting up environment variables
7 for a project, scaffolding .env templates, validating an existing .env file,
8 documenting required configuration, or checking that .gitignore covers env
9 files. Backs the /env command.
10metadata:
11 version: "1.0.0"
12 tags: "environment, dotenv, secrets, configuration, scaffolding, validation"
13 author: Ship Shit Dev
14when_to_use: "/env, set up environment variables, create .env.example, validate .env, missing env var, document environment configuration, env template, secrets in git"
15---
16
17# Env Setup
18
19Make a project's environment configuration explicit: find every variable the
20code reads, keep `.env.example` truthful, verify the developer's real `.env`
21satisfies it, and make sure no secret file can reach git.
22
23## Contract
24
25Inputs:
26
27- A repository; mode `setup` (default, discover + scaffold + validate),
28 `validate` (check only), or `scaffold` (regenerate templates only).
29
30Outputs:
31
32- The discovered variable inventory grouped by service, gaps between code and
33 `.env.example`, missing/unset required variables, and any `.gitignore` holes.
34
35Creates/Modifies:
36
37- `setup`/`scaffold`: creates or updates `.env.example` (and per-app templates
38 in a monorepo). May add missing `.env*` rules to `.gitignore`.
39- Never creates, edits, or overwrites a real `.env`/`.env.local` — it reports
40 what is missing there and leaves the values to the developer.
41
42External Side Effects:
43
44- None. Reads the codebase and env files locally; never transmits values.
45
46Confirmation Required:
47
48- Before overwriting an existing `.env.example` that has hand-written comments
49 or values the scan did not produce.
50
51## When to Use
52
53- Setting up environment variables for a new project or app
54- Regenerating `.env.example` after configuration drift
55- Validating that a `.env` satisfies what the code requires
56- Auditing that `.gitignore` keeps secret env files out of git
57
58## Phase 1: Discover Required Variables
59
60Scan the codebase for environment reads:
61
62```bash
63grep -rEoh "(process\.env|import\.meta\.env)(\.[A-Z0-9_]+|\[['\"][A-Z0-9_]+['\"]\])" \
64 --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
65 --include="*.mjs" --include="*.cjs" \
66 --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build \
67 --exclude-dir=.next --exclude-dir=coverage . \
68 | grep -oE "[A-Z0-9_]{2,}" | sort -u
69```
70
71**Treat that grep as a starting inventory, never as the answer.** It knows one
72language family (JS/TS) and two syntaxes (`process.env.X` and
73`process.env["X"]`, plus the `import.meta.env` equivalents). It cannot see a
74variable read through a helper (`getEnv("STRIPE_KEY")`), a destructure
75(`const { DATABASE_URL } = process.env`), a dynamic key, or a non-JS service in
76the same repo — Python `os.environ`, Go `os.Getenv`, Dockerfiles, CI workflows.
77Exclusions are directory-scoped (`--exclude-dir`) because filtering `grep -oh`
78output by path is impossible: `-o` prints only the matched text and `-h`
79suppresses the filename, so a downstream `grep -v node_modules` matches nothing
80and silently filters nothing.
81
82Widen the sweep by hand from there: framework config (`next.config.*`,
83`nest-cli.json`, deploy config), schema-based env validation modules
84(zod/valibot env files), container and CI definitions, and existing `.env*`
85files. In a monorepo, inventory per app/package — apps often need different
86variables. Report the inventory as "found by scan + found by hand", so a reader
87can see what the automated pass could not cover.
88
89## Phase 2: Generate .env.example
90
91Create or update `.env.example` from the inventory. Group by service with a
92comment header per group, placeholder values only — never a real credential:
93
94```env
95# Application
96NODE_ENV=development
97PORT=3001
98
99# Database
100DATABASE_URL=postgresql://user:password@host:5432/dbname
101
102# Authentication
103AUTH_SECRET=...
104
105# Monitoring
106SENTRY_DSN=https://...
107```
108
109For monorepos, write per-app templates when apps diverge. Preserve existing
110hand-written comments; confirm before overwriting anything the scan did not
111produce. Document any variable whose purpose is not obvious from its name.
112
113## Phase 3: Validate
114
115- Every variable the code reads appears in `.env.example`; every template
116 variable is actually read somewhere (flag dead entries).
117- The local `.env` (if present) sets every required variable; report gaps
118 without printing secret values.
119- For TypeScript projects, recommend schema-based env validation (e.g. zod) at
120 app startup so missing variables fail fast — point at where to add it rather
121 than wiring it unasked.
122
123## Phase 4: Keep Secrets Out of Git
124
125- `.gitignore` must cover `.env`, `.env.local`, and every `.env.*` variant
126 **except** `.env.example` (which must be committed).
127- Check nothing secret is already tracked: `git ls-files '.env*'` should return
128 only templates. A tracked secret file is a finding to surface — removing it
129 from history belongs to `git-safety`, not this skill.
130- For production, point at platform-native secret stores (AWS Secrets Manager,
131 Vercel/hosting env vars) — real values never live in the repo.
132
133## Final Report
134
135State the mode that ran, variables discovered (per app where relevant),
136template files created or updated, validation gaps, and any `.gitignore` or
137tracked-secret findings.
138
139## Anti-Patterns
140
141- **Writing real values.** This skill produces templates and reports; actual
142 secrets are entered by the developer or a secret manager.
143- **Printing secret values in output.** Name the variable, never its value.
144- **Guessing variables the code never reads.** The template mirrors the code,
145 not a generic stack checklist.