Skip to content

feat(skills): support extends: bundled in SKILL.md to allow extending bundled skills #2379

@wenshao

Description

@wenshao

Summary

The bundled /review skill ships with 4 fixed review dimensions (Correctness & Security, Code Quality, Performance & Efficiency, Undirected Audit). Users who want to add custom review dimensions (e.g., Accessibility, API Compatibility, Compliance) currently have to copy the entire SKILL.md into .qwen/skills/review/SKILL.md and maintain it themselves — a full override with no composition.

This proposal adds a generic extends: bundled mechanism to the skill system, allowing users to append content to a bundled skill without replacing it entirely.

Motivation

Different teams care about different review aspects:

  • Frontend teams may want an Accessibility dimension
  • API teams may want an API Compatibility dimension
  • Regulated industries may want a Compliance & Privacy dimension

The current skill precedence system (project > user > extension > bundled) only supports full replacement. This forces users to fork the bundled SKILL.md, losing future updates. A composition mechanism solves this cleanly.

Design

User experience

Create .qwen/skills/review/SKILL.md:

---
name: review
extends: bundled
---

### Agent 5: Accessibility

Focus areas:

- ARIA attributes and roles on interactive elements
- Keyboard navigation support
- Screen reader compatibility
- Color contrast ratios

### Agent 6: API Compatibility

Focus areas:

- Breaking changes to public APIs
- Backward compatibility of data formats

When /review is invoked, the user's body is appended to the bundled skill's body. The LLM sees all 6 dimensions and launches 6 parallel review agents.

Implementation

1. SkillConfig type (packages/core/src/skills/types.ts)

Add optional field:

extends?: SkillLevel;

2. SkillManager.loadSkill (packages/core/src/skills/skill-manager.ts)

When a skill has extends: bundled:

  • Load the bundled skill with the same name
  • Concatenate: bundledSkill.body + "\n\n" + extendingSkill.body
  • Return the merged result
if (skill.extends === 'bundled') {
  const base = await this.findSkillByNameAtLevel(skill.name, 'bundled');
  if (!base) {
    throw new SkillError(`Cannot extend: bundled skill "${skill.name}" not found`, SkillErrorCode.NOT_FOUND);
  }
  skill.body = base.body + '\n\n' + skill.body;
  skill.extends = undefined; // mark as resolved
}

3. SKILL.md wording (packages/core/src/skills/bundled/review/SKILL.md)

-Launch **four parallel review agents** to analyze the changes from different angles.
+Launch **parallel review agents** (one per dimension listed below) to analyze the changes from different angles.
-Combine results from all four agents into a single, well-organized review.
+Combine results from all agents into a single, well-organized review.

What this does NOT change

  • BundledSkillLoader — remains generic, no skill-specific logic
  • settings.json — no new settings
  • Directory conventions — reuses existing .qwen/skills/
  • File watching — .qwen/skills/ is already watched

Edge cases

Scenario Behavior
extends: bundled but no bundled skill with that name Error: Cannot extend: bundled skill "xxx" not found
No extends field Current behavior (full override), no breaking change
extends with a value other than bundled Error: unsupported (v1 only supports bundled)
Extending skill has empty body Use bundled body as-is, emit warning
User wants to disable a built-in dimension Add natural language instruction in appended body (e.g., "**Skip the Undirected Audit dimension
above.**") — the review is LLM-driven, so this works

Scope

  • packages/core/src/skills/types.ts — add extends field
  • packages/core/src/skills/skill-manager.ts — extend resolution logic (~20 lines)
  • packages/core/src/skills/bundled/review/SKILL.md — dynamic agent count wording
  • Tests for the above

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions