From 67d9fcdcfc65e2fdba1848f147522e5a60cf784e Mon Sep 17 00:00:00 2001 From: Joao Moura Date: Mon, 6 Jul 2026 19:01:33 -0700 Subject: [PATCH] fix(cli): load project .env in the declarative-flow runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The declarative-flow path never loaded .env — flow projects (type = "flow") missed API keys/config that crew projects pick up. The JSON-crew path loads Path.cwd()/.env with override=True (run_crew._run_json_crew); mirror that at the top of run_declarative_flow() so flow projects behave the same regardless of where crewai is installed. Test: run_declarative_flow_loads_project_env. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh --- lib/cli/src/crewai_cli/run_declarative_flow.py | 9 +++++++++ lib/cli/tests/test_run_declarative_flow.py | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/cli/src/crewai_cli/run_declarative_flow.py b/lib/cli/src/crewai_cli/run_declarative_flow.py index 7fd727698..7be34a13c 100644 --- a/lib/cli/src/crewai_cli/run_declarative_flow.py +++ b/lib/cli/src/crewai_cli/run_declarative_flow.py @@ -52,6 +52,15 @@ def run_declarative_flow(definition: str | Path, inputs: str | None = None) -> N for interactively, and everything is validated against the schema before kickoff — so a bare ``crewai run`` on a configured flow just works. """ + # Load the project's .env before kickoff, mirroring the JSON-crew path + # (run_crew._run_json_crew) so flow projects pick up API keys/config the + # same way regardless of where crewai is installed. + from dotenv import load_dotenv + + env_file = Path.cwd() / ".env" + if env_file.exists(): + load_dotenv(env_file, override=True) + provided = _parse_inputs(inputs) or {} flow = load_declarative_flow(definition) diff --git a/lib/cli/tests/test_run_declarative_flow.py b/lib/cli/tests/test_run_declarative_flow.py index b45f40e59..df6c0af00 100644 --- a/lib/cli/tests/test_run_declarative_flow.py +++ b/lib/cli/tests/test_run_declarative_flow.py @@ -1,5 +1,6 @@ from __future__ import annotations +import os from pathlib import Path import pytest @@ -353,6 +354,23 @@ def test_reserved_id_input_is_forwarded_not_dropped( assert "Ignoring unknown input 'id'" not in captured.err +def test_run_declarative_flow_loads_project_env( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + # Flow projects must pick up the project's .env, like crew projects do, + # overriding any pre-existing value. + monkeypatch.chdir(tmp_path) + monkeypatch.setenv("DECL_FLOW_ENV_PROBE", "old") + (tmp_path / ".env").write_text("DECL_FLOW_ENV_PROBE=from_dotenv\n", encoding="utf-8") + path = _write(tmp_path, REQUIRED_FLOW_YAML) + + run_declarative_flow_module.run_declarative_flow( + str(path), '{"prospect_email":"a@b.com"}' + ) + + assert os.environ["DECL_FLOW_ENV_PROBE"] == "from_dotenv" + + def test_id_only_input_skips_required_validation(tmp_path: Path) -> None: # Resume via `crewai run --inputs '{"id":"..."}'` must not be blocked by the # required-field check: kickoff hydrates required state from persistence.