diff --git a/lib/cli/src/crewai_cli/create_json_crew.py b/lib/cli/src/crewai_cli/create_json_crew.py index 362f98e16..3c7a0dba4 100644 --- a/lib/cli/src/crewai_cli/create_json_crew.py +++ b/lib/cli/src/crewai_cli/create_json_crew.py @@ -20,6 +20,7 @@ from crewai_cli.model_catalog import get_provider_models from crewai_cli.platform_tools_catalog import PLATFORM_TOOLS from crewai_cli.tui_picker import pick_many, pick_one from crewai_cli.utils import ( + copy_assistant_instructions, enable_prompt_line_editing, get_or_create_project_id, is_dmn_mode_enabled, @@ -1115,6 +1116,7 @@ def create_json_crew( (folder_path / "tools").mkdir() (folder_path / "skills").mkdir() (folder_path / "knowledge").mkdir() + copy_assistant_instructions(folder_path) if platform_token: os.environ["CREWAI_PLATFORM_INTEGRATION_TOKEN"] = platform_token diff --git a/lib/cli/src/crewai_cli/templates/AGENTS.md b/lib/cli/src/crewai_cli/templates/AGENTS.md index 57962bdef..534fa21d7 100644 --- a/lib/cli/src/crewai_cli/templates/AGENTS.md +++ b/lib/cli/src/crewai_cli/templates/AGENTS.md @@ -59,7 +59,7 @@ These snake_case flags still work but are hidden from `--help`. Prefer kebab-cas 1. Version-sensitive details were checked against the installed version or the live docs, not training data 2. All LLM references use `crewai.LLM` or string shorthand (`"openai/gpt-4o"`) 3. All tool imports come from `crewai.tools` or `crewai_tools` -4. Crew classes use `@CrewBase` decorator with YAML config files +4. Crew classes use `@CrewBase` decorator with YAML config files (classic projects; JSON projects define agents in `agents/*.jsonc` and tasks in `crew.jsonc`) 5. Python >=3.10, <3.14 6. Code matches the API from the live docs, not just this file 7. Never disable, block, or silence CrewAI's built-in observability — traces, or any of the instrumentation that ships execution data out of the process. Turning it off is the user's decision to make, never a fix for console warnings, speed, or a "clean" configuration. @@ -175,7 +175,22 @@ crewai deploy remove # Delete a deployment ## Project Structure -### Crew Project +### JSON Crew Project (default for `crewai create crew`) +``` +my_crew/ +├── agents/ +│ └── researcher.jsonc # One agent per file (role, goal, backstory, llm, tools) +├── crew.jsonc # Tasks, process, memory, inputs +├── tools/ # Custom tools (Python), referenced as custom: +├── skills/ # Agent skills +├── knowledge/ # Knowledge files for agents +├── .env +└── pyproject.toml +``` + +There is no `crew.py`, `main.py`, or `config/*.yaml`: edit the JSONC files instead of writing crew classes. Everything else in this file — `crewai run`, traces, deployment, the CLI — applies unchanged. `crewai create crew --classic` produces the Python/YAML layout below. + +### Classic Crew Project (`crewai create crew --classic`) ``` my_crew/ ├── src/my_crew/ diff --git a/lib/cli/tests/test_create_crew.py b/lib/cli/tests/test_create_crew.py index 1569dd180..f173fed80 100644 --- a/lib/cli/tests/test_create_crew.py +++ b/lib/cli/tests/test_create_crew.py @@ -1012,3 +1012,44 @@ def test_scaffolded_agents_md_tells_assistants_to_keep_observability_on( assert "Turning it off is the user's decision to make" in keep_on assert "- Treating built-in observability" in agents_md assert "free" not in agents_md.lower() + + +def test_json_create_scaffolds_assistant_instructions(tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + with mock.patch( + "crewai_cli.create_json_crew._wizard_agents_and_tasks", + return_value=( + [ + { + "name": "researcher", + "role": "Researcher", + "goal": "Research", + "backstory": "Researcher", + "llm": "openai/gpt-4o", + "tools": [], + "planning": False, + "allow_delegation": False, + } + ], + [ + { + "name": "research_task", + "description": "Research", + "expected_output": "Findings", + "agent": "researcher", + "context": [], + } + ], + {"process": "sequential", "memory": False, "inputs": {}}, + ), + ): + json_crew.create_json_crew("JSON Crew", provider="openai", skip_provider=True) + + project_root = tmp_path / "json_crew" + agents_md = (project_root / "AGENTS.md").read_text(encoding="utf-8") + assert "CrewAI Reference for AI Coding Assistants" in agents_md + assert "crew.jsonc" in agents_md + claude_md = (project_root / "CLAUDE.md").read_text(encoding="utf-8") + assert "@AGENTS.md" in claude_md.splitlines() + gemini_md = (project_root / "GEMINI.md").read_text(encoding="utf-8") + assert "@./AGENTS.md" in gemini_md.splitlines() diff --git a/lib/crewai-core/tests/test_telemetry_export_logs.py b/lib/crewai-core/tests/test_telemetry_export_logs.py index d84501ef5..fddc26da8 100644 --- a/lib/crewai-core/tests/test_telemetry_export_logs.py +++ b/lib/crewai-core/tests/test_telemetry_export_logs.py @@ -10,6 +10,7 @@ from __future__ import annotations from collections.abc import Iterator import logging +import os import threading from unittest.mock import patch @@ -31,7 +32,10 @@ FINAL_ERROR = "Failed to export span batch due to timeout, max retries or shutdo def _finished_span() -> ReadableSpan: memory = InMemorySpanExporter() - provider = TracerProvider() + # The suite runs with OTEL_SDK_DISABLED=true, which makes a fresh + # TracerProvider a no-op that records nothing. + with patch.dict(os.environ, {"OTEL_SDK_DISABLED": "false"}): + provider = TracerProvider() provider.add_span_processor(SimpleSpanProcessor(memory)) provider.get_tracer("test").start_span("probe").end() (span,) = memory.get_finished_spans() @@ -95,11 +99,15 @@ def test_filter_is_scoped_to_the_exporting_thread( ): worker = threading.Thread(target=exporter.export, args=([_finished_span()],)) worker.start() - assert entered.wait(5) - logging.getLogger(OTLP_LOGGER).warning("user exporter: collector down") - release.set() - worker.join(10) + try: + assert entered.wait(5) + logging.getLogger(OTLP_LOGGER).warning("user exporter: collector down") + finally: + release.set() + exporter.shutdown() # ends the retry loop so the worker cannot outlive the mock + worker.join(10) + assert not worker.is_alive() assert _otlp_messages(caplog) == ["user exporter: collector down"] diff --git a/lib/crewai-core/tests/test_telemetry_shutdown.py b/lib/crewai-core/tests/test_telemetry_shutdown.py index b0bbd24de..602718396 100644 --- a/lib/crewai-core/tests/test_telemetry_shutdown.py +++ b/lib/crewai-core/tests/test_telemetry_shutdown.py @@ -12,7 +12,6 @@ import time from typing import cast from unittest.mock import MagicMock, patch -import crewai_core.telemetry as telemetry_module from crewai_core.telemetry import SafeOTLPSpanExporter, Telemetry from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter import pytest @@ -52,7 +51,7 @@ def test_exit_hook_stops_waiting_at_the_flush_deadline( monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture, ) -> None: - monkeypatch.setattr(telemetry_module, "FINAL_FLUSH_SECONDS", 1) + monkeypatch.setattr("crewai_core.telemetry.FINAL_FLUSH_SECONDS", 1) live_telemetry.provider.get_tracer("test").start_span("probe").end() with (