How to Build Custom Skills in Qwen Code: Best Practices and Implementation Guide

To build effective custom Skills in Qwen Code, create a self-contained directory with a SKILL.md manifest, use lowercase hyphenated names, and write keyword-rich descriptions that explain both what the skill does and when the model should invoke it.

Qwen Code treats Skills as modular capabilities that extend the agent's functionality through self-contained directories discovered at runtime. Each skill relies on a SKILL.md manifest file that the SkillManager ([packages/core/src/skills/skill-manager.ts](https://github.com/QwenLM/qwen-code/blob/main/packages/core/src/skills/skill-manager.ts)) parses, validates, and caches, while the SkillTool ([packages/core/src/tools/skill.ts](https://github.com/QwenLM/qwen-code/blob/main/packages/core/src/tools/skill.ts)) handles dynamic registration and invocation. Mastering the architecture and following established conventions ensures your custom skills integrate seamlessly with the agent's tool system.

Understanding the Skill Architecture

The Skill subsystem operates through a coordinated pipeline involving discovery, caching, and dynamic tool registration. When Qwen Code starts, the SkillManager scans three distinct locations for skill directories:

  • Personal Skills: ~/.qwen/skills/
  • Project Skills: .qwen/skills/ in the current repository
  • Extension Skills: Provided by installed extensions

The Discovery and Caching Pipeline

The manager executes a structured discovery process via SkillManager.listSkills, which walks the skill directories and processes each SKILL.md through parseSkillFileInternal. During parsing, SkillManager.validateConfig ensures that mandatory fields (name and description) are present and non-empty, storing valid configurations in the skillsCache. The system uses chokidar to watch skill bases and calls scheduleRefresh to hot-reload changes without restarting the agent.

Runtime Tool Integration

The SkillTool registers a change listener on the manager; on any cache update, it triggers refreshSkills and rebuilds the tool definition via updateDescriptionAndSchema. This injects a dynamically generated JSON schema into the LLM's available tools. When the model invokes the tool, SkillToolInvocation calls SkillManager.loadSkillForRuntime to resolve the base directory and return the skill's body content, enabling the model to execute any referenced scripts or templates.

Folder Structure and Naming Conventions

Consistent organization prevents parsing errors and ensures the manager correctly indexes your capabilities.

Directory Layout

Store each skill in its own folder with SKILL.md at the root. The manager expects this specific file to define the skill configuration. You may include optional subdirectories such as scripts/, templates/, or docs/ to support the skill's operation:

.qwen/skills/pdf-extractor/
├── SKILL.md
├── scripts/
│   └── extract.py
└── templates/
    └── prompt.txt

Naming Standards

Use lowercase, hyphen-separated names (e.g., pdf-extractor, git-commit-generator). Avoid spaces or special characters. These names become keys in the skillsCache and identifiers in the JSON schema passed to the model; simple strings prevent collisions and parsing errors during tool registration.

Writing an Effective SKILL.md Manifest

The manifest serves as both configuration and documentation, directly impacting whether the model selects your skill during inference.

Required Front-Matter Fields

Every SKILL.md must include YAML front-matter with these mandatory fields:

  • name: The unique identifier (match the folder name)
  • description: A detailed explanation of functionality
  • allowedTools (optional): Array of built-in tool names the skill may invoke

The SkillManager.parseSkillContent function validates that name and description are non-empty strings. The allowedTools array restricts which base capabilities the skill can access during execution.

Description Quality and Model Discovery

Write descriptions that specify what the skill does and when it should be used. Include keyword-rich phrasing that matches likely user requests. The SkillTool.updateDescriptionAndSchema method embeds this text directly into the tool definition consumed by the LLM, making the description the primary signal for model selection.

Skill Precedence and Scope Management

Understanding how Qwen Code resolves duplicate names and manages capability boundaries prevents conflicts.

Loading Priority

Skills follow a strict precedence order when names collide: Project → User → Extension. If a project-level skill shares a name with a personal-level skill, the project version wins. The SkillManager.listSkills method handles this via internal seenNames tracking during the discovery phase.

Scope Isolation

Keep each skill focused on a single capability (e.g., extract-pdf-text rather than document-processor). Narrow scope prevents ambiguous matches and reduces the probability of name collisions across different skill levels.

Development, Testing, and Debugging

Validate your skills before deploying them to team members.

Validation and Error Checking

Run qwen --debug after creating a skill to surface YAML parsing errors or validation failures. Errors are recorded in SkillManager.parseErrors and logged through the centralized debugLogger system ([packages/core/src/utils/debugLogger.ts](https://github.com/QwenLM/qwen-code/blob/main/packages/core/src/utils/debugLogger.ts)).

Testing Skill Discovery

Prompt the model with a request that should trigger the skill (e.g., "Extract tables from this PDF"). Verify that the agent calls the Skill tool first. If the model fails to select the skill, refine the description to include clearer trigger phrases.

Security and Collaboration Best Practices

Safe skill development requires attention to both data protection and team workflows.

Security Considerations

Never embed secrets, API keys, or credentials in SKILL.md or supporting scripts. Skills execute within the agent's sandbox, not a trusted environment. Reference external configuration or environment variables for sensitive data.

Sharing Skills

Place shared skills under .qwen/skills/ in your repository and commit them to version control. Teammates automatically load these capabilities on their next startup, enabling collaborative workflows without additional configuration.

Complete Example: PDF Extractor Skill

The following demonstrates a minimal yet complete skill implementation.

Directory structure:

~/.qwen/skills/pdf-extractor/
├── SKILL.md
├── scripts/
│   └── extract.py
└── templates/
    └── prompt.txt

SKILL.md content:

---
name: pdf-extractor
description: Extract plain text and tables from PDF files. Use when a user asks to read or summarize a PDF document.
allowedTools:
  - web-fetch
  - bash
---

# PDF Extractor Skill

The skill provides a small Python helper that uses `pdfminer.six` to read PDFs.

## How to use

1. Call the skill with `skill: "pdf-extractor"`.
2. In the returned body you will see the absolute base directory.
3. Run the helper script from the base directory, e.g.:

```bash
python scripts/extract.py path/to/file.pdf

The script prints the extracted text to stdout.


**Installation commands:**

```bash
mkdir -p ~/.qwen/skills/pdf-extractor/scripts
cat > ~/.qwen/skills/pdf-extractor/SKILL.md <<'EOF'
--- (content from above) ---
EOF

# Add your Python script under scripts/extract.py

When a user asks to process a PDF, the model invokes the Skill tool with {"skill": "pdf-extractor"}, receiving the skill body and base directory path to execute python scripts/extract.py.

Summary

  • Structure: Create self-contained directories with SKILL.md at the root and optional subfolders for scripts or templates.
  • Naming: Use lowercase, hyphen-separated identifiers to prevent cache collisions and schema parsing errors.
  • Manifest: Include mandatory name and description fields in YAML front-matter; add allowedTools to restrict capability access.
  • Discovery: The SkillManager scans personal, project, and extension directories, with project-level skills taking precedence over user-level ones.
  • Description: Write specific, keyword-rich descriptions explaining both functionality and invocation triggers to ensure model discoverability.
  • Security: Keep secrets out of skill files; commit shared skills to .qwen/skills/ for team collaboration.

Frequently Asked Questions

What naming convention should I use for custom Skills in Qwen Code?

Use lowercase, hyphen-separated names such as pdf-extractor or git-commit-msg. Avoid spaces or special characters because the skill name becomes a key in the internal skillsCache and appears in the JSON schema provided to the LLM.

How does Qwen Code handle duplicate skill names across different directories?

The system applies a precedence hierarchy: Project skills override User skills, which override Extension skills. The SkillManager.listSkills method tracks seenNames during discovery and keeps only the first occurrence encountered in that priority order.

Why is my custom Skill not appearing in the tool list?

Run qwen --debug to check for YAML parsing errors or validation failures in SkillManager.parseErrors. Ensure your SKILL.md includes non-empty name and description fields in the front-matter, and verify the file is located in one of the three valid skill directories (~/.qwen/skills/, .qwen/skills/, or an extension path).

Can I restrict which built-in tools my custom Skill can access?

Yes. Include the optional allowedTools array in your SKILL.md front-matter, listing specific tool names such as bash, web-fetch, or read-file. The SkillManager validates this configuration and the execution context respects these boundaries during runtime.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →