UAT: SkillConfigSchema.from_yaml() rejects spec-compliant skill YAML with skill: wrapper key and cleveragents: version header #2481

Open
opened 2026-04-03 18:37:16 +00:00 by freemo · 1 comment
Owner

Metadata

  • Branch: fix/skill-yaml-wrapper-key-parsing
  • Commit Message: fix(skills): handle spec-compliant skill: wrapper key and cleveragents: version header in SkillConfigSchema
  • Milestone: v3.6.0
  • Parent Epic: #392

Summary

SkillConfigSchema.from_yaml() and from_yaml_file() fail with a ValidationError when given skill YAML files that follow the spec-defined format. The spec shows skill YAML files with two structural elements that the current parser does not handle:

  1. A top-level skill: wrapper key containing the skill definition
  2. A top-level cleveragents: version: "3.0" version header

Both of these cause SkillConfigSchema to raise a pydantic.ValidationError because:

  • extra="forbid" is set on SkillConfigSchema, so unknown top-level keys like cleveragents: are rejected
  • The skill: wrapper key is not unwrapped before validation, so the schema sees {"skill": {...}} instead of the skill fields directly

Expected Behavior (from spec)

The specification (docs/specification.md, Skill Configuration Files section) shows the canonical skill YAML format as:

# File: skills/devops-toolkit.yaml
cleveragents:
  version: "3.0"

skill:
  name: local/devops-toolkit
  description: "Full-stack development tools..."
  tools:
    - local/run-migrations
  includes:
    - local/file-ops

SkillConfigSchema.from_yaml() should parse this format correctly, unwrapping the skill: key and ignoring the cleveragents: version header.

Actual Behavior

yaml_content = """
cleveragents:
  version: "3.0"

skill:
  name: local/devops-toolkit
  description: "Full-stack development tools"
"""
SkillConfigSchema.from_yaml(yaml_content)
# Raises: pydantic.ValidationError
# - cleveragents: Extra inputs are not permitted
# - name: Field required (because skill: wrapper is not unwrapped)

Code Location

  • src/cleveragents/skills/schema.pySkillConfigSchema.from_yaml() and from_yaml_file()
  • The _normalize_keys() helper does camelCase normalization but does not unwrap skill: or strip cleveragents:

Comparison: Tool CLI handles this correctly

The agents tool add CLI (src/cleveragents/cli/commands/tool.py) already handles the analogous tool: wrapper key:

# Handle spec-compliant 'tool:' wrapper key format
if isinstance(config_dict, dict) and "tool" in config_dict:
    config_dict = config_dict["tool"]

# Ignore 'cleveragents:' version header if present
if isinstance(config_dict, dict) and "cleveragents" in config_dict:
    del config_dict["cleveragents"]

The same pattern must be applied in SkillConfigSchema.from_yaml().

Subtasks

  • In SkillConfigSchema.from_yaml(), after yaml.safe_load(), check if the top-level dict has a skill: key and unwrap it
  • Strip the cleveragents: key from the top-level dict before validation
  • Add unit tests (Behave) for spec-compliant YAML with skill: wrapper and cleveragents: header
  • Ensure from_yaml_file() delegates to the updated from_yaml() (it already does)

Definition of Done

  • SkillConfigSchema.from_yaml() successfully parses skill YAML files with skill: wrapper key and cleveragents: version header
  • SkillConfigSchema.from_yaml() continues to parse flat YAML (without wrapper) for backward compatibility
  • Unit tests cover both formats
  • nox -e unit_tests passes

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-uat-tester

## Metadata - **Branch**: `fix/skill-yaml-wrapper-key-parsing` - **Commit Message**: `fix(skills): handle spec-compliant skill: wrapper key and cleveragents: version header in SkillConfigSchema` - **Milestone**: v3.6.0 - **Parent Epic**: #392 ## Summary `SkillConfigSchema.from_yaml()` and `from_yaml_file()` fail with a `ValidationError` when given skill YAML files that follow the spec-defined format. The spec shows skill YAML files with two structural elements that the current parser does not handle: 1. A top-level `skill:` wrapper key containing the skill definition 2. A top-level `cleveragents: version: "3.0"` version header Both of these cause `SkillConfigSchema` to raise a `pydantic.ValidationError` because: - `extra="forbid"` is set on `SkillConfigSchema`, so unknown top-level keys like `cleveragents:` are rejected - The `skill:` wrapper key is not unwrapped before validation, so the schema sees `{"skill": {...}}` instead of the skill fields directly ## Expected Behavior (from spec) The specification (`docs/specification.md`, Skill Configuration Files section) shows the canonical skill YAML format as: ```yaml # File: skills/devops-toolkit.yaml cleveragents: version: "3.0" skill: name: local/devops-toolkit description: "Full-stack development tools..." tools: - local/run-migrations includes: - local/file-ops ``` `SkillConfigSchema.from_yaml()` should parse this format correctly, unwrapping the `skill:` key and ignoring the `cleveragents:` version header. ## Actual Behavior ```python yaml_content = """ cleveragents: version: "3.0" skill: name: local/devops-toolkit description: "Full-stack development tools" """ SkillConfigSchema.from_yaml(yaml_content) # Raises: pydantic.ValidationError # - cleveragents: Extra inputs are not permitted # - name: Field required (because skill: wrapper is not unwrapped) ``` ## Code Location - `src/cleveragents/skills/schema.py` — `SkillConfigSchema.from_yaml()` and `from_yaml_file()` - The `_normalize_keys()` helper does camelCase normalization but does not unwrap `skill:` or strip `cleveragents:` ## Comparison: Tool CLI handles this correctly The `agents tool add` CLI (`src/cleveragents/cli/commands/tool.py`) already handles the analogous `tool:` wrapper key: ```python # Handle spec-compliant 'tool:' wrapper key format if isinstance(config_dict, dict) and "tool" in config_dict: config_dict = config_dict["tool"] # Ignore 'cleveragents:' version header if present if isinstance(config_dict, dict) and "cleveragents" in config_dict: del config_dict["cleveragents"] ``` The same pattern must be applied in `SkillConfigSchema.from_yaml()`. ## Subtasks - [ ] In `SkillConfigSchema.from_yaml()`, after `yaml.safe_load()`, check if the top-level dict has a `skill:` key and unwrap it - [ ] Strip the `cleveragents:` key from the top-level dict before validation - [ ] Add unit tests (Behave) for spec-compliant YAML with `skill:` wrapper and `cleveragents:` header - [ ] Ensure `from_yaml_file()` delegates to the updated `from_yaml()` (it already does) ## Definition of Done - `SkillConfigSchema.from_yaml()` successfully parses skill YAML files with `skill:` wrapper key and `cleveragents:` version header - `SkillConfigSchema.from_yaml()` continues to parse flat YAML (without wrapper) for backward compatibility - Unit tests cover both formats - `nox -e unit_tests` passes --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-uat-tester
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • MoSCoW: Should Have — Spec compliance or quality improvement that should be included in the milestone.

Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **MoSCoW**: Should Have — Spec compliance or quality improvement that should be included in the milestone. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
freemo added this to the v3.7.0 milestone 2026-04-05 05:07:09 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core#2481
No description provided.