name = "crewai-workspace" description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks." readme = "README.md" requires-python = ">=3.10,<3.14" authors = [ { name = "Joao Moura", email = "joao@crewai.com" } ] [dependency-groups] dev = [ "ruff==0.15.1", "mypy==1.19.1", "pre-commit==4.5.1", "bandit==1.9.2", "pytest==9.0.3", "pytest-asyncio==1.3.0", "pytest-subprocess==1.5.3", "vcrpy==8.2.1", # pinned, lower versions break pytest-recording "pytest-recording==0.13.4", "pytest-randomly==4.0.1", "pytest-timeout==2.4.0", "pytest-xdist==3.8.0", "pytest-split==0.11.0", "types-requests~=2.31.0.6", "types-pyyaml==6.0.*", "types-regex==2026.1.15.*", "types-appdirs==1.4.*", "boto3-stubs[bedrock-runtime]==1.42.40", "types-psycopg2==2.9.21.20251012", "types-pymysql==1.1.0.20250916", "types-aiofiles~=25.1.0", "types-redis~=4.6", "commitizen>=4.13.9", "pip-audit==2.9.0", ] [tool.ruff] src = ["lib/*"] extend-exclude = [ "lib/crewai/src/crewai/cli/templates", "lib/cli/src/crewai_cli/templates", "lib/crewai/tests/", "lib/crewai-tools/tests/", "lib/cli/tests/", ] respect-gitignore = true force-exclude = true fix = true target-version = "py310" [tool.ruff.format] docstring-code-format = true [tool.ruff.lint] future-annotations = true extend-select = [ "E", # pycodestyle errors (style issues) "F", # Pyflakes (code errors) "B", # flake8-bugbear (bug prevention) "S", # bandit (security issues) "RUF", # ruff-specific rules "N", # pep8-naming (naming conventions) "W", # pycodestyle warnings "I", # isort (import formatting) "T", # flake8-print (print statements) # "D", # pydocstyle (docstring conventions) disabled until "PERF", # performance issues "PIE", # flake8-pie (unnecessary code) "TID", # flake8-tidy-imports (import best practices) "ASYNC", # async/await best practices "RET", # flake8-return (return improvements) "SIM118", # use `key in dict` instead of `key in dict.keys()` "UP006", # use collections.abc "UP007", # use X | Y for unions "UP035", # use dict/list instead of typing.Dict/List "UP037", # remove quotes from type annotations "UP045", # use X | None instead of Optional[X] "UP004", # use isinstance instead of type "UP008", # use super() instead of super(Class, self) "UP010", # use isinstance for type checks "UP018", # use str() instead of "string" "UP031", # use f-strings for .format() "UP032", # use f-strings for .format() with positional "I001", # sort imports "I002", # remove unused imports ] ignore = ["E501"] # ignore line too long globally [tool.ruff.lint.flake8-tidy-imports] ban-relative-imports = "all" [tool.ruff.lint.flake8-type-checking] runtime-evaluated-base-classes = ["pydantic.BaseModel"] [tool.ruff.lint.isort] no-sections = false case-sensitive = true combine-as-imports = true force-single-line = false force-sort-within-sections = true known-first-party = [] section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"] lines-after-imports = 2 split-on-trailing-comma = true [tool.ruff.lint.pydocstyle] convention = "google" ignore-decorators = ["typing.overload"] [tool.ruff.lint.per-file-ignores] "lib/crewai/tests/**/*.py" = ["S101", "RET504", "S105", "S106"] # Allow assert statements, unnecessary assignments, and hardcoded passwords in tests "lib/crewai-tools/tests/**/*.py" = ["S101", "RET504", "S105", "S106", "RUF012", "N818", "E402", "RUF043", "S110", "B017"] # Allow various test-specific patterns "lib/crewai-files/tests/**/*.py" = ["S101", "RET504", "S105", "S106", "B017", "F841"] # Allow assert statements and blind exception assertions in tests "lib/cli/tests/**/*.py" = ["S101", "RET504", "S105", "S106"] # Allow assert statements in tests "lib/crewai-core/tests/**/*.py" = ["S101", "RET504", "S105", "S106"] # Allow assert statements in tests "lib/devtools/tests/**/*.py" = ["S101"] [tool.mypy] strict = true disallow_untyped_defs = true disallow_any_unimported = true no_implicit_optional = true check_untyped_defs = true warn_return_any = true show_error_codes = true warn_unused_ignores = true python_version = "3.12" exclude = "(?x)(^lib/crewai/src/crewai/cli/templates/|^lib/cli/src/crewai_cli/templates/|^lib/crewai/tests/|^lib/crewai-tools/tests/|^lib/crewai-files/tests/|^lib/cli/tests/|^lib/devtools/tests/)" plugins = ["pydantic.mypy"] [tool.bandit] exclude_dirs = ["lib/crewai/src/crewai/cli/templates", "lib/cli/src/crewai_cli/templates"] [tool.pytest.ini_options] markers = [ "telemetry: mark test as a telemetry test (don't mock telemetry)", ] testpaths = [ "lib/crewai/tests", "lib/crewai-tools/tests", "lib/crewai-files/tests", "lib/cli/tests", "lib/crewai-core/tests", ] asyncio_mode = "strict" asyncio_default_fixture_loop_scope = "function" addopts = "--tb=short -n auto --timeout=60 --dist=loadfile --max-worker-restart=2 --block-network --import-mode=importlib" python_files = "test_*.py" python_classes = "Test*" python_functions = "test_*" [tool.commitizen] name = "cz_customize" version_provider = "scm" tag_format = "$version" allowed_prefixes = ["Merge", "Revert"] changelog_incremental = true update_changelog_on_bump = false [tool.commitizen.customize] schema = "(): " schema_pattern = "^(feat|fix|refactor|perf|test|docs|chore|ci|style|revert)(\\(.+\\))?!?: .{1,72}" bump_pattern = "^(feat|fix|perf|refactor|revert)" bump_map = { feat = "MINOR", fix = "PATCH", perf = "PATCH", refactor = "PATCH", revert = "PATCH" } info = "Commits must follow Conventional Commits 1.0.0." [tool.uv] exclude-newer = "3 days" # These security fixes are newer than the global supply-chain cutoff. exclude-newer-package = { pypdf = "2026-08-07T00:00:00Z", msgpack = "2026-06-20T00:00:00Z", pydantic-settings = "2026-06-20T00:00:00Z", langsmith = "2026-06-20T00:00:00Z", gitpython = "2026-08-05T00:00:00Z" } # composio-core pins rich<14 but textual requires rich>=14. # onnxruntime 1.24+ dropped Python 3.10 wheels; cap it so qdrant[fastembed] resolves on 3.10. # fastembed 0.7.x and docling 2.63 cap pillow<12; the removed APIs don't affect them. # langchain-core <1.2.31 has GHSA-926x-3r5x-gfhw and is required by langchain-text-splitters 1.1.2+. # langchain-core 1.0.0-1.3.2 has GHSA-pjwx-r37v-7724 (unsafe deserialization via broad load() allowlists); force 1.3.3+. # langchain-text-splitters <1.1.2 has GHSA-fv5p-p927-qmxr (SSRF bypass in split_text_from_url). # transformers 4.57.6 has CVE-2026-1839; force 5.4+ (docling 2.84 allows huggingface-hub>=1). # cryptography 46.0.6 has CVE-2026-39892; force 46.0.7+. # cryptography <=48.0.x has GHSA-m2h6-j472-rp4c, GHSA-jwv3-5hgf-82ww; fixed in 49.0.0. # cryptography <50.0.0 has GHSA-g6cj-pr64-35w5 (PKCS#7 Bleichenbacher oracle); force 50.0.0+. # pypdf <6.10.2 has GHSA-4pxv-j86v-mhcw, GHSA-7gw9-cf7v-778f, GHSA-x284-j5p8-9c5p. # pypdf <6.14.2 has GHSA-jm82-fx9c-mx94 and GHSA-5qjq-93h5-hrgp/GHSA-55h5-xmcq-c37v/GHSA-g867-7843-wf8q/GHSA-5xf7-4p34-54qr; force 6.14.2+. # pypdf <6.15.0 has GHSA-fwg2-594c-jp42 and GHSA-fp3f-mc75-235c (unbounded runtime/memory on large content # and /ToUnicode streams); force 6.15.0+. Its exclude-newer-package cutoff is bumped to 2026-08-07 to admit # that release. # uv <0.11.15 has GHSA-4gg8-gxpx-9rph (and earlier GHSA-pjjw-68hj-v9mw); force 0.11.15+. # python-multipart <0.0.27 has GHSA-pp6c-gr5w-3c5g (DoS via unbounded multipart headers). # gitpython <3.1.50 has GHSA-mv93-w799-cj2w (config_writer newline injection bypassing the 3.1.49 patch -> RCE via core.hooksPath). # gitpython <3.1.51 has GHSA-2f96-g7mh-g2hx, GHSA-v396-v7q4-x2qj, and GHSA-956x-8gvw-wg5v. # gitpython <=3.1.51 has GHSA-rwj8-pgh3-r573; fixed in 3.1.52. # gitpython 3.1.52 has GHSA-3rp5-jjmw-4wv2, GHSA-fjr4-x663-mwxc, GHSA-6p8h-3wgx-97gf, and GHSA-r9mr-m37c-5fr3; force 3.1.55+. # gitpython <3.1.56 has GHSA-p538-c434-8v24 (arbitrary file truncation via `git rev-list --output` argument # injection) and <3.1.57 has GHSA-3f7w-8rr8-f37f (unguarded git option forwarding in IndexFile.checkout and # TagReference); force 3.1.57+. # gitpython <3.1.58 has GHSA-9rj7-rf2p-w77r, GHSA-4gmw-gg2m-w46p, GHSA-hh9p-6wh2-4mfc, GHSA-wvpp-8hx9-p66j and # GHSA-jm78-9fvv-mhgr (further unguarded git option forwarding in Repo.init, read-tree and git-config, plus # arbitrary file read via --pathspec-from-file); force 3.1.58+. Its exclude-newer-package cutoff is bumped to # 2026-08-05 to admit that release. # pyasn1 <0.6.4 has GHSA-8ppf-4f7h-5ppj and GHSA-hm4w-wwcw-mr6r; force 0.6.4+. # urllib3 <2.7.0 has GHSA-qccp-gfcp-xxvc (ProxyManager cross-origin redirect leaks Authorization/Cookie) and GHSA-mf9v-mfxr-j63j (streaming decompression-bomb bypass); force 2.7.0+. # langsmith <0.8.18 has GHSA-3644-q5cj-c5c7 (public prompt manifest deserialization, SSRF/secret disclosure) # and GHSA-f4xh-w4cj-qxq8; force 0.8.18+. # authlib <1.6.12 has GHSA-jj8c-mmj3-mmgv (CSRF bypass in cache-based state storage) and PYSEC-2026-188. # pip 26.1.1 has PYSEC-2026-196; force 26.1.2+. # aiohttp <=3.13.x has GHSA-jg22-mg44-37j8, GHSA-hg6j-4rv6-33pg; fixed in 3.14.0; force 3.14.0+. # aiohttp <=3.14.1 has GHSA-mq44-7p77-q5h7, GHSA-mfx4-hv73-q22v; fixed in 3.14.2. # aiohttp <=3.14.2 has GHSA-cq5v-8q36-5273 (C parser OOB read); force 3.14.3+. # docling-core 2.74.0 has GHSA-j5xp-7m2f-49jv, GHSA-jmmv-h3mp-59v8; force 2.74.1+. # pip <26.1.1 has GHSA-58qw-9mgm-455v (archive handling); OSV considers 26.1.1 unaffected. # paramiko <5.0.0 has GHSA-r374-rxx8-8654 (SHA-1 in rsakey.py); OSV considers 5.0.0 unaffected. Transitive via composio-core. # starlette <1.3.1 has PYSEC-2026-161, GHSA-jp82-jpqv-5vv3, and GHSA-82w8-qh3p-5jfq. Transitive via fastapi. # msgpack <1.2.1 has GHSA-6v7p-g79w-8964; transitive via pip-audit[filecache]. # nltk <3.10.0 has GHSA-qvv7-cg9c-w4x3 (DNS-rebinding SSRF bypass in # nltk.pathsec.urlopen), GHSA-fg7f-2386-8897 (ReDoS in ReviewsCorpusReader), and # GHSA-xh95-f55m-82fw (path traversal in FramenetCorpusReader.frame); all fixed # in 3.10.0. 3.10.0 also clears PYSEC-2026-597, whose last affected version is # 3.9.4, so that ignore is no longer needed. Transitive via # crewai-tools[xml] -> unstructured. # pydantic-settings <2.14.2 has GHSA-4xgf-cpjx-pc3j. # h2 <=4.4.0 has GHSA-6hr6-w5qg-qmwg (CVE-2026-71554): duplicate Host headers # can facilitate request smuggling; fixed in 4.4.1. Transitive via # qdrant-client -> httpx[http2]. # Keep OpenAI on the SDK range required by CrewAI when transitive dependencies # loosen or pin their own lower versions. override-dependencies = [ "openai>=2.30.0,<3", "rich>=13.7.1", "onnxruntime<1.24; python_version < '3.11'", "pillow>=12.3.0", "langchain-core>=1.3.3,<2", "langchain-text-splitters>=1.1.2,<2", "urllib3>=2.7.0", "transformers>=5.4.0; python_version >= '3.10'", "cryptography>=50.0.0", "pypdf>=6.15.0,<7", "uv>=0.11.15,<1", "python-multipart>=0.0.27,<1", "gitpython>=3.1.58,<4", "pyasn1>=0.6.4", "langsmith>=0.8.18,<1", "authlib>=1.6.12", "pip>=26.1.2", "aiohttp>=3.14.3", # [chunking] carried here because override-dependencies replace the whole # requirement; without it the docling extra's chunking deps get stripped. "docling-core[chunking]>=2.74.1", "paramiko>=5.0.0", "starlette>=1.3.1", "msgpack>=1.2.1", "pydantic-settings>=2.14.2", "setuptools>=83.0.0", # PYSEC-2026-3447 "nltk>=3.10.0", "h2>=4.4.1", ] [tool.uv.workspace] members = [ "lib/crewai", "lib/crewai-tools", "lib/devtools", "lib/crewai-files", "lib/cli", "lib/crewai-core", ] [tool.uv.sources] crewai = { workspace = true } crewai-tools = { workspace = true } crewai-devtools = { workspace = true } crewai-files = { workspace = true } crewai-cli = { workspace = true } crewai-core = { workspace = true }