Skip to content

refactor: extract CLI into standalone crewai-cli package#4884

Draft
greysonlalonde wants to merge 8 commits intomainfrom
gl/chore/refactor-cli
Draft

refactor: extract CLI into standalone crewai-cli package#4884
greysonlalonde wants to merge 8 commits intomainfrom
gl/chore/refactor-cli

Conversation

@greysonlalonde
Copy link
Contributor

Summary

  • Extracts the CLI from lib/crewai/src/crewai/cli/ into a standalone lib/cli/ package (crewai-cli) with its own pyproject.toml, entry point, and dependencies
  • Leaves a backward-compat shim in crewai.cli.cli that re-exports from crewai_cli when installed, or shows an install hint otherwise
  • Adds crewai[cli] optional extra to install the new package alongside crewai
  • Adds pre-flight validation to deploy commands to catch missing pyproject.toml, lockfile, or src/<name>/crew.py locally before hitting the server

Commit breakdown

Commit Description
c0689aa Scaffold lib/cli package and register as workspace member
4f9a8f4 Move all CLI source modules to crewai_cli with updated imports
3732de7 Move and adapt all CLI tests
96fc584 Remove old CLI from crewai package, add backward-compat shim
8fd7a73 Add deploy pre-flight validation (fixes blind server-side failures)

Test plan

  • uv run --package crewai-cli crewai --help works standalone
  • uv run --package crewai crewai --help works via the shim
  • uv run pytest lib/cli/tests/ — all new CLI tests pass
  • uv run pytest lib/crewai/tests/cli/ — remaining crewai CLI tests pass
  • crewai deploy create from a directory missing pyproject.toml shows pre-flight error
  • crewai deploy create from a directory missing lockfile shows pre-flight error

Add the new lib/cli package skeleton with pyproject.toml, README,
and __init__.py. Register it as a uv workspace member and update
root linting, mypy, bandit, and pytest config to include the new
package paths.
Copy all CLI source modules from lib/crewai/src/crewai/cli/ to the
new lib/cli/src/crewai_cli/ package, updating internal imports from
crewai.cli.* to crewai_cli.* throughout.

Includes: authentication, deploy, enterprise, organization, settings,
tools, triggers, templates, and all top-level CLI command modules.

Also excludes lib/cli/ from pre-commit mypy checks to match existing
behavior (original CLI code has the same type gaps).
Move and adapt all CLI tests from lib/crewai/tests/cli/ to
lib/cli/tests/, updating import paths from crewai.cli.* to
crewai_cli.* and adjusting mock targets accordingly.
Remove all CLI modules and tests that have been moved to the
crewai-cli package. Replace cli.py with a thin shim that re-exports
from crewai_cli when available, or shows an install hint otherwise.

Update crewai pyproject.toml to add a [cli] extra pointing to
crewai-cli and comment out the old entry point. Add py.typed marker
to crewai_cli for mypy compatibility.
# Conflicts:
#	lib/crewai/src/crewai/cli/cli.py
Validate that pyproject.toml, a lockfile (uv.lock or poetry.lock),
and the expected src/<project>/crew.py or config directory exist
locally before making any API calls. This surfaces clear, actionable
errors on the CLI instead of cryptic server-side deployment failures.
The backward-compat shim is unnecessary — nothing imports from
crewai.cli.cli and the entry point lives in crewai-cli now.
"""Tests for TokenManager with atomic file operations."""

import json
import os
self.settings = settings

@abstractmethod
def get_authorize_url(self) -> str: ...
def get_authorize_url(self) -> str: ...

@abstractmethod
def get_token_url(self) -> str: ...
def get_token_url(self) -> str: ...

@abstractmethod
def get_jwks_url(self) -> str: ...
def get_jwks_url(self) -> str: ...

@abstractmethod
def get_issuer(self) -> str: ...
def get_issuer(self) -> str: ...

@abstractmethod
def get_audience(self) -> str: ...
def get_audience(self) -> str: ...

@abstractmethod
def get_client_id(self) -> str: ...
self.assertEqual(self.api.api_key, self.api_key)
self.assertEqual(self.api.headers["Authorization"], f"Bearer {self.api_key}")
self.assertEqual(self.api.headers["Content-Type"], "application/json")
self.assertTrue("CrewAI-CLI/" in self.api.headers["User-Agent"])
selected_index = int(choice) - 1
if 0 <= selected_index < len(choices):
return choices[selected_index]
except ValueError:
file_path = storage_path / filename
try:
file_path.unlink()
except FileNotFoundError:
Ruff fails when checking .py files in the templates directory because
it discovers the nearby pyproject.toml which contains {{folder_name}}
placeholders that are invalid TOML. Add the new template path to the
CI grep filter, matching the existing exclusion for the original path.
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