Skip to content

fix(cli): load the agent's .env into locally run ACP and worker processes - #515

Open
michaelxu2288 wants to merge 2 commits into
scaleapi:nextfrom
michaelxu2288:fix/cli-load-dotenv-local-run
Open

fix(cli): load the agent's .env into locally run ACP and worker processes#515
michaelxu2288 wants to merge 2 commits into
scaleapi:nextfrom
michaelxu2288:fix/cli-load-dotenv-local-run

Conversation

@michaelxu2288

@michaelxu2288 michaelxu2288 commented Sep 10, 2026

Copy link
Copy Markdown

Problem

getting_started/project_structure.md says a .env next to manifest.yaml "is automatically loaded when placed alongside your manifest.yaml file, but only for local development". Nothing does that today:

  • agentex agents run builds the child environment from os.environ plus the manifest (create_agent_environment).
  • EnvironmentVariables.refresh() loads .env from Path(__file__).parents[2], which is site-packages for an installed SDK, never the agent folder, and .env.local from cwd.parent.
  • ProjectConfigLoader._load_env only feeds config templating.

Values from .env reach a process only when some import happens to call load_dotenv() first. litellm does, on import (litellm/__init__.py), which is why the Temporal + OpenAI Agents template appears to work (its model client is built lazily inside the activity, after imports) while Temporal + Pydantic AI fails at import time of project/agent.py with openai.OpenAIError: Missing credentials. Verified with a print at the top of both workers: OpenAI Agents worker sees LITELLM_API_KEY only after its imports; the Pydantic AI worker never does.

Fix

create_agent_environment(manifest, manifest_dir) merges <manifest dir>/.env (python-dotenv dotenv_values, already a dependency) into the environment handed to both the ACP and worker subprocesses, without overriding variables already set in the shell (python-dotenv semantics). run_agent passes manifest_file.parent. 16-line diff plus three tests (merge, shell precedence, no file / no manifest_dir) that render a real manifest via the init helpers.

Verification

  • tests/lib/cli/test_run_handlers_env.py: 3 passed; streaming handler tests still pass; ruff clean.
  • Live, Temporal + Pydantic AI scaffold with only LITELLM_API_KEY in .env, patched SDK installed into its venv: before, no reply and Missing credentials; after, reply in 4.7 s, zero worker errors.

Pairs with #514 ("fix(templates): map LITELLM_API_KEY to OPENAI_API_KEY in Temporal workers"): once .env is in the process environment from the start, that mapping at the top of run_worker.py becomes deterministic instead of depending on import order.

https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3

RetriggerConfidence Score: 4/5

The PR is not yet safe to merge because .env can override runtime identity, port, or workflow settings derived from the manifest.

Fix All in CursorFindings

  1. P1 Dotenv overrides manifest settings
  2. P1 Dotenv defaults are overwritten
Fix with agent prompt
### Issue 1
src/agentex/lib/cli/handlers/run_handlers.py:476-478
A `.env` entry can now overwrite manifest-derived runtime settings such as `AGENT_NAME`, `ACP_PORT`, `WORKFLOW_TASK_QUEUE`, and `HEALTH_CHECK_PORT`. These values are added through `env_vars`, but `manifest_env` contains only the explicit `agent.env` mapping. A conflicting dotenv value therefore replaces the manifest-derived value and can start the ACP or worker with the wrong identity, port, task queue, or health-check configuration. Preserve all manifest-derived keys while still allowing `.env` to replace built-in local defaults.

### Issue 2
src/agentex/lib/cli/handlers/run_handlers.py:423-425
The `.env` values are loaded before `env_vars` is built, and the later unconditional `env.update(env_vars)` replaces overlapping values. For example, a local Temporal project with `REDIS_URL=redis://custom:6380` in `.env` still receives `redis://localhost:6379`. This makes the new loading behavior ineffective for common runtime settings such as `REDIS_URL`, `TEMPORAL_ADDRESS`, and `ENVIRONMENT`. Please apply dotenv values after the built-in defaults while preserving the intended shell and manifest precedence, and add a regression test for an overlapping key.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

  • Passes the manifest directory into subprocess environment construction.
  • Loads dotenv values without replacing exported shell variables or explicit agent.env entries.
  • Keeps ENVIRONMENT fixed to development.
  • Adds focused tests for dotenv loading, shell precedence, missing files, and local-default overrides.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  S[Shell environment] --> M[Apply manifest-derived settings]
  M --> D[Apply eligible .env values]
  D --> E[Child process environment]
  E --> A[ACP process]
  E --> W[Temporal worker]
Loading

Reviews (2) · Last reviewed commit: "fix(cli): apply .env after the built-in ..."

…sses

The docs say a .env next to manifest.yaml is loaded automatically for local
development, but nothing did: agentex agents run built the child environment
from os.environ plus the manifest, and EnvironmentVariables.refresh() looks
for .env two directories above the installed module (site-packages), never
the agent folder. Values in .env only reached a process when some import
happened to call load_dotenv() first (litellm does, on import). That is why
the OpenAI Agents Temporal template worked (its model client is built lazily
after imports) while the Pydantic AI one failed at import time with
openai.OpenAIError: Missing credentials.

Merge <manifest dir>/.env into the environment handed to both the ACP and
worker subprocesses, without overriding variables already set in the shell
(python-dotenv semantics). Add tests for merge, shell precedence, and the
no-file / no-manifest_dir cases.

Claude-Session: https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
Comment on lines +423 to +425
for key, value in dotenv_values(env_file).items():
if value is not None and key not in env:
env[key] = value

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Dotenv defaults are overwritten

The .env values are loaded before env_vars is built, and the later unconditional env.update(env_vars) replaces overlapping values. For example, a local Temporal project with REDIS_URL=redis://custom:6380 in .env still receives redis://localhost:6379. This makes the new loading behavior ineffective for common runtime settings such as REDIS_URL, TEMPORAL_ADDRESS, and ENVIRONMENT. Please apply dotenv values after the built-in defaults while preserving the intended shell and manifest precedence, and add a regression test for an overlapping key.

Knowledge Base Used: Command-line workflows

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/cli/handlers/run_handlers.py
Line: 423-425

Comment:
**Dotenv defaults are overwritten**

The `.env` values are loaded before `env_vars` is built, and the later unconditional `env.update(env_vars)` replaces overlapping values. For example, a local Temporal project with `REDIS_URL=redis://custom:6380` in `.env` still receives `redis://localhost:6379`. This makes the new loading behavior ineffective for common runtime settings such as `REDIS_URL`, `TEMPORAL_ADDRESS`, and `ENVIRONMENT`. Please apply dotenv values after the built-in defaults while preserving the intended shell and manifest precedence, and add a regression test for an overlapping key.

**Knowledge Base Used:** [Command-line workflows](https://app.greptile.com/scale-ai/-/custom-context/knowledge-base/scaleapi/scale-agentex-python/-/docs/command-line-workflows.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Pushed 0a24841: .env is now applied after the built-in local defaults, so a custom REDIS_URL or TEMPORAL_ADDRESS in .env takes effect, while the manifest's env block and variables already set in the shell still win, and ENVIRONMENT stays pinned to development (that is what makes it a local run). Added test_dotenv_overrides_builtin_local_defaults_but_not_environment covering exactly the overlapping-key case; the four env tests pass.

michaelxu2288 added a commit to michaelxu2288/scale-agentex-python that referenced this pull request Sep 10, 2026
…apping the key

The worker is a separate process and agents run does not load the project
.env into it today, so the LITELLM_API_KEY -> OPENAI_API_KEY mapping ran
against an empty environment. Call load_dotenv() first (as acp.py already
does), so the template works on its own; scaleapi#515 makes the CLI load .env for
both processes as well.

Claude-Session: https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
Loading .env before env_vars meant env.update(env_vars) clobbered any
overlapping key, so a custom REDIS_URL or TEMPORAL_ADDRESS in .env had no
effect. Apply .env after the defaults, below the manifest env block and the
shell, and keep ENVIRONMENT pinned to development; add a regression test.

Claude-Session: https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
Comment on lines +476 to +478
if key in os.environ or key in manifest_env:
continue
env[key] = value

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Dotenv overrides manifest settings

A .env entry can now overwrite manifest-derived runtime settings such as AGENT_NAME, ACP_PORT, WORKFLOW_TASK_QUEUE, and HEALTH_CHECK_PORT. These values are added through env_vars, but manifest_env contains only the explicit agent.env mapping. A conflicting dotenv value therefore replaces the manifest-derived value and can start the ACP or worker with the wrong identity, port, task queue, or health-check configuration. Preserve all manifest-derived keys while still allowing .env to replace built-in local defaults.

Knowledge Base Used: Command-line workflows

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/cli/handlers/run_handlers.py
Line: 476-478

Comment:
**Dotenv overrides manifest settings**

A `.env` entry can now overwrite manifest-derived runtime settings such as `AGENT_NAME`, `ACP_PORT`, `WORKFLOW_TASK_QUEUE`, and `HEALTH_CHECK_PORT`. These values are added through `env_vars`, but `manifest_env` contains only the explicit `agent.env` mapping. A conflicting dotenv value therefore replaces the manifest-derived value and can start the ACP or worker with the wrong identity, port, task queue, or health-check configuration. Preserve all manifest-derived keys while still allowing `.env` to replace built-in local defaults.

**Knowledge Base Used:** [Command-line workflows](https://app.greptile.com/scale-ai/-/custom-context/knowledge-base/scaleapi/scale-agentex-python/-/docs/command-line-workflows.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant