ANTIGRAVITY LABJP
Articles/Agents & Manager
Agents & Manager/2026-05-09Intermediate

Why Antigravity Agents Can't Read Your .env File — Three Propagation Paths to Check First

When an Antigravity agent fails with Missing API_KEY but the same build works in your terminal, the cause is one of three env propagation paths. Diagnose each.

antigravity429agents124env2troubleshooting105dotenv2

One evening I asked an Antigravity agent to take a Next.js project all the way to a production build, and it stopped on the very last step with Missing environment variable: STRIPE_SECRET_KEY. In my own terminal, npm run build ran cleanly, and echo $STRIPE_SECRET_KEY printed the expected value — yet the moment the agent ran the same command, the variable was empty. If you have spent an afternoon staring at the same error, you are not alone.

In almost every case I have seen, this is not a .env configuration problem in the strict sense. It is a misunderstanding of how Antigravity agents propagate environment variables to the processes they spawn. Below I walk through the three paths I have personally tripped over, and finish with a four-step setup I now use on every personal project.

Picture the three paths an env var can travel before reaching your agent

Before you start changing files, it helps to keep three propagation paths in your head. Diagnosis becomes much faster once you know which one is broken.

  • Path A — Inheritance from the shell. When you launch Antigravity from a terminal (antigravity .), every variable that your shell startup exported is inherited by child processes
  • Path B — Framework-level dotenv loading. Frameworks like Next.js (.env.local), Vite (import.meta.env), or Python's python-dotenv actively read files at runtime
  • Path C — The env block the agent constructs. When Antigravity spawns a subprocess (typically because of a task definition or AGENTS.md), it builds an explicit env block that may or may not include what you expect

Whenever I hear "it works in the terminal but not from the agent," one of these paths is silently severed. Let's walk through each.

Case 1: GUI-launched Antigravity does not inherit your shell config

If you start Antigravity from the macOS Dock, the Windows Start Menu, or a Linux app launcher, the variables you export in ~/.zshrc or ~/.bashrc will not be present for the agent. This was the first trap I fell into, and I lost half a day to it.

The check is straightforward. Open Antigravity's integrated terminal and run:

# Quick check that your shell init actually ran
echo "shell=$SHELL"
echo "node=$(which node)"
echo "stripe=${STRIPE_SECRET_KEY:0:7}..."  # show just the first 7 characters
# Expected output when shell init was inherited correctly:
# shell=/bin/zsh
# node=/Users/you/.nvm/versions/node/v22.5.0/bin/node
# stripe=sk_test...

If stripe=... is empty, or node resolves to the system default (/usr/bin/node), your interactive shell config is not running. GUI-launched processes only inherit values from ~/.zshenv (zsh) or launchctl setenv (macOS) — anything you put in ~/.zshrc is invisible to the agent.

My personal rule, after living with this issue for a couple of years, is to keep secrets inside the project as .env.local rather than in the shell. Shell-only setups always break the moment you move to a new machine.

Case 2: Values you wrote in AGENTS.md are guidance, not an env block

As I covered in the AGENTS.md not-working diagnosis guide, AGENTS.md is a natural-language brief for the agent. It is not a process env block.

# Bad — the agent will read this, but never export anything
## Environment
- API_KEY = sk_live_xxx
- DATABASE_URL = postgres://...

Even when the agent dutifully reads this file, the values do not show up as process.env.API_KEY for any process it spawns. Writing real secret values in markdown is also a leakage risk. Instead, use AGENTS.md to describe where the secrets live and how they are loaded.

# Better
## Environment
- All secrets live in `.env.local` at the repo root
- Update `.env.example` whenever you add a new variable
- Local commands rely on dotenv being auto-loaded by `npm run dev`

The agent's job is to plan and execute. Tell it where the values come from and how to load them; do not bake them into the brief.

Case 3: Your framework's dotenv loader is looking at the wrong working directory

Next.js and Vite resolve .env.local relative to the current working directory of the spawned process. If your agent thinks it ran npm run build from the monorepo root but actually cd'd into a sub-package first, there will be no .env.local to find, and nothing will be loaded.

// scripts/check-env.mjs — make the env-resolution path observable
import { existsSync } from 'node:fs';
import path from 'node:path';
import dotenv from 'dotenv';
 
const cwd = process.cwd();
console.log('CWD:', cwd);
 
// Walk through the candidate locations
const candidates = [
  path.join(cwd, '.env.local'),
  path.join(cwd, '.env'),
  path.join(cwd, '..', '.env.local'),
];
 
for (const file of candidates) {
  console.log(file, existsSync(file) ? 'FOUND' : 'missing');
}
 
// Load explicitly
const result = dotenv.config({ path: '.env.local' });
console.log('Loaded keys:', Object.keys(result.parsed ?? {}));
console.log('STRIPE prefix:', (process.env.STRIPE_SECRET_KEY ?? '').slice(0, 7));
 
// Expected output when run from a monorepo root:
// CWD: /Users/you/projects/myapp
// /Users/you/projects/myapp/.env.local FOUND
// Loaded keys: [ 'STRIPE_SECRET_KEY', 'DATABASE_URL', 'OPENAI_API_KEY' ]
// STRIPE prefix: sk_test

When I ask the agent to run this script, the log immediately tells me where it looked and what it found. That observability turns a 30-minute hunt into a 30-second one. I now drop this script into every new project before I write a single feature.

A four-step setup that propagates env vars reliably

Here is the actual configuration I run on personal projects. The example uses Next.js, but the same idea applies to Python (python-dotenv) or Go (godotenv).

Step 1 — Consolidate everything into .env.local at the repo root.

Avoid scattering many .env.* files. Keep one .env.local for local development and a checked-in .env.example describing the shape.

Step 2 — Make dotenv loading explicit in package.json.

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "build:agent": "node -r dotenv/config node_modules/.bin/next build dotenv_config_path=.env.local",
    "test:env": "node scripts/check-env.mjs"
  }
}

A separate build:agent script gives you a stable entry point. Mention it in AGENTS.md ("Use npm run build:agent to verify production builds") and the propagation path stops drifting.

Step 3 — Set envFile in .vscode/tasks.json.

Antigravity shares the VS Code task system, so going through tasks is the most reliable propagation path.

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build (agent)",
      "type": "shell",
      "command": "npm run build:agent",
      "options": {
        "envFile": "${workspaceFolder}/.env.local"
      },
      "problemMatcher": []
    }
  ]
}

Step 4 — Tell the agent to gate deployment work behind test:env.

Add a pre-flight section near the top of AGENTS.md:

## Pre-flight check
Before any production build or task that calls an external API, run `npm run test:env`.
- Confirm that `Loaded keys` includes `STRIPE_SECRET_KEY` and `DATABASE_URL`.
- Confirm that `STRIPE prefix` starts with `sk_`.
If anything is missing, stop and report. Do not proceed to deployment.

Once this is in place, the agent catches an empty env before the build, not after fifteen minutes of compilation. That single change has saved me more time than any other tweak in this list.

If you want to go deeper, I recommend reading the AGENTS.md authoring guide, my Antigravity .env management strategy, and how to prevent agent context drift. Together they cover the structural side of keeping environment-dependent tasks reliable.

Quick notes for Python and Go projects

The propagation paths are identical in other ecosystems; only the loaders change.

For Python projects I add python-dotenv and load explicitly at the top of the entry script: from dotenv import load_dotenv; load_dotenv('.env.local'). The diagnostic equivalent of check-env.mjs is a four-line snippet that prints os.getcwd() plus os.environ.get('STRIPE_SECRET_KEY', '<empty>')[:7]. If you are using Poetry or uv, remember that running through the package manager (uv run python main.py) injects the project's virtualenv but does not auto-load .env.local — you still need a loader call.

For Go projects I rely on github.com/joho/godotenv and gate deployment work behind a make verify-env target that uses the same idea: print the working directory, walk candidate paths, and confirm a few prefixes. Go's compile-time errors will not catch a missing variable, so the runtime check matters even more here.

The point is that the four-step setup is portable. Whatever your stack, name a single command that can prove the env is loaded, mention that command in AGENTS.md, and require the agent to run it before anything irreversible.

A two-minute checklist for the next time this happens

Whenever I get bitten again, I run through this short list before changing anything else:

  • In the integrated terminal, run echo $SHELL and which node — make sure you are not on the system Node
  • Run npm run test:env and confirm every expected key shows up
  • Verify that .env.local is owned by you and readable
  • For monorepos, double-check the pnpm -w or turbo run scope
  • Print pwd to make sure the agent did not stay inside a subdirectory after a previous step

Software work, in the end, is a long sequence of making invisible propagation paths visible one at a time. The error message itself rarely tells you what you need; what really matters is whether you already know how the environment is being assembled behind it.

Drop scripts/check-env.mjs into your project today. The next time the same error appears, having a known first command to run takes most of the anxiety out of the moment. Thank you for reading.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Agents & Manager2026-05-30
When the Antigravity Agent Says 'command not found' for node or python: Causes and Fixes
It works in your own terminal, but the Antigravity agent hits command not found. Starting from how PATH inheritance works, here are concrete fixes for nvm, pyenv, Homebrew, and WSL setups—plus how to confirm the fix actually took.
Agents & Manager2026-05-26
Why Antigravity's Browser Sub-Agent Reads SPAs as Empty Pages — and Three Wait Strategies That Stuck for Me
When you hand an SPA dashboard to Antigravity's Browser Sub-Agent, get_page_text often returns before the real content is rendered, and the agent reports an empty page. Here is how I diagnose the symptom and the three wait strategies that have stabilized my routine.
Agents & Manager2026-05-05
Debugging Antigravity AI Agents: A Systematic Diagnosis Guide
A systematic approach to diagnosing AI agent failures in Antigravity—covering startup failures, tool call errors, loop detection, and incorrect behavior—with practical debugging patterns for each.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →