skill
envguard
Environment-variable audit CLI with Supabase Edge Functions support
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/Tresnanda/envguard itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 25, 2026envguard
Environment-variable audits for Python, JavaScript, shell, PowerShell, and Supabase Edge Function projects.
envguard scans a codebase for environment variable references, compares those references with .env.example, and can optionally include Supabase Edge Function secrets in the same audit. It helps catch stale config, missing deployment secrets, and undocumented variables before they become production incidents.
Why Use It
Environment variables tend to drift as projects grow. Old keys stay in example files, new keys are added directly to code, and serverless secrets can linger after features are removed. envguard gives you a fast local check that is easy to run before deploys or in CI.
It reports six classes of findings:
| Issue | Meaning |
|---|---|
UNUSED | A key exists in .env.example but is not referenced in the scanned code. |
MISSING | A required key is referenced in code but is not present in .env.example or fetched Supabase secrets. This is blocking by default. |
OPTIONAL | A defaulted/guarded key is absent from config. This is advisory and does not fail CI. |
EXTERNAL | A key appears to belong to another runtime/container, such as an embedded script executed over SSH. This is advisory and does not fail CI. |
IGNORED | A missing key was explicitly ignored by project config or CLI flags. |
ORPHANED | A Supabase secret exists but is not referenced in code or documented in .env.example. |
Installation
Requires Python 3.9 or newer.
macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/Tresnanda/envguard/main/install.sh | bash
Windows PowerShell:
irm https://raw.githubusercontent.com/Tresnanda/envguard/main/install.ps1 | iex
For unattended installs, pass --yes:
curl -fsSL https://raw.githubusercontent.com/Tresnanda/envguard/main/install.sh | bash -s -- --yes
The installer uses pipx, checks Python and optional Supabase tooling, then offers a simple numbered Supabase token setup. If you paste SUPABASE_ACCESS_TOKEN during install, it is saved to your user shell environment, not to project config. It may ask whether to star the GitHub repo, defaulting to yes; if it cannot star from the terminal, it prints the repo link instead. After install, run envguard in your terminal to start the guided audit. The wizard checks for a newer GitHub version and asks before updating.
Manual install:
pipx install .
For local development:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Quick Start
Run the audit from the root of a project that contains .env.example:
envguard
On an interactive terminal, the bare command opens a guided command builder. It detects dotenv files including .env.example and real .env, Supabase Edge Function projects, and existing project config, then shows the generated command before running it. To force the immediate current-directory scan, use:
envguard --no-wizard
You can also open the guide explicitly:
envguard wizard
Update to the latest GitHub version at any time:
envguard update
Agent Skill
envguard includes an optional agent skill for Codex and other agents that use
the open Skills CLI. The skill teaches agents to run envguard before changing
environment files, deployment config, Supabase Edge Functions, or CI secrets,
and to report findings without exposing secret values.
Install the skill:
npx skills add Tresnanda/envguard --skill envguard
Install globally for all projects:
npx skills add Tresnanda/envguard --skill envguard -g
List the skill without installing:
npx skills add Tresnanda/envguard -l
Scan another directory:
envguard /path/to/project
Emit machine-readable JSON:
envguard --json
Emit a compact one-line terminal summary for chat or CI step summaries:
envguard --summary
# envguard: red — 2 missing, 1 unused, 3 optional (exit 1)
Inspect secret readiness across dotenv, the current shell environment, and Supabase secret names without printing any values:
envguard doctor
envguard matrix apps/web --json
The doctor/matrix command is opt-in and reports one row per referenced key with its requirement class (required, optional, external, or ignored), whether the key name is present in the selected dotenv file, the current process environment, and fetched Supabase secrets, plus a readiness status. It never prints dotenv values, shell environment values, Supabase token values, or Supabase secret values. It exits non-zero when a required key is missing from all checked sources unless --allow-missing is used.
Map provider ownership for referenced key names without fetching or printing secret values:
envguard ownership
envguard owners apps/web --json
The ownership map shows each key name, its inferred owner, where it should live, where the key name was observed, and orphaned-looking names. It recognizes source/owner contexts such as Supabase Edge Function secrets, GitHub Actions secrets.KEY references, Vercel/Netlify/Cloudflare project config, dotenv templates, the current process environment, and well-known runtime built-ins like GITHUB_*, VERCEL_*, NETLIFY, and CF_PAGES_*. Provider CLIs are not queried for values; Supabase remote names are included only through the same opt-in/auto-safe secret-name checks used by doctor.
Print a proposal-only remediation plan for missing or orphaned secret findings:
envguard plan
envguard doctor --plan apps/web
Plan mode builds on the doctor matrix and emits redacted, copy-pasteable next steps such as adding empty placeholders to .env.example, setting a Supabase secret placeholder, marking a key optional/external, or reviewing an orphaned Supabase secret. It is dry by default: no prompts, backups, dotenv writes, or secret writes are performed, and real dotenv values or shell/Supabase secret values are never printed.
Create a baseline for existing drift, then fail only on new findings:
envguard --write-baseline .envguard-baseline.json
envguard --baseline .envguard-baseline.json
Emit GitHub Actions annotations in CI logs:
envguard ci
Generate a copy-pasteable GitHub Actions workflow without writing files:
envguard ci-template
envguard ci-template apps/web
The generator reuses [tool.envguard] defaults, prefers committed dotenv templates such as .env.example, avoids referencing a real .env by default, and prints only secret names or GitHub secret placeholders — never dotenv values.
Use a custom dotenv file:
envguard --dotenv config/example.env
Exclude generated or noisy paths:
envguard --exclude "fixtures/**" --exclude "docs/examples/**"
Allow advisory findings without failing a workflow:
envguard --allow-unused
envguard --allow-missing
Mark known project-specific runtime behavior without hiding other real issues:
envguard --optional CONVO_BOT
envguard --external SUPABASE_SERVICE_ROLE_KEY
envguard --ignore-missing LEGACY_FLAG
By default, terminal output summarizes issue counts without printing long reference tables. Show the full tables when you need file and line details:
envguard --details
Interactively prune unused keys from .env.example:
envguard --fix
Supabase Edge Functions
envguard can include Supabase Edge Function secrets in the audit. This is useful when some production-only values should not appear in .env.example but still need to satisfy references in Edge Function code.
export SUPABASE_ACCESS_TOKEN="sbp_..."
envguard supabase your-project-ref
When Supabase secrets are included:
- Referenced keys are considered available if they exist in either
.env.exampleor Supabase. - Supabase secrets that are not referenced and not documented in
.env.exampleare reported asORPHANED. .env.examplekeys that are not referenced are still reported asUNUSED.
Create an access token at app.supabase.com/account/tokens. Your project reference is the ID in a Supabase project URL such as https://app.supabase.com/project/your-project-ref.
envguard also detects Supabase projects automatically from [tool.envguard], the Supabase CLI linked-project file at supabase/.temp/project-ref, supabase/config.toml, SUPABASE_PROJECT_REF, or SUPABASE_PROJECT_ID. Remote secrets are fetched only when a project ref is known, local Edge Functions are present, and either SUPABASE_ACCESS_TOKEN is available or an authenticated supabase CLI can run supabase secrets list --project-ref <ref> --output json, so ordinary scans stay predictable.
The Supabase access token can come from SUPABASE_ACCESS_TOKEN in your shell, the selected dotenv file, the project .env, or a secure prompt in envguard wizard. Tokens entered in the wizard are used only for that run. They are not printed, written to pyproject.toml, or included in the generated command preview. If you prefer Supabase CLI auth, run supabase login and supabase link in the project; envguard will use the CLI when no access token is available.
Set scan_supabase = false in [tool.envguard] to opt out of Supabase-specific behavior for a project. This disables Supabase project detection, remote secret fetching, and local supabase/functions/** scanning unless you explicitly pass --supabase-project for a one-off run.
CI Onboarding Generator
Run envguard ci-template [path] from your repository root to print a ready-to-paste GitHub Actions workflow:
envguard ci-template > /tmp/envguard-workflow.yml
The command is dry-output only: it prints YAML to stdout and does not create .github/workflows or edit your project. The generated workflow:
- Installs envguard from the GitHub repo.
- Runs
envguard ciso findings appear as GitHub annotations. - Adds the project path when you pass one, for monorepos such as
apps/web. - Includes a safe
--dotenvargument when a committed template like.env.example,.env.sample, or.env.templateis detected. - Reuses
[tool.envguard]inpyproject.tomlautomatically instead of duplicating config in CI. - Adds a
SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}placeholder only when Supabase Edge Functions and a project ref are detected. - Avoids printing dotenv values or local secret values. If only a real
.envexists locally, the workflow leaves it out and suggests committing a template contract.
Example output:
# Generated by `envguard ci-template` (dry output; no files were written).
# Paste this into .github/workflows/envguard.yml and adjust branch/install pinning as needed.
name: Envguard
on:
pull_request:
push:
branches: [main]
jobs:
envguard:
name: Env var drift check
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install envguard
run: python -m pip install git+https://github.com/Tresnanda/envguard.git
- name: 🛡️ Scan env contracts
run: |
envguard ci apps/web --dotenv apps/web/.env.example
Dotenv Format
envguard accepts standard dotenv-style keys from .env.example, .env.sample, .env.template, or a real .env file passed with --dotenv .env:
DATABASE_URL=postgres://localhost
API_KEY=
BARE_SECRET
export SUPABASE_URL=https://example.supabase.co
SUPABASE_ACCESS_TOKEN="sbp_..." # comments are fine
Comments and blank lines are ignored. Invalid variable names are skipped. Values are used only to discover sensitive integration tokens such as SUPABASE_ACCESS_TOKEN; envguard does not print dotenv values in audit output.
Project Configuration
You can store team defaults in pyproject.toml so developers and CI use the same scan settings without wrapper scripts:
envguard init --dotenv config/example.env --exclude "fixtures/**"
[tool.envguard]
dotenv = "config/example.env"
exclude = ["fixtures/**", "docs/examples/**"]
supabase_project = "your-project-ref"
scan_supabase = true
optional = ["CLI_DEFAULT_BOT"]
external = ["REMOTE_CONTAINER_SECRET"]
ignore_missing = ["LEGACY_FLAG"]
CLI flags still work on top of this configuration. For example, --exclude adds more ignore patterns, --optional / --external / --ignore-missing add per-run requirement overrides, and --supabase-project overrides the configured project. Use scan_supabase = false when a repository keeps Supabase examples or vendored functions locally but should not include supabase/functions/** or remote Supabase secrets in normal audits.
Supported Reference Patterns
envguard detects common direct environment-variable access patterns:
| Runtime | Pattern | Example |
|---|---|---|
| Python | os.getenv("KEY") | os.getenv("DATABASE_URL") |
| Python | os.environ["KEY"] | os.environ["SECRET_KEY"] |
| Python | os.environ.get("KEY") | os.environ.get("DEBUG") |
| JavaScript | process.env.KEY | process.env.API_KEY |
| JavaScript | process.env["KEY"] | process.env["API_KEY"] |
| Deno | Deno.env.get("KEY") | Deno.env.get("SUPABASE_URL") |
| Shell | ${KEY} | ${DATABASE_URL} |
| Shell | $KEY | $PATH |
| PowerShell | $env:KEY | $env:SUPABASE_ACCESS_TOKEN |
| PowerShell | ${env:KEY} | ${env:SUPABASE_URL} |
| PowerShell | [Environment]::GetEnvironmentVariable("KEY") | [Environment]::GetEnvironmentVariable("DATABASE_URL") |
| Generic | env("KEY") | env("LOG_LEVEL") |
| Windows-style | %KEY% | %USERNAME% |
Dynamic expressions such as os.getenv(prefix + "_TOKEN") are intentionally not inferred.
CLI Reference
usage: envguard [-h] [--path PATH] [--json] [--summary]
[--github-annotations] [--plan] [--fix] [--fix-dry-run]
[--fix-real-env]
[--supabase-project SUPABASE_PROJECT]
[--dotenv DOTENV] [--baseline BASELINE]
[--write-baseline WRITE_BASELINE] [--debug] [--details]
[--exclude PATTERN]
[--optional KEY] [--external KEY] [--ignore-missing KEY]
[--allow-unused] [--allow-missing] [--no-wizard]
[path|wizard|doctor|matrix|plan|ci|ci-template|supabase|init|update] [...]
options:
path Optional project path, e.g. envguard apps/web.
wizard Build and optionally run an audit command interactively.
doctor [path] Show key readiness across dotenv/env/Supabase sources.
matrix [path] Alias for doctor.
plan [path] Print dry remediation proposals from doctor findings.
ci [path] Shortcut for GitHub Actions annotations.
ci-template [path] Print a copy-pasteable GitHub Actions workflow.
supabase ID [path] Shortcut for Supabase secret comparison.
init [path] Write or update [tool.envguard] in pyproject.toml.
update Update envguard from GitHub.
-h, --help Show help and exit.
--path PATH Project path to scan. Defaults to the current directory.
--json Print a JSON report.
--summary Print one compact terminal summary line.
--github-annotations Print GitHub Actions annotations for CI logs.
--plan Print dry, copy-pasteable remediation proposals for doctor findings.
--fix Interactively remove unused keys from .env.example.
--fix-dry-run Preview unused dotenv entries that --fix would prune without writing files.
--fix-real-env Allow --fix to edit a real .env file instead of only templates.
--supabase-project ID Fetch Supabase Edge Function secrets for this project.
--dotenv PATH Path to dotenv file. Defaults to auto-detected templates or .env.
--baseline PATH Suppress known findings listed in an envguard baseline JSON file.
--write-baseline PATH Write current findings to a secret-safe baseline JSON file and exit.
--exclude PATTERN Glob pattern to exclude from scanning. Can be repeated.
--optional KEY Mark a missing key as optional/defaulted. Can be repeated.
--external KEY Mark a missing key as owned by another runtime/container. Can be repeated.
--ignore-missing KEY Ignore a missing key entirely. Can be repeated.
--allow-unused Do not fail on unused keys or orphaned Supabase secrets.
--allow-missing Do not fail on missing referenced variables.
--details Show detailed issue tables with file references.
--no-wizard Run the default scan instead of the interactive guide.
--debug Print detected references and parsed keys.
Summary Output
--summary prints exactly one plain-text line and uses the same exit-code rules as the default report:
envguard: red — 2 missing, 1 unused, 3 optional (exit 1)
The status is red when blocking findings would make envguard exit non-zero, yellow when findings are present but allowed/advisory, and green when the scan is clean. Counts include nonzero missing, unused, optional, external, ignored, and Supabase orphaned findings.
Baselines
Baselines let legacy projects adopt envguard incrementally. Write the current findings once, commit the generated JSON, and keep CI strict for any new drift:
envguard --write-baseline .envguard-baseline.json
envguard --baseline .envguard-baseline.json
Baseline files store only finding classes and key names — no dotenv values, reference paths, Supabase tokens, or secret values:
{
"version": 1,
"findings": {
"unused": ["OLD_API_KEY"],
"missing": ["DATABASE_URL"],
"optional_missing": [],
"external_missing": [],
"ignored_missing": [],
"supabase_orphans": []
}
}
You can also store the path in project config:
[tool.envguard]
baseline = ".envguard-baseline.json"
Matching findings are suppressed before output and exit-code calculation. New
unbaselined MISSING, UNUSED, or ORPHANED findings still fail unless you
also pass the existing --allow-* flags.
JSON Output
{
"unused": ["OLD_API_KEY"],
"missing": ["NEW_SECRET"],
"optional_missing": ["LOCAL_TIMEOUT_MS"],
"external_missing": ["REMOTE_CONTAINER_SECRET"],
"ignored_missing": ["LEGACY_FLAG"],
"supabase_orphans": ["LEGACY_EDGE_SECRET"],
"references": {
"DATABASE_URL": [
{
"file": "/path/to/app.py",
"line": 12,
"pattern": "os.getenv",
"requirement": "required",
"reason": ""
}
]
}
}
Exit Codes
| Code | Meaning |
|---|---|
0 | No blocking findings were found. Advisory optional/external/ignored findings may still be present. |
1 | The audit found blocking issues or could not complete. |
--allow-unused suppresses failure for unused .env.example keys and orphaned Supabase secrets. --allow-missing suppresses failure for required missing referenced keys. Optional, external, and ignored missing keys are advisory by default and still appear in the selected output format.
Development
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check .
License
MIT. See LICENSE.