refactor(skills): move Skills Repository to experimental + CREWAI_EXPERIMENTAL gate

Moves the registry/cache pieces of PR #5867 under crewai.experimental.skills
and the CLI commands under `crewai experimental skill`. The stable local-file
skills feature (loader, parser, validation, models) stays in crewai.skills.

Both entry points now require CREWAI_EXPERIMENTAL=1:
- resolve_registry_ref() calls require_experimental_skills() before resolving
- The `crewai experimental` CLI group raises UsageError when the flag is unset

SkillDownloadStarted/CompletedEvent move out of crewai.events.types.skill_events
into crewai.experimental.skills.events.

* refactor(skills): move 'version' off SkillFrontmatter into metadata

The skill version is now stored as `metadata.version` rather than a
top-level field on `SkillFrontmatter`. A `before` validator lifts any
top-level YAML `version:` into `metadata['version']` so existing SKILL.md
files keep parsing.
This commit is contained in:
Greyson LaLonde
2026-05-28 09:38:10 -07:00
committed by GitHub
parent 2148c7ed77
commit ed91100a0f
23 changed files with 193 additions and 84 deletions

View File

@@ -17,6 +17,7 @@ from crewai_cli.crew_chat import run_chat
from crewai_cli.deploy.main import DeployCommand
from crewai_cli.enterprise.main import EnterpriseConfigureCommand
from crewai_cli.evaluate_crew import evaluate_crew
from crewai_cli.experimental.skills.main import SkillCommand
from crewai_cli.install_crew import install_crew
from crewai_cli.kickoff_flow import kickoff_flow
from crewai_cli.organization.main import OrganizationCommand
@@ -26,7 +27,6 @@ from crewai_cli.replay_from_task import replay_task_command
from crewai_cli.reset_memories_command import reset_memories_command
from crewai_cli.run_crew import run_crew
from crewai_cli.settings.main import SettingsCommand
from crewai_cli.skills.main import SkillCommand
from crewai_cli.task_outputs import load_task_outputs
from crewai_cli.tools.main import ToolCommand
from crewai_cli.train_crew import train_crew
@@ -544,8 +544,19 @@ def tool_publish(is_public: bool, force: bool) -> None:
@crewai.group()
def experimental() -> None:
"""Experimental, unstable commands. Subject to change without notice."""
import os
if os.environ.get("CREWAI_EXPERIMENTAL") != "1":
raise click.UsageError(
"Experimental commands are gated. Set CREWAI_EXPERIMENTAL=1 to enable."
)
@experimental.group(name="skill")
def skill() -> None:
"""Skill Repository related commands."""
"""Skill Repository related commands (experimental)."""
@skill.command(name="create")

View File

@@ -23,9 +23,10 @@ console = Console()
_SKILL_MD_TEMPLATE = """\
---
name: {name}
version: 0.1.0
description: |
A short description of what this skill does.
metadata:
version: 0.1.0
---
## Instructions
@@ -147,7 +148,7 @@ class SkillCommand(BaseCommand, PlusAPIMixin):
)
else:
try:
from crewai.skills.cache import SkillCacheManager
from crewai.experimental.skills.cache import SkillCacheManager
cache = SkillCacheManager()
cache.store(org, name, version, archive_bytes)
@@ -191,7 +192,10 @@ class SkillCommand(BaseCommand, PlusAPIMixin):
raise SystemExit(1) from exc
name = frontmatter.get("name")
version = frontmatter.get("version")
raw_metadata = frontmatter.get("metadata")
version = (
raw_metadata.get("version") if isinstance(raw_metadata, dict) else None
)
description = frontmatter.get("description")
if not name:
@@ -362,10 +366,13 @@ class SkillCommand(BaseCommand, PlusAPIMixin):
return result
def _read_version(self, skill_md: Path) -> str | None:
"""Read the version field from a SKILL.md file, or None."""
"""Read the version from a SKILL.md file's metadata, or None."""
try:
fm = self._parse_frontmatter(skill_md.read_text())
return fm.get("version")
raw_metadata = fm.get("metadata")
if isinstance(raw_metadata, dict):
return raw_metadata.get("version")
return None
except Exception:
return None