Require explicit CrewAI project definitions (#6358)

* Require explicit CrewAI project definitions

JSON crews and declarative flows now resolve from `[tool.crewai]`
metadata instead of implicit filename discovery. This makes project type
selection deterministic, prevents stray `crew.json(c)` files from changing
CLI behavior, and centralizes definition path validation for run, install,
deploy validation, plotting, and memory reset paths.

`[tool.crewai].definition` must be a project-local file path. Absolute
paths, `~`, missing files, directories, and paths escaping the project root
are rejected so deploy and runtime commands use the same contract.

Breaking changes and migration paths:

* JSON crew projects are no longer discovered from `crew.json` or
  `crew.jsonc` alone. Add explicit metadata:

  ```toml
  [tool.crewai]
  type = "crew"
  definition = "crew.jsonc"
  ```

* Declarative flow projects must use a valid project-local definition path:

  ```toml
  [tool.crewai]
  type = "flow"
  definition = "flows/research.yaml"
  ```

* `Flow.from_definition(definition)` is removed. Use:

  ```python
  Flow.from_declaration(contents=definition)
  ```

* `FlowDefinition.to_json()` and `FlowDefinition.to_yaml()` are removed.
  Use `FlowDefinition.to_dict()` and serialize with the caller's JSON or
  YAML library.

* `FlowDefinition.from_dict()` is removed. Use:

  ```python
  FlowDefinition.from_declaration(contents=data)
  ```

* `FlowDefinition.json_schema()` is removed. Use Pydantic's schema API only
  where schema generation is intentionally needed:

  ```python
  FlowDefinition.model_json_schema(by_alias=True)
  ```

* `crewai_cli.run_crew.find_crew_json_file()` and `_has_json_crew()` are
  removed. Use `configured_project_json_crew()` or the shared
  `crewai_core.project.configured_project_definition("crew")` helper.

* `crewai reset-memories` now only loads JSON crews declared through
  `[tool.crewai].definition`, and invalid declared JSON crew definitions
  fail instead of silently falling back to classic crew discovery.

* Address code review comments
This commit is contained in:
Vinicius Brasil
2026-06-26 12:07:03 -07:00
committed by GitHub
parent e10c17fcf6
commit 596150188b
19 changed files with 723 additions and 471 deletions

View File

@@ -40,14 +40,18 @@ from typing import Any
from crewai.project.json_loader import (
JSONProjectValidationError,
find_crew_json_file,
find_json_project_file,
validate_crew_project,
)
from crewai_core.project import (
ProjectDefinitionError,
configured_project_definition,
get_crewai_project_config,
get_crewai_project_type,
read_toml,
)
from rich.console import Console
from crewai_cli.utils import parse_toml
console = Console()
logger = logging.getLogger(__name__)
@@ -159,24 +163,16 @@ class DeployValidator:
@property
def _is_json_crew(self) -> bool:
"""True for JSON crew projects, deferring to the declared type.
A flow project that also contains a crew.json(c) file validates as
the flow it declares in pyproject.toml, not as a JSON crew.
"""
if find_crew_json_file(self.project_root) is None:
return False
"""True for JSON crew projects with configured crew definitions."""
pyproject_path = self.project_root / "pyproject.toml"
if not pyproject_path.exists():
return True
return False
try:
data = parse_toml(pyproject_path.read_text())
data = read_toml(pyproject_path)
except Exception:
return True
declared_type: str | None = (
(data.get("tool") or {}).get("crewai", {}).get("type")
)
return declared_type != "flow"
return False
crewai_config = get_crewai_project_config(data)
return crewai_config.get("type") == "crew" and "definition" in crewai_config
def run(self) -> list[ValidationResult]:
"""Run all checks. Later checks are skipped when earlier ones make
@@ -208,14 +204,32 @@ class DeployValidator:
def _run_json_checks(self) -> list[ValidationResult]:
"""Validation suite for JSON-defined crew projects."""
crew_path = find_crew_json_file(self.project_root)
self._check_pyproject()
self._check_lockfile()
try:
crew_path = configured_project_definition(
"crew",
pyproject_data=self._pyproject,
project_root=self.project_root,
)
except ProjectDefinitionError as exc:
self._add(
Severity.ERROR,
"invalid_crew_definition",
"[tool.crewai] definition is invalid",
detail=str(exc),
hint=(
"Set `[tool.crewai] definition` to a project-local JSON "
"or JSONC crew file."
),
)
return self.results
if crew_path is None:
return self.results
agents_dir = self.project_root / "agents"
self._check_pyproject()
self._check_lockfile()
agents_dir = crew_path.parent / "agents"
agents_dir_ok = self._check_json_agents_dir(agents_dir)
project = None
@@ -346,7 +360,7 @@ class DeployValidator:
return False
try:
self._pyproject = parse_toml(pyproject_path.read_text())
self._pyproject = read_toml(pyproject_path)
except Exception as e:
self._add(
Severity.ERROR,
@@ -374,9 +388,7 @@ class DeployValidator:
self._project_name = name
self._package_name = normalize_package_name(name)
self._is_flow = (self._pyproject.get("tool") or {}).get("crewai", {}).get(
"type"
) == "flow"
self._is_flow = get_crewai_project_type(self._pyproject) == "flow"
return True
def _check_lockfile(self) -> None: